home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Unsorted BBS Collection
/
thegreatunsorted.tar
/
thegreatunsorted
/
programming
/
misc_programming
/
combine.asm
< prev
next >
Wrap
Assembly Source File
|
1996-10-19
|
11KB
|
458 lines
; COMBINE.ASM Interrupt List combiner
; by Ralf Brown
; last edit: 19oct96
NAME COMBINE
TITLE Combine Interrupt List sections
; declare all the segments in the order in which they are to appear in the
; executable
CODE SEGMENT 'CODE'
CODE ENDS
STACKSEG SEGMENT PUBLIC WORD 'STACK'
STACKSEG ENDS
BUFFERSEG SEGMENT PUBLIC WORD 'DATA'
BUFFERSEG ENDS
;
DGROUP GROUP CODE,STACKSEG,BUFFERSEG
;;------------------------------------------------------------------------
FFBLK struc
ff_reserved db 15h dup (?)
ff_attrib db ?
ff_ftime dw ?
ff_fdate dw ?
ff_fsize dd ?
ff_fname db 13 dup (?)
FFBLK ends
;;------------------------------------------------------------------------
CODE SEGMENT 'CODE'
ORG 100h ; this is a .COM file
ASSUME CS:DGROUP,DS:DGROUP,ES:DGROUP,SS:DGROUP
combine:
jmp near ptr main
banner db 13,"COMBINE v2.00",9,"Ralf Brown 1996",13,10,"$",26
usage_msg db "Usage:",9,"COMBINE [options] dest-dir",13,10
db 9,"where {dest-dir} is the directory in which to place",13,10
db 9," the combined list ('.' for the current directory)",13,10
db 10
db 9,"options:",13,10
db 9,9,"-d",9,"delete sections after copying",13,10
db 10
db "All sections of the interrupt list must be in the current directory."
db "$"
bad_dos_msg db "Need DOS 2.0+$"
bad_drive_msg db "Invalid destination drive$"
no_mem_msg db "Insufficient memory$"
no_files_msg db "No section files found!$"
readerr_msg db "Read Error$"
writeerr_msg db "Write Error$"
diskfull_msg db "Disk full? while writing$"
no_disk_msg db "Out of space on destination drive",13,10,"$"
retry_msg db "Try again with -d to delete while copying$"
cant_create_msg db "Check directory name -- unable to create "
combined_file db "INTERRUP.LST",0,"$"
section_file db "INTERRUP.A",0,"$"
section_letter equ section_file+9
missing_msg db "unavailable (skipped)"
crlf db 13,10,"$"
section_heading db "Interrupt List, part "
section_hdr_len equ $-section_heading
complete_msg db "Done.$"
;
; flags affecting operation
;
del_after_copy db 0
;
; data needed while processing
;
filehandle equ di ; output file's handle
numsections db 26
dest_drive db 0
nondefault_dest db 0
ftime dw 0
fdate dw 0
filesize_lo dw 0
filesize_hi equ bp
; (since we don't use disk_buffer until after FindFirst is no longer needed,
; save memory by overlaying the two)
FindFirst equ DGROUP:disk_buffer
;;------------------------------------------------------------------------
write_string:
mov ah,9
int 21h
ret
;;------------------------------------------------------------------------
skip_whitespace:
lodsb
cmp al,' '
je skip_whitespace
cmp al,9
je skip_whitespace
dec si ; unget the last character
; set ZF to indicate whether we got to end of cmdline
cmp al,0Dh
ret
;;------------------------------------------------------------------------
get_destination_file:
mov bx,si ; remember start of destination name
get_dest_file_loop:
lodsb
cmp al,' '
je got_dest_end
cmp al,9
je got_dest_end
cmp al,0Dh
jne get_dest_file_loop
got_dest_end:
dec si ; unget last character
mov di,si
mov al,[si-1] ; check end of path -- is it terminated
cmp al,'\' ; by a slash or backslash?
je dest_has_slash
cmp al,'/'
je dest_has_slash
cmp al,':'
je dest_has_slash
mov al,'\'
stosb
dest_has_slash:
mov si,offset combined_file
dest_copy_loop:
lodsb
stosb
cmp al,0
jne dest_copy_loop
; OK, now open the destination file
; (BX is still pointing at start of pathname)
cmp byte ptr [bx+1],':'
jne got_dest_drive
mov al,[bx]
and al,0DFh ; force to uppercase
sub al,'A'
jb got_dest_drive
cmp al,dest_drive
je got_dest_drive
mov dest_drive,al
mov nondefault_dest,al
got_dest_drive:
mov ah,3Ch ; create the output file
xor cx,cx ; no special file attributes
mov dx,bx
int 21h
mov dx,offset cant_create_msg
jc exit_with_err_2
mov filehandle,ax
ret
;;------------------------------------------------------------------------
check_total_size:
mov byte ptr section_letter,'A'-1
mov ah,1Ah ; set DTA
mov dx,offset FindFirst
int 21h
xor si,si ; keep track of # of sections found
check_size_loop:
inc byte ptr section_letter
cmp byte ptr section_letter,'Z'
ja short get_free_space
mov ah,4Eh ; find first
mov cx,001Fh ; ...regardless of attribute
mov dx,offset section_file
int 21h
jc check_size_loop
inc si ; another section found
mov ax,FindFirst.ff_ftime
mov ftime,ax
mov ax,FindFirst.ff_fdate
mov fdate,ax
mov ax,word ptr FindFirst.ff_fsize
mov dx,word ptr FindFirst.ff_fsize+2
cmp del_after_copy,0
je count_full_size
cmp nondefault_dest,0
jnz count_full_size
cmp dx,filesize_hi
jb check_size_loop
ja check_size_bigger
cmp ax,filesize_lo
jbe check_size_loop
check_size_bigger:
mov filesize_lo,ax
mov filesize_hi,dx
jmp check_size_loop
count_full_size:
add filesize_lo,ax
adc filesize_hi,dx
jmp check_size_loop
get_free_space:
test si,si ; check number of sections found
mov dx,offset no_files_msg
jz short exit_with_err_2
mov dl,dest_drive
inc dx
mov ah,36h ; get free disk space
int 21h
cmp ax,0FFFFh
jne got_free_space
mov dx,offset bad_drive_msg
exit_with_err_2:
jmp near ptr exit_with_errmsg
got_free_space:
mul cx ; DX:AX <- AX*CX
mov cx,dx ; store high half of intermediate
mul bx ; DX:AX <- low(AX*CX)*BX
xchg ax,bx ; store low half of second interm.
xchg cx,dx ; store high half of second interm.
mul dx ; DX:AX <- high(AX*CX)*BX
xchg ax,bx ; DX:BX:0000h + CX:AX = result
add bx,cx
adc dx,0 ; DX:BX:AX = AX*BX*CX = free space
jnz plenty_free_space ; >4G free?
sub ax,filesize_lo
sbb bx,filesize_hi
jnb plenty_free_space
not_enough_space:
mov dx,offset no_disk_msg
call write_string
cmp nondefault_dest,0
jnz size_check_failed
cmp del_after_copy,0
jne size_check_failed
mov dx,offset retry_msg
call write_string
size_check_failed:
mov al,2
jmp exit
plenty_free_space:
ret
;;------------------------------------------------------------------------
check_section_header:
push si
push di
mov si,offset DGROUP:disk_buffer
mov di,offset section_heading
mov cx,section_hdr_len
or cx,cx
rep cmpsb
jnz not_section_heading
scan_curr_section:
lodsb
cmp al,' ' ; scan for the " of "
jne scan_curr_section
add si,3 ; skip "of "
xor cl,cl
num_sections_loop:
lodsb
sub al,'0'
jb num_sections_done
cmp al,9
ja num_sections_done
mov ch,al
mov al,10
mul cl
mov cl,al
add cl,ch
jmp num_sections_loop
num_sections_done:
mov numsections,cl
got_num_sections:
not_section_heading:
pop di
pop si
ret
;;------------------------------------------------------------------------
; in: SI = file handle for current section
copy_section:
mov ax,4201h
mov bx,filehandle
xor cx,cx
xor dx,dx
int 21h ; get current file position (== size)
mov filesize_lo,ax
mov filesize_hi,dx
copy_section_loop:
mov ah,3Fh
mov bx,si
mov cx,disk_buffer_end - disk_buffer
mov dx,offset DGROUP:disk_buffer
int 21h
jc copy_read_error
mov cx,ax ; write same number of bytes read
mov ah,40h
mov bx,filehandle
;; mov dx,offset DGROUP:disk_buffer
int 21h
mov dx,offset writeerr_msg
jc copy_error
mov dx,offset diskfull_msg
cmp ax,cx
jb copy_error
; check for section header at start of buffer, and extract number
; of sections from it
push cx
call check_section_header
pop ax
cmp ax,disk_buffer_end - disk_buffer ; continue until only partial
je copy_section_loop ; buffer read (EOF hit)
ret
copy_read_error:
mov dx,offset readerr_msg
copy_error:
; truncate output to size before section was started
push dx ; store error message
mov ax,4200h
mov bx,filehandle
mov cx,filesize_hi
mov dx,filesize_lo
int 21h
mov ah,40h
xor cx,cx ; write zero bytes to truncate
int 21h
pop dx ; get back error message
;; fall through to exit_with_errmsg ;;
;;------------------------------------------------------------------------
exit_with_errmsg:
call write_string
; exit with errorlevel 1
mov al,01h
jmp near ptr exit
main:
ASSUME CS:DGROUP, DS:DGROUP, ES:DGROUP, SS:DGROUP
mov dx,offset banner
call write_string
; relocate the stack
mov sp,offset DGROUP:stackbot
; ensure that we have enough memory
mov ax,cs
add ax,1000h ; require 64K memory
cmp ax,ds:[0002h] ; is end of mem at least 64K above CS?
mov dx,offset no_mem_msg
ja exit_with_errmsg
mov si,81h ; point at start of cmdline
mov bl,[si-1] ; get length of cmdline
mov bh,0
mov byte ptr [bx+si],0Dh ; ensure cmdline properly terminated
cld
call skip_whitespace
mov dx,offset usage_msg
jz exit_with_errmsg
get_cmdline_switches:
call skip_whitespace
jz not_a_switch
cmp al,'-' ; is it a switch?
jne not_a_switch
lodsb ; get the switch character
lodsb ; get the switch itself
and al,0DFh ; force to uppercase
cmp al,'D'
;; mov dx,offset usage_msg
jne exit_with_errmsg
mov del_after_copy,1
jmp get_cmdline_switches
not_a_switch:
mov ah,19h ; get default drive
int 21h
mov dest_drive,al
mov ah,30h
int 21h
cmp al,2
mov dx,offset bad_dos_msg
jb exit_with_errmsg
call get_destination_file
xor filesize_hi,filesize_hi
call check_total_size
;
; OK, all the preliminaries are done now, so go concatenate the
; sections of the interrupt list
;
mov al,'A'-1
concat_loop:
inc ax
mov section_letter,al
sub al,'A'-1
cmp al,numsections
ja concat_done
mov dx,offset section_file
call write_string
mov ax,3D00h
int 21h
mov dx,offset missing_msg
jc concat_loop_end
mov si,ax
call copy_section
mov ah,3Eh
mov bx,si ; BX <- section file's handle
int 21h ; close the file
cmp del_after_copy,0
je concat_no_del
mov ah,41h
mov dx,offset section_file
int 21h
concat_no_del:
mov dx,offset crlf
concat_loop_end:
call write_string
mov al,section_letter
jmp concat_loop
concat_done:
mov dx,offset complete_msg
call write_string
mov al,00h ; successful completion
exit:
push ax
mov dx,offset crlf
call write_string
mov bx,filehandle ; set timestamp of combined file to
mov cx,ftime ; be that of the last of the sections
mov dx,fdate
mov ax,5701h ; (set file time & date)
int 21h
mov ah,3Eh ; close the destination file
int 21h
pop ax
mov ah,4Ch
int 21h
CODE ENDS
STACKSEG SEGMENT PUBLIC WORD 'STACK'
stacktop dw 160 dup (?)
stackbot label byte
STACKSEG ENDS
BUFFERSEG SEGMENT PUBLIC WORD 'DATA'
disk_buffer db 62*1024 dup (?)
disk_buffer_end label byte
BUFFERSEG ENDS
END combine