Category : BBS Programs+Doors
Archive   : RBBS-ASM.ZIP
Filename : QBARCV6.ASM

 
Output of file : QBARCV6.ASM contained in archive : RBBS-ASM.ZIP
page 74,132
title ARCV - Verbose ARC directory listing

; Special version of ARCV to be called by QB program
; usage:
;
; CALL ARCV (Workname$,"filename[.PAK]", RETCD%) ' CPC151AC
;
; notes:
; This code originated from ARCV 1.15d - Verbose ARC directory display
; written by V.Buerg and was modified to run as a called routine under
; Microsoft QuickBasic. It was further modified to allow PAK files by
; Robert J. Simoneau.
;
; Change 9/14/86 to dis-allow wildcards
; Change 1/1/87 to recognize squash format
; Change 2/18/87 to support network usage - - - - Jon Martin ' CPC151A
; Change 1/7/89 to support Pak files -------------Bob Simoneau

; Change 890320 to support ZIP files David Kirschbaum, Toad Hall
; - Question: Why do we "have to look for the damned thing" when it
; comes to finding ARC/PAK headers? All comments are at file ends,
; so the header should be EXACTLY where it should be .. at the end of
; the file's compressed code. Hacked severely to reflect this,
; and vastly cleaning up the code.
; - Replaced old SDIR Binary to Ascii conversion with a hacked version
; from JMODEM .. about 10 times faster, plus offers integer conversion
; as well as long integers.
;v1.3 - FAAR RBBS reports this sucker runs once and then just returns
; a usage message (in the output file).
; Trying to find out why. Found it .. dumb mistake, not clearing
; variables between runs.
; - Adding true EOF testing for file pointer bumps.
; ZIP files have a good way to find EOF (e.g., the central directory),
; but PAK and ARC files don't.
; - Added some more error msgs.
; - Tightened hex output (CvH).
; - Reduced buffer sizes to minimum (archdr and inbuf).
;
;v1.4 - Adding the new Japanese .LHZ capability. Toad Hall
; See LHARC10E.ZIP (available on GEnie and BBS's) for details.
; - Neatening up total line.
; - Found some bugs in trying to predetermine ARC/PAK EOF.
; Fixed (hopefully).
; - Added a bunch of [bx] references .. saved 100 bytes!
; - Credits for LHARC (.LHZ) file header structure to:
; Daniel Durbin
; SysOp: Cygnus X-1 BBS | CIS: 73447,1744
; (805) 541-8505 (data) | GEnie: D.DURBIN
; EL major at PolySlo | [email protected]
; from his LVIEW.C code.
;
;Fix - Correct bug that kept version 1.4 from functioning when linked
;08/23/89 with RBBS-PC that had been compiled using QB4.5 compiler.
; As it turned out it was an out and out bug that just did not
; happen to crash when RBBS-PC was compiled using QB3.0.
;
; Jon Martin AIRCOMM (415) 689-2090
;
;Fix - Correct bug that did not support Implode as valid ZIP compression
;09/02/89 type.
;
; Jon Martin AIRCOMM (415) 689-2090
;
STDOUT equ 1 ;Standard Output v1.3
STDERR equ 2 ;Std Error (console) v1.3
FALSE equ 0
TRUE equ NOT FALSE
DEBUG equ FALSE

Print macro name ; display a field
mov dx,offset name
call PrintS
endm

header struc ; archive header
aMbrflag db 1AH ;unique ARC/PAK flag v1.3
aCmpMeth db 0 ; compression code
aMbrName db 13 dup (0) ; file name
aCmpSiz dw 0,0 ; file size in archive
aModDate dw 0 ; creation date
aModTime dw 0 ; creation time
aCrc16 dw 0 ; cyclic redundancy check
aUncmpSiz dw 0,0 ; true file size, bytes
header ends

ARCHDRLEN equ 29 ;size of ARC/PAK header. v1.3

;v1.3 ZIP Local file header structure:

zLocalEntry STRUC

zdig0 db 50H,4BH,03H,04H ;local file header signature 4 bytes
;(0x04034b50)
zVerMade dw ? ;version needed to extract 2 bytes
zBitflag dw ? ;general purpose bit flag 2 bytes
zCmpMeth dw ? ;compression method 2 bytes
zModTime dw ? ;last mod file time 2 bytes
zModDate dw ? ;last mod file date 2 bytes
zCrc32 dw ?,? ;crc-32 4 bytes
zCmpSiz dw ?,? ;compressed size 4 bytes
zUncmpSiz dw ?,? ;uncompressed size 4 bytes
zNameLen dw ? ;filename length 2 bytes
zExtraLen dw ? ;extra field length 2 bytes
zMbrName db ? ;filename (variable size)
;extra field (variable size)
ZLocalEntry ENDS

ZIPHDRLEN equ 30 ;length of initial ZIP hdr read v1.3

;v1.4 LZH header structure

lzhlfh STRUC ;Local file header
lUnk1 db ?,? ;char unknown1[2]; ;?
lCmpMeth db 5 dup(?) ;char method[5]; ;compression method
lCmpSiz dw ?,? ;long csize; ;compressed size
lUncmpSiz dw ?,? ;long fsize; ;uncompressed size
lModTime dw ? ;int ftime; ;last mod file time
lModDate dw ? ;int fdate; ;last mod file date
lFAttr db ? ;char fattr; ;file attributes
lUnk2 db ? ;char unknown2; ;?
lNameLen db ? ;char namelen; ;filename length
lMbrName db ? ;char *fname; ;filename
;lCrc16 dw ? ;int crc; ;crc-16
lzhlfh ENDS

LZHHDRLEN equ 22 ;not including lMbrName or lCrc16


CSEG segment public para 'CODE'
assume CS:CSEG,DS:CSEG,ES:CSEG

public ArcV

ArcV proc far
push bp ; save BASIC reg
mov bp,sp ; get parameter list pointer
mov CS:stkptr,sp ; save stack ptr
mov CS:saveds,DS ; save QB seg reg
mov CS:savees,ES ; save QB seg reg
call Start ; do our thing v1.3

; set DOS error level and exit
;v1.3a We aren't relying on the CF flag anymore to indicate errors.
; Instead, check AL.
; 0 = success
; 1 = command line parm error
; 2..6 are file-related (not found, etc.)
; 11 = Invalid format (probably didn't find a member header)
; 13 = invalid data (probably a bad file header structure)
; 18 = Unexpected EOF ('no further files to be found')

Exit: mov sp,stkptr ; restore entry stack value

push ax ;save error value v1.3

;v1.3 Numerous errors could be returned

or al,al ;no errors?
jz Exit_NoErr ;yep, ok

mov bx,offset errtbl ;assume unknown error
mov di,bx ;various error values
mov cx,ERRTBLLEN ;table length
repne scasb ;find the offset
jnz Err_TblDone ;unknown, BX has table start

dec di ;back up to actual error
sub di,bx ;current psn - start = relative nr
mov bx,di ;into BX for msg offset

Err_TblDone:
shl bx,1 ;*2 for words
Err_Unk:
add bx,offset errmsgtbl ;table of addresses

mov dx,[bx] ;ptr to string
call PrintS ;output error msg

Exit_NoErr:

mov bx,word ptr outhdl ; close listing file
cmp bl,STDERR ;never opened or STDERR? v1.3
jna Exit1 ;not a real handle v1.3
mov ah,3eh ;close file handle
int 21h
Exit1:
mov bx,word ptr archdl ;close ARC/PAK/ZIP file v1.3
or bx,bx ; if it was opened v1.3
jz Exit2 ; nope v1.3
mov ah,3EH ;close file handle v1.3
int 21H ; v1.3
Exit2: ; v1.3

;v1.3 Adding a test to insure we switched DTAs
; (so we don't blow away the caller's DTA with a vector 0:0!)

lds dx,dword ptr savedta ;get orig DTA vector
or dx,dx ;did we ever get it?
jz Exit_NoDTA ;nope
mov ax,DS ;check out seg
or ax,ax
jz Exit_NoDTA ;nope
mov ah,1ah ;set DTA
int 21h
Exit_NoDTA:

les ax,dword ptr CS:saveds ;recover calling seg regs 08/23/89
;(low word is orig DS) 08/23/89
mov ds,ax ; 08/23/89
ASSUME DS:NOTHING,ES:NOTHING ;a reminder

pop ax ;restore error level v1.3
xor ah,ah ;insure msb clear v1.3a

mov bp,sp ; parm ptr from entry
mov 6[bp],ax ;return retcd variable v1.3
pop bp
ret 6 ; clear parms from stack ' CPC151A

subttl '--- constants, equates and work areas'
page

CR equ 13
LF equ 10
BEL equ 7
TAB equ 9

STOPPER equ 0 ; end of display line indicator
ARCMARK equ 26 ; special archive marker
ARCVER equ 10 ; highest compression code used

even ;v1.3a

stkptr dw 0 ; stack pointer upon entry

arctitl db CR,LF,'Archive: ' ;keep this even v1.3a
saveds dw 0 ; QB seg reg
savees dw 0 ; QB seg reg

subttl '--- i/o control variables'
page

INBUFSZ equ 128 ;512 ; size of input buffer v1.3

;v1.3 Completely reordered these runtime variables
; so we can purge them with one fell swoop

PURGESTART equ $ ; v1.3

totsf dw 0,0 ; average stowage factor
totlen dw 0,0 ; total of file lengths
totsize dw 0,0 ; total of file sizes
totmbrs dw 0 ; total number of files

archdl dw 0 ; file handle
fileptr dw 0 ; ptr to filename part of arcname
arclen dw 0 ;full archive filename length v1.3
arcname db 76 dup (0)

outhdl dw 0 ; handle for output listing v1.3
templen dw 0 ;output filename length v1.3
temp db 76 dup (0) ; and temporary file name

filelen dw 0,0 ;absolute archive file length v1.3a
curpsn dw 0,0 ;remember current file pointer psn v1.3a

savedta dw 0,0 ; addr of QB dta
dta db 48 dup (0) ; data transfer area

even ; v1.3

PURGELEN EQU ($ - PURGESTART) SHR 1 ;amount to purge each run v1.3

; display lines for verbose

vhdr db CR,LF
db CR,LF,'Name Length Stowage SF Size now Date Time CRC '
db CR,LF,'============ ======== ======== ==== ======== ========= ====== ===='
db CR,LF ;v1.4
db STOPPER

;vline db CR,LF
vline label byte ;v1.4
vname db 14 dup (' ')
vlength db ' ' ; length in archive v1.3
vstyle db ' ' ; compression method
vfactor db ' xx% ' ; compression factor
vsize db 10 dup (' ') ; actual file bytes
vdate db 'dd ' ; creation date
vmonth db 'mmm '
vyear db 'yy '
vtime db 'hh:mm ' ; creation time
vcrc db 'xxxx' ; crc in hex
db CR,LF ;v1.4
db STOPPER

hundred dw 100 ; for computing percentages

; final totals line

vthdr db '------ --- -------- ---- --------',CR,LF ;v1.4
db '*Total ' ;v1.4
vtmbrs db ' '
vtlen db 8 dup (' '),' '
db 10 dup (' ')
vtsf db ' % '
vtsize db 8 dup (' ')
db CR,LF ; for tom
db STOPPER

sign db ' '

styles db ' ----- ' ; 1 = old, no compression
db ' ----- ' ; 2 = new, no compression
db ' Packed ' ; 3 = dle for repeat chars
db 'Squeezed' ; 4 = huffman encoding
db 'crunched' ; 5 = lz, no dle
db 'crunched' ; 6 = lz with dle
db 'Crunched' ; 7 = lz with readjust
db 'Crunched' ; 8 = lz with readjust and dle
db 'Squashed' ; 9 = 13-bit lz with no dle
db ' Crushed' ;10 = Pak10 file ---------Bob Simoneau

;v1.3 ZIP compression types:

zstyles label byte
db ' Stored' ;0 - The file is stored (no compression)
db ' Shrunk' ;1 - The file is Shrunk
db 'Reduced1' ;2 - Reduced with compression factor 1
db 'Reduced2' ;3 - Reduced with compression factor 2
db 'Reduced3' ;4 - Reduced with compression factor 3
db 'Reduced4' ;5 - Reduced with compression factor 4
db 'Imploded' ;6 - New don't know format v1.6

;v1.4 LZH compression types are already coded as 5 chars of text
; in the compressed file.
; All we need to do is pad them out to the correct width.

months db 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec '

ARCPAK = 0 ; v1.3
ZIP = 1 ; v1.4
LZH = 2 ; v1.4
ftype db ZIP ;flag which type file v1.3

;v1.4 4 types of archive file

ziptype db 'ZIP'
arctype db 'ARC'
paktype db 'PAK'
lzhtype db 'LZH' ;v1.4
larctype db 'LZS' ;v1.4 not enabled for now

;zfilesig db 50H,4BH,03H,04H ;local file header signature v1.3
;zdirsig db 50H,4BH,01H,02H ;central file header signature v1.3

ZSIG equ 4B50H ;unique ZIP signature v1.4
ZFILESIG equ 0403H ;file member signature v1.4
ZDIRSIG equ 0201H ;central file header signature v1.4

;v1.3 Centralizing errors at the exit point

; 1 = command line parm error
; 2..6 are file-related (not found, etc.)
; 11 = Invalid format (probably didn't find a member header)
; 12 = Invalid file type (not an ARC, PAK, ZIP)
; 13 = invalid data (probably a bad file header structure)
; 18 = Unexpected EOF ('no further files to be found')

errtbl db 0,1,2,3,4,5,6,11,12,13,18,25,27,29,30 ;v1.3a
ERRTBLLEN equ $ - errtbl

errmsgtbl dw msg0,msg1,msg2,msg3 ;v1.3a
dw msg4,msg5,msg6,msg11
dw msg12,msg13,msg18,msg25
dw msg27,msg29,msg30

msg0 db 'Unknown error',0

msg1 db 'Invalid function number',0
msg2 db 'Archive file not found',0
msg3 db 'Path not found',0
msg4 db 'No handle available',0
msg5 db 'Access denied',0
msg6 db 'Invalid handle',0
msg11 db 'Archive header error',0
msg12 db 'Invalid file type',0
msg13 db 'Archive format error',0
msg18 db 'No further files to be found',0
msg25 db 'Disk seek error',0
msg27 db 'Disk sector not found',0
msg29 db 'Write error',0
msg30 db 'Read error',0


subttl '--- mainline processing'
page
;
Start proc near ; v1.3

mov ax,CS ;just set ES for now v1.3
mov ES,ax
ASSUME DS:NOTHING,ES:CSEG ;a reminder v1.3a

;v1.3 Insure all variables are cleared
cld
mov di,offset PURGESTART
xor ax,ax ;clear all the variables v1.3
mov cx,PURGELEN ;nr words to clear v1.3
rep stosw ; v1.3

;v1.3 Move first parameter (output filename) into code space

mov si,word ptr 10[bp] ; ptr to parameter vector ' CPC151A
lodsw ; get string length ' CPC151A
mov cx,ax ; ' CPC151A
jcxz Copy_Parm2 ;empty, forget it v1.3
mov di,offset templen ;str length v1.3
stosw ;save length v1.3
mov si,[si] ; get string offset v1.3a
rep movsb ;copy in the string v1.3

Copy_Parm2:

;v1.3 Now copy 2d parameter (target archive filename)

mov si,word ptr 8[bp] ; ptr to parameter vector
lodsw ; get string length
mov cx,ax ; v1.3
jcxz Parm2_Done ;forget it v1.3
mov di,offset arclen ;archive name length v1.3
stosw ;save length v1.3
mov si,[si] ; get string offset v1.3
mov ah,'a' ;constant for uppercasing v1.3
Parm2_Upper: ; v1.3
lodsb ;snarf char v1.3
cmp al,ah ;need uppercasing? v1.3
jb Parm2_NoU ;nope v1.3
sub al,20H ;uppercase it v1.3
Parm2_NoU: ; v1.3
stosb ; v1.3
loop Parm2_Upper ; v1.3

Parm2_Done:

;v1.3 All done with DS

mov ax,CS ; v1.3
mov DS,ax ; v1.3
ASSUME DS:CSEG,ES:CSEG ;a reminder v1.3a

mov ax,STDERR ;assume no output filename v1.3a
cmp temp,0 ;any output filename? v1.3
jz Temp_Opened ;nope, use STDERR v1.3a

;v1.3 Forcing output file to STDERR for debugging.
;v1.3 mov al,1 ; will show usage v1.3
;v1.3 ret ;back to Exit v1.3

;v1.3a mov ax,STDERR ;force to STDERR v1.3
;v1.3a jmp short Temp_Opened ;continue v1.3

;Got_Temp:
mov dx,offset temp ; open temporary file for output
xor cx,cx ;no special attributes v1.3
mov ah,3ch ;create file
int 21h
jnb Temp_Opened ;fine v1.3
ret ;back to Exit, AL=error code v1.3
;CF set v1.3a
Temp_Opened:
mov outhdl,ax ;save handle

;v1.3 Parse the target archive name
; Separate path from name
; Insure it's an ARC, PAK or ZIP type.

mov di,offset arclen ;archive name length v1.3
mov ax,[di] ;snarf length v1.3a
inc di ;bump to name proper v1.3a
inc di ; v1.3a
mov cx,ax ;into CX for scans to come v1.3a
jcxz No_ArcName ;no length, ergo no name v1.3a

mov dx,ax ;save in DX for later v1.3
xor al,al ;will scan for AsciiZ terminator v1.3
cmp [di],al ;no name at all? v1.3
jnz Got_ArcName ;yep v1.3

No_ArcName:
mov al,2 ;'Archive file not found' v1.3
ret ;back to Exit v1.3

Got_ArcName:

;v1.3 We have some sort of target name.
; But is it a legal type?
; DX = filename length
; DI -> archive filename (arcname)

add di,dx ;+ length -> last char+1 v1.3
dec di ;back up to last char v1.3
mov bx,di ;BX -> last char v1.3

mov al,'\' ;look for normal path delimiter v1.3
mov cx,dx ;length for scan v1.3
std ;backwards scanning now v1.3
repne scasb ; v1.3
jz Got_Start ;found one v1.3

;Ugh .. tired of typing in v1.3's!

mov di,bx ;back to end
mov cx,dx ;restore length
mov al,'/' ;funny path delimiter
repne scasb
jz Got_Start ;found one

mov di,bx ;back to end .. sigh ..
mov cx,dx ;restore length
mov al,':' ;ok, how about a drive?
repne scasb
jnz No_Paths ;nope, DI -> name start

Got_Start:
inc di ;bump up to the separator
No_Paths:
inc di ;bump to the first name char
cld ;forward again
mov fileptr,di ;remember real filename start

;v1.4 You MUST specify the type .. .ARC, .PAK, .ZIP, or .LZH.
; If .ARC or .PAK, we'll use the old code to display ARC-type
; files.
;v1.4 Else if ZIP or LZH, it's a totally new format!
; We remember the type archiving format in 'ftype'.

;v1.3 DS:SI -> filename's first char.

mov al,'.' ;find the separator v1.3
mov cx,word ptr 12 ;max of 12 chars v1.3
repne scasb ;find it v1.3
jnz BadType ;forget it v1.3

mov dx,di ;save pointer to file type v1.3
;(just past the separator) v1.3
mov ax,3 ;3 chars constant

mov ftype,ZIP ;assume ZIP

mov si,offset ziptype ;is it a ZIP?
mov di,dx ;back to filename type
mov cx,ax ;3 chars
repz cmpsb ;compare
jz Got_Type ;a match

mov ftype,ARCPAK ;ok, assume ARC or PAK v1.3a

mov si,offset arctype ;is it an ARC? v1.3
mov di,dx ;back to filename type
mov cx,ax ;3 chars
repz cmpsb ;compare
jz Got_Type ;a match

mov si,offset paktype ;is it a PAK?
mov di,dx ;back to filename type
mov cx,ax ;3 chars
repz cmpsb ;compare
jz Got_Type ;a match

;v1.4 Adding .LZH types
mov ftype,LZH ;ok, assume .LZH file v1.4

mov si,offset lzhtype ;is it an LZH?
mov di,dx ;back to filename type
mov cx,ax ;3 chars
repz cmpsb ;compare
jz Got_Type ;a match

BadType:
mov al,12 ;'Invalid file type' v1.3a
ret ;back to Exit v1.3

Got_Type: ;v1.3

; find first matching file

push ES
mov ah,2fh ; get current dta ptr
int 21h ; returned in ES:bx
mov savedta,ES
mov savedta[2],bx
pop ES

mov dx,offset dta ; set local dta for murkers
mov ah,1ah
int 21h

call OpenArc ; see if archive exists
; jb ArcV_X ;nope, return, AL = error v1.3
jnb ArcV1 ;ok
jmp ArcV_X ;nope, return, AL=error v1.4

;v1.3a Display archive filename, header,
; then into a loop for each archive member.

ArcV1: mov dx,fileptr ;pointer to filename v1.3a
call PrintS ;display, CR/LF v1.3a
jb ArcV_X ;output failed v1.3a

Print vhdr
jb ArcV_X ;output failed, AL = error v1.3

ArcVNext:
IF DEBUG
Print debug1
jmp short debugj1
debug1 db 'Calling GetHdr',CR,LF,0
debugj1:
ENDIF
call GetHdr ; load next header
jb ArcV_NoHdr ;failed somehow, AL=error v1.3a
;(could be EOF, which is ok) v1.3a
IF DEBUG
Print debug2
jmp short debugj2
debug2 db 'Calling ArcVgo',CR,LF,0
debugj2:
ENDIF
call ArcVgo ;format, write out file report
jb Arcv_NoHdr ;something failed, AL=error v1.3a

IF DEBUG
Print debug3
jmp short debugj3
debug3 db 'Calling Bump_ArcPtrs',CR,LF,0
debugj3:
ENDIF
call Bump_ArcPtrs ;bump to next archive file v1.3
jnb ArcVNext ;loop if ok, else AL=error v1.3a
;(could be EOF) v1.3a

ArcV_NoHdr:
cmp archdr.aCmpMeth,0 ; archive eof?
jnz ArcV_X ;nope, something else happened v1.3

cmp totmbrs,0 ;any totals? v1.3
jz ArcV_X ;nope v1.3
push ax ;save previous error value v1.3
call Format_Totals ;yep, format and output v1.3
pop ax ;restore prev err value v1.3

ArcV_X: ret ;AL=error v1.3a

Start endp ; v1.3


;v1.3 Format, display single line for each member
; On success, return:
; CF clear
; AL = 0
; On error, return:
; CF set (because of output write fail)
; AL = error code

ArcVgo proc near
mov di,offset vname ; copy file name
mov si,offset archdr.aMbrName
mov cx,word ptr 13 ;up to 12 chars long, AsciiZ 0
ArcV3:
lodsb
or al,al ; end of name? v1.3
je ArcV4
stosb
loop ArcV3
jmp short ArcV5

ArcV4:
mov al,' ' ; pad with blanks
rep stosb
ArcV5:
; reduce the size/length to word values

mov bx,offset archdr.aCmpSiz ;-> compressed size v1.4
mov cx,[bx] ;.lo v1.4
mov dx,2[bx] ;.hi v1.4
mov bx,offset archdr.aUncmpSiz ;-> uncompressed size v1.4
mov ax,2[bx] ;.hi v1.4
mov bx,[bx] ;.lo v1.4

ArcV51: or ax,ax ; big number?
jz ArcV52 ; nope, can use it
shr ax,1 ; yup, divide by two
rcr bx,1
shr dx,1
rcr cx,1
jmp short ArcV51

ArcV52:
mov ax,bx ; low word of actual size
mov sign,' '
cmp ax,cx ; arc member is larger?
jb ArcV520
sub ax,cx ; amount saved
jmp short ArcV56

ArcV520:
sub ax,cx
neg ax
mov sign,'-'

ArcV56:
mul hundred ; to percentage
add ax,50
adc dx,0 ; round up percent
or bx,bx ; empty file?
jnz ArcV53
mov ax,100
jmp short ArcV54

ArcV53: div bx
ArcV54:
cmp ax,100 ; archive fouled?
jbe ArcV55
sub ax,ax
ArcV55:
mov di,offset vfactor-2 ;format stowage factor v1.3
call Asciify ;display AX

mov al,sign
mov vfactor,al

mov cx,word ptr 3 ;gonna need it in a sec v1.4
cmp ftype,LZH ;LZH type? (compression method v1.4
; is already text) v1.4
jnz ArcV_GetStyles ;nope v1.4

;v1.4 The LZH compression method (5 chars) is still in inbuf.

mov si,offset inbuf.lCmpMeth ;-> 5-char compression v1.4
; method string v1.4
mov di,si
add di,5 ;point to beyond chars v1.4
mov ax,' ' ;need 3 trailing blanks v1.4
stosw
stosb
mov di,offset vstyle+1 ;indent to be neat v1.4
jmp short ArcV_GotStyle ;skip v1.4

ArcV_GetStyles: ; v1.4

mov si,offset zstyles ;assume ZIP v1.3
cmp ftype,ZIP ;ZIP file? v1.3
jz ArcV55A ;yep v1.3
mov si,offset styles ;ARC or PAK v1.3
ArcV55A: ; v1.3

sub bx,bx ; determine style
mov bl,archdr.aCmpMeth
dec bl ;adjust for table offset v1.3
;v1.4 mov cl,3 ; eight bytes each entry
;v1.4 CX = 3 (eight bytes each entry)
shl bx,cl ;*8

add si,bx ;point into style table v1.3
mov di,offset vstyle

ArcV_GotStyle: ; v1.4
inc cx ;CX=4=words to move v1.4
rep movsw ; v1.3

mov bx,offset archdr.aCmpSiz ;-> compressed size v1.4
mov ax,[bx] ;.lo v1.4
mov dx,2[bx] ;.hi v1.4
mov bx,offset totsize ;-> accumulated compressed size v1.4
add [bx],ax ;.lo v1.4
adc 2[bx],dx ;.hi v1.4

mov di,offset vsize ;format file size v1.3
call Asciify_Long ; v1.3

mov bx,offset archdr.aUncmpSiz ;-> uncompressed size v1.4
mov ax,[bx] ;.lo v1.4
mov dx,2[bx] ;.hi v1.4
mov bx,offset totlen ;-> total length accumulator v1.4
add [bx],ax ;.lo v1.4
adc 2[bx],dx ;.hi v1.4

mov di,offset vlength ;format file length v1.3
call Asciify_Long ; v1.3

mov ax,archdr.aModDate ; format file date
call GetDate

mov ax,archdr.aModTime ; format file time
call GetTime

mov ax,archdr.aCrc16 ; format crc in hex
mov di,offset vcrc
call Cvh

inc totmbrs ;NOW bump total count v1.3a
Print vline ; display this file info
;(may return error) v1.3a
ret

ArcVgo endp


subttl '--- load next archive header'
page

;v1.3 Adding ZIP file searching
;v1.3a For ARC/PAK files, now testing to see if we're at the archive
; file end. If so (a proper file), return with EOF (CF set
; but AL=0).
; Archive files may have picked up some garbage on the end
; (from XMODEM xfers, whatever). We'll see if we at LEAST have
; enough data for an archive header.
; If not, assume EOF, ignoring garbage.
; If there's more than 29 bytes of garbage .. the header will be
; garbage and we're gonna report a format error .. but that's ok for now.
; Zip files have a definite ending (the central directory,
; and they'll look out for their own endings.
;
; Also returning CF and AL per any errors.

GetHdr proc near

xor ax,ax ;handy 0
mov archdr.aCmpMeth,al ;assume archive EOF

cmp ftype,ZIP ;doing ZIP files?
jnz GH_NotZip ;nope v1.4
jmp Get_ZipHdr ;yep, they look out for themselves

GH_NotZip:
cmp ftype,LZH ;doing an LZH file? v1.4
jnz GH_ArcPak_Hdr ;nope v1.4
jmp Get_LZHHdr ;yep v1.4

GH_ArcPak_Hdr: ; v1.4

;v1.3 New code
; ARC/PAK headers look like this:
;aMbrFlag db 1AH ;unique header flag
;aCmpMeth db 0 ; compression code
;aMbrName db 13 dup (0) ; file name
;aCmpSiz dw 0,0 ; file size in archive
;aModDate dw 0 ; creation date
;aModTime dw 0 ; creation time
;aCrc16 dw 0 ; cyclic redundancy check
;aUncmpSiz dw 0,0 ; true file size, bytes

mov dx,offset archdr ;read into here
mov cx,ARCHDRLEN ;nr bytes to read
mov bx,archdl ;archive file handle
mov ah,3FH ;read from file/device
int 21H
jnb GH_ChkHdr ;read ok v1.3a
ret ;return CF set, AL=error v1.3a

GH_ChkHdr:
mov bx,dx ;DS:BX -> structure start v1.3a

cmp [bx].aMbrFlag,ARCMARK ;start of header?
jne Hdr_InvalFmt ;'invalid format', exit CF set

mov al,[bx].aCmpMeth ;type compression
cmp al,ARCVER ;reasonable code?
ja Hdr_InvalFmt ;nope, funny stuff

or al,al ; archive eof?
je Hdr_RetCF ;yep, done, return CF set
;but AL=0 = not a REAL error v1.3a
cmp al,1 ; old format?
jne GetHdrX ; if so, it's short
mov si,offset archdr.aCmpSiz ; CPC15-1C
mov di,offset archdr.aUncmpSiz ; CPC15-1C
movsw ; v1.3
movsw ; v1.3
GetHdrX:
xor al,al ;return AL=0, success v1.3a
clc
ret

Hdr_InvalFmt:
mov al,0BH ;'invalid format'
Hdr_EarlyEOF: ; ;v1.4
mov [bx].aCmpMeth,al ;signal EOF or invalid format v1.4
Hdr_RetCF:
stc ;return CF set, AL=error
ret

GetHdr endp


Get_ZipHdr proc near
;v1.4 GetHdr Subroutine for ZIP files
;v1.3 Reads in ZIP file entry.
; Then scans for the unique file entry signature.
; On success:
; DS:BX -> file entry directory structure
; CF clear
; Else CF set for failure

call Read_Zip_Entry
jb Get_ZHdrX ;failed, AL=ERRORLEVEL

mov bx,offset inbuf ;use for field base
mov di,offset archdr.aCmpMeth ;moving into this structure

;v1.4 Remember, the ZIP header we'll be snarfing data from
; looks like this:
;zVerMade dw ? ;version needed to extract 2 bytes
;zBitflag dw ? ;general purpose bit flag 2 bytes
;zCmpMeth dw ? ;compression method 2 bytes
;zModTime dw ? ;last mod file time 2 bytes
;zModDate dw ? ;last mod file date 2 bytes
;zCrc32 dw ?,? ;crc-32 4 bytes
;zCmpSiz dw ?,? ;compressed size 4 bytes
;zUncmpSiz dw ?,? ;uncompressed size 4 bytes
;zNameLen dw ? ;filename length 2 bytes
;zExtraLen dw ? ;extra field length 2 bytes
;zMbrName db ? ;filename (variable size)
;extra field (variable size)
;
; and the ARC/PAK record we'll be formatting to
; looks like this:
;aMbrFlag db 1AH
;aCmpMeth db 0 ; compression code
;aMbrName db 13 dup (0) ; file name
;aCmpSiz dw 0,0 ; file size in archive
;aModDate dw 0 ; creation date
;aModTime dw 0 ; creation time
;aCrc16 dw 0 ; cyclic redunancy check
;aUncmpSiz dw 0,0 ; true file size, bytes

mov ax,[bx].zCmpMeth ;compression method
inc al ;bump to be non-0
stosb ;-> aCmpMeth

;For now, assuming a normal file name (no paths)

mov ax,[bx].zNameLen ;filename length
and ax,15 ;constrain to max 12 chars
mov cx,ax ;into CX for move
lea si,[bx].zMbrName ;pointer to actual filename
rep movsb ;do the move
xor al,al ;terminating 0
stosb

mov di,offset archdr.aCmpSiz ;bump past name

; mov ax,[bx].zCmpSiz ;compressed size.lo
; stosw ; -> aCmpSiz
; mov ax,[bx].zCmpSiz[2] ;compressed size.hi
; stosw ; -> aCmpSiz[2]
mov si,offset inbuf.zCmpSiz ;-> compressed size
movsw ;aCmpSiz.lo
movsw ;aCmpSiz.hi

mov ax,[bx].zModDate ;last mod date
stosw ; -> aModDate
mov ax,[bx].zModTime ;last mod time
stosw ; -> aModTime
mov ax,[bx].zCrc32 ;CRC-32 value.lo
stosw ; -> aCrc16

; mov ax,[bx].zUncmpSiz ;uncompressed size.lo
; stosw ; -> aUncmpSiz
; mov ax,[bx].zUncmpSiz[2] ;uncompressed size.hi
; stosw ; -> aUncmpSiz[2]
mov si,offset inbuf.zUncmpSiz ;-> uncompressed size
movsw ;aUncmpSiz.lo
movsw ;aUncmpSiz.hi

xor ax,ax ;return AX 0
clc ;return CF clear
Get_ZHdrX:
ret

Get_ZipHdr endp ;GetHdr subroutine



Get_LZHHdr proc near
;v1.4 GetHdr Subroutine for LZH headers
; LZH file header has already been read in to inbuf.
;
; If all is ok, we move the appropriate LZH fields into the
; standard ARC/PAK structure (archdr) (so far as we can).
;
; Gleaning from the LHARCDOC documentation, the 'laCmpMeth' field
; (5 characters) can be:
; '-lh0-' stored as is (no compression)
; '-lh1-' compressed by LZHuf coding
; There appear to be at least two more possible compression codes
; that may appear: "LARC type 4 and type 5" (whatever they may be!).
;
; Assuming this field will ALWAYS be text, we are NOT gonna try to
; snarf some magic code number out of the field, but will just
; protect the field (in inbuf) and move the text directly into our
; formatted display line later.
;
; The only way we can test this as an LZH header is to look
; for a '-%%%-' starting at the 2d header byte (the laCmpMeth
; field).
;
; On success:
; DS:BX -> file entry directory structure
; CF clear
; Else CF set for failure

;v1.4 LZH files don't have a decent, clean EOF header.
; We have to test for near-EOF the hard way.

mov di,offset archdr.aMbrFlag ;moving into this structure
mov ax,001AH ;fake ARC/PAK flag
stosw ; and EOF compression code

xor ax,ax ;handy 0
mov bx,offset filelen ;-> file length
mov dx,[bx] ;file length.lo
mov cx,2[bx] ;file length.hi

mov bx,offset curpsn ;for fast access
cmp cx,2[bx] ;length.hi = psn.hi?
jnz GL_AddHdr ;nope
cmp dx,[bx] ;length.lo = psn.lo?
jz GL_TrueEof ;yep, we're exactly at EOF

GL_AddHdr:
sub dx,LZHHDRLEN ;sub header length
sbb cx,ax ;0 ;handle the borrow
jb GL_Eof ;<0, beyond EOF
sub dx,[bx] ;- file psn.lo
sbb cx,2[bx] ;- file psn.hi, minus any borrows
jnb GL_NotEof ;not near end .. ok

;There must've been junk on the file end.
;However .. there ALWAYS seems to be junk on the end.
; So .. we'll return no message at all (AL=0)
;If we ever figure out how to detect a TRUE LZH EOF,
;we can enable this ERRORLEVEL=18 business.

GL_Eof:
; mov al,18 ;'No further files to be found'
GL_TrueEof:
stc ;CF set for EOF v1.4
ret

GL_NotEof:

push di ;save ptr -> archdr.aMbrName
call Read_LZH_Entry
pop di
jb Get_LHdrX ;failed, AL=ERRORLEVEL

mov bx,offset inbuf ;use for field base

;v1.4 Remember, the LZH header we'll be snarfing data from
; looks like this:
;lUnk1 db ?,? ;char unknown1[2]; ;?
;lCmpMeth db 5 dup(?) ;char method[5]; ;compression method
;lCmpSiz dw ?,? ;long csize; ;compressed size
;lUncmpSiz dw ?,? ;long fsize; ;uncompressed size
;lModTime dw ? ;int ftime; ;last mod file time
; ; (msdos format)
;lModDate dw ? ;int fdate; ;last mod file date
;lfAttr db ? ;char fattr; ;file attributes
;unknown2 db ? ;char unknown2; ;?
;lNameLen db ? ;char namelen; ;filename length
;
;lMbrName db ? ;char *fname; ;filename
;;lCrc16 dw ? ;int crc; ;crc-16
;
; and the ARC/PAK record we'll be formatting to
; looks like this:
;aMbrFlag db 1AH
;aCmpMeth db 0 ; compression code
;aMbrName db 13 dup (0) ; file name
;aCmpSiz dw 0,0 ; file size in archive
;aModDate dw 0 ; creation date
;aModTime dw 0 ; creation time
;aCrc16 dw 0 ; cyclic redundancy check
;aUncmpSiz dw 0,0 ; true file size, bytes

mov al,[bx].lNameLen ;filename length
and ax,15 ;constrain to max 12 chars
mov cx,ax ;into CX for move
mov si,offset inbuf.lMbrName ;-> actual filename
rep movsb ;do the move
xor al,al ;terminating 0
stosb

;In LZH headers, the 2-byte CRC16 word lies immediately
;after the filename.
;Snarf it now and stuff in the ARC header.

lodsw ;lCrc16
push ax ;save a sec

mov di,offset archdr.aCmpSiz ;bump past name

; mov ax,[bx].lCmpSiz ;compressed size.lo
; stosw ; -> aCmpSiz
; mov ax,[bx].lCmpSiz[2] ;compressed size.hi
; stosw ; -> aCmpSiz[2]
mov si,offset inbuf.lCmpSiz ;-> compressed size
movsw ;aCmpSiz.lo
movsw ;aCmpSiz.hi

mov ax,[bx].lModDate ;last mod date
stosw ; -> aModDate
mov ax,[bx].lModTime ;last mod time
stosw ; -> aModTime
pop ax ;CRC-16 value
stosw ; -> aCrc16
; mov ax,[bx].lUncmpSiz ;uncompressed size.lo
; stosw ; -> aUncmpSiz
; mov ax,[bx].lUncmpSiz[2] ;uncompressed size.hi
; stosw ; -> aUncmpSiz[2]
mov si,offset inbuf.lUncmpSiz ;-> uncompressed size
movsw ;aUncmpSiz.lo
movsw ;aUncmpSiz.hi

xor ax,ax ;return AX 0
clc ;return CF clear
Get_LHdrX:
ret

Get_LZHHdr endp ;GetHdr Subroutine v1.4


Read_LZH_Entry proc near ;GetHdr Subroutine v1.4

mov dx,offset inbuf ;read into here
mov cx,LZHHDRLEN ;entry structure size
;(does NOT include variable
; length filename, and the
;two CRC bytes following the
;filename)
mov bx,archdl ;file handle
call ReadZ_It ;try to read in header
;(up to filename)
jb ReadL_Eof ;failed, AL=error

mov si,dx ;structure start
mov al,'-' ;test for '-l%-' or whatever
cmp [si].lCmpMeth,al ;first part of compression
;method string?
jnz ReadL_InvalDat ;bogus, failed
cmp [si].lCmpMeth+4,al ;how about last char?
jz ReadL_Ok1 ;yep, fine
ReadL_InvalDat:
mov al,0DH ;force to 'invalid data'
ReadL_Eof:
mov archdr.aCmpMeth,al ;set per EOF or error
stc ;return CF set
ret

ReadL_Ok1:
mov dx,offset inbuf.lMbrName ;-> lMbrName psn
mov cl,inbuf.lNameLen ;length of member filename
xor ch,ch ;clear msb

call ReadZ_It ;read in the name
jb ReadL_Eof ;failed
add dx,cx ;bump buff ptr past name
mov cx,2 ;LZH CRC is a word
call ReadZ_It ;read in the CRC word
jb ReadL_Eof ;failed
ret ;success

Read_LZH_Entry endp ;GetHdr Subroutine v1.4


Read_Zip_Entry proc near ;GetHdr Subroutine

mov dx,offset inbuf ;read into here
mov cx,ZIPHDRLEN ;entry structure size
;(does NOT include filename or
; Extra fields, which are
;dynamic)
mov bx,archdl ;file handle
call ReadZ_It ;try to read in header
;(up to filename)
jb ReadZ_Eof ;failed, AL=error v1.3a

mov si,dx ;->file signature v1.4
lodsw ;snarf first 2 chars v1.4
cmp ax,ZSIG ;ZIP header? v1.4
jnz ReadZ_InvalDat ;nope, bogus v1.4
lodsw ;file or central sig v1.4
cmp ax,ZFILESIG ;next member? v1.4
jz ReadZ_Ok1 ;yep, fine v1.4
cmp ax,ZDIRSIG ;central directory? v1.4
;(means we're done) v1.4
mov al,0 ;assume yes, EOF v1.4
jz ReadZ_Eof ;yep v1.4

ReadZ_InvalDat:
mov al,0DH ;'Invalid data' v1.4
ReadZ_Eof: ; v1.3a
mov archdr.aCmpMeth,al ;set per EOF or error v1.3a
stc ;return CF set v1.3a
ret

ReadZ_Ok1:
mov dx,offset inbuf.zMbrName ;move to zFilename psn
mov cx,inbuf.zNameLen ;length of member filename
;fall thru to ... v1.3a

;v1.4 Common subroutine for ReadZ and Read_LZH
; DX -> buffer
; CX = bytes to read
; BX MUST have archdl .. so protect BX!

ReadZ_It:
mov ah,3FH ;read from file/device
int 21H
jb ReadZ_ItX ;failed, error in AX v1.3a

;v1.4 We'll update our curpsn file pointers later
; when we try to read past compressed file contents.

;v1.4 add curpsn,ax ;bump current file ptr v1.3a
;by amount read v1.3a
;v1.4 adc word ptr curpsn[2],0 ;bump psn.hi if carry v1.3a

cmp ax,cx ;read all we expected?
mov ax,0 ;clear AX v1.3a
jz ReadZ_ItX ;yep, return CF clear v1.3a
mov al,0BH ;assume unexpected EOF
;('invalid format')
stc

ReadZ_ItX:
ret ;CF, AL set per error v1.3a

Read_Zip_Entry endp ;GetHdr subroutine


;v1.3 Common subroutine
; Bumps archive file pointers to next entry
; On success, return:
; CF clear
; AL = 0
; On failure (e.g., couldn't move ptrs), return:
; CF set
; AL = error

Bump_ArcPtrs proc near

cmp ftype,ZIP ;ZIP file? v1.3
jz Next_ZEntry ;bump file ptr to next entry v1.3

;v1.3 Entirely new code

mov bx,offset archdr.aCmpSiz ;-> encoded file length v1.4
mov dx,[bx] ;.lo v1.4
mov cx,2[bx] ;.hi
jmp short Bump_Common ;common code


;v1.3 Positions ZIP file pointer to next local entry.
; We've already read in the entire header, plus the filename,
; so the file pointer should be just beyond the filename
; (at the Extra field).
; Move file pointers beyond the Extra field, and then past
; the actual entry data (the compressed size).

Next_ZEntry:

mov bx,offset inbuf ;point back to structure
mov dx,[bx].zCmpSiz ;size.lo
mov cx,[bx].zCmpSiz[2] ;size.hi
add dx,[bx].zExtraLen ;add in extra field length
adc cx,0 ;in case of carry

Bump_Common:

mov bx,archdl ;file handle
mov ax,4201H ;move pointer from current loc
int 21H
jb Bump_X ;seek error v1.3a
;return CF set, AL=error v1.3a

;v1.4 Updating curpsn variables now
; so the NEXT GetHdr call will have current data.
mov bx,offset curpsn
mov [bx],ax
mov 2[bx],dx
xor ax,ax ;AX,CF clear v1.3a
Bump_X:
ret

Bump_ArcPtrs endp


;v1.3 Formats, displays totals

Format_Totals proc near

mov ax,totmbrs ;total members v1.3
mov di,offset vtmbrs-2 ;format total members v1.3
call Asciify ; v1.3

mov bx,offset totlen ;-> total actual file size v1.4
mov ax,[bx] ;.lo v1.4
mov dx,2[bx] ;.hi v1.4

push ax ;save totlen.lo v1.4
push dx ; and totlen.hi v1.4

mov di,offset vtlen ;format total actual file size v1.3
call Asciify_Long ; v1.3

mov bx,offset totsize ;-> total compressed file sizes v1.4
mov ax,[bx] ;.lo v1.4
mov dx,2[bx] ;.hi v1.4

push ax ;save totsize.lo v1.4
push dx ; and totsize.hi v1.4

mov di,offset vtsize ;format total archive file size v1.3
call Asciify_Long ; v1.3

; reduce the total size/length to word values

pop dx ;totsize.hi v1.4
pop cx ;totsize.lo v1.4
pop ax ;totlen.hi v1.4
pop bx ;totlen.lo v1.4

ArcV2b: or ax,ax ; big number?
jz ArcV2c ; nope, can use it
shr ax,1 ; yup, divide by two
rcr bx,1
shr dx,1
rcr cx,1
jmp short ArcV2b

ArcV2c:
mov ax,bx
mov sign,' ' ; whata kludge
cmp ax,cx ; arc is bigger than orig?
jb ArcV2c1
sub ax,cx ; amount saved
jmp short ArcV2f

ArcV2c1:
sub ax,cx
neg ax
mov sign,'-'

ArcV2f:
mul hundred ; to percentage
add ax,50
adc dx,0 ; round up percent
or bx,bx ; empty file?
jnz ArcV2d
mov ax,100
jmp short ArcV2e

ArcV2d: div bx
ArcV2e:
mov di,offset vtsf-2 ;format stowage factor v1.3
call Asciify ;AX v1.3

mov al,sign
mov vtsf,al
Print vthdr ; display totals
ret

Format_Totals endp


OpenArc proc near ; open new archive

mov dx,offset arcname
mov ax,3d00h ; for input
int 21h
jnb Open_GetSize ;opened ok v1.3a
ret ;return CF set, AL=error v1.3a

Open_GetSize:
mov bx,ax ;handle into BX v1.3a
mov archdl,ax ; save file handle

;v1.3a We get the total file size now for later EOF testing.
xor dx,dx ;0 offset
xor cx,cx
mov ax,4202H ;from file end
int 21H
mov filelen,ax ;length.low
mov filelen[2],dx ;length.hi
xor cx,cx ;back to start
xor dx,dx
mov ax,4200H ;psn file pointer from start
int 21H
ret ;CF should be clear

OpenArc endp


ClosArc proc near

mov bx,archdl ; previous handle
or bx,bx ; already open?
jz Closed
mov ah,3eh ; yes, so close it
int 21H
Closed: mov archdl,0 ;flag as closed
ret

ClosArc endp

;
; print null-terminated (AsciiZ) string like int 21h function 9
; Enter with DS:DX -> AsciiZ string
; destroys AX
; On success, return:
; CF clear
; AL = 0
; On failure (write fail), return:
; CF set
; AL = error

PrintS proc near

push di ;v1.3
push bx
push cx

mov cx,0FFFFH ;max scan v1.3
xor al,al ;handy 0 v1.3
mov di,dx ;string start v1.3
repne scasb ;find the terminator v1.3
inc cx ;adjust v1.3
not cx ;CX=length v1.3

mov bx,outhdl ; using std out or temp file
or bx,bx ;never opened? v1.3
jnz Print_S1 ;nope, we got a handle v1.3
inc bx ;make it StdErr v1.3
inc bx
Print_S1: ; v1.3
mov ah,40h ; write to file
int 21h
jnb PrintS_Done ;fine v1.3

;v1.3 What happens if we're trying to write to an output file
; and THAT fails? Even error msgs can't get out.
; We switch to StdErr, that's what!

mov di,ax ;save error level v1.3a
mov bx,STDERR ;force to STdErr v1.3a
mov outhdl,bx ;and for future output v1.3a
mov ah,40H ;write to STDOUT v1.3a
int 21H ;(CX,DX unchanged) v1.3a
mov ax,di ;restore orig error v1.3a
stc ;return CF set v1.3a

PrintS_Done:
pop cx ; recover registers
pop bx
pop di
ret

PrintS endp

page
;
; format the time (in AX)

time record hour:5,min:6,sec:5 ;packed time

GetTime proc near ;format the date
mov di,offset vtime
or ax,ax ;it is zero?
jz GotTime

push ax ;save date
and ax,mask hour ;get hour part
mov cl,hour ;bits to shift
shr ax,cl
call Cnvrt1
stosw
mov al,':'
stosb

GT3: pop ax ;get the time back
and ax,mask min ;get min part
mov cl,min ;bits to shift
call Cnvrt
stosw
GotTime:ret
GetTime endp


Cnvrt2 proc near ;convert to ascii
call Cnvrt
cmp al,'0' ;suppress leading zero
jne Cnvrtd
mov al,' '
ret

Cnvrt: shr ax,cl
Cnvrt1: aam ;make al into bcd
or ax,'00' ; and to ascii
xchg al,ah
Cnvrtd: ret
Cnvrt2 endp

page
;
; format the date (in AX)

date record yr:7,mo:4,dy:5 ;packed date

GetDate proc near ;format the date
or ax,ax ;is it zero?
jz GotDate

push ax ;save date
and ax,mask yr ;get year part
mov cl,yr ;bits to shift
call Cnvrt
mov di,offset vyear
or al,'8' ;adjust for base year
stosw

pop bx ;get the date back
push bx ;save it
and bx,mask mo ;get month part
mov cl,mo ;bits to shift
shr bx,cl
add bx,bx ; form month table index
add bx,bx
lea si,word ptr months-4[bx]
mov cx,word ptr 3
mov di,offset vmonth
rep movsb

pop ax ;get the date back
and ax,mask dy ;get day part
mov cl,dy ;bits to shift
call Cnvrt
mov di,offset vdate
stosw
GotDate:ret
GetDate endp

page
;
;v1.3 A severely hacked single/double precision number conversion function.
; Originally from JMODEM, but severely hacked by Toad Hall.
; ES:DI -> string
; Destroys everything almost.

;Enter here if integer in AX
Asciify proc near

xor dx,dx ; clear fake long.hi
mov si,ax ;move integer into SI
xor ah,ah ;clear msb (flag)
jmp short Ascii_Ax ;jump into the code

;Enter here if long integer in DX:AX.
Asciify_Long:

mov si,ax ;move long.lo into SI
xor ah,ah ;clear msb (flag)
Comment ~
MOV CX,3B9AH ; Get billions
MOV BX,0CA00H
CALL Subtr ; Subtract them out

MOV CX,05F5H ; Get hundred-millions
MOV BX,0E100H
CALL Subtr ; Subtract them out
Comment ends ~

and dx,4FFH ;seems likely v1.3
MOV CX,word ptr 0098H ; Get ten-millions
MOV BX,9680H
CALL Subtr ; Subtract them out

MOV CX,word ptr 000FH ; Get millions
MOV BX,4240H
CALL Subtr ; Subtract them out

MOV CX,word ptr 1 ; Get hundred-thousands
MOV BX,86A0H
CALL Subtr ; Subtract them out

Ascii_Ax:
xor cx,cx ; Get ten-thousands
MOV BX,2710H
CALL Subtr ; Subtract them out
MOV BX,03E8H
CALL Subtr ; Subtract them out

MOV BX,word ptr 0064H
CALL Subtr ; Subtract them out
MOV BX,word ptr 10
CALL Subtr ; Subtract them out
mov ax,si ;residual in SI
add AL,'0' ; Add bias to residual
stosb ; Put in the string
RET

;Common subroutine for Asciify

Subtr: mov al,'0'-1

Subtr1: INC al ; Bump the digit character
SUB si,BX ; Dword subtraction
SBB DX,CX
JNB Subtr1 ; Continue until a carry

ADD si,BX ; One too many, add back
ADC DX,CX ; and the remainder

cmp al,'0'
jnz Subtr2 ;nope, turn off leading flag, stuff
or ah,ah ;no more leading spaces?
jnz Sub_Stuff ;right, stuff the '0'
mov al,' ' ;make it neat with leading spaces
Sub_Stuff:
stosb ;stuff the char
RET

Subtr2: inc ah ;turn off leading space flag
stosb
ret
Asciify ENDP


;v1.3a Convert 16-bit binary word in AX
; to hex ASCII string at ES:DI
; (No need to save any registers)

hexchar db '0123456789ABCDEF'

Cvh proc near

mov si,offset hexchar ;for faster access v1.3a
mov dx,ax ; save 16-bits

mov bl,dh ; third nibble
mov cx,0F04H ;CL=4 for shifting, v1.3a
;CH=0FH for masking v1.3a
shr bl,cl
mov al,[si][bx] ;snarf hex char v1.3a
stosb

mov bl,dh ; last nibble
and bl,ch ;0fh ; v1.3a
mov al,[si][bx] ;snarf hex char v1.3a
stosb

mov bl,dl ; first nibble
sub bh,bh
shr bl,cl ; isolate (CL still 4) v1.3a
mov al,[si][bx] ;snarf hex char v1.3a
stosb

mov bl,dl ; second nibble
and bl,ch ;0fh ; isolate v1.3a
mov al,[si][bx] ;snarf hex char v1.3a
stosb
ret

Cvh endp

subttl '--- i/o data areas'

ArcV endp

archdr db 30 dup (0) ; i/o area for a header v1.3a

inbuf db INBUFSZ dup (0) ;just big enough for ZIP
;directories and filenames v1.3a

CSEG ENDS
END


  3 Responses to “Category : BBS Programs+Doors
Archive   : RBBS-ASM.ZIP
Filename : QBARCV6.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/