home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / arcutil / zdir13c.arc / ZDIR13C.ASM next >
Encoding:
Assembly Source File  |  1989-03-27  |  40.1 KB  |  1,649 lines

  1. ;ZDIR .ZIP directory utility
  2. ;From a disassembly and hack of ADIR.EXE
  3.  
  4. ;v1.3c    Bug:  I'd written code to handle no cmdline parms at all,
  5. ;    but failed to test it!  Turns out system locks up!
  6. ;    Thanks to FAAR RBBS for alerting me.  Sloppy testing procedures.
  7.  
  8. ;v1.3b    Bug:  Forgot the added "-v" verbose switch as the FIRST PSP
  9. ;    cmdline argument would blow away using our PSP FCB's to get
  10. ;    the parsed member filename.
  11. ;    Using _Args (from KEGELUNX unix-like cmdline parsing)
  12. ;    to handle the -v switch anywhere on cmdline.
  13. ;    (Affects Parse_CmdLine only.)
  14.  
  15. ;v1.3a    23 Mar 89
  16. ; -    Adding file comment display to verbose mode.
  17. ; -    Because of the occasional padding (by XMODEM) of garbage to the
  18. ;    end of a file, we're back to reading a full 256 bytes at the
  19. ;    ZIP file end to find that end structure (149 bytes for the largest
  20. ;    likely ENDDIR structure, plus the padding to the next 128 boundary).
  21. ;    If you don't HAVE any of these files, change ENDOFS back to 149.
  22.  
  23. ;v1.3    22 Mar 89
  24. ; -    Adding verbose display (a -v switch).
  25. ;    Cribbing code from QBARCV3.ASM (my improvements on QBARV2.ASM,
  26. ;    a utility for RBBS ARC/PAK displays).
  27. ;    Usage:  ZDIR -v foob    (yep, -v must be first parm)
  28.  
  29. ;v1.2    21 Mar 89
  30. ; -    Missed the obvious .. the very last structure in a ZIP file
  31. ;    (call it ENDDIR) contains a pointer to the central directory.
  32. ;    Since the only variable length fields in that last structure
  33. ;    are fairly short (zip comments, etc.), it should be MUCH smaller.
  34. ;    We won't need that huge 5Kb SWAG for the initial directory read.
  35. ;    Cutting buffer down to 128 bytes, reading in ENDDIR to get that
  36. ;    central directory pointer, and then going right to central directory.
  37. ;    Since the max possible ZIP file comment (in ENDDIR) is 7FH bytes,
  38. ;    the max possible ENDDIR would be 7FH + 22 (normal structure size)
  39. ;    or 149 bytes (ENDOFS).
  40. ; -    Moved initial cmdline parsing down to code end
  41. ;    (just to clean up things)
  42. ; -    Caught a bug .. failed on a single '*' wildcard cmdline parm.
  43.  
  44. ;v1.1    18 Mar 89
  45. ; -    Added full pathing capabilities for target .ZIP files.
  46. ; -    Added ambiguous member screening (e.g., search FOOB.ZIP
  47. ;    for just *.ASM files).
  48. ; -    Cleaned up the kludgey ADIR wildcard finds with all its
  49. ;    multiple DTAs, etc.
  50. ; -    Still no way to test for member filename paths.
  51.  
  52. ;Original ADIR.EXE fixes:
  53. ; - Fixed bug that never closed any files!
  54. ; - Changed to .COM format, tightened, etc.
  55.  
  56. ;ZIP functional changes:  MANY!  I consider this almost a total rewrite
  57. ;(except for the kludge with wildcard finds from the original ADIR.EXE).
  58.  
  59. ; - Since the filename length is variable (and may include paths),
  60. ;   the handling, formatting and display is significantly different
  61. ;   than in ADIR.
  62. ; - Have to put back the ambiguous member parsing.
  63.  
  64. ;David Kirschbaum
  65. ;Toad Hall
  66.  
  67. FALSE    equ    0
  68. TRUE    equ    NOT FALSE
  69. CR    equ    0DH
  70. LF    equ    0AH
  71. STDOUT    equ    1
  72. STDERR    equ    2
  73. ENDOFS    equ    256    ;149    ;enough for largest possible        v1.2
  74.                 ;ZIP end directory structure.        v1.2
  75.                 ;(to include XMODEM padding)        v1.3a
  76.  
  77. Print    macro    name            ; display a field
  78.     mov    dx,offset name
  79.     call    PrintS
  80.     endm
  81.  
  82.  
  83. ;PKZIP central directory structure:
  84.  
  85. zdirEntry    STRUC
  86. zsig1    db    50H,4BH,01H,02H    ;central file header signature    4 bytes
  87.                 ;(0x02014b50)
  88. zVerMade    dw    ?    ;version made by        2 bytes
  89. zVerExt        dw    ?    ;version needed to extract    2 bytes
  90. zBitflag    dw    ?    ;general purpose bit flag    2 bytes
  91. zCmpMeth    dw    ?    ;compression method        2 bytes
  92. zModTime    dw    ?    ;last mod file time         2 bytes
  93. zModDate    dw    ?    ;last mod file date        2 bytes
  94. zCrc32        dw    ?,?    ;crc-32               4 bytes
  95. zCmpSiz        dw    ?,?    ;compressed size        4 bytes
  96. zUncmpSiz    dw    ?,?    ;uncompressed size        4 bytes
  97. zNameLen    dw    ?    ;filename length        2 bytes
  98. zExtraLen    dw    ?    ;extra field length        2 bytes
  99. zFilCmtLen    dw    ?    ;file comment length        2 bytes
  100. zDskNrPtr    dw    ?    ;disk number start        2 bytes
  101. zIntAttr    dw    ?    ;internal file attributes    2 bytes
  102. zExtAttr    dw    ?,?    ;external file attributes    4 bytes
  103. zHdrOfs        dw    ?,?    ;relative offset of local header 4 bytes
  104. zFilename    db    ?    ;filename (variable size)
  105.                 ;extra field (variable size)
  106.                 ;file comment (variable size)
  107. zdirEntry    ENDS
  108.  
  109. ;      End of central dir record:
  110.  
  111. zdirEnd    STRUC
  112. zEndSig    db    50H,4BH,05H,06H    ;end of central dir signature    4 bytes
  113.                 ;(0x06054b50)
  114. zDskNr    dw    ?        ;number of this disk        2 bytes
  115. zDirDsk    dw    ?        ;number of the disk with the
  116.                 ;start of the central directory    2 bytes
  117. zDskNrEntry dw    ?        ;total number of entries in
  118.                 ;the central dir on this disk    2 bytes
  119. zDirNrEntry dw    ?        ;total number of entries in
  120.                 ;the central dir        2 bytes
  121. zDirSiz    dw    ?,?        ;size of the central directory   4 bytes
  122. zDirOfs    dw    ?,?        ;offset of start of central
  123.                 ;directory with respect to
  124.                 ;the starting disk number    4 bytes
  125. zCmtLen dw    ?        ;zipfile comment length        2 bytes
  126. zCmt    db    ?        ;zipfile comment (variable size)
  127. zdirEnd    ENDS
  128.  
  129.  
  130. CSEG    segment    para public
  131.     assume    CS:CSEG,DS:CSEG
  132.  
  133.     org    5CH        ;FCB #1
  134.     db    ?        ;drive val
  135. fcb1    db    10H dup(?)    ;5DH, FCB #1 first char
  136. fcb2    db    10H dup(?)    ;6DH, FCB #2 first char
  137.     org    80H
  138. nchar    db    ?
  139. params    db    ?
  140.  
  141. ;program entry point
  142.     org    100H
  143.  
  144. Zdir    proc    near
  145.     jmp    Start        ;skip over runtime data
  146.  
  147.  
  148. usage    db    CR,LF,9,9, 'ZDIR version 1.03c, 880327',CR,LF
  149.     db    9,9,'David Kirschbaum, Toad Hall',CR,LF
  150.     db    9,9, 'USAGE: ',9,'ZDIR zipname[.zip] [afn] [-v]',CR,LF
  151.     db    9,9,9,'zipname may be ambiguous (wildcarded)',CR,LF
  152.     db    9,9,9,'afn = ambiguous member file name', CR,LF
  153.     db    9,9,9,'-v  = verbose display',CR,LF
  154. USAGELEN equ    $ - usage
  155.  
  156. ziptyp    db    '.ZIP'
  157. ZIPTYPLEN    equ    $ - ziptyp
  158.  
  159. msg1    db    CR,LF, 9, 9, 9, ' ZIP file: '
  160. MSG1LEN    equ    $ - msg1
  161. msg2    db    'ZIP file not found',CR,LF
  162. MSG2LEN    equ    $ - msg2
  163. msg3    db    'Central directory not found',CR,LF
  164. MSG3LEN    equ    $ - msg3
  165. msg4    db    'ZIP is out of alignment or it''s not a ZIP'
  166. crlf    db    CR,LF
  167. MSG4LEN    equ    $ - msg4
  168. CRLFLEN    equ    $ - crlf
  169.  
  170. rivvvt    db    'Rivvvvt',CR,LF
  171. RVTLEN    equ    $ - rivvvt
  172.  
  173.  
  174. handle    dw    0
  175. flag1    db    LOW(TRUE)        ;Find First flag        v1.3
  176. verbose    db    LOW(FALSE)        ;verbose display switch        v1.3
  177. znameptr dw    0            ;point past ZIP target file path v1.1
  178. mnameptr dw    0            ;remember .zFilename start    v1.1
  179. dirNrEntry dw    0            ;central directory file count    v1.2
  180. dirctr    dw    0            ;for counting down members    v1.3
  181.  
  182. Comment        ~  Looks like:
  183. +filename.typ 000K / 000K  +filename.typ 000K / 000K  +filename.typ 000K / 000K
  184. Comment    ends    ~
  185. blankline db    '         .       K /    K           .       K /    K  '
  186.       db    '         .       K /    K',CR,LF
  187. LINELEN    equ    $ - blankline
  188.  
  189. ;v1.3    Verbose display data
  190. ;    display lines for verbose
  191.  
  192. vhdr    db    CR,LF
  193.  db 'Name          Length    Stowage    SF   Size now  Date       Time    CRC '
  194.  db CR,LF
  195.  db '============  ========  ========  ====  ========  =========  ======  ===='
  196.  db CR,LF
  197. VHDRLEN    equ    $ - vhdr
  198.  
  199. vline    label    byte        ;db    CR,LF
  200. vname    db    14 dup (' ')
  201. vlength db    '          '    ; length in archive            v1.3
  202. vstyle  db    '          '    ; compression method
  203. vfactor db    ' xx%  '    ; compression factor
  204. vsize    db    10 dup (' ')    ; actual file bytes
  205. vdate    db    'dd '        ; creation date
  206.  vmonth db    'mmm '
  207.  vyear  db    'yy  '
  208.  vtime  db    'hh:mm   '    ; creation time
  209.  vcrc    db    'xxxx'        ; crc in hex
  210.     db    CR,LF
  211. VLINELEN    equ    $ - vline
  212.  
  213.  
  214. ;    final totals line
  215.  
  216. vthdr    db    '*Total    ' ;                   ' CPC151A
  217.  vtmbrs db    '    '
  218.  vtlen  db    8 dup (' '),'  '
  219.     db    10 dup (' ')
  220.  vtsf    db    '   %  '
  221.  vtsize db    8 dup (' ')
  222.     db    CR,LF        ; for tom
  223. VTHDRLEN    equ    $ - vthdr
  224.  
  225. totcmp  dw    0,0        ; total of file lengths
  226. totuncmp dw    0,0        ; total of file sizes
  227. totmbrs dw    0        ; total number of files
  228. TOTLEN    equ    $ - totcmp
  229.  
  230. ttotcmp    dw    0,0
  231. ttotuncmp dw    0,0
  232. ttotmbrs dw    0
  233.  
  234. ;v1.3    ZIP compression types:
  235.  
  236. zstyles    label    byte
  237.     db    '  Stored'    ;0 - The file is stored (no compression)
  238.     db    '  Shrunk'    ;1 - The file is Shrunk
  239.     db    'Reduced1'    ;2 - Reduced with compression factor 1
  240.     db    'Reduced2'    ;3 - Reduced with    "    "    2
  241.     db    'Reduced3'    ;4 - Reduced with    "    "    3
  242.     db    'Reduced4'    ;5 - Reduced with    "    "    4
  243.  
  244. months  db    'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec '
  245.  
  246.  
  247. Zdir    endp
  248.  
  249. Start    proc    near
  250.  
  251.     call    Parse_CmdLine            ;parse cmdline for    v1.2
  252.                         ;target filenames
  253.     jb    Jmp_Msg_Term            ;failed            v1.2
  254.  
  255. ;Let's get to work
  256.  
  257.     call    Find_Zip
  258.     jnc    ZipLup_73            ;found the first one
  259.      mov    dx,offset msg2            ;'Zipfile not found'
  260.      mov    cx,MSG2LEN
  261. Jmp_Msg_Term:
  262.      jmp    Msg_Term            ;display, terminate
  263.  
  264. ZipLup_73:
  265.     call    Read_CentralDir            ;try to read in file trailer
  266.     jnb    Got_Dir                ;found it, DS:BX -> directory
  267.  
  268.      mov    dx,offset msg3            ;'No central directory'
  269.      mov    cx,MSG3LEN
  270.      jmp    short Next1            ;right to next ZIP file v1.2
  271.  
  272. Got_Dir:
  273.     cmp    verbose,LOW(TRUE)        ;verbose mode?        v1.3
  274.     jnz    Got_NotVerbose            ;nope
  275.      mov    dx,offset vhdr            ;display verbose header    v1.3
  276.      mov    cx,VHDRLEN
  277.      call    Pr_StdOut
  278.      jmp    short MemberLup
  279.  
  280. Got_NotVerbose:
  281.     call    Refresh_LineBuff        ;Init formatted display line
  282.  
  283. MemberLup:
  284.     cmp    word ptr [bx],4B50H        ;signature?
  285.     jnz    Bad_Dir                ;nope, bogus
  286.     cmp    word ptr 2[bx],0201H        ;normal entry?
  287.     jnz    Bad_Dir                ;nope, bogus        v1.2
  288.  
  289. ;Normal directory entry.  Display it.
  290.  
  291.     call    Show_FileData            ;display entry info
  292.     dec    dirctr                ;decr nr entries    v1.3
  293.     jz    Next_Zip            ;last entry        v1.2
  294.      jmp    MemberLup            ;next member
  295.  
  296.  
  297. Bad_Dir:
  298.     mov    dx,offset msg4            ;'ZIP is out of alignment'
  299.     mov    cx,MSG4LEN            ; or not a .ZIP file'
  300.     call    Pr_StdOut            ;display msg
  301.  
  302. Next_Zip:
  303.     mov    dx,offset crlf            ;need a new line
  304.     mov    cx,CRLFLEN            ;length
  305.     cmp    verbose,LOW(TRUE)        ;verbose mode?        v1.3
  306.     jz    Show_Verbose_Totals        ;yep, maybe display totals v1.3
  307.  
  308.     mov    ax,offset LINEBUFF        ;formatted line start
  309.     cmp    di,ax                ;got any file entries?
  310.     jz    Next1                ;nope
  311.      dec    di                ;back up over the two spaces
  312.      dec    di                ; from the last file size
  313.      mov    dx,ax                ;DX'll need it for display
  314.      mov    cx,ax                ;CX will be nr chars
  315.      mov    ax,0A0DH            ;CR/LF
  316.      stosw                    ;stuff
  317.      stosw                    ;2 CR/LFs
  318.      xchg    cx,di                ;CX = end, DI = start
  319.      sub    cx,di                ;end - start = length
  320.      jmp    short Next1
  321.  
  322. ;v1.3    Verbose mode
  323. Show_Verbose_Totals:
  324.     cmp    totmbrs,0            ;any totals?
  325.     jz    Next1                ;nope
  326.      call    Format_Totals            ;yep, format
  327.                         ;CX,DX prepared for ...
  328. Next1:
  329.     call    Pr_StdOut            ;display line seg or CR/LF
  330. Next2:
  331.     call    Find_Zip            ;next .ZIP file
  332.     jnc    ZipLup_73            ;found it, loop
  333.  
  334.     cmp    verbose,LOW(TRUE)        ;verbose mode?
  335.     jnz    No_More                ;nope
  336.  
  337. ;v1.3    We've been accumulating overall totals.
  338. ;    Now display them.  Gotta move the total totals
  339. ;    into the totals (where Format_Totals expects them).
  340.  
  341.     mov    ax,ttotmbrs            ;accumulated total mbrs
  342.     cmp    ax,dirNrEntry            ;just the one ZIP?
  343.     jz    No_More                ;yep, forget the total totals
  344.  
  345.     mov    si,offset ttotcmp        ;move total totals
  346.     mov    di,offset totcmp        ;into totals
  347.     mov    cx,TOTLEN SHR 1            ;nr words
  348.     rep    movsw
  349.  
  350.     call    Pr_CrLf                ;down extra line
  351.     call    Format_Totals            ;format overall totals
  352.     call    Pr_StdOut            ;display them
  353.  
  354. No_More:
  355.     mov    dx,offset rivvvt
  356.     mov    cx,RVTLEN            ;fall thru to...
  357.     xor    ax,ax                ;ERRORLEVEL 0
  358.  
  359. Msg_Term:
  360.     push    ax                ;save errorlevel
  361.     call    Pr_StdOut            ;display error msg
  362.     pop    ax
  363.     mov    ah,4Ch                ;terminate, AL = ERRORLEVEL
  364.     int    21h
  365.  
  366. Start    endp
  367.  
  368.  
  369. ;SUBROUTINE
  370.  
  371. Find_Zip    proc    near
  372.  
  373. ;We reset our DTA to the default PSP DTA each time through.
  374. ;The actual ZIP file open uses another one.
  375.  
  376.     mov    dx,80H                ;use PSP DTA
  377.     mov    ah,1AH                ;set DTA
  378.     int    21h
  379.  
  380.     cmp    flag1,0FFh            ;first time thru?
  381.     jne    FindNext_162            ;nope
  382.  
  383. ;First time through
  384.     not    flag1                ;set to NOT first time thru
  385.  
  386.     mov    dx,offset ziptarget        ;DS:DX -> zip target name
  387.     xor    cx,cx                ;read-only
  388.     mov    ah,4Eh                ;find first
  389.     int    21h
  390.     jmp    short Find_Done
  391.  
  392. FindNext_162:
  393.     mov    ah,4Fh                ;find next
  394.     int    21h
  395. Find_Done:
  396.     jb    FindZ_X                ;failed, return CF set
  397.     call    Move_FileName            ;move name in after path
  398.                         ;to create full name for open
  399.  
  400. ;Found target file.  Announce, set new DTA, open it.
  401.  
  402.     mov    dx,offset msg1            ;'Zip file: '
  403.     mov    cx,MSG1LEN
  404.     call    Pr_StdOut
  405.     Print    ziptarget            ;'filename.zip'        v1.3
  406.     call    Pr_CrLf                ;new line
  407.  
  408. ;We need a new DTA for the file open/read so we don't blow away
  409. ;the find first/find next stuff in the PSP DTA.
  410.  
  411.     mov    dx,offset dta1BA        ;DS:DX -> new DTA
  412.     mov    ah,1Ah                ;set DTA
  413.     int    21h
  414.  
  415.     mov    dx,offset ziptarget        ;DS:dx -> filename buffer
  416.     mov    ax,3D00H            ;open file, read only
  417.     int    21h
  418.     mov    handle,ax            ;save handle
  419. FindZ_X:
  420.     ret
  421. Find_Zip    endp
  422.  
  423.  
  424. Move_FileName    proc    near
  425.  
  426.     mov    si,9EH                ;FCB #1 +1
  427.     mov    di,znameptr            ;pointer to after path
  428.     mov    cx,13                ;include AsciiZ 0
  429.     rep    movsb
  430.     ret
  431.  
  432. Move_FileName    endp
  433.  
  434.  
  435. ;Reads in file tailer.
  436. ;Then scans for the unique central directory signature.
  437. ;On success:
  438. ;    DS:BX -> central directory structure
  439. ;    readlen = nr bytes actually read
  440. ;    CF clear
  441. ;Else CF set for failure
  442.  
  443. Read_CentralDir    proc    near
  444.  
  445.     xor    cx,cx                ;CX:DX = offset from end
  446.     xor    dx,dx                ;to very end
  447.     mov    bx,handle            ;file handle
  448.     mov    ax,4202H            ;move file pointer to end
  449.     int    21H                ;gets file size in DX:AX
  450.     jb    RCD_Close            ;seek failed
  451.  
  452.     sub    ax,ENDOFS            ;back up psn.lo
  453.     jnb    Read1                ;ok, no problem
  454.      sub    dx,1                ;got a borrow, decr psn.hi
  455.      jnb    Read1                ;no problem
  456.       xor    ax,ax                ;sigh .. small file ..
  457.       xor    dx,dx                ; .. back to very start
  458. Read1:
  459.     mov    cx,dx                ;psn.hi
  460.     mov    dx,ax                ;psn.lo
  461.     mov    ax,4200H            ;now move from start
  462.     int    21H                ;CX:DX point to offset from end
  463.                         ;(big) or to start (small)
  464.     jb    RCD_Close            ;failed, close up
  465.  
  466.     mov    cx,ENDOFS            ;try to read this much
  467.     mov    dx,offset DIRBUFF        ;into our directory buffer
  468.     mov    di,dx                ;DI'll need it in a second
  469.     mov    ah,3FH                ;read from file/device
  470.     int    21H
  471.     jb    RCD_Close            ;failed, close up
  472.  
  473. ;v1.2    First scan the end structure to locate the central directory.
  474.  
  475.     call    Sig_Scan            ;find the structure start
  476.     jb    RCD_InvalidDir            ;failed, close and exit
  477.  
  478. ; ES:DI -> end structure start (the signature)
  479. ;v1.3a    While we have the end structure, let's pick up and display
  480. ;    any ZIP file comment.
  481.     mov    cx,[di].zCmtLen            ;comment length
  482.     jcxz    RCD_NoComment            ;nope, forget it
  483.  
  484.      lea    dx,[di].zCmt            ;DS:DX -> comment
  485.      call    Pr_StdOut            ;display it.
  486.      call    Pr_CrLf                ;and a new line
  487.  
  488. RCD_NoComment:
  489.  
  490. ; Pick up the central directory file pointer (long integer):
  491. ; It's a pointer directly to the central directory start.
  492. ; This will only work for single-disk ZIP files.
  493.  
  494.     mov    si,[di].zDirSiz            ;save central directory size
  495.  
  496.     mov    ax,[di].zDirNrEntry        ;nr central dir entries
  497.     mov    dirNrEntry,ax            ;save it for later
  498.     mov    dirctr,ax            ;two places
  499.  
  500.     mov    dx,[di].zDirOfs            ;central directory offset.lo
  501.     mov    cx,[di].zDirOfs[2]        ;offset.hi
  502.     mov    ax,4200H            ;move file ptrs from start
  503.     int    21H
  504.     jb    RCD_Close            ;seek failed, close and exit
  505.  
  506.     mov    cx,si                ;read central dir size bytes
  507.     mov    dx,offset dirbuff        ;into our directory buffer
  508.     mov    ah,3FH                ;read from file/device
  509.     int    21H
  510.     jb    RCD_Close            ;failed, forget it
  511.  
  512.     mov    di,dx                ;DI -> dir start
  513.     xor    ax,ax                ;return AX=0 for ok
  514.     cmp    word ptr [di],4B50H        ;is it a signature?
  515.     jnz    RCD_InvalidDir            ;nope
  516.      cmp    word ptr 2[di],0201H        ;is it a file entry sig?
  517.      jz    RCD_Close            ;yep, good to go, CF clear
  518.  
  519. RCD_InvalidDir:
  520.     mov    al,11                ;Invalid format
  521.     stc                    ;insure CF set, AL=error
  522. RCD_Close:
  523.     mov    dx,ax                ;save error value (if any)
  524.     pushf                    ;save flags
  525.     mov    ah,3EH                ;close file
  526.     int    21H                ;(BX = file handle)
  527.     popf                    ;restore orig flags
  528.     mov    ax,dx                ;and any error value
  529.     mov    bx,di                ;if it went well,
  530.                         ;DS:BX -> central dir struc
  531.     ret
  532.  
  533.  
  534. ;v1.2    Subroutine for Read_CentralDir
  535. ;    Scans backwards through buffer for a directory end signature.
  536. ;    Enter with:
  537. ;    SI = second two signature bytes
  538. ;    DX -> buffer start
  539. ;    AX = bytes read
  540.  
  541. ;We must scan at the byte level (since a member or directory entry
  542. ;can be ANY length).
  543.  
  544. Sig_Scan:
  545.     mov    di,dx                ;ES:DI -> DIRBUFF
  546.                         ;(now a ZIP end dir structure)
  547.     add    di,ax                ;+ bytes read = -> buff end
  548.     mov    cx,ax                ;bytes read for the scan
  549.     inc    cx                ;debug for MAX size
  550.     inc    cx
  551.     mov    ax,4B50H            ;scan for first signature char
  552.                         ;(same for all structures) v1.2
  553.     mov    si,0605H            ;2d 2 chars of a directory
  554.                         ;end structure signature
  555.     std                    ;scan from end to start
  556.  
  557. SS_Lup:
  558.     repne    scasb                ;ES:DI -> read buffer
  559.     jnz    No_Sig                ;not found
  560.     jcxz    No_Sig                ;scanned it all
  561.  
  562. ;ES:DI -> the byte BEFORE the 50H signature
  563.  
  564.     cmp    2[di],ah            ;2d signature byte?
  565.     jnz    SS_Lup                ;nope, keep searching
  566.     cmp    3[di],si            ;last 2 signature bytes?
  567.     jnz    SS_Lup                ;nope, keep searching
  568.  
  569.     inc    di                ;bump from that last scasb
  570.                         ;DS:DI -> dir structure
  571.     cld                    ;forwards again to be neat
  572.     clc                    ;CF clear for success
  573.     ret
  574.  
  575. No_Sig:    cld                    ;forward again to be neat
  576.     stc                    ;return CF set for failure
  577.     ret
  578.  
  579. Read_CentralDir    endp
  580.  
  581.  
  582. ;SUBROUTINE
  583. ;1 call
  584. Show_FileData    proc    near
  585.  
  586. ;v1.1    Adding tests for cmdline member name testing
  587.     call    Member_Test            ;see if file is eligible
  588.     jb    SF_NextRec            ;nope, forget it
  589.  
  590.     push    bx
  591.  
  592.     cmp    verbose,LOW(TRUE)        ;verbose?        v1.3
  593.     jnz    SFD_NonVerbose            ;nope            v1.3
  594.      call    Show_Verbose            ;yep, show verbose    v1.3
  595.      jmp    short SFD_BumpPtrs
  596.  
  597. SFD_NonVerbose:
  598.     call    Stuff_FileName            ;parse, pad at ES:DI
  599.  
  600.     lea    si,[bx].zCmpSiz            ;compressed size (long int)
  601.     call    Stuff_FileSize            ;to ES:DI
  602.  
  603.     lea    si,[bx].zUncmpSiz        ;uncompressed size
  604.     inc    di                ;adjust line ptr
  605.     call    Stuff_FileSize            ;stuff uncompressed size
  606.                         ; to ES:DI
  607.     cmp    di,offset LINEBUFF + LINELEN    ;hit end?
  608.     jb    SFD_BumpPtrs            ;nope
  609.      mov    dx,offset LINEBUFF        ;display the line
  610.      mov    cx,LINELEN            ;length
  611.      call    Pr_StdOut            ;display it
  612.      call    Refresh_LineBuff        ;refresh dynamic variable
  613.  
  614. SFD_BumpPtrs:
  615.     pop    bx
  616.  
  617. SF_NextRec:
  618. ;Now bump our BX pointer to the next entry
  619.     lea    ax,[bx].zFilename        ;from filename start
  620.     add    ax,[bx].zNameLen        ;add in name field length
  621.     add    ax,[bx].zExtraLen        ;and extra field length
  622.     add    ax,[bx].zFilCmtLen        ;and file comment field length
  623.     mov    bx,ax                ;should be next record
  624.     ret
  625.  
  626. Show_FileData    endp
  627.  
  628. ;v1.1    Tests to see if THIS file is eligible (e.g., meets the ambiguous
  629. ;    filename entered on cmdline at startup).
  630. ;    If no such parm, accept it (return CF clear).
  631. ;    If it matches, return CF clear.
  632. ;    If no match, return CF set.
  633.  
  634. ;    While we're here, let's Asciify that stupid ZIP directory file name
  635. ;    for later tests.
  636.  
  637. Member_Test    proc    near
  638.  
  639.     mov    cx,[bx].zNameLen        ;name length
  640.     jcxz    MT_Fail1            ;zero .. flunk it!
  641.  
  642.     push    di                ;save formatted line pointer
  643.  
  644.     lea    si,[bx].zFilename        ;dirEntry filename
  645.     mov    di,si                ;start
  646.     dec    di                ;back it up one
  647.     mov    ax,di                ;remember new start
  648.     mov    dx,cx                ;save length
  649.  
  650.     rep    movsb                ;move it left 1 byte
  651.     mov    byte ptr [di],0            ;AsciiZ the name
  652.  
  653.     mov    cx,dx                ;restore count
  654.     mov    si,ax                ;new start
  655.     mov    mnameptr,ax            ;assume no paths
  656.  
  657.     cmp    byte ptr 1[si],':'        ;a drive separator?
  658.     jnz    MT_NoDrive            ;nope
  659.      mov    ax,2
  660.      add    si,ax                ;bump past d:
  661.      sub    cx,ax                ;adjust length counter
  662.      jbe    MT_Fail                ;zeroed out, flunk it!
  663.  
  664. MT_NoDrive:
  665.  
  666. ;Check for directory slashes
  667.     mov    di,si                ;starting point
  668.     mov    al,'\'                ;scan for directory slashes
  669.  
  670. MT_SlashScan:
  671.     repne    scasb
  672.     jnz    MT_NoSlash            ;none
  673.      jcxz    MT_Fail                ;zeroed out, flunk it!
  674.      mov    si,di                ;new starting point
  675.      jmp    MT_SlashScan            ;and try again until all gone
  676.  
  677. MT_NoSlash:
  678.  
  679. ;SI now points at first filename char.
  680.  
  681.     mov    mnameptr,si            ;remember the new address
  682.  
  683.     cmp    byte ptr pname1,20H        ;empty 2d cmdline parm?
  684.     jz    MT_Done                ;empty, forget the compares
  685.  
  686.     mov    di,offset fcb3            ;ES:DI -> dynamic working FCB
  687.     mov    dx,di                ;save a sec
  688.     xor    ax,ax                ;fill with 0's
  689.     mov    cx,6                ;clear old 12-byte filename
  690.     rep    stosw
  691.     mov    di,dx                ;ES:DI -> dynamic working FCB
  692.     mov    ax,2900H + 00001101b        ;parse filename
  693.                         ;(strip leading spaces,
  694.                         ; don't set drive spec,
  695.                         ; change only if valid)
  696.     int    21H
  697.     cmp    al,0FFH                ;failed?
  698.     jz    MT_Fail                ;yep
  699.  
  700. ;We can now compare two expanded file names .. the 2d cmdline parm
  701. ;and the ZIP file member.
  702.  
  703.     inc    di                ;skip leading 0 in filename
  704.     mov    si,offset pname1        ;possible 2d cmdline parm
  705.  
  706. MT_CmpLup:
  707.     lodsb                    ;arg1 char
  708.     or    al,al                ;hit end?
  709.     jz    MT_Done                ;yep, done with a match
  710.     mov    ah,[di]                ;snarf expanded name char
  711.     inc    di                ;bump expanded filename pointer
  712.     cmp    al,'?'                ;wildcard? (no test)
  713.     jz    MT_CmpLup            ;yep, no test
  714.     cmp    al,ah                ;match?
  715.     jz    MT_CmpLup            ;yep, continue
  716.  
  717. MT_Fail:                    ;no match
  718.     pop    di                ;restore formatted line ptr
  719.  
  720. MT_Fail1:
  721.     stc                    ;return CF set
  722. MT_X:    ret
  723.  
  724. MT_Done:
  725.     pop    di
  726.     clc                    ;return CF clear for success
  727.     ret
  728.  
  729. Member_Test    endp
  730.  
  731.  
  732. ;v1.1    ES:DI -> next position on formatted line
  733. ;    zFilename is now AsciiZed
  734. ;    mnameptr contains ptr to original or real zFilename start
  735. ;    (paths stripped)
  736.  
  737. Stuff_FileName    proc    near
  738.  
  739.     push    di                ;save formatted line ptr
  740.  
  741.     mov    al,' '                ;assume no paths
  742.     lea    si,[bx].zFilename        ;dirEntry filename start
  743.     dec    si                ;adjust for previous backup
  744.     cmp    si,mnameptr            ;same as member search?
  745.     jz    SN_NoPaths            ;yep, means no paths
  746.      mov    si,mnameptr            ;pick up REAL start
  747.      mov    al,'+'                ;stuff a symbol for paths
  748. SN_NoPaths:
  749.     stosb                    ;stuff space or '+'
  750.     mov    dx,di                ;name start
  751.     add    dx,8                ;bump to the dot
  752.  
  753. SN_Lup:    lodsb
  754.     or    al,al                ;hit AsciiZ 0 yet?
  755.     jz    SN_Done                ;yep
  756.     cmp    al,'.'                ;.typ separator?
  757.     jnz    SN_NoDot            ;nope
  758.      cmp    di,dx                ;where the dot should go?
  759.      jz    SN_NoDot            ;yep, put it there
  760.      mov    di,dx                ; bump to the dot psn
  761. SN_NoDot:
  762.     stosb                    ;stuff in formatted line
  763.     jmp    SN_Lup
  764.  
  765. SN_Done:
  766.     pop    di                ;orig ptr
  767.     add    di,14                ;bump to size psn
  768.     ret
  769.  
  770. Stuff_FileName    endp
  771.  
  772.  
  773. ;SUBROUTINE
  774. ;2 calls
  775. Stuff_FileSize    proc    near
  776.     push    bx                ;Preserve BX! (dta ptr)
  777.  
  778.     add    di,3                ;move to number string end
  779.     push    di                ;save it (ptr to last digit)
  780.  
  781.     mov    ax,[si]
  782.     mov    dx,[si+2]
  783.     add    ax,3FFh                ;div 1024 to get Kb
  784.     adc    dx,0
  785.     mov    cl,0Ah
  786.     shr    ax,cl
  787.     mov    cl,6
  788.     shl    dx,cl
  789.     add    ax,dx
  790.  
  791.     mov    si,0Ah
  792. SFS_Lup:
  793.     xor    dx,dx
  794.     div    si
  795.     add    dl,30H                ;asciify
  796.     dec    di                ;back up the digit pointer
  797.     mov    [di],dl                ;stuff digit in buffer
  798.     or    ax,ax                ;number done?
  799.     jnz    SFS_Lup                ;nope
  800.  
  801.     pop    di                ;restore line buffer ptr
  802.     add    di,3                ;bump past ' / ' or ' | '
  803.     pop    bx
  804.     ret
  805.  
  806. Stuff_FileSize    endp
  807.  
  808.  
  809. ;v1.3    Verbose display functions
  810. ;v1.3    Format, display single line for each member
  811. ;    On success, return:
  812. ;     CF clear
  813. ;     AL = 0
  814. ;    On error, return:
  815. ;     CF set (because of output write fail)
  816. ;     AL = error code
  817. ;    Preserve BX (buffer ptr)
  818.  
  819. sign    db    ' '                ;local variable
  820. hundred dw    100                ; for computing percentages
  821.  
  822. Show_Verbose    proc    near
  823.  
  824.     mov    si,mnameptr            ;move real member name
  825.                         ;(no paths)
  826.     mov    di,offset vname            ;into formatted line
  827.     mov    cx,word ptr 13            ;13 spaces in field
  828. SV_Lup:
  829.     lodsb                    ;snarf char
  830.     or    al,al                ;AsciiZ ending?
  831.     jz    SV_5                ;yep
  832.     stosb
  833.     loop    SV_Lup
  834.  
  835. SV_5:
  836.     mov    al,' '
  837.     rep    stosb                ;pad with spaces
  838.  
  839. ; reduce the size/length to word values
  840.  
  841.     mov    si,[bx].zUncmpSiz        ; get uncompressed file size
  842.     mov    ax,[bx].zUncmpSiz[2]
  843.  
  844.     mov    cx,[bx].zCmpSiz            ;compressed size
  845.     mov    dx,[bx].zCmpSiz[2]
  846.  
  847. SV_51: or    ax,ax                ; big number?
  848.     jz    SV_52                ; nope, can use it
  849.      shr    ax,1                ; yup, divide by two
  850.      rcr    si,1
  851.      shr    dx,1
  852.      rcr    cx,1
  853.      jmp    SV_51                ;loop
  854.  
  855. SV_52:
  856.     mov    ax,si                ; low word of actual size
  857.     mov    sign,' '
  858.     cmp    ax,cx                ; arc member is larger?
  859.     jb    SV_520
  860.      sub    ax,cx                ; amount saved
  861.      jmp    short SV_56
  862.  
  863. SV_520:
  864.     sub    ax,cx
  865.     neg    ax
  866.     mov    sign,'-'
  867.  
  868. SV_56:
  869.     mul    hundred                ; to percentage
  870.     add    ax,50
  871.     adc    dx,0                ; round up percent
  872.     or    si,si                ; empty file?
  873.     jnz    SV_53
  874.      mov    ax,100
  875.      jmp    short SV_54
  876.  
  877. SV_53: div    si
  878. SV_54:
  879.     cmp    ax,100                ; archive fouled?
  880.     jbe    SV_55
  881.      sub    ax,ax
  882. SV_55:
  883.     mov    di,offset vfactor-2        ;format stowage factor
  884.     call    Asciify                ;display AX
  885.  
  886.     mov    al,sign
  887.     mov    vfactor,al
  888.  
  889.     mov    si,[bx].zCmpMeth        ;method of compression
  890.     mov    cl,3                ; eight bytes each entry
  891.     shl    si,cl
  892.  
  893.     add    si,offset zstyles        ;point into style table
  894.     mov    di,offset vstyle
  895.     mov    cx,word ptr 4            ;move as words (8 bytes)
  896.     rep    movsw
  897.  
  898.     mov    dx,[bx].zCmpSiz[2]        ;compressed size.hi
  899.     mov    ax,[bx].zCmpSiz            ;compressed size
  900.     add    totuncmp,ax            ;accumulate
  901.     adc    totuncmp[2],dx
  902.     mov    di,offset vsize            ;format file size
  903.     call    Asciify_Long
  904.  
  905.     mov    dx,[bx].zUncmpSiz[2]        ;uncompressed size.hi
  906.     mov    ax,[bx].zUncmpSiz        ;uncompressed size.lo
  907.     add    totcmp,ax            ;accumulate
  908.     adc    totcmp[2],dx
  909.     mov    di,offset vlength        ;format file length
  910.     call    Asciify_Long
  911.  
  912.     mov    ax,[bx].zModDate        ; format file date
  913.     call    GetDate
  914.  
  915.     mov    ax,[bx].zModTime        ; format file time
  916.     call    GetTime
  917.  
  918.     mov    ax,[bx].zCrc32            ; format crc in hex
  919.     mov    di,offset vcrc            ;(just low word for now)
  920.     call    Cvh
  921.  
  922.     inc    totmbrs                ;bump total file count
  923.  
  924.     mov    dx,offset vline            ;display formatted info
  925.     mov    cx,VLINELEN
  926.     call    Pr_StdOut
  927.     ret
  928.  
  929. Show_Verbose    endp
  930.  
  931.  
  932. ;v1.3    Formats, displays verbose totals
  933.  
  934. Format_Totals    proc    near
  935.  
  936.     mov    ax,totmbrs        ;total members
  937.     add    ttotmbrs,ax        ;accumulate
  938.     mov    di,offset vtmbrs-2    ;format total members
  939.     call    Asciify
  940.  
  941.     mov    dx,totcmp[2]        ;total compressed file size
  942.     mov    ax,totcmp
  943.     add    ttotcmp,ax        ;accumulate total totals
  944.     adc    ttotcmp[2],dx
  945.     mov    di,offset vtlen        ;format total compressed file size
  946.     call    Asciify_Long
  947.  
  948.     mov    dx,totuncmp[2]        ; total uncompressed file size
  949.     mov    ax,totuncmp
  950.     add    ttotuncmp,ax        ;accumulate total totals
  951.     adc    ttotuncmp[2],dx
  952.     mov    di,offset vtsize    ;format total uncompressed file size
  953.     call    Asciify_Long
  954.  
  955. ; reduce the total size/length to word values
  956.  
  957.     mov    si,totcmp        ; get compressed file size
  958.     mov    ax,totcmp[2]
  959.     mov    cx,totuncmp        ; uncompressed file size
  960.     mov    dx,totuncmp[2]
  961.  
  962. FTDiv:    or    ax,ax            ; big number?
  963.     jz    FT2            ; nope, can use it
  964.      shr    ax,1            ; yup, divide by two
  965.      rcr    si,1
  966.      shr    dx,1
  967.      rcr    cx,1
  968.      jmp    short FTDiv
  969.  
  970. FT2:
  971.     mov    ax,si
  972.     mov    sign,' '        ;whata kludge
  973.     cmp    ax,cx            ;compressed > uncompressed?
  974.     jb    FT3            ;yep
  975.      sub    ax,cx            ;amount saved
  976.      jmp    short FT4
  977.  
  978. FT3:    sub    ax,cx
  979.     neg    ax
  980.     mov    sign,'-'
  981.  
  982. FT4:    mul    hundred            ; to percentage
  983.     add    ax,50
  984.     adc    dx,0            ; round up percent
  985.     or    si,si            ; empty file?
  986.     jnz    Ft5
  987.      mov    ax,100
  988.      jmp    short FT6
  989.  
  990. FT5:    div    si
  991. FT6:    mov    di,offset vtsf-2    ;format stowage factor
  992.     call    Asciify            ;AX
  993.  
  994.     mov    al,sign
  995.     mov    vtsf,al
  996.  
  997.     mov    di,offset totcmp    ;starting at totcmp
  998.     mov    cx,TOTLEN/2        ;length of totals to clear (words)
  999.     xor    ax,ax            ;handy 0
  1000.     rep    stosw
  1001.  
  1002.     mov    dx,offset vthdr        ;prepare to display totals
  1003.     mov    cx,VTHDRLEN        ;msg length
  1004.     ret                ;to display
  1005.  
  1006. Format_Totals    endp
  1007.  
  1008.  
  1009. ;    format the time (in AX)
  1010.  
  1011. time    record  hour:5,min:6,sec:5    ;packed time
  1012.  
  1013. GetTime proc    near            ;format the date
  1014.     mov    di,offset vtime
  1015.     or    ax,ax            ;it is zero?
  1016.     jz    GotTime
  1017.  
  1018.     push    ax            ;save date
  1019.     and    ax,mask hour        ;get hour part
  1020.     mov    cl,hour            ;bits to shift
  1021.     shr    ax,cl
  1022.     call    Cnvrt1
  1023.     stosw
  1024.     mov    al,':'
  1025.     stosb
  1026.  
  1027. GT3:    pop    ax            ;get the time back
  1028.     and    ax,mask min        ;get min part
  1029.     mov    cl,min            ;bits to shift
  1030.     call    Cnvrt
  1031.     stosw
  1032. GotTime:ret
  1033.  
  1034. GetTime endp
  1035.  
  1036.  
  1037. Cnvrt2  proc    near            ;convert to ascii
  1038.  
  1039.     call    Cnvrt
  1040.     cmp    al,'0'            ;suppress leading zero
  1041.     jne    Cnvrtd
  1042.      mov    al,' '
  1043.      ret
  1044.  
  1045. Cnvrt:  shr    ax,cl
  1046. Cnvrt1: aam                ;make al into bcd
  1047.     or    ax,'00'            ; and to ascii
  1048.     xchg    al,ah
  1049. Cnvrtd: ret
  1050. Cnvrt2  endp
  1051.  
  1052.     page
  1053.  
  1054. ;    format the date (in AX)
  1055.  
  1056. date    record  yr:7,mo:4,dy:5        ;packed date
  1057.  
  1058. GetDate proc    near            ;format the date
  1059.     or    ax,ax            ;is it zero?
  1060.     jz    GotDate
  1061.  
  1062.     push    bx            ;preserve BX (buff ptr)
  1063.  
  1064.     push    ax            ;save date
  1065.     and    ax,mask yr        ;get year part
  1066.     mov    cl,yr            ;bits to shift
  1067.     call    Cnvrt
  1068.     mov    di,offset vyear
  1069.     or    al,'8'            ;adjust for base year
  1070.     stosw
  1071.  
  1072.     pop    bx            ;get the date back
  1073.     push    bx            ;save it
  1074.     and    bx,mask mo        ;get month part
  1075.     mov    cl,mo            ;bits to shift
  1076.     shr    bx,cl
  1077.     add    bx,bx            ; form month table index
  1078.     add    bx,bx
  1079.     lea    si,word ptr months-4[bx]
  1080.     mov    cx,word ptr 3
  1081.     mov    di,offset vmonth
  1082.     rep    movsb
  1083.  
  1084.     pop    ax            ;get the date back
  1085.     and    ax,mask dy        ;get day part
  1086.     mov    cl,dy            ;bits to shift
  1087.     call    Cnvrt
  1088.     mov    di,offset vdate
  1089.     stosw
  1090.  
  1091.     pop    bx            ;restore buff ptr
  1092. GotDate:ret
  1093.  
  1094. GetDate endp
  1095.  
  1096.  
  1097. ;v1.3    A severely hacked single/double precision number conversion function.
  1098. ;    Originally from JMODEM, but severely hacked by Toad Hall.
  1099. ;    ES:DI -> string
  1100. ;    Destroys everything almost.
  1101.  
  1102. ;Enter here if integer in AX
  1103. Asciify    proc    near
  1104.  
  1105.     push    bx            ;save buff ptr
  1106.  
  1107.     xor    dx,dx            ; clear fake long.hi
  1108.     mov    si,ax            ;move integer into SI
  1109.     xor    ah,ah            ;clear msb (flag)
  1110.     jmp    short Ascii_Ax        ;jump into the code
  1111.  
  1112. ;Enter here if long integer in DX:AX.
  1113. Asciify_Long:
  1114.  
  1115.     push    bx            ;save buff ptr
  1116.  
  1117.     mov    si,ax            ;move long.lo into SI
  1118.     xor    ah,ah            ;clear msb (flag)
  1119.  
  1120. Comment        ~
  1121. Taking out the extremely high numbers to reduce column width.
  1122.  
  1123.     MOV    CX,3B9AH        ; Get billions
  1124.     MOV    BX,0CA00H
  1125.     CALL    Subtr            ; Subtract them out
  1126.  
  1127.     MOV    CX,05F5H        ; Get hundred-millions
  1128.     MOV    BX,0E100H
  1129.     CALL    Subtr            ; Subtract them out
  1130. Comment    ends    ~
  1131.  
  1132.     and    dx,4FFH            ;seems likely
  1133.     MOV    CX,word ptr 0098H    ; Get ten-millions
  1134.     MOV    BX,9680H
  1135.     CALL    Subtr            ; Subtract them out
  1136.  
  1137.     MOV    CX,word ptr 000FH    ; Get millions
  1138.     MOV    BX,4240H
  1139.     CALL    Subtr            ; Subtract them out
  1140.  
  1141.     MOV    CX,word ptr 1        ; Get hundred-thousands
  1142.     MOV    BX,86A0H
  1143.     CALL    Subtr            ; Subtract them out
  1144.  
  1145. Ascii_Ax:
  1146.     xor    cx,cx            ; Get ten-thousands
  1147.     MOV    BX,2710H
  1148.     CALL    Subtr            ; Subtract them out
  1149.     MOV    BX,03E8H
  1150.     CALL    Subtr            ; Subtract them out
  1151.  
  1152.     MOV    BX,word ptr 0064H
  1153.     CALL    Subtr            ; Subtract them out
  1154.     MOV    BX,word ptr 10
  1155.     CALL    Subtr            ; Subtract them out
  1156.     mov    ax,si            ;residual in SI
  1157.     add    AL,'0'            ; Add bias to residual
  1158.     stosb                ; Put in the string
  1159.  
  1160.     pop    bx            ;restore buff ptr
  1161.     RET
  1162.  
  1163. ;Common subroutine for Asciify
  1164.  
  1165. Subtr:    mov    al,'0'-1
  1166.  
  1167. Subtr1:    INC    al            ; Bump the digit character
  1168.     SUB    si,BX            ; Dword subtraction
  1169.     SBB    DX,CX
  1170.     JNB    Subtr1            ; Continue until a carry
  1171.  
  1172.     ADD    si,BX            ; One too many, add back
  1173.     ADC    DX,CX            ;   and the remainder
  1174.  
  1175.     cmp    al,'0'
  1176.     jnz    Subtr2            ;nope, turn off leading flag, stuff
  1177.      or    ah,ah            ;no more leading spaces?
  1178.      jnz    Sub_Stuff        ;right, stuff the '0'
  1179.       mov    al,' '            ;make it neat with leading spaces
  1180. Sub_Stuff:
  1181.     stosb                ;stuff the char
  1182.     RET
  1183.  
  1184. Subtr2:    inc    ah            ;turn off leading space flag
  1185.     stosb
  1186.     ret
  1187.  
  1188. Asciify    ENDP
  1189.  
  1190.  
  1191. ;v1.3    Convert 16-bit binary word in AX
  1192. ;    to hex ASCII string at ES:DI
  1193. ;    (Protect BX, directory array pointer)
  1194.  
  1195. hexchar db    '0123456789ABCDEF'
  1196.  
  1197. Cvh    proc    near
  1198.  
  1199.     push    bx            ;save buff ptr
  1200.  
  1201.     mov    si,offset hexchar    ;for faster access
  1202.     mov    dx,ax            ; save 16-bits
  1203.  
  1204.     mov    bl,dh            ; third nibble
  1205.     xor    bh,bh            ;clear msb
  1206.     mov    cx,0F04H        ;CL=4 for shifting,
  1207.                     ;CH=0FH for masking
  1208.     shr    bl,cl
  1209.     mov    al,[si][bx]        ;snarf hex char
  1210.     stosb
  1211.  
  1212.     mov    bl,dh            ; last nibble
  1213.     and    bl,ch    ;0fh
  1214.     mov    al,[si][bx]        ;snarf hex char
  1215.     stosb
  1216.  
  1217.     mov    bl,dl            ; first nibble
  1218.     shr    bl,cl            ; isolate (CL still 4)
  1219.     mov    al,[si][bx]        ;snarf hex char
  1220.     stosb
  1221.  
  1222.     mov    bl,dl            ; second nibble
  1223.     and    bl,ch    ;0fh        ; isolate
  1224.     mov    al,[si][bx]        ;snarf hex char
  1225.     stosb
  1226.  
  1227.     pop    bx            ;restore buff ptr
  1228.     ret
  1229.  
  1230. Cvh    endp
  1231.  
  1232.  
  1233. ;SUBROUTINE
  1234.  
  1235. Pr_CrLf    proc    near
  1236.     mov    dx,offset crlf
  1237.     mov    cx,CRLFLEN            ;fall through to ...
  1238.  
  1239. Pr_CrLf    endp
  1240.  
  1241. Pr_StdOut    proc    near
  1242.  
  1243.     push    bx                ;preserve bx
  1244.     mov    bx,STDOUT
  1245.     mov    ah,40H                ;write
  1246.     int    21H
  1247.     pop    bx
  1248.     ret
  1249.  
  1250. Pr_StdOut    endp
  1251.  
  1252.  
  1253. ;v1.3    print null-terminated (AsciiZ) string like int 21h function 9
  1254. ;    Enter with DS:DX -> AsciiZ string
  1255. ;    destroys AX
  1256. ;    On success, return:
  1257. ;     CF clear
  1258. ;     AL = 0
  1259. ;    On failure (StdOut write fail), return:
  1260. ;     CF set
  1261. ;     AL = error
  1262.  
  1263. PrintS  proc    near
  1264.  
  1265.     mov    cx,0FFFFH        ;max scan            v1.3
  1266.     xor    al,al            ;handy 0            v1.3
  1267.     mov    di,dx            ;string start            v1.3
  1268.     repne    scasb            ;find the terminator        v1.3
  1269.     inc    cx            ;adjust                v1.3
  1270.     not    cx            ;CX=length            v1.3
  1271.  
  1272.     call    Pr_StdOut        ;display to StdOut
  1273.  
  1274.     ret
  1275.  
  1276. PrintS  endp
  1277.  
  1278.  
  1279. ;Reinit our nonverbose formatted display line
  1280.  
  1281. Refresh_LineBuff    proc    near
  1282.  
  1283.     mov    si,offset blankline        ;formatted display line
  1284.     mov    ax,offset LINEBUFF        ;dynamic data area
  1285.     mov    di,ax                ;move to ...
  1286.     mov    cx,LINELEN            ;length
  1287.     rep    movsb
  1288.     mov    di,ax                ;ES:DI -> formatted line start
  1289.     ret
  1290.  
  1291. Refresh_LineBuff    endp
  1292.  
  1293.  
  1294. ;v1.2    Parses cmdline for target files.
  1295. ;    If failure:
  1296. ;      Returns CF set,
  1297. ;      AL = ERRORLEVEL,
  1298. ;      DX -> error msg
  1299. ;v1.3    Adding command line switch ('-v') parsing.
  1300. ;v1.3b    And fixing the bug.
  1301.  
  1302. Parse_CmdLine    proc    near
  1303.  
  1304.     call    _Args                ;parse cmdline
  1305.                         ;returns AX = argc
  1306.     or    ax,ax                ;any argc?
  1307.     jnz    Got_Parm            ;yep
  1308.  
  1309. Cmd_Err:
  1310.      mov    dx,offset usage            ;intro, usage
  1311.      mov    cx,USAGELEN            ;total length
  1312.      mov    al,1                ;errorlevel 1
  1313.      stc                    ;CF set
  1314.      ret                    ;for a jmp to Msg_Term
  1315.  
  1316. Got_Parm:
  1317.     mov    cx,ax                ;argc
  1318.  
  1319. ;See if any of the argv's are our '-v' verbose switch.
  1320. ;If so, turn switch on, clear that argv.
  1321.  
  1322.     cmp    cx,1                ;just 1 arg?
  1323.     jz    Chk_ZipName            ;yep, can't be any switches
  1324.  
  1325.     mov    bx,offset argv[2]        ;start with ^argv(1)
  1326.  
  1327. Chk_VSwitch:
  1328.     mov    si,[bx]                ;argv^(1)
  1329.     cmp    word ptr [si],'V-'        ;'-V' backwards
  1330.     jnz    Chk_VRelup            ;nope
  1331.      cmp    byte ptr 2[si],0        ;Just the '-v'?
  1332.      jnz    Chk_VRelup            ;nope, must be a name
  1333.       not    verbose                ;got '-v', verbose on
  1334.       mov    byte ptr [si],0            ;clear this argv
  1335.       cmp    cx,argc                ;first argc?
  1336.       jnz    Chk_V_NoShift            ;nope
  1337.        inc    argc                ; .. sigh .. readjust
  1338.        call    _Shift                ;yep, move other args down one
  1339.                         ;(will decr argc again)
  1340. Chk_V_NoShift:
  1341.        dec    argc                ;final decr to eliminate it
  1342.        jmp    short Chk_ZipName        ;done
  1343.  
  1344. Chk_VRelup:
  1345.       add    bx,2                ;next argv^
  1346.       loop    Chk_VSwitch            ;check all args
  1347.  
  1348. ;If argv(1) was the '-v' switch,
  1349. ;that argv has been cleared via the _Shift call.
  1350. ;The target zip file name HAS to be argv(1)!
  1351.  
  1352. Chk_ZipName:
  1353.  
  1354.     mov    cx,argc                ;argc arg counter
  1355.     jcxz    Cmd_Err                ;he only had a switch!
  1356.  
  1357.     mov    bx,offset argv[2]        ;^argv(1)
  1358.     mov    si,[bx]                ;argv^(argc)
  1359.     call    Parse_MoveZipName        ;handle the zip name
  1360. ;    mov    byte ptr [si],0            ;clear this arg
  1361.     call    _Shift                ;move argv's down one
  1362.  
  1363. ;Check for member testing (2d or 3d argv).
  1364. ;We make the call even if argc = 0 (to clear a buffer)
  1365.  
  1366. Chk_MbrName:
  1367.     call    Parse_MoveMbrName        ;handle the member name
  1368.  
  1369. Parse_Done:
  1370.     clc
  1371.     ret
  1372.  
  1373. Parse_CmdLine    endp
  1374.  
  1375. ;v1.3b    Cmdline parsing subroutine
  1376. ;    Moves argv into our targetfile buffer,
  1377. ;    picks up a pointer to past the paths (if any)
  1378. ;    SI -> argv
  1379.  
  1380. Parse_MoveZipName    proc    near
  1381.  
  1382.     push    si                ;save SI
  1383.  
  1384.     mov    bx,offset ziptarget        ;full zip target filename
  1385.  
  1386.     mov    di,bx
  1387.     mov    cx,64                ;clear ziptarget
  1388.     xor    ax,ax
  1389.     rep    stosw
  1390.  
  1391.     mov    di,bx                ;DI -> ziptarget
  1392.  
  1393. Move_ZipName:
  1394.     lodsb                    ;snarf cmdline char
  1395.     or    al,al                ;AsciiZ terminator?
  1396.     jz    Parse_Zip_Type            ;yep
  1397.      stosb                    ;stuff
  1398.      jmp    Move_ZipName
  1399.  
  1400.  
  1401. Parse_Zip_Type:
  1402.  
  1403. ;DI -> last ziptarget's real char +1
  1404.  
  1405.     mov    dx,di                ;end, last char +1
  1406.     sub    dx,bx                ;end - start = length
  1407.  
  1408.     mov    di,bx                ;back to start
  1409.     mov    cx,dx                ;counter for a scan
  1410.     mov    al,'.'
  1411.     repne    scasb                ;find a .TYP separator
  1412.  
  1413. ;DI -> char after '.' or actual filename end
  1414.     jnz    No_Type
  1415.      dec    di                ;back up to the '.'
  1416. No_Type:
  1417.     mov    si,offset ziptyp        ;assume need full '.ZIP'
  1418.     mov    cx,4                ;4 chars
  1419.     rep    movsb                ;copy .ZIP in
  1420.  
  1421.     mov    dx,di                ;end
  1422.     sub    dx,bx                ;end - start = length
  1423.  
  1424.     dec    di                ;adjust from last movsb
  1425.     std                    ;backwards
  1426.  
  1427.     mov    si,di                ;SI -> ziptarget last char
  1428.  
  1429. ;BX = ziptarget start
  1430. ;SI -> ziptarget lastchar
  1431. ;DX = ziptarget length
  1432. ;DI -> ziptarget lastchar
  1433.  
  1434. ;Now find any path separators in ziptarget
  1435.  
  1436.     mov    cx,dx                ;scan length
  1437.     mov    al,'\'                ;subdir dividers
  1438.     repne    scasb                ;scan till we hit one
  1439.     jz    Zip_GotPath            ;DI -> char before the '\'
  1440.  
  1441.     mov    di,si                ;back to last char
  1442.     mov    cx,dx                ;scan length
  1443.     mov    al,':'                ;how about just drive?
  1444.     repne    scasb
  1445.     jnz    Zip_NoPath            ;nope, DI -> ziptarget-1
  1446.                         ;skip the extra inc
  1447. Zip_GotPath:
  1448.     inc    di                ;bump to '\' or ':'
  1449. Zip_NoPath:
  1450.     inc    di                ;and past it to filename's char
  1451.     cld                    ;forward again
  1452.     mov    znameptr,di            ;points to start of
  1453.                         ;true filename (beyond path)
  1454.                         ;for later appending Find Next
  1455.                         ;filenames to path
  1456.     pop    si                ;restore
  1457.     ret
  1458.  
  1459. Parse_MoveZipName    endp
  1460.  
  1461. ;v1.3b    Cmdline parsing subroutine
  1462. ;    Has DOS parse the member name (could be wildcards).
  1463. ;    Moves that parsed name into runtime buffer.
  1464. ;    Enters with SI -> AsciiZ member name.
  1465.  
  1466. Parse_MoveMbrName    proc    near
  1467.     
  1468.     mov    di,offset pname1
  1469.     mov    cx,6                ;12 bytes long
  1470.     mov    ax,2020H
  1471.     rep    stosw                ;clear with spaces
  1472.  
  1473.     mov    cx,argc                ;argc counter
  1474.     jcxz    Parse_MbrDone            ;all done, no member
  1475.  
  1476.     mov    bx,offset argv[2]        ;it's now ^argv(2)
  1477.     mov    si,[bx]                ;argv^(argc)
  1478.  
  1479.     mov    di,offset fcb3
  1480.     mov    ax,2900H + 00001100b        ;parse filename
  1481.                         ;(no leading spaces,
  1482.                         ; don't set drive spec,
  1483.                         ; change only if valid)
  1484.     int    21H
  1485.     cmp    al,0FFH                ;failed?
  1486.     jz    Parse_MbrDone            ;yep
  1487.  
  1488.      mov    si,di                ;0 preceding parsed name
  1489.      inc    si                ;bump past 0
  1490.      mov    di,offset pname1        ;dynamic variable space
  1491.      mov    cx,6                ;11 filename chars + AsciiZ 0
  1492.      rep    movsw
  1493.  
  1494. Parse_MbrDone:
  1495.     ret
  1496.  
  1497. Parse_MoveMbrName    endp
  1498.  
  1499. ;---- args.asm ----------------------------------------------------------
  1500. ;from KEGELUNX.ARC Unix-like utils.
  1501. ;
  1502. ; Args parses the command line into a unix-style parameter array.
  1503. ; CALL _ARGS to have it parse the cmdline.
  1504. ; Argc and Argv are just as in C; argc = # of params on cmd line,
  1505. ; argv is an array of pointers to strings (null terminated, of course). 
  1506. ; Because MS-DOS doesn't pass us the name used to invoke the program,
  1507. ; argv[0] always points to a null string.
  1508. ; _Shift updates argc.
  1509. ;
  1510. ;--------------------------------------------------------------------------
  1511.  
  1512. ; Maximum number of parameters
  1513. MAXPARMS    equ    4
  1514.  
  1515. _Args    proc    near
  1516.     ; initialize
  1517.     cld                ; clear decrement mode
  1518.     mov    bx, 2            ; argc = 0 (will sub 2 from bx at end)
  1519.     mov    argv[0], offset null    ; prog name unknown; set to null.
  1520.     mov    si,offset PARAMS    ; i = 0
  1521.     mov    cl,nchar        ; cx = # of chars in command line
  1522.     xor    ch,ch
  1523.     jcxz    Args_Done        ; no arg chars -> we're done.
  1524.  
  1525.     mov    di,offset argbuff    ;big arg buffer
  1526.  
  1527.     ; Move arguments out of default DTA.
  1528.     push    cx
  1529.     push    di
  1530.     rep    movsb
  1531.     pop    si
  1532.     pop    cx
  1533.  
  1534.     ; Big loop- find arguments...
  1535.     mov    ah,20H        ;handy space
  1536. ParmL:
  1537.     ; Little loop #1: strip leading blanks from argument.
  1538.     ; while (i<NCHAR && params[i] = ' ') do i++;
  1539. StripL:    lodsb            ; al = [si++]
  1540.     cmp    al,ah        ; space?
  1541.     loopz    StripL        ; if so, keep skipping.
  1542.     jne    Args_GotOne    ; If we found a nonblank, skip zero test.
  1543.     jcxz    Args_Done    ; found no unblank chars -> we're done.
  1544.  
  1545. Args_GotOne:
  1546.     dec    si        ; bump SI back to start of nonblank. 
  1547.     inc    cx
  1548.     mov    argv[bx],si    ; save pointer to this string
  1549.  
  1550.     ; Little loop #2: skip nonblank chars.
  1551.     ; while (i<NCHAR && params[i] <> ' ') do i++;
  1552. SkipL:    lodsb
  1553.     cmp    al,ah
  1554.     loopnz    SkipL
  1555.     jz    Oky
  1556.                 ; Last char of line was not blank.
  1557.      inc    si        ; make next statement put null AFTER arg.
  1558. Oky:
  1559.     mov    byte ptr [si][-1], 0    ; put null at end of arg
  1560.     add    bx,2        ; argc++;
  1561.  
  1562.     jcxz    Args_Done    ; if we ran off end of cmdline, no more args.
  1563.  
  1564.     cmp    bx, MAXPARMS*2
  1565.     jb    ParmL        ; loop if argc < MAXPARMS.
  1566.  
  1567. Args_Done:    ; All done finding parms; now share argc with caller.
  1568.     mov    ax,bx
  1569.     sub    ax, 2
  1570.     shr    ax, 1
  1571.     mov    argc,ax        ;save argc
  1572.     or    ax,ax        ;no args at all?            v1.3c
  1573.     jz    Args_X        ;yep, leave now                v1.3c
  1574.  
  1575. ;While we're here, let's uppercase all the args
  1576.  
  1577.     mov    cx,ax        ;argc loop counter
  1578.     mov    dl,20H        ;handy constant for uppercasing
  1579.     mov    ah,'a'        ;and for testing
  1580.     mov    bx,offset argv[2]    ;^argv(1)
  1581.  
  1582. Args_UpLoop:
  1583.     mov    si,[bx]        ;argv^(argc)
  1584.     dec    si        ;prep for upcoming...
  1585. Argv_UpLoop:
  1586.     inc    si
  1587.     mov    al,[si]        ;snarf char
  1588.     or    al,al        ;argv^(argc) end?
  1589.     jz    Args_Relup    ;yep, bump argc
  1590.     cmp    al,ah    ;'a'    ;lowercase?
  1591.     jb    Argv_UpLoop    ;nope
  1592.      sub    [si],dl        ;uppercase
  1593.      jmp    Argv_UpLoop    ;next char
  1594.  
  1595. Args_Relup:
  1596.     add    bx,2        ;next argv^
  1597.     loop    Args_UpLoop
  1598.  
  1599.     mov    ax,argc        ;return argc
  1600. Args_X:
  1601.     ret
  1602.  
  1603. _Args    endp
  1604.  
  1605. ;---- _Shift: --------------------------------------------
  1606. ; Shifts %2 to %1, %3 to %2, etc.  Leaves %0 alone.
  1607. ; Works by shuffling argv[*].
  1608.  
  1609. _Shift    proc    near
  1610.     cld
  1611.     mov    si, offset argv[4]
  1612.     mov    di, offset argv[2]
  1613.     mov    cx, MAXPARMS
  1614.     rep    movsw
  1615.     dec    argc
  1616.     ret
  1617. _Shift    endp
  1618.  
  1619.  
  1620. ;---- parameter count, array ----------------
  1621. ; Pointers to up to MAXPARMS parameter strings are held here.
  1622.  
  1623. null    dw    0        ; the null string
  1624. argc    dw    ?
  1625. argv    dw    MAXPARMS dup (null)
  1626.  
  1627.  
  1628. ;Dynamic variables start here.
  1629. ;Not REAL big .. we could calculate them and release unneeded memory ..
  1630. ;but who needs it?  This ain't TSR, and the normal 64Kb required for
  1631. ;a .COM program shouldn't stress anyone's system capacity.
  1632.  
  1633. dta1BA        equ    $            ;alternate DTA
  1634. ziptarget    equ    dta1BA + 42        ;up to 128 bytes
  1635. pname1        equ    ziptarget + 128        ;11-byte FCB filename + 0
  1636. fcb3        equ    pname1 + 14        ;full 44-byte FCB
  1637.  
  1638. Comment        ~ Looks like:
  1639. +filename.typ 000K / 000K  +filename.typ 000K / 000K  +filename.typ 000K / 000K
  1640. Comment    ends    ~
  1641. argbuff        equ    fcb3 + 44        ;cmdline parsing buff    v1.3b
  1642. linebuff    equ    argbuff            ;82 chars long
  1643. dirbuff        equ    linebuff + 82        ;ENDOFS bytes long
  1644.  
  1645.  
  1646. CSEG    ends
  1647.     end    Zdir
  1648.  
  1649.