home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / pcmagazi / pcmanage / dcompres.asm next >
Assembly Source File  |  1990-01-20  |  36KB  |  1,876 lines

  1. .MODEL    small
  2. cseg    segment para    public 'CODE'
  3. assume    cs:cseg
  4. include    sq.pub
  5. ;;;;;;;;;;;;;;;;;
  6. ;;
  7. ;;    DCOMPRES - Keeps track of last access time and date for a file,
  8. ;;                 decompresses already compressed files when accessed
  9. ;;    Copyright (c) 1989 by Ziff Communications Co.
  10. ;;    Program by Ross M. Greenberg  Version 1.1
  11. ;;;;;;;;;;;;;;;;;
  12.  
  13.  
  14. org    100h
  15.  
  16. TRUE        equ    1
  17. FALSE        equ    0
  18. NULL        equ    0
  19.  
  20. CR    equ    0dh
  21. LF    equ    0ah
  22. BELL    equ    07h
  23.  
  24. start:
  25.     jmp    install                ; It's traditional!
  26.  
  27. MAX_FILES    equ    100            ; max files in index
  28. FN_SIZE        equ    14            ; filename + dot + extension
  29. MAX_FN_SIZE    equ    64 + FN_SIZE        ; and the maximum path
  30.  
  31. ;;;;;;;;;;;;;;;;;
  32. ;; this structure should be an even number of bytes or contortions in C will
  33. ;; occur
  34. ;;;;;;;;;;;;;;;;
  35. file    struc
  36.     filename_len    dw    0
  37.     filename    db    FN_SIZE    dup (0)
  38.     left_ptr    dw    0
  39.     right_ptr    dw    0
  40.     date        dw    2    dup (0)
  41.     time        dw    2    dup (0)
  42.     status        db    0    ;normal = 0, compressed = 1 , del = 2
  43.     access_cnt    db    0    ; extra byte. Why not?
  44. file    ends
  45.  
  46. BUF_SIZE    equ    size file * MAX_FILES
  47.  
  48. NORMAL        equ    0
  49. COMPRESSED    equ    1
  50. DELETED        equ    2
  51.  
  52.  
  53. num_files    dw    0        ;don't separate these three!!!
  54. dir_name2    db    MAX_FN_SIZE    dup(0)
  55. buffer        db    BUF_SIZE    dup(0)
  56.  
  57. tag        db    0cdh, 020h, 'PCOMPRES'    ; don't separate these two
  58. TAG_LEN        equ    $ - tag
  59. file_out    db    'PCOMPRES.$$$', 0     ; or these two
  60. FILE_OUT_LEN    equ    $ - file_out
  61. index_name    db    'INDEX.CMP',0        ; don;t separate these two
  62. INDEX_NAME_LEN    equ    $ - index_name
  63.  
  64.  
  65. dir_name    db    MAX_FN_SIZE    dup(0)
  66. dir_name3    db    MAX_FN_SIZE    dup(0)
  67. dir_name4    db    MAX_FN_SIZE    dup(0)
  68. file_name    db    FN_SIZE        dup(0)
  69. tmp_buffer    db    MAX_FN_SIZE    dup(0)
  70. tmp_buf2    db    FN_SIZE        dup(0)
  71. dos_handle    dw    0
  72. in_handle    dw    0
  73. was_compressed    dw    0
  74. tmp_len        dw    0
  75. my_psp        dw    0
  76. users_psp    dw    0
  77. index_handle    dw    0
  78. file_seg    dw    0
  79. file_off    dw    0
  80. dirty_bit    dw    0
  81. in_use        dw    0
  82. switch_off    dw    0
  83. last_dos    dw    0
  84. old_dx        dw    0
  85. ignore_status    dw    0
  86. attributes    dw    1
  87. old_attrb    dw    0
  88. dos_ver1    db    0
  89. dos_ver2    db    0
  90. tag_buf        db    TAG_LEN    dup    (0)
  91.  
  92. table    struc
  93.     cmp_code    dw    0
  94.     suffix        db    0
  95. table    ends
  96.  
  97. MAX_CODE    equ    4096
  98. RESET_TABLE    equ    (MAX_CODE - 1)
  99.  
  100. codes    db    (MAX_CODE * size table)    dup (0)
  101. which_code    dw    0
  102.     
  103. codes_used    dw    0
  104.  
  105. stack        db    MAX_CODE    dup    (0)
  106. s_ptr        dw    stack
  107.  
  108. INBUF_SIZE    equ    3000
  109. in_buffer    db    INBUF_SIZE    dup    (0)
  110. out_buf        db    INBUF_SIZE    dup    (0)
  111. out_handle    dw    0
  112. out_cnt        dw    0
  113. buff_cnt    dw    0
  114. buff_size    dw    0
  115. tmp        db    0
  116. hold        dw    0
  117. old_code    dw    0
  118. last_char    db    0
  119. incode        dw    0
  120.  
  121. screen_msg    db    'Decompressing File...Standby'
  122. SCREEN_LEN    equ    ($ - screen_msg)
  123. screen_attrb    db    SCREEN_LEN dup(09fh);
  124. screen_segment    dw    0b800h
  125. SCREEN_OFFSET    equ    2 * ((12 * 80) + (40 - SCREEN_LEN/2))
  126.  
  127.  
  128. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  129. ;; Function 6c -- new to DOS 4.x is a pain.  All other functions operating
  130. ;; on files have consistent usage of ds:dx for the pointer to the file name.
  131. ;; Not this puppy.  Dile name is in ds:si.  Makes more sense, but it isn't
  132. ;; consistant.  This kludge makes it *look* consistent
  133. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  134.  
  135. set_6c:    cmp    byte ptr cs:[last_dos + 1], 06ch
  136.     jnz    not_6c1
  137.     mov    cs:[old_dx], dx
  138.     mov    dx, si
  139. not_6c1:
  140.     ret
  141.  
  142. ;;;;;;;;;;;;;;;;;;;;;;;;
  143. ;; The reverse of the above
  144. ;;;;;;;;;;;;;;;;;;;;;;;;
  145. reset_6c:    cmp    byte ptr cs:[last_dos + 1], 06ch
  146.     jnz    not_6c2
  147.     mov    dx, cs:[old_dx]
  148. not_6c2:
  149.     ret
  150.  
  151. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  152. ;;  Routine called by PCMANAGE to turn on and off the COMPRES program,
  153. ;;  dump out and read back in the file (if one is on memory)
  154. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  155. set_flag:
  156.     push    ds
  157.     push    cs
  158.     pop    ds
  159.  
  160.     mov    [switch_off], dx
  161.     mov    bx, [index_handle]        ; close file on change
  162.     cmp    bx, 0                ; first time?
  163.     jz    not_yet                ; yes
  164.  
  165.     inc    [in_use]
  166.     push    ax
  167.     push    bx
  168.  
  169.     mov    ah, 051h
  170.     int    21h
  171.     mov    [users_psp], bx
  172.     mov    bx, [my_psp]
  173.     mov    ah, 050h
  174.     int    21h
  175.  
  176.     pop    bx
  177.     pop    ax
  178.     call    update_file
  179.     mov    ah, 03eh
  180.     int    21h
  181.  
  182.     push    cx
  183.     push    dx
  184.     mov    ax, 04301h
  185.     mov    dx, offset dir_name
  186.     mov    cx, [old_attrb]
  187.     int    21h
  188.     pop    dx
  189.     pop    cx
  190.  
  191.     mov    [dir_name], 0
  192.  
  193.     mov    bx, [users_psp]
  194.     mov    ah, 050h
  195.     int    21h
  196.     dec    [in_use]
  197.  
  198. not_yet:
  199.     pop    ds
  200.     ret
  201.  
  202.  
  203. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  204. ;; New Dos Interrupt Service Routine
  205. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  206.  
  207. old_dos    dw    0            ; first the offset
  208.     dw    0            ; then the segment
  209.  
  210. new_dos    proc    far
  211.     pushf                ; save current flags,
  212.     sti                ; and turn on ints
  213.  
  214.     cmp    ax, 0fedch        ; our installation call?
  215.     jnz    @F
  216.     mov    ax, 0cdefh        ; yes. Return the inverse
  217.     popf
  218.     iret
  219.  
  220. @@:    cmp    ah, 0dch        ; one of our calls to toggle?
  221.     jnz    @F            ; no
  222.     call    set_flag        ; yes.  Do it, and pass it on.
  223. @@:
  224.     cmp    cs:[in_use], TRUE    ; no recursion!
  225.     jz    @F
  226.     cmp    cs:[switch_off], TRUE    ; turned off?
  227.     jz    @F
  228.  
  229. ;;;;;;;;;;;;;;;;;;;;;;;;
  230. ;;  We care about any file access call.  If not a function we care about,
  231. ;;  simply call the original DOS
  232. ;;;;;;;;;;;;;;;;;;;;;;;;
  233.  
  234.     cmp    ah, 0fh
  235.     jz    open
  236. ;    cmp    ah, 013h
  237. ;    jz    delete
  238.     cmp    ah, 016h
  239.     jz    create
  240.     cmp    ah, 03ch
  241.     jz    h_create
  242.     cmp    ah, 03dh
  243.     jz    h_open
  244.     cmp    ah, 06ch
  245.     jz    h_open
  246. ;    cmp    ah, 041h
  247. ;    jz    n_delete
  248.     cmp    ah, 04bh
  249.     jnz    not_execute            ; kludge
  250.     jmp    execute
  251. not_execute:
  252.     cmp    ah, 05ah
  253.     jz    h_create
  254.     cmp    ah, 05bh
  255.     jz    h_create
  256.     
  257. @@:
  258.     popf
  259.     jmp    dword ptr cs:[old_dos]
  260.  
  261. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  262. ;; Process all the FCB calls
  263. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  264.  
  265. open:
  266. delete:
  267. create:
  268.     mov    cs:[last_dos], ax        ; save for re-execute later
  269.     mov    cs:[in_use], TRUE        ; no recursion!
  270.     call    dword ptr cs:[old_dos]        ; do the original call
  271.     pushf
  272.     jnc    op_good                ; if good continue
  273.     jmp    op_failed            ; else why bother?
  274.  
  275. op_good:
  276.     push    dx                ; translate FCB filenames into
  277.     push    ds                ; ASCIIZ filenames
  278.     call    fcb_stuff
  279.     push    ax
  280.     push    bx
  281.  
  282.     mov    ax, 03d00h            ; open with handle for the
  283.     int    21h                ; ioctl -- our psp
  284.     mov    cs:[dos_handle], ax
  285.     call    lookup                ; main function call
  286.     mov    bx, cs:[dos_handle]        ; close file in our psp
  287.     mov    ah, 03eh
  288.     int    21h
  289.     pop    bx
  290.     pop    ax
  291.  
  292.     pop    ds
  293.     pop    dx
  294.  
  295.     cmp    cs:[was_compressed], TRUE    ; must we play?
  296.     jnz    normal1                ; no, skip
  297.  
  298.                         ; yes, continue
  299. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  300. ;; first, close then delete the file using users fcb, then rename the tmp
  301. ;; file to the name in the fcb, then re-do the users operation
  302. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  303.     mov    cs:[was_compressed], FALSE
  304.     push    ax
  305.     mov    ah, 010h
  306.     int    21h                ; close the file
  307.     mov    ah, 013h
  308.     int    21h                ; delete it
  309.  
  310. ;;;;;;;;;;;;;;;
  311. ;; use handle rename. Filename in tmp_buffer still. Decompressed in temp file
  312. ;;;;;;;;;;;;;;;
  313.     call    rename
  314.  
  315.     mov    ax, cs:[last_dos]        ; reissue the call
  316.     int    21h
  317.  
  318.     pop    ax
  319.  
  320. normal1:
  321.     jmp    op_failed            ; common return
  322.  
  323. ;;;;;;;;;;;;;;;;;;;
  324. ;; Process all handle operations here....
  325. ;;;;;;;;;;;;;;;;;;;
  326. h_create:
  327. h_open:
  328. n_delete:
  329.     mov    cs:[last_dos], ax
  330.     mov    cs:[in_use], TRUE
  331.     call    dword ptr cs:[old_dos]        ; issue the users call.
  332.     pushf
  333.     sti
  334.     jc    op_failed            ; if it failed, simply return
  335.     mov    cs:[dos_handle], ax
  336.  
  337.     call    set_6c                ; kludge on 4.x 6c call
  338.  
  339.     call    lookup                ; main call, file is open
  340.  
  341.     call    reset_6c            ; reset from 4.x call
  342.  
  343.     cmp    cs:[was_compressed], TRUE    ; do anything unusual?
  344.     jnz    normal2                ; no
  345.  
  346. ;;;;;;;;;;;;;;;;;;
  347. ;;  Rename the file
  348. ;;;;;;;;;;;;;;;;;;
  349.  
  350.     push    ax
  351.     call    handle_stuff            ; do the rename
  352.     mov    ax, cs:[last_dos]        ; issue original call again
  353.     int    21h
  354.  
  355.     pop    ax
  356.  
  357. normal2:
  358. op_failed:
  359.     popf
  360.     mov    cs:[in_use], FALSE
  361.     ret    2
  362.  
  363. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  364. ;; Reset the compressed flag, close the file, delete it, rename it, return
  365. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  366.  
  367. handle_stuff proc near
  368.  
  369.     mov    cs:[was_compressed], FALSE
  370.  
  371.     push    bx
  372.     push    dx
  373.     push    ds
  374.  
  375.     mov    bx, cs:[dos_handle]
  376.     mov    ah, 03eh
  377.     int    21h
  378.     push    cs
  379.     pop    ds
  380.     mov    dx, offset cs:tmp_buffer
  381.     mov    ah, 041h
  382.     int    21h
  383.     call    rename
  384.  
  385.     pop    ds
  386.     pop    dx
  387.     pop    bx
  388.     ret
  389. handle_stuff    endp
  390.  
  391. ;;;;;;;;;;;;;;;;;;;;;
  392. ;; handles a little differently.  Obviously, the file must be decompressed
  393. ;; before the call...
  394. ;;;;;;;;;;;;;;;;;;;;;
  395. execute:
  396.     mov    cs:[in_use], TRUE
  397.  
  398.     push    ax
  399.     push    bx
  400.  
  401.     mov    ax, 03d00h            ; open with handle
  402.     int    21h
  403.     mov    cs:[dos_handle], ax
  404.  
  405.     call    lookup                ; main work
  406.  
  407.     mov    bx, cs:[dos_handle]        ; close file
  408.     mov    ah, 03eh
  409.     int    21h
  410.  
  411.     pop    bx
  412.     pop    ax
  413.  
  414.     cmp    cs:[was_compressed], TRUE    ; skip exciting stuff?
  415.     jnz    normal3                ; yes
  416.  
  417.     push    ax
  418.     call    handle_stuff            ; do the rename
  419.     pop    ax
  420.  
  421. normal3:
  422.     popf
  423.     mov    cs:[in_use], FALSE
  424.     jmp    dword ptr cs:[old_dos]        ; execute the program
  425.  
  426. new_dos    endp
  427.  
  428. ;;;;;;;;;;;;;;;;;;;;;;;;;
  429. ;;  This routine makes an FCB entry, extended or not, into a semi-qualified
  430. ;;  ASCIIZ filename
  431. ;;;;;;;;;;;;;;;;;;;;;;;;;
  432.  
  433. fcb_stuff    proc    near
  434.     push    ax
  435.     push    cx
  436.     push    si
  437.     push    di
  438.     push    es
  439.  
  440.     mov    si, dx
  441.     cmp    byte ptr ds:[si], 0ffh        ; extended FCB?
  442.     jnz    @F                ; normal
  443.     add    si, 7                ; point to the filename, 7
  444.                         ; bytes into extended FCB
  445. @@:    push    cs
  446.     pop    es
  447.     mov    di, offset cs:tmp_buf2        ; ASCIIZ buffer
  448.     cmp    byte ptr ds:[si], 0        ; default drive?
  449.     jz    @F                ; yes
  450.     mov    al, ds:[si]            ; no. add drive to buffer
  451.     mov    es:[di], al
  452.     add    byte ptr es:[di], 'A' - 1
  453.     mov    byte ptr es:[di + 1], ':'
  454.     add    di, 2                ; to filename position
  455.  
  456. @@:    inc    si                ; and bypass the drive in FCB
  457.  
  458.     mov    cx, 11                ; filename(8) + extension(3)
  459.                         ; always left justified, space
  460.                         ; filled
  461. file_lp:
  462.     mov    al, ds:[si]
  463.     cmp    al, ' '                ; space?
  464.     jz    @F                ; yes, so skip it
  465.     mov    es:[di], al            ; no, stuff the character
  466.     inc    di
  467.  
  468. @@:    cmp    cx, 4                ; at start of extension?
  469.     jnz    @F
  470.     mov    byte ptr es:[di], '.'        ; yes. stuff a dot
  471.     inc    di
  472.  
  473. @@:    inc    si
  474.     loop    file_lp                ; for entire filename
  475.     mov    byte ptr es:[di], 0        ; zero the end byte
  476.  
  477.     pop    es
  478.     pop    di
  479.     pop    si
  480.     pop    cx
  481.     pop    ax
  482.  
  483.     push    cs
  484.     pop    ds
  485.     mov    dx, offset tmp_buf2        ; point to the ASCIIZ filename
  486.  
  487.     ret
  488.  
  489. fcb_stuff    endp
  490.  
  491. ;;;;;;;;;;;;;;;;;;;;;;;
  492. ;;    do_pathing routine
  493. ;;
  494. ;;    DOS 2.x does not have an AH = 0x60 call, so this routine will
  495. ;;    have (almost) the same effect.  It doesn't handle assigns.
  496. ;;;;;;;;;;;;;;;;;;;;;;;
  497. up_case    proc    near
  498.     push    ax
  499.     push    di
  500.     push    bx
  501.     mov    bx, 0
  502.  
  503. @@:    mov    al, cs:[di + bx]        ; strip any spaces
  504.     cmp    al, ' '
  505.     jnz    not_sp
  506.     inc    bx
  507.     jmp    @B
  508.  
  509. not_sp:
  510.     jl    @F
  511.     cmp    al, 'a'
  512.     jl    no_upper
  513.     sub    al, 'a' - 'A'
  514.     jmp    no_slash
  515.  
  516. no_upper:
  517.     cmp    al, '/'
  518.     jnz    no_slash
  519.     mov    al, '\'
  520.  
  521. no_slash:
  522.     mov    cs:[di], al
  523.     inc    di
  524.     jmp    @B
  525.  
  526. @@:    pop    bx
  527.     pop    di
  528.     pop    ax
  529.     ret
  530.  
  531. up_case    endp
  532.  
  533.  
  534. do_dir    proc    near
  535.  
  536.     push    ax
  537.     push    dx
  538.     push    si
  539.     push    ds
  540.  
  541.     push    cs
  542.     pop    ds
  543.  
  544.     mov    dl, cs:[di - 2]
  545.     sub    dl, 'A' - 1
  546.     mov    si, di
  547.     mov    byte ptr cs:[si], '\'
  548.     inc    si
  549.     mov    byte ptr cs:[si], 0
  550.     mov    ah, 047h
  551.  
  552.     pushf
  553.     call    dword ptr cs:[old_dos]
  554.  
  555.     pop    ds
  556.     pop    si
  557.     pop    dx
  558.     pop    ax
  559.  
  560. @@:    cmp    byte ptr cs:[di], 0
  561.     jz    @F
  562.     inc    di
  563.     jmp    @B
  564.  
  565. @@:    cmp    byte ptr cs:[di - 1], '\'
  566.     jz    @F
  567.     cmp    byte ptr cs:[di - 1], '/'
  568.     jz    @F
  569.     mov    byte ptr cs:[di], '\'
  570.     inc    di
  571. @@:    mov    byte ptr cs:[di], 0
  572.     ret
  573. do_dir    endp
  574.  
  575.  
  576. do_pathing    proc    near
  577.     push    ax
  578.     push    si
  579.     push    di
  580.  
  581.     cmp    byte ptr ds:[si + 1], ':'    ; is there a disk?
  582.     jnz    @F                ; no
  583.     mov    ax, ds:[si]            ; yes. Move it
  584.     mov    cs:[di], ax
  585.     add    di, 2                ; and move the ptrs
  586.     add    si, 2
  587.     jmp    got_disk
  588.  
  589. @@:    push    ax                ; no disk. Get default
  590.     mov    ah, 19h
  591.     pushf
  592.     call    dword ptr cs:[old_dos]
  593.     add    al, 'A'                ; turn it into a letter
  594.     mov    cs:[di], al
  595.     inc    di
  596.     mov    byte ptr cs:[di], ':'        ; and add the colon
  597.     inc    di
  598.     pop    ax
  599.  
  600. got_disk:
  601.     cmp    byte ptr ds:[si], '\'        ; is there a path?
  602.     jz    @F                ; yes
  603.     cmp    byte ptr ds:[si], '/'
  604.     jz    @F                ; yes
  605.  
  606.     call    do_dir                ; no. Get one into cs:[di]
  607.  
  608. @@:    mov    al, ds:[si]            ; move what's there in source
  609.     cmp    al, ' '                ; until end
  610.     jle    @F
  611.     mov    cs:[di], al
  612.     inc    si
  613.     inc    di
  614.     jmp    @B
  615.  
  616. @@:    mov    byte ptr cs:[di], 0        ; trailing null
  617.  
  618.  
  619.  
  620.     pop    di
  621.     pop    si
  622.     pop    ax
  623.  
  624.     ret
  625.  
  626. do_pathing    endp
  627.  
  628.  
  629.  
  630.  
  631. ;;;;;;;;;;;;;;;;;;;;;;;
  632. ;; Main routine.
  633. ;;
  634. ;; 1.  Determine if a file or device.  If device, return.
  635. ;; 2.  Determine if fixed disk. If not, return
  636. ;; 3.  Fully qualify file/pathname with undocumented AH=60h call
  637. ;; 4.  Save users PSP, reset with our own.  Handle table in users might be
  638. ;;     full...
  639. ;; 5.  Scan path name, isolate last '\' (separates path from filename)
  640. ;;     saving the length of the path.
  641. ;; 6.  Save the path in one location, the filename in another
  642. ;; 7.  Stuff the name of the index file to the tail of the path
  643. ;; 8.  Determine if this is the same index filepath as already loaded
  644. ;; 9.  If not, write file if needed.
  645. ;;10.  Load new file.  If not there, create one -- and dummy the file out.
  646. ;;11.  Reset to the beginning of the binary tree index
  647. ;;12.  Find the file in index.  If found, then goto 14
  648. ;;13.  File not in index. If room, add it and return:  file has not been
  649. ;;     compressed, obviously.  New entry updated with current date and time.
  650. ;;14.  If file not compressed, merely update date and time and return.
  651. ;;15.  If file is compressed, check to make sure it is, then decompress it
  652. ;;     into temporary file named PCOMPRESS.$$$ and return
  653. ;;16.  If, upon examination file is not a compressed one, reset to normal
  654. ;;     status
  655. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  656.  
  657. lookup:
  658.     mov    cs:[was_compressed], FALSE
  659.  
  660.     cld
  661.     push    ax
  662.     push    bx
  663.     push    cx
  664.     push    dx
  665.     push    si
  666.     push    di
  667.     push    ds
  668.     push    es
  669.  
  670.  
  671.     push    dx
  672.     mov    ax, 04400h            ; ioctl call returns status
  673.     mov    bx, cs:[dos_handle]        ; in the dx register
  674.     mov    cx, 2
  675.     xor    dx, dx
  676.     int    21h
  677.     test    dx, 080h            ; devices have high bit set
  678.     pop    dx
  679.  
  680.     jz    @F                ; not set, a file
  681.     jmp    done2                ; is a character device
  682.     
  683. @@:    push    cs                ; a regular file
  684.     pop    es
  685.  
  686.     mov    si, dx
  687.     mov    di, offset tmp_buffer
  688.     cmp    byte ptr cs:[dos_ver2], 3    ; is this DOS 2.x or >=3.x
  689.     jge    dos_3x                ; >= 3.x
  690.  
  691.     call    do_pathing            ; DOS 2.x does not have AH=60
  692.     jmp    done_path            ; common point
  693.  
  694. dos_3x:    mov    ah, 60h                ; undocumented DOS call to
  695.     int    21h                ; fully qualify a file/path
  696.                         ; knows about SUBST and ASSIGN
  697. done_path:
  698.     call    up_case                ; upper case what's there.
  699.  
  700.     call    is_excluded            ; on exclude list?
  701.     jnc    not_excluded            ; no
  702.     jmp    done2                ; yes, so skip.
  703.  
  704. not_excluded:
  705.     mov    dl, es:[di]            ; get the disk letter
  706.     sub    dl, 'A' - 1            ; A=1, B=2, etc...
  707.     mov    ah, 1ch                ; get disk parameters
  708.     int    21h
  709.     cmp    byte ptr [bx], 0f8h        ; on return, DS:BX points to
  710.     jz    @F                ; first FAT entry. F8 is fixed
  711.     jmp    done2                ; disk. Anything else, we skip
  712.  
  713. @@:    mov    ah, 051h            ; get users PSP, save
  714.     int    21h                ; then swap our's in.
  715.     mov    cs:[users_psp], bx
  716.     mov    bx, cs:[my_psp]
  717.     mov    ah, 050h
  718.     int    21h
  719.  
  720. ;;;;;;;;;;;;;;;;;
  721. ;; separate the path from the filename into two buffers.
  722. ;;;;;;;;;;;;;;;;;
  723.  
  724.     xor    cx, cx
  725. end_path:
  726.     mov    al, es:[di]
  727.     cmp    al, 0            ; end of path? (ASCIIZ)
  728.     jz    @F            ; yes
  729.     inc    cx
  730.     inc    di
  731.     cmp    al, '\'            ; path delimiter?
  732.     jnz    end_path
  733.     mov    cs:[tmp_len], cx    ; save length
  734.     jmp    end_path
  735.  
  736. @@:    push    cs            ; create path to filename
  737.     pop    ds
  738.     mov    si, offset cs:[tmp_buffer]
  739.     mov    di, offset cs:[dir_name]
  740.     mov    cx, cs:[tmp_len]
  741.  
  742.     cld
  743. @@:    movsb                    ; move the path over
  744.     loop    @B
  745.  
  746. ;;;;;;;;;;;;;;;;
  747. ;;  Stuff index name onto path
  748. ;;;;;;;;;;;;;;;;
  749.  
  750.     mov    si, offset cs:[index_name]
  751.     mov    cx, INDEX_NAME_LEN
  752.     cld
  753. @@:    movsb
  754.     loop    @B
  755.  
  756. ;;;;;;;;;;;;;;;;
  757. ;;  Stuff temporary filename onto path
  758. ;;;;;;;;;;;;;;;;
  759.     mov    si, offset cs:[tmp_buffer]
  760.     mov    di, offset cs:[dir_name3]
  761.     mov    cx, cs:[tmp_len]
  762.  
  763.     cld
  764. @@:    movsb                    ; move the path over
  765.     loop    @B
  766.  
  767.  
  768.     mov    si, offset cs:[file_out]
  769.     mov    cx, FILE_OUT_LEN
  770.     cld
  771. @@:    movsb
  772.     loop    @B
  773.  
  774. ;;;;;;;;;;;;;;;;;;;;;;;;
  775. ;;  Same index name as last time?
  776. ;;;;;;;;;;;;;;;;;;;;;;;;
  777.  
  778.     mov    si, offset cs:[dir_name]
  779.     mov    di, offset cs:[dir_name2]
  780.     mov    cx, cs:[tmp_len]
  781.     cld
  782.     repz    cmpsb                ; pop out on no match
  783.     cmp    byte ptr cs:[di], 'I'        ; first letter of "INDEX.CMP"
  784.     jnz    @F                ; not a match
  785.     cmp    cx, 0                ; all through and a match?
  786.     jnz    @F
  787.     jmp    a_match                ; yes
  788.                         ; no match, fall through
  789.  
  790. ;;;;;;;;;;;;;;;;;;;;;
  791. ;;  New index file.  Close the old one first, then create a new one
  792. ;;  if needed with blank entries.
  793. ;;;;;;;;;;;;;;;;;;;;;
  794.  
  795. index_open:
  796. @@:    mov    bx, [index_handle]        ; close file on change
  797.     cmp    bx, 0                ; first time?
  798.     jz    @F                ; yes
  799.     call    update_file            ; update the old file and
  800.     mov    ah, 03eh            ; do the close
  801.     int    21h
  802.  
  803. reset_attrb:
  804.     push    cx
  805.     mov    ax, 04301h
  806.     mov    dx, offset dir_name2
  807.     mov    cx, [old_attrb]
  808.     int    21h
  809.     pop    cx
  810.  
  811.  
  812. @@:    mov    ax, 04300h            ; save the current attributes
  813.     mov    dx, offset dir_name
  814.     int    21h
  815.     jc    no_file
  816.     mov    [old_attrb], cx
  817.  
  818.     mov    ax, 04301h            ; make it readable/writable
  819.     mov    dx, offset dir_name
  820.     mov    cx, 0
  821.     int    21h
  822.  
  823.     mov    ax, 3d02h            ; open the new file up
  824.     mov    dx, offset dir_name
  825.     int    21h
  826.     jc    no_file                ; no file. Create one.
  827.  
  828.     mov    cs:[index_handle], ax
  829.     mov    bx, ax
  830.  
  831.     mov    cs:[num_files], 0        ;; ??
  832.     mov    cx, size num_files + BUF_SIZE + MAX_FN_SIZE
  833.     mov    dx, offset cs:[num_files]    ; buffer to read into
  834.     mov    ah, 03fh
  835.     int    21h
  836.     jnc    a_match                ; read okay!
  837.  
  838. no_file:
  839.     mov    ah, 03ch            ; create a new file
  840.     mov    dx, offset cs:dir_name
  841.     mov    cx, 0
  842.     int    21h
  843.  
  844.     push    cs:[attributes]            ; mov attributes as if old file
  845.     pop    cs:[old_attrb]
  846.  
  847.     jnc    @F
  848.     jmp    done                ;problem
  849.  
  850.  
  851. ;;;;;;;;;;;;;
  852. ;; Zero out what will be the contents of the new file
  853. ;;;;;;;;;;;;;
  854. @@:    mov    bx, ax
  855.     mov    cs:[index_handle], ax
  856.  
  857.     mov    cx, size num_files + BUF_SIZE + MAX_FN_SIZE
  858.                         ; Zero out buffer
  859.     mov    di, offset cs:num_files
  860. @@:    mov    byte ptr cs:[di], 0
  861.     inc    di
  862.     loop    @B
  863.  
  864.     mov    si, offset cs:[dir_name]    ; but load index file name
  865.     mov    di, offset cs:[dir_name2]
  866.     mov    cx, cs:[tmp_len]
  867.     add    cx, INDEX_NAME_LEN
  868.  
  869.     cld
  870. @@:    movsb
  871.     loop    @B
  872.  
  873. ;;;;;;;;;;;;;;;;;;;
  874. ;; write out with zero files, index filename, an empty buffer
  875. ;;;;;;;;;;;;;;;;;;;
  876.     mov    cx, BUF_SIZE + size num_files + MAX_FN_SIZE
  877.     mov    dx, offset cs:num_files
  878.     mov    ah, 040h
  879.     int    21h
  880.     call    commit                ; make sure it gets written
  881.  
  882. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  883. ;;    At this point, the index is loaded into memory. Find the file
  884. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  885.  
  886. a_match:
  887.     mov    si, offset cs:[tmp_buffer]
  888.     add    si, cs:[tmp_len]            ;pointer to filename
  889.     mov    di, offset cs:[file_name]
  890.     mov    cs:[file_seg], es
  891.     mov    cs:[file_off], di
  892.  
  893. @@:    mov    al, ds:[si]                ; move filename again
  894.     mov    es:[di], al
  895.     inc    di
  896.     inc    si
  897.     cmp    al, 0
  898.     jnz    @B
  899.  
  900.     push    cs
  901.     pop    ds
  902.  
  903.     mov    ax, 1                ; get first one
  904.     call    get_pointer            ; bx gets pointer to entry
  905.  
  906. look_lp:
  907.     mov    ds, cs:[file_seg]        ; source seg
  908.     push    cs
  909.     pop    es                ; target seg - the buffer
  910.  
  911.     mov    si, cs:[file_off]        ; get back the filename
  912.     mov    di, bx
  913.     add    di, filename            ; and point to it in record
  914.     mov    cx, word ptr cs:[bx].filename_len    
  915.     cmp    cx, 0
  916.     jz    no_match            ; if empty record
  917.  
  918. @@:    mov    al, ds:[si]
  919.     cmp    al, es:[di]
  920.     jnz    no_match            ; try again
  921.     inc    si
  922.     inc    di
  923.     loop    @B
  924.  
  925.     inc    cs:[dirty_bit]            ; found it!
  926.     call    update                ; a match.  Update it.
  927.     jmp    done
  928.  
  929.                         
  930. done:
  931.     mov    bx, cs:[users_psp]        ;reset users PSP and return
  932.     mov    ah, 050h
  933.     int    21h
  934. done2:
  935.     pop    es
  936.     pop    ds
  937.     pop    di
  938.     pop    si
  939.     pop    dx
  940.     pop    cx
  941.     pop    bx
  942.     pop    ax
  943.     ret
  944.  
  945. ;;;;;;;;;;;;;;;
  946. ;; Current entry isn't what we want.  Try next one.
  947. ;;;;;;;;;;;;;;;
  948.  
  949. no_match:
  950.     push    cs
  951.     pop    ds
  952.     mov    ax, [bx].left_ptr    ; assume less than
  953.     mov    dx, left_ptr
  954.     jl    @F
  955.     mov    ax, [bx].right_ptr    ; greater than, use right pointer
  956.     mov    dx, right_ptr
  957. @@:    cmp    ax, 0            ; end of the line?
  958.     jz    @F            ; yes
  959.     call    get_pointer        ; bx points to next entry
  960.     jmp    look_lp            ; se if a match
  961.  
  962. ;;;;;;;;;;
  963. ;; insert routine
  964. ;;;;;;;;;;
  965. @@:    cmp    cs:[num_files], MAX_FILES    ; full already?
  966.     jnz    @F            ; no
  967.     jmp    done            ; yes.  Ignore it.
  968. @@:    inc    cs:[num_files]        ; increase the count
  969.     mov    ax, cs:[num_files]
  970.     add    bx, dx            ; left or right pointer offset
  971.     mov    cs:[bx], ax
  972.     inc    cs:[dirty_bit]
  973.     call    get_pointer        ; point to empty record
  974.  
  975. ;;;;;;;;;;;;;;;;;;
  976. ;; copy the name into the buffer
  977. ;;;;;;;;;;;;;;;;;;
  978.     mov    ds, cs:[file_seg]    ; source seg
  979.     push    cs
  980.     pop    es            ; target seg - the buffer
  981.  
  982.     mov    si, cs:[file_off]    ; get back the filename
  983.     mov    di, bx
  984.     add    di, filename
  985.     xor    cx, cx
  986.     cld
  987. @@:    movsb
  988.     inc    cx
  989.     cmp    byte ptr ds:[si], 0
  990.     jnz    @B
  991. ;;;;;;;;;;;;;;;;
  992. ;; set up the rest of the entry
  993. ;;;;;;;;;;;;;;;;
  994.  
  995.     mov    byte ptr es:[di], 0        ; trailing null: nice for 'C'
  996.     mov    cs:[bx].filename_len, cx
  997.     mov    cs:[bx].left_ptr, 0
  998.     mov    cs:[bx].right_ptr, 0
  999.     mov    cs:[bx].access_cnt, 1
  1000.     mov    cs:[bx].status, NORMAL
  1001.     inc    cs:[dirty_bit]
  1002.  
  1003.     call    update                ; add date and time
  1004.     jmp    done
  1005.  
  1006. ;;;;;;;;;;;;;;;;;;;;;
  1007. ;;  Returns bx as in  bx = (ax * size entry) + buffer offset
  1008. ;;  ax is the entry we seek
  1009. ;;;;;;;;;;;;;;;;;;;;
  1010.  
  1011.  
  1012. get_pointer    proc    near
  1013.     push    cx
  1014.     push    dx
  1015.  
  1016.     dec    ax
  1017.     mov    bx, ax
  1018.     mov    cx, size file
  1019.     mul    cx
  1020.     xchg    ax, bx
  1021.     add    bx, offset cs:[buffer]
  1022.  
  1023.     pop    dx
  1024.     pop    cx
  1025.     ret
  1026. get_pointer    endp
  1027.  
  1028. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1029. ;;  Write all the stuff in the current buffer out to disk
  1030. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1031. update_file    proc    near
  1032.     push    ax
  1033.     push    bx
  1034.     push    cx
  1035.     push    dx
  1036.     push    ds
  1037.  
  1038.     push    cs
  1039.     pop    ds
  1040.  
  1041.  
  1042.     mov    cs:[dirty_bit], 0        ; now we're clean
  1043.  
  1044.     xor    cx, cx                ; lseek to beginning
  1045.     xor    dx, dx
  1046.     mov    ax, 04200h
  1047.     mov    bx, cs:[index_handle]
  1048.     int    21h
  1049.  
  1050.     mov    dx, offset num_files         ; write it
  1051.     mov    cx, BUF_SIZE + size num_files + MAX_FN_SIZE
  1052.     mov    ah, 040h
  1053.     int    21h
  1054.  
  1055.     call    commit                ; make sure it's written
  1056.  
  1057.     pop    ds
  1058.     pop    dx
  1059.     pop    cx
  1060.     pop    bx
  1061.     pop    ax
  1062.     ret
  1063. update_file    endp
  1064.  
  1065. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1066. ;; Add date and time.  If compressed, decompress.
  1067. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1068.  
  1069. update:
  1070.     mov    ah, 02ah        ; get the date
  1071.     int    21h
  1072.     mov    cs:[bx].date, cx
  1073.     mov    cs:[bx].date + 2, dx
  1074.     mov    ah, 02ch        ; get the time
  1075.     int    21h
  1076.     mov    cs:[bx].time, cx    ; stuff them
  1077.     mov    cs:[bx].time + 2, dx
  1078.     inc    cs:[bx].access_cnt    ; up the access count
  1079.     cmp    cs:[ignore_status], TRUE
  1080.     jz    do_it_anyway
  1081.     cmp    cs:[bx].status, COMPRESSED
  1082.     jnz    @F            ; normal
  1083. do_it_anyway:
  1084.     push    bx            ; save the entry pointer
  1085.     call    decompress        ; expand the file
  1086.     pop    bx
  1087.     mov    cs:[bx].status, NORMAL    ; reset the status
  1088.     inc    cs:[dirty_bit]        ; we have to write now.
  1089. @@:    ret
  1090.  
  1091. ;;;;;;;;;;;;;;;;;;;;;;;;
  1092. ;;  Is it really compressed?
  1093. ;;;;;;;;;;;;;;;;;;;;;;;;
  1094. decompress:
  1095.     push    ax
  1096.     push    bx
  1097.     push    cx
  1098.     push    dx
  1099.     push    di
  1100.     push    si
  1101.  
  1102. ;;;;;;;;;;;;
  1103. ;; Read the first few bytes, see if it matches our unique entry
  1104. ;;;;;;;;;;;;
  1105.     mov    dx, offset cs:tmp_buffer
  1106.     mov    ax, 3d00h
  1107.     int    21h
  1108.     jc    bad_decom2        ; can't decompress if can't open!
  1109.  
  1110.     mov    cs:[in_handle], ax
  1111.     mov    bx, ax
  1112.     mov    cx, TAG_LEN         ; read the first coupla bytes in
  1113.     mov    dx, offset cs:tag_buf
  1114.     mov    ah, 03fh
  1115.     int    21h
  1116.     jc    bad_decom        ; too short for one of ours!
  1117.     cmp    ax, TAG_LEN
  1118.     jl    bad_decom
  1119.  
  1120.     mov    si, offset cs:tag    ; our tag line?
  1121.     mov    di, dx
  1122.     mov    cx, TAG_LEN
  1123. @@:    mov    al, byte ptr cs:[si]
  1124.     cmp    al, byte ptr cs:[di]
  1125.     jnz    bad_decom
  1126.     inc    si
  1127.     inc    di
  1128.     loop    @B            ; a match?
  1129.  
  1130.     call    do_decomp        ; yes! Decompress it
  1131.  
  1132. bad_decom:
  1133.     mov    bx, cs:[in_handle]    ; close the file
  1134.     mov    ah, 03eh
  1135.     int    21h
  1136. bad_decom2:
  1137.     cmp    cs:[bx].status, NORMAL    ; if it was normal, don't set dirty bit
  1138.     jz    @F
  1139.     mov    cs:[dirty_bit], TRUE
  1140.  
  1141. @@:    pop    si
  1142.     pop    di
  1143.     pop    dx
  1144.     pop    cx
  1145.     pop    bx
  1146.     pop    ax
  1147.  
  1148.     ret
  1149.  
  1150. ;;;;;;;;;;;;;;;;;;;;;;;;;;
  1151. ;;  Open a duplicate handle on the file, then close the duplicate handle.
  1152. ;;  This causes brain damaged dos to commit the file, regardless of
  1153. ;;  version
  1154. ;;;;;;;;;;;;;;;;;;;;;;;;;;
  1155. commit    proc    near
  1156.     push    ax
  1157.     push    bx
  1158.     mov    ah, 045h
  1159.     mov    bx, cs:[index_handle]
  1160.     int    21h
  1161.     mov    bx, ax
  1162.     mov    ah, 03eh
  1163.     int    21h
  1164.     pop    bx
  1165.     pop    ax
  1166.     ret
  1167. commit    endp
  1168.  
  1169. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1170. ;;  LZW compression routines
  1171. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1172.  
  1173. ;;;;;;;;;;;;;;;;
  1174. ;; Zero out the table.
  1175. ;;;;;;;;;;;;;;;;
  1176.  
  1177. init_tab    proc    near
  1178.     push    ax
  1179.     push    cx
  1180.     push    si
  1181.     push    ds
  1182.  
  1183.     xor    ax, ax
  1184.     mov    cx, 256
  1185.     mov    si, offset cs:codes
  1186.     push    cs
  1187.     pop    ds
  1188. lp:
  1189.     mov    [si].cmp_code, 0
  1190.     mov    [si].suffix, al
  1191.     inc    al
  1192.     add    si, size table
  1193.     loop    lp
  1194.  
  1195.     mov    cs:[codes_used], 256
  1196.  
  1197.     pop    ds
  1198.     pop    si
  1199.     pop    cx
  1200.     pop    ax
  1201.     ret
  1202. init_tab    endp
  1203.  
  1204. sdate    dw    0
  1205. stime    dw    0
  1206.  
  1207. save_date    proc    near
  1208.     push    ax
  1209.     push    cx
  1210.     push    dx
  1211.  
  1212.     mov    ax, 05700h
  1213.     int    21h
  1214.     mov    cs:[sdate], dx
  1215.     mov    cs:[stime], cx
  1216.  
  1217.     pop    dx
  1218.     pop    cx
  1219.     pop    ax
  1220.     ret
  1221. save_date    endp
  1222.  
  1223. set_date    proc    near
  1224.     push    ax
  1225.     push    cx
  1226.     push    dx
  1227.  
  1228.     mov    dx, cs:[sdate]
  1229.     mov    cx, cs:[stime]
  1230.     mov    ax, 05701h
  1231.     int    21h
  1232.  
  1233.     pop    dx
  1234.     pop    cx
  1235.     pop    ax
  1236.  
  1237.     ret
  1238.  
  1239. set_date    endp
  1240.  
  1241.  
  1242.  
  1243.  
  1244.  
  1245. ;;;;;;;;;;;;;;;;;;;;;
  1246. ;;  Actual decompression routine
  1247. ;;;;;;;;;;;;;;;;;;;;;
  1248.  
  1249. do_decomp    proc    near
  1250.  
  1251.     call     paint            ; XT owners don't think we crashed...
  1252.  
  1253.     call    init_tab
  1254.  
  1255.     mov    cs:[which_code], 0    ; initialize a bunch of variables
  1256.     mov    cs:[hold], 0
  1257.     mov    cs:[s_ptr], offset cs:stack    ; not a real stack
  1258.     mov    cs:[out_cnt], 0
  1259.     mov    cs:[buff_cnt], 0
  1260.     mov    cs:[buff_size], 0
  1261.     mov    cs:[tmp], 0
  1262.  
  1263.     push    bx
  1264.     mov    bx, cs:[in_handle]
  1265.     call    save_date
  1266.     pop    bx
  1267.  
  1268.     push    cs
  1269.     pop    ds
  1270.  
  1271.     mov    dx, offset cs:dir_name3        ; create the temporary file
  1272.     xor    cx, cx
  1273.     mov    ah, 03ch
  1274.     int    21h
  1275.     mov    cs:[out_handle], ax
  1276.  
  1277.     call    get_code        ; read a code in
  1278.     mov    bl, al            ; save it
  1279.     call    stuff            ; stuff on the stack
  1280.     call    unstuff            ; unstuff into the output file
  1281.     mov    cs:[old_code], ax    ; save it
  1282.     mov    cs:[last_char], bl    ; save it
  1283. decode:
  1284.     call    get_code        ; loop. Get a code. expand it.
  1285.     jc    exit            ; we're done on carry
  1286.     cmp    ax, RESET_TABLE        ; table full in compressor?
  1287.     jnz    no_exit
  1288.  
  1289.     call    init_tab        ; yes. Reset everything
  1290.  
  1291.     call    get_code        ; and start over
  1292.     mov    bl, al
  1293.     call    stuff
  1294.     call    unstuff
  1295.     mov    cs:[old_code], ax
  1296.     jmp    decode            ; now we're back to normal
  1297.  
  1298. exit:
  1299.     call    output            ; exit. Force output of last code
  1300.  
  1301.  
  1302.     mov    bx, cs:[out_handle]
  1303.     call    set_date
  1304.     mov    ah, 03eh
  1305.     int    21h            ; close decomp'ed temp file
  1306.  
  1307.     mov    cs:[was_compressed], TRUE
  1308.  
  1309.     call    paint            ; Yo! XT owner! Wake up!
  1310.     ret                ; good-run exit point
  1311.  
  1312. no_exit:
  1313.     mov    cs:[incode], ax        ; save the code
  1314.     cmp    ax, cs:[codes_used]    ; already in table?
  1315.     jl    @F            ; yes
  1316.  
  1317. ;;;;;;;;;;;;;;;;;;;;;;;;;
  1318. ;; Special class of codes for highly repetitive strings.  The code can
  1319. ;; be transmitted before it exists!  So, we simply add a new code
  1320. ;;;;;;;;;;;;;;;;;;;;;;;;;
  1321.     mov    ax, cs:[old_code]
  1322.     mov    bl, cs:[last_char]
  1323.     call    stuff
  1324.  
  1325. @@:    push    ax            ; save the code
  1326.     mov    cx, size table        ; get the suffix
  1327.     mul    cx
  1328.     mov    si, ax
  1329.     add    si, offset cs:codes
  1330.     pop    ax
  1331.     cmp    ax, 256            ; "low" code?
  1332.     jl    @F            ; yup. End loop
  1333.     mov    bl,cs:[si].suffix
  1334.     call    stuff            ; enter onto stack
  1335.     mov    ax, cs:[si].cmp_code    ; next code in code sequence
  1336.     jmp    @B            ; loop
  1337.  
  1338. @@:    mov    bl, cs:[si].suffix    ; do the last char
  1339.     mov    cs:[last_char], bl    ; and save it
  1340.     call    stuff            ; add to stack
  1341.     call    unstuff            ; write out whole stack
  1342.     
  1343.     cmp    cs:[codes_used], MAX_CODE    ; full table?
  1344.     jz    @F                ; yup
  1345.  
  1346. ;;;;;;;;;;;;;;;;;;;;
  1347. ;;  Add the code into the table
  1348. ;;;;;;;;;;;;;;;;;;;;;
  1349.     mov    ax, cs:[codes_used]
  1350.     mov    cx, size table
  1351.     mul    cx
  1352.     mov    si, ax
  1353.     add    si, offset cs:codes
  1354.     mov    ax, cs:[old_code]
  1355.     mov    cs:[si].cmp_code, ax
  1356.     mov    al, cs:[last_char]
  1357.     mov    cs:[si].suffix, al
  1358.     inc    cs:[codes_used]        ; up the number of codes used in table
  1359.  
  1360. @@:    mov    ax, cs:[incode]        ; save original code
  1361.     mov    cs:[old_code], ax
  1362.     jmp    decode            ; next!
  1363.  
  1364. do_decomp    endp
  1365.  
  1366.  
  1367.  
  1368. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1369. ;;  The codes are actually 12 bit entities:  a byte and a half.  So, take
  1370. ;;  turns reading two bytes, returning 12 bits, then one byte, returning
  1371. ;;  old half byte (a nibble) and new byte.  That's a code.  And it fits
  1372. ;;  within a register.  How nifty!
  1373. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1374. get_code:
  1375.     cmp    cs:[which_code], 0        ; even or odd code?
  1376.     jnz    odd_code
  1377.  
  1378.     call    get_byte            ; get the first byte
  1379.     jc    get_code_ret            ; eof
  1380.  
  1381.     xor    ax, ax
  1382.     mov    al, byte ptr cs:[tmp]        ; get byte 
  1383.     mov    cl, 4                ; and pop it down a nibble
  1384.     shl    ax, cl
  1385.  
  1386.     call    get_byte            ; get next byte
  1387.     jc    get_code_ret            ; eof
  1388.  
  1389.     mov    bx, ax                ; turn it into a code and save
  1390.     xor    ax, ax                ; left over nibble.
  1391.     mov    al, byte ptr cs:[tmp]
  1392.     mov    cs:[hold], ax
  1393.     and    cs:[hold], 0fh            ; set the leftover flag.
  1394.     mov    cl, 4
  1395.     shr    ax, cl
  1396.     or    ax, bx
  1397.     mov    cs:[which_code], 1
  1398.     clc
  1399.     jmp    get_code_ret
  1400.  
  1401. odd_code:
  1402.     mov    ax, cs:[hold]            ; retrieve left over nibble
  1403.     mov    cl, 8                ; pop it up
  1404.     shl    ax, cl
  1405.     call    get_byte            ; get next byte
  1406.     jc    get_code_ret            ; eof?  Shouldn't happen
  1407.     or    al, byte ptr cs:[tmp]        ; add it in
  1408.     mov    cs:[which_code], 0        ; set for even read next time
  1409.  
  1410. get_code_ret:
  1411.     ret                    ; code in ax
  1412.  
  1413. ;;;;;;;;;;;;;;;;;;;;;;
  1414. ;;  characfter in bl gets stuffed onto stack
  1415. ;;;;;;;;;;;;;;;;;;;;;;
  1416. stuff:
  1417.     push    si
  1418.     mov    si, cs:[s_ptr]
  1419.     inc    cs:[s_ptr]
  1420.     mov    byte ptr cs:[si], bl
  1421.     pop    si
  1422.     ret
  1423.  
  1424. ;;;;;;;;;;;;;;;;;;;;;;;;
  1425. ;;  Get characters off stack in reverse order. Add to buffer. Write buffer
  1426. ;;  if it gets too large
  1427. ;;;;;;;;;;;;;;;;;;;;;;;;
  1428. unstuff:
  1429.     push    ax
  1430.     push    bx
  1431.     push    si
  1432.  
  1433.     mov    si, cs:[s_ptr]
  1434.  
  1435. unstuff_lp:
  1436.     dec    si
  1437.     cmp    si, offset cs:stack
  1438.     jl    unstuff_end
  1439.     cmp    cs:[out_cnt], INBUF_SIZE
  1440.     jnz    @F
  1441.     call    output
  1442. @@:    mov    al, byte ptr cs:[si]
  1443.     mov    bx, cs:[out_cnt]
  1444.     inc    cs:[out_cnt]
  1445.     add    bx, offset cs:out_buf
  1446.     mov    byte ptr cs:[bx], al
  1447.     jmp    unstuff_lp
  1448.  
  1449. unstuff_end:
  1450.     mov    cs:[s_ptr], offset cs:stack    ; reset the stack
  1451.     pop    si
  1452.     pop    bx
  1453.     pop    ax
  1454.     ret
  1455.  
  1456. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1457. ;;  Write the data out to the output temporary file
  1458. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1459. output    proc    near
  1460.     cmp    cs:[out_cnt], 0
  1461.     jz    output_ret
  1462.  
  1463.     push    ax
  1464.     push    bx
  1465.     push    cx
  1466.     push    dx
  1467.     push    ds
  1468.  
  1469.     mov    bx, cs:[out_handle]
  1470.     mov    cx, cs:[out_cnt]
  1471.     mov    ah, 040h
  1472.     push    cs
  1473.     pop    ds
  1474.     mov    dx, offset cs:out_buf
  1475.     int    21h
  1476.     mov    cs:[out_cnt], 0
  1477.  
  1478.     pop    ds
  1479.     pop    dx
  1480.     pop    cx
  1481.     pop    bx
  1482.     pop    ax
  1483.  
  1484. output_ret:
  1485.     ret
  1486. output    endp
  1487.  
  1488. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1489. ;;  Read a buffer in. Return next byte in buffer, reading in buffers as
  1490. ;;  required.
  1491. ;;  Return with carry set when you reach EOF.
  1492. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;    
  1493. get_byte    proc    near
  1494.     push    ax
  1495.     push    bx
  1496.     push    cx
  1497.     push    dx
  1498.  
  1499.     mov    ax, cs:[buff_cnt]
  1500.     cmp    ax, cs:[buff_size]
  1501.     jnz    buffer_ok
  1502.  
  1503.  
  1504.     mov    dx, offset cs:in_buffer
  1505.     mov    cx, INBUF_SIZE        ; must be evenly divisible by 1.5
  1506.     mov    bx, cs:[in_handle]
  1507.     mov    ah, 03fh
  1508.     int    21h
  1509.     mov    cs:[buff_size], ax
  1510.     mov    cs:[buff_cnt], 0
  1511.     cmp    ax, 0
  1512.     jz    eof
  1513.  
  1514. buffer_ok:
  1515.     clc
  1516.     mov    bx, cs:[buff_cnt]
  1517.     inc    cs:[buff_cnt]
  1518.     mov    al, byte ptr cs:[bx + in_buffer]
  1519.     mov    cs:[tmp], al
  1520.     jmp    get_byte_ret
  1521.  
  1522. eof:
  1523.     stc
  1524.  
  1525. get_byte_ret:
  1526.     pop    dx
  1527.     pop    cx
  1528.     pop    bx
  1529.     pop    ax
  1530.     ret
  1531. get_byte    endp
  1532.  
  1533. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1534. ;;  Simply rename the temporary file into the real filename name
  1535. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1536.  
  1537. rename    proc    near
  1538.     push    ax
  1539.     push    dx
  1540.     push    di
  1541.     push    ds
  1542.     push    es
  1543.  
  1544.     push    cs
  1545.     pop    ds
  1546.     push    cs
  1547.     pop    es
  1548.     mov    di, offset cs:tmp_buffer
  1549.     mov    dx, offset cs:dir_name3
  1550.     mov    ah, 056h
  1551.     int    21h
  1552.  
  1553.     pop    es
  1554.     pop    ds
  1555.     pop    di
  1556.     pop    dx
  1557.     pop    ax
  1558.     ret
  1559.  
  1560. rename    endp
  1561.  
  1562. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1563. ;;  Paint message on screen by exchanging bytes. Two calls and everything
  1564. ;;  is back to normal
  1565. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1566. paint    proc    near
  1567.     push    ax
  1568.     push    cx
  1569.     push    si
  1570.     push    di
  1571.     push    es
  1572.     mov    es, cs:[screen_segment]
  1573.     mov    si, SCREEN_OFFSET
  1574.     xor    di, di
  1575.     mov    cx, SCREEN_LEN
  1576. scr_lp1:
  1577.     mov    ax, word ptr es:[si]
  1578.     xchg    al, cs:[screen_msg + di]
  1579.     xchg    ah, cs:[screen_attrb + di]
  1580.     mov    word ptr es:[si], ax
  1581.     inc    si
  1582.     inc    si
  1583.     inc    di
  1584.     loop    scr_lp1
  1585.  
  1586.     pop    es
  1587.     pop    di
  1588.     pop    si
  1589.     pop    cx
  1590.     pop    ax
  1591.     ret
  1592. paint    endp
  1593.  
  1594. save_pattern    dw    0
  1595. exclude_cnt    dw    0
  1596.  
  1597.  
  1598. is_excluded    proc    near
  1599.  
  1600.     cmp    [exclude_cnt], 0        ; don't run till we're ready!
  1601.     jnz    @F
  1602.     ret
  1603.  
  1604. @@:    push    ax
  1605.     push    si
  1606.     push    di
  1607.     push    ds
  1608.  
  1609.     push    cs
  1610.     pop    ds
  1611.  
  1612.     mov    si, di                ; entering with filename in di
  1613.     mov    di, offset install        ; table in di, now.
  1614.  
  1615.     push    si                ; pretend we're already started
  1616.  
  1617. major_loop:
  1618.     mov    cs:[save_pattern], 0
  1619.     pop    si
  1620.     push    si
  1621.  
  1622. cmp_loop:
  1623.     mov    al, cs:[si]
  1624.     mov    ah, cs:[di]
  1625.     cmp    ax, 0
  1626.     jz    bad_item    ; ran off both of them...match!
  1627.     cmp    ax, 00d00h    ; return from file is match, too
  1628.     jz    bad_item
  1629.     cmp    ax, 00a00h    ; so is newline
  1630.     jz    bad_item
  1631.     cmp    ah, '?'        ; wild card?
  1632.     jz    wild1        ; yes
  1633.     cmp    ah, '*'
  1634.     jnz    not_wild    ; no
  1635.  
  1636.     inc    di
  1637.     mov    cs:[save_pattern], di
  1638.     mov    ah, cs:[di]
  1639.     cmp    ah, ' '
  1640.     jle    bad_item    ; end * means a match
  1641. wild_lp:
  1642.     mov    al, cs:[si]
  1643.     cmp    al, ' '
  1644.     jl    no_match_up
  1645.  
  1646.     cmp    al, ah
  1647.     jz    cmp_loop    ;recurse
  1648.     inc    si
  1649.     jmp    wild_lp
  1650.  
  1651. bad_item:
  1652.     stc
  1653.     pop    si
  1654.  
  1655.     pop    ds
  1656.     pop    di
  1657.     pop    si
  1658.     pop    ax
  1659.     ret
  1660.  
  1661. not_wild:
  1662.     cmp    ah, al
  1663.     jz    wild1
  1664.     cmp    al, '?'
  1665.     jz    wild1
  1666.     cmp    cs:[save_pattern], 0
  1667.     jz    no_match_up
  1668.     mov    di, cs:[save_pattern]
  1669.     mov    ah, cs:[di]
  1670.     jmp    wild_lp
  1671.  
  1672. wild1:
  1673.     inc    si
  1674.     inc    di
  1675.     jmp    cmp_loop
  1676. no_match_up:
  1677.     cmp    ah, ' '        ; goto end of table entry
  1678.     jle    next_item
  1679.  
  1680.     inc    di
  1681.     mov    ah, cs:[di]
  1682.     jmp    no_match_up
  1683. next_item:
  1684.     mov    cs:[save_pattern], 0
  1685.     inc    di        ; end of table?
  1686.     mov    ah, cs:[di]
  1687.     cmp    byte ptr cs:[di], 0ffh
  1688.     jz    end_of_table    ; yes
  1689.  
  1690.     cmp    ah, ' '        ; return, linefeed, etc
  1691.     jle    next_item
  1692.  
  1693.     jmp    major_loop
  1694.  
  1695. end_of_table:
  1696.     clc
  1697.     pop    si
  1698.  
  1699.     pop    ds
  1700.     pop    di
  1701.     pop    si
  1702.     pop    ax
  1703.     ret
  1704.  
  1705. is_excluded    endp
  1706.  
  1707. very_end:
  1708.     mov    cx, [exclude_cnt]            ;move the table
  1709.     cmp    cx, 0
  1710.     jz    no_exclude
  1711.  
  1712.     mov    si, offset exclude_buffer        ; from
  1713.     mov    di, offset install            ; to
  1714.  
  1715. @@:    mov    al, [si]
  1716.     mov    [di], al
  1717.     inc    si
  1718.     inc    di
  1719.     loop    @B
  1720.  
  1721.     mov    byte ptr [di], 0ffh            ; end of table
  1722.  
  1723. no_exclude:
  1724.     mov    ax, 03100h
  1725.     mov    dx, offset install
  1726.     add    dx, exclude_cnt                ; add in table bytes
  1727.     mov    cl, 4
  1728.     shr    dx, cl
  1729.  
  1730.     inc    dx
  1731.     int    21h
  1732.     int    20h
  1733.  
  1734.  
  1735.  
  1736. ;; end of resident code
  1737. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1738. ;; start of transient code
  1739.  
  1740.  
  1741. ;;;;;;;;;;;;;;;;;;;;;;
  1742. ;;  See if we're already installed.  If so, print a message and exit
  1743. ;;  Otherwise, save the old Dos interrupt vector, take it over for our
  1744. ;;  purposes, output a nice message, and save our own psp in the code
  1745. ;;  segment before exiting with a bunch of memory saved
  1746.  
  1747. install:
  1748.     mov    ax, 0fedch
  1749.     int    21h
  1750.     cmp    ax, 0cdefh
  1751.     jnz    @F
  1752.     jmp    already_in
  1753.  
  1754. @@:    mov    ah, 30h
  1755.     int    21h
  1756.     mov    cs:[dos_ver1], ah
  1757.     mov    cs:[dos_ver2], al
  1758.  
  1759.     mov    ax, 03521h
  1760.     int    21h
  1761.     mov    cs:[old_dos], bx
  1762.     mov    cs:[old_dos + 2], es
  1763.  
  1764.     mov    ax, 02521h
  1765.     push    cs
  1766.     pop    ds
  1767.     mov    dx, offset new_dos
  1768.     int    21h
  1769.     mov    dx, offset good_inst_msg
  1770.     mov    ah, 9
  1771.     int    21h
  1772.     mov    ah, 051h
  1773.     int    21h
  1774.     mov    cs:[my_psp], bx
  1775.  
  1776.     mov    si, 80h            ; point to arguments
  1777.     mov    cl, byte ptr [si]
  1778.     xor    ch, ch
  1779.     cmp    cx, 0
  1780.     jz    @F
  1781. @@:    inc    si
  1782.     cmp    byte ptr [si], '-'
  1783.     jz    got_minus
  1784.     cmp    byte ptr [si], '/'
  1785.     jnz    not_arg
  1786. got_minus:
  1787.     cmp    byte ptr [si + 1], 'i'
  1788.     jz    got_arg
  1789.     cmp    byte ptr [si + 1], 'I'
  1790.     jnz    not_ignore
  1791. got_arg:
  1792.     mov    cs:[ignore_status], TRUE
  1793.     jmp    not_arg
  1794.  
  1795. not_ignore:                    ; -A#
  1796.     cmp    byte ptr [si + 1], 'a'
  1797.     jz    got_arg2
  1798.     cmp    byte ptr [si + 1], 'A'
  1799.     jnz    not_arg
  1800. got_arg2:
  1801.     mov    al, byte ptr [si + 2]
  1802.     sub     al, '0'
  1803.     jl    not_arg
  1804.     cmp    al, 3
  1805.     jg    not_arg
  1806.                     ;0= visible, writable
  1807.                     ;1= hidden, writable
  1808.                     ;2= visible, not writable
  1809.                     ;3= hidden, not writable
  1810.     test    al, 1
  1811.     jz    not_hidden
  1812.     or    cs:[attributes], 2
  1813. not_hidden:
  1814.     test    al, 2
  1815.     jz    not_write_protect
  1816.     or    cs:[attributes], 1
  1817.  
  1818. not_write_protect:
  1819.  
  1820. not_arg:
  1821.     loop    @B
  1822.  
  1823. @@:    call    read_exclude
  1824.  
  1825.     jmp    very_end
  1826.  
  1827. read_exclude    proc    near
  1828.     push    ax
  1829.     push    bx
  1830.     push    cx
  1831.     push    dx
  1832.  
  1833.     mov    ax, 03d02h
  1834.     mov    dx, offset exclude_name
  1835.     int    21h
  1836.     jc    @F
  1837.     mov    bx, ax
  1838.     mov    ah, 03fh
  1839.     mov    dx, offset exclude_buffer
  1840.     mov    cx, 02000h
  1841.     int    21h
  1842.     mov    [exclude_cnt], ax
  1843.     mov    ah, 03eh
  1844.     int    21h
  1845.  
  1846. @@:    pop    dx
  1847.     pop    cx
  1848.     pop    bx
  1849.     pop    ax
  1850.     ret
  1851. read_exclude    endp
  1852. exclude_buffer    equ    $
  1853.  
  1854.  
  1855. already_in:
  1856.     mov    dx, offset bad_inst_msg
  1857.     mov    ah, 9
  1858.     int    21h
  1859.     mov    ax, 04c01h
  1860.     int    21h
  1861.     
  1862. bad_inst_msg    db    CR, LF, BELL, 'DCOMPRES already installed...'
  1863.         db    CR, LF, '$'
  1864. good_inst_msg    db    CR, LF, 'DCOMPRES Copyright (c) 1989 by Ziff Communications Co.', CR, LF
  1865.         db    '         Program by Ross M. Greenberg'
  1866.         db    CR, LF, LF, 'DCOMPRESS V1.1 installed.', CR, LF, LF, '$'
  1867. exclude_name    db    'C:\DCOMPRES.EXL', 0
  1868.  
  1869.  
  1870. @@    equ    good_inst_msg
  1871.  
  1872.  
  1873. cseg    ends
  1874. end    start
  1875.  
  1876.