You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

494 lines
11 KiB

; COMBINE.ASM Interrupt List combiner
; by Ralf Brown
; last edit: 22mar98
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.10",9,"Ralf Brown 1996,1998",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 9,9,"-p",9,"combine PORTS.LST instead of INTERRUP.LST",13,10
db 10
db "All sections of the interrupt/ports 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,"$"
combined_file2 db "PORTS.LST",0
combined_file2_len equ $-combined_file2
section_file1 db "INTERRUP.A",0,"$"
section_letter equ section_file1+9
section_file2 db " PORTS"
section_file2_len equ $-section_file2
section_file2_ofs equ 3
missing_msg db "unavailable (skipped)"
crlf db 13,10,"$"
section_heading1 db "Interrupt List, part "
section_hdr_len1 equ $-section_heading1
section_heading2 db "Ports List, part "
section_hdr_len2 equ $-section_heading2
complete_msg db "Done.$"
;
; flags affecting operation
;
del_after_copy db 0
section_file dw offset section_file1
section_heading dw offset section_heading1
section_hdr_len dw section_hdr_len1
;
; 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,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,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
xor cx,cx
xor dx,dx
mov bx,filehandle
int 21h
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 dx,offset DGROUP:disk_buffer
mov bx,filehandle
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 cx,filesize_hi
mov dx,filesize_lo
mov bx,filehandle
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,'P'
je want_ports
cmp al,'D'
;; mov dx,offset usage_msg
jne exit_with_errmsg
mov del_after_copy,1
jmp get_cmdline_switches
want_ports:
jmp config_for_ports
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,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 bx,si ; BX <- section file's handle
mov ah,3Eh ; DOS function: close file handle
int 21h
cmp del_after_copy,0
je concat_no_del
mov ah,41h ; DOS function: delete file
mov dx,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 ax,5701h ; (set file time & date)
mov bx,filehandle
mov cx,ftime ; set timestamp of combined file to
mov dx,fdate ; be that of the last of the sections
int 21h
mov ah,3Eh ; DOS function: close file handle
int 21h
pop ax
mov ah,4Ch
int 21h
config_for_ports:
mov section_heading,offset section_heading2
mov section_hdr_len,section_hdr_len2
push di
push si
push cx
;; copy combined_file2 over combined_file
mov cx,combined_file2_len
mov si,offset combined_file2
mov di,offset combined_file
rep movsb
;; copy section_file2 over section_file1
mov cx,section_file2_len
mov si,offset section_file2
mov di,offset section_file1
rep movsb
pop cx
pop si
pop di
add section_file,section_file2_ofs
jmp get_cmdline_switches
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