home *** CD-ROM | disk | FTP | other *** search
/ The Unsorted BBS Collection / thegreatunsorted.tar / thegreatunsorted / programming / misc_programming / combine.asm < prev    next >
Assembly Source File  |  1996-10-19  |  11KB  |  458 lines

  1. ; COMBINE.ASM    Interrupt List combiner
  2. ;        by Ralf Brown
  3. ;        last edit: 19oct96
  4.  
  5.         NAME    COMBINE
  6.         TITLE    Combine Interrupt List sections
  7.  
  8. ; declare all the segments in the order in which they are to appear in the
  9. ; executable
  10. CODE    SEGMENT 'CODE'
  11. CODE    ENDS
  12. STACKSEG SEGMENT PUBLIC WORD 'STACK'
  13. STACKSEG ENDS
  14. BUFFERSEG SEGMENT PUBLIC WORD 'DATA'
  15. BUFFERSEG ENDS
  16. ;
  17. DGROUP    GROUP    CODE,STACKSEG,BUFFERSEG
  18.  
  19. ;;------------------------------------------------------------------------
  20.  
  21. FFBLK struc
  22.   ff_reserved    db 15h dup (?)
  23.   ff_attrib    db ?
  24.   ff_ftime    dw ?
  25.   ff_fdate    dw ?
  26.   ff_fsize    dd ?
  27.   ff_fname    db 13 dup (?)
  28. FFBLK ends
  29.  
  30. ;;------------------------------------------------------------------------
  31.  
  32. CODE    SEGMENT 'CODE'
  33.     ORG    100h            ; this is a .COM file
  34.     ASSUME    CS:DGROUP,DS:DGROUP,ES:DGROUP,SS:DGROUP
  35.  
  36. combine:
  37.     jmp    near ptr main
  38.  
  39. banner        db    13,"COMBINE v2.00",9,"Ralf Brown 1996",13,10,"$",26
  40. usage_msg    db    "Usage:",9,"COMBINE [options] dest-dir",13,10
  41.         db    9,"where {dest-dir} is the directory in which to place",13,10
  42.         db    9,"  the combined list ('.' for the current directory)",13,10
  43.         db    10
  44.         db    9,"options:",13,10
  45.         db    9,9,"-d",9,"delete sections after copying",13,10
  46.         db    10
  47.         db    "All sections of the interrupt list must be in the current directory."
  48.         db    "$"
  49.  
  50. bad_dos_msg    db    "Need DOS 2.0+$"
  51. bad_drive_msg    db    "Invalid destination drive$"
  52. no_mem_msg    db    "Insufficient memory$"
  53. no_files_msg    db    "No section files found!$"
  54. readerr_msg    db    "Read Error$"
  55. writeerr_msg    db    "Write Error$"
  56. diskfull_msg    db    "Disk full? while writing$"
  57. no_disk_msg    db    "Out of space on destination drive",13,10,"$"
  58. retry_msg    db    "Try again with -d to delete while copying$"
  59.  
  60. cant_create_msg db    "Check directory name -- unable to create "
  61. combined_file    db    "INTERRUP.LST",0,"$"
  62. section_file    db    "INTERRUP.A",0,"$"
  63. section_letter equ section_file+9
  64. missing_msg    db    "unavailable (skipped)"
  65. crlf        db    13,10,"$"
  66. section_heading db    "Interrupt List, part "
  67. section_hdr_len equ $-section_heading
  68. complete_msg    db    "Done.$"
  69.  
  70. ;
  71. ; flags affecting operation
  72. ;
  73. del_after_copy    db    0
  74.  
  75. ;
  76. ; data needed while processing
  77. ;
  78. filehandle    equ    di        ; output file's handle
  79. numsections    db    26
  80. dest_drive    db    0
  81. nondefault_dest    db    0
  82. ftime        dw    0
  83. fdate        dw    0
  84. filesize_lo    dw    0
  85. filesize_hi    equ    bp
  86.  
  87. ; (since we don't use disk_buffer until after FindFirst is no longer needed,
  88. ; save memory by overlaying the two)
  89. FindFirst    equ    DGROUP:disk_buffer
  90.  
  91. ;;------------------------------------------------------------------------
  92.  
  93. write_string:
  94.     mov    ah,9
  95.     int    21h
  96.     ret
  97.  
  98. ;;------------------------------------------------------------------------
  99.  
  100. skip_whitespace:
  101.     lodsb
  102.     cmp    al,' '
  103.     je    skip_whitespace
  104.     cmp    al,9
  105.     je    skip_whitespace
  106.     dec    si            ; unget the last character
  107.     ; set ZF to indicate whether we got to end of cmdline
  108.     cmp    al,0Dh
  109.     ret
  110.  
  111. ;;------------------------------------------------------------------------
  112.  
  113. get_destination_file:
  114.     mov    bx,si            ; remember start of destination name
  115. get_dest_file_loop:
  116.     lodsb
  117.     cmp    al,' '
  118.     je    got_dest_end
  119.     cmp    al,9
  120.     je    got_dest_end
  121.     cmp    al,0Dh
  122.     jne    get_dest_file_loop
  123. got_dest_end:
  124.     dec    si            ; unget last character
  125.     mov    di,si
  126.     mov    al,[si-1]        ; check end of path -- is it terminated
  127.     cmp    al,'\'            ;   by a slash or backslash?
  128.     je    dest_has_slash
  129.     cmp    al,'/'
  130.     je    dest_has_slash
  131.     cmp    al,':'
  132.     je    dest_has_slash
  133.     mov    al,'\'
  134.     stosb
  135. dest_has_slash:
  136.     mov    si,offset combined_file
  137. dest_copy_loop:
  138.     lodsb
  139.     stosb
  140.     cmp    al,0
  141.     jne    dest_copy_loop
  142.     ; OK, now open the destination file
  143.     ; (BX is still pointing at start of pathname)
  144.     cmp    byte ptr [bx+1],':'
  145.     jne    got_dest_drive
  146.     mov    al,[bx]
  147.     and    al,0DFh            ; force to uppercase
  148.     sub    al,'A'
  149.     jb    got_dest_drive
  150.     cmp    al,dest_drive
  151.     je    got_dest_drive
  152.     mov    dest_drive,al
  153.     mov    nondefault_dest,al
  154. got_dest_drive:
  155.     mov    ah,3Ch            ; create the output file
  156.     xor    cx,cx            ; no special file attributes
  157.     mov    dx,bx
  158.     int    21h
  159.     mov    dx,offset cant_create_msg
  160.     jc    exit_with_err_2
  161.     mov    filehandle,ax
  162.     ret
  163.  
  164. ;;------------------------------------------------------------------------
  165.  
  166. check_total_size:
  167.     mov    byte ptr section_letter,'A'-1
  168.     mov    ah,1Ah            ; set DTA
  169.     mov    dx,offset FindFirst
  170.     int    21h
  171.     xor    si,si            ; keep track of # of sections found
  172. check_size_loop:
  173.     inc    byte ptr section_letter
  174.     cmp    byte ptr section_letter,'Z'
  175.     ja    short get_free_space
  176.     mov    ah,4Eh            ; find first
  177.     mov    cx,001Fh        ; ...regardless of attribute
  178.     mov    dx,offset section_file
  179.     int    21h
  180.     jc    check_size_loop
  181.     inc    si            ; another section found
  182.     mov    ax,FindFirst.ff_ftime
  183.     mov    ftime,ax
  184.     mov    ax,FindFirst.ff_fdate
  185.     mov    fdate,ax
  186.     mov    ax,word ptr FindFirst.ff_fsize
  187.     mov    dx,word ptr FindFirst.ff_fsize+2
  188.     cmp    del_after_copy,0
  189.     je    count_full_size
  190.     cmp    nondefault_dest,0
  191.     jnz    count_full_size
  192.     cmp    dx,filesize_hi
  193.     jb    check_size_loop
  194.     ja    check_size_bigger
  195.     cmp    ax,filesize_lo
  196.     jbe    check_size_loop
  197. check_size_bigger:
  198.     mov    filesize_lo,ax
  199.     mov    filesize_hi,dx
  200.     jmp    check_size_loop
  201.  
  202. count_full_size:
  203.     add    filesize_lo,ax
  204.     adc    filesize_hi,dx
  205.     jmp    check_size_loop
  206.  
  207. get_free_space:
  208.     test    si,si            ; check number of sections found
  209.     mov    dx,offset no_files_msg
  210.     jz    short exit_with_err_2
  211.     mov    dl,dest_drive
  212.     inc    dx
  213.     mov    ah,36h            ; get free disk space
  214.     int    21h
  215.     cmp    ax,0FFFFh
  216.     jne    got_free_space
  217.     mov    dx,offset bad_drive_msg
  218. exit_with_err_2:
  219.     jmp    near ptr exit_with_errmsg
  220. got_free_space:
  221.     mul    cx            ; DX:AX <- AX*CX
  222.     mov    cx,dx            ; store high half of intermediate
  223.     mul    bx            ; DX:AX <- low(AX*CX)*BX
  224.     xchg    ax,bx            ; store low half of second interm.
  225.     xchg    cx,dx            ; store high half of second interm.
  226.     mul    dx            ; DX:AX <- high(AX*CX)*BX
  227.     xchg    ax,bx            ; DX:BX:0000h + CX:AX = result
  228.     add    bx,cx
  229.     adc    dx,0            ; DX:BX:AX = AX*BX*CX = free space
  230.     jnz    plenty_free_space    ; >4G free?
  231.     sub    ax,filesize_lo
  232.     sbb    bx,filesize_hi
  233.     jnb    plenty_free_space
  234. not_enough_space:
  235.     mov    dx,offset no_disk_msg
  236.     call    write_string
  237.     cmp    nondefault_dest,0
  238.     jnz    size_check_failed
  239.     cmp    del_after_copy,0
  240.     jne    size_check_failed
  241.     mov    dx,offset retry_msg
  242.     call    write_string
  243. size_check_failed:
  244.     mov    al,2
  245.     jmp    exit
  246. plenty_free_space:
  247.     ret
  248.  
  249. ;;------------------------------------------------------------------------
  250.  
  251. check_section_header:
  252.     push    si
  253.     push    di
  254.     mov    si,offset DGROUP:disk_buffer
  255.     mov    di,offset section_heading
  256.     mov    cx,section_hdr_len
  257.     or    cx,cx
  258.     rep    cmpsb
  259.     jnz    not_section_heading
  260. scan_curr_section:
  261.     lodsb
  262.     cmp    al,' '            ; scan for the " of "
  263.     jne    scan_curr_section
  264.     add    si,3            ; skip "of "
  265.     xor    cl,cl
  266. num_sections_loop:
  267.     lodsb
  268.     sub    al,'0'
  269.     jb    num_sections_done
  270.     cmp    al,9
  271.     ja    num_sections_done
  272.     mov    ch,al
  273.     mov    al,10
  274.     mul    cl
  275.     mov    cl,al
  276.     add    cl,ch
  277.     jmp    num_sections_loop
  278. num_sections_done:
  279.     mov    numsections,cl
  280. got_num_sections:
  281. not_section_heading:    
  282.     pop    di
  283.     pop    si
  284.     ret
  285.  
  286. ;;------------------------------------------------------------------------
  287.  
  288. ; in:    SI = file handle for current section
  289. copy_section:
  290.     mov    ax,4201h
  291.     mov    bx,filehandle
  292.     xor    cx,cx
  293.     xor    dx,dx
  294.     int    21h            ; get current file position (== size)
  295.     mov    filesize_lo,ax
  296.     mov    filesize_hi,dx
  297. copy_section_loop:
  298.     mov    ah,3Fh
  299.     mov    bx,si
  300.     mov    cx,disk_buffer_end - disk_buffer
  301.     mov    dx,offset DGROUP:disk_buffer
  302.     int    21h
  303.     jc    copy_read_error
  304.     mov    cx,ax            ; write same number of bytes read
  305.     mov    ah,40h
  306.     mov    bx,filehandle
  307. ;;    mov    dx,offset DGROUP:disk_buffer
  308.     int    21h
  309.     mov    dx,offset writeerr_msg
  310.     jc    copy_error
  311.     mov    dx,offset diskfull_msg
  312.     cmp    ax,cx
  313.     jb    copy_error
  314.     ; check for section header at start of buffer, and extract number
  315.     ; of sections from it
  316.     push    cx
  317.     call    check_section_header
  318.     pop    ax
  319.     cmp    ax,disk_buffer_end - disk_buffer ; continue until only partial
  320.     je    copy_section_loop         ;   buffer read (EOF hit)
  321.     ret
  322.  
  323. copy_read_error:
  324.     mov    dx,offset readerr_msg
  325. copy_error:
  326.     ; truncate output to size before section was started
  327.     push    dx            ; store error message
  328.     mov    ax,4200h
  329.     mov    bx,filehandle
  330.     mov    cx,filesize_hi
  331.     mov    dx,filesize_lo
  332.     int    21h
  333.     mov    ah,40h
  334.     xor    cx,cx            ; write zero bytes to truncate
  335.     int    21h
  336.     pop    dx            ; get back error message
  337.     ;; fall through to exit_with_errmsg ;;
  338.  
  339. ;;------------------------------------------------------------------------
  340.  
  341. exit_with_errmsg:
  342.     call    write_string
  343.     ; exit with errorlevel 1
  344.     mov    al,01h
  345.     jmp    near ptr exit
  346.  
  347. main:
  348.     ASSUME    CS:DGROUP, DS:DGROUP, ES:DGROUP, SS:DGROUP
  349.     mov    dx,offset banner
  350.     call    write_string
  351.     ; relocate the stack
  352.     mov    sp,offset DGROUP:stackbot
  353.     ; ensure that we have enough memory
  354.     mov    ax,cs
  355.     add    ax,1000h        ; require 64K memory
  356.     cmp    ax,ds:[0002h]        ; is end of mem at least 64K above CS?
  357.     mov    dx,offset no_mem_msg
  358.     ja    exit_with_errmsg
  359.     mov    si,81h            ; point at start of cmdline
  360.     mov    bl,[si-1]        ; get length of cmdline
  361.     mov    bh,0
  362.     mov    byte ptr [bx+si],0Dh    ; ensure cmdline properly terminated
  363.     cld
  364.     call    skip_whitespace
  365.     mov    dx,offset usage_msg
  366.     jz    exit_with_errmsg
  367. get_cmdline_switches:
  368.     call    skip_whitespace
  369.     jz    not_a_switch
  370.     cmp    al,'-'            ; is it a switch?
  371.     jne    not_a_switch
  372.     lodsb                ; get the switch character
  373.     lodsb                ; get the switch itself
  374.     and    al,0DFh            ; force to uppercase
  375.     cmp    al,'D'
  376. ;;    mov    dx,offset usage_msg
  377.     jne    exit_with_errmsg
  378.     mov    del_after_copy,1
  379.     jmp    get_cmdline_switches
  380. not_a_switch:
  381.     mov    ah,19h            ; get default drive
  382.     int    21h
  383.     mov    dest_drive,al
  384.     mov    ah,30h
  385.     int    21h
  386.     cmp    al,2
  387.     mov    dx,offset bad_dos_msg
  388.     jb    exit_with_errmsg
  389.     call    get_destination_file
  390.     xor    filesize_hi,filesize_hi
  391.     call    check_total_size
  392.     ;
  393.     ; OK, all the preliminaries are done now, so go concatenate the
  394.     ; sections of the interrupt list
  395.     ;
  396.     mov    al,'A'-1
  397. concat_loop:
  398.     inc    ax
  399.     mov    section_letter,al
  400.     sub    al,'A'-1
  401.     cmp    al,numsections
  402.     ja    concat_done
  403.     mov    dx,offset section_file
  404.     call    write_string
  405.     mov    ax,3D00h
  406.     int    21h
  407.     mov    dx,offset missing_msg
  408.     jc    concat_loop_end
  409.     mov    si,ax
  410.     call    copy_section
  411.     mov    ah,3Eh
  412.     mov    bx,si            ; BX <- section file's handle
  413.     int    21h            ; close the file
  414.     cmp    del_after_copy,0
  415.     je    concat_no_del
  416.     mov    ah,41h
  417.     mov    dx,offset section_file
  418.     int    21h
  419. concat_no_del:
  420.     mov    dx,offset crlf
  421. concat_loop_end:
  422.     call    write_string
  423.     mov    al,section_letter
  424.     jmp    concat_loop
  425.  
  426. concat_done:
  427.     mov    dx,offset complete_msg
  428.     call    write_string
  429.     mov    al,00h            ; successful completion
  430. exit:
  431.     push    ax
  432.     mov    dx,offset crlf
  433.     call    write_string
  434.     mov    bx,filehandle        ; set timestamp of combined file to
  435.     mov    cx,ftime        ;   be that of the last of the sections
  436.     mov    dx,fdate
  437.     mov    ax,5701h        ; (set file time & date)
  438.     int    21h
  439.     mov    ah,3Eh            ; close the destination file
  440.     int    21h
  441.     pop    ax
  442.     mov    ah,4Ch
  443.     int    21h
  444.  
  445. CODE ENDS
  446.  
  447. STACKSEG SEGMENT PUBLIC WORD 'STACK'
  448. stacktop dw    160 dup (?)
  449. stackbot label byte
  450. STACKSEG ENDS
  451.  
  452. BUFFERSEG SEGMENT PUBLIC WORD 'DATA'
  453. disk_buffer db 62*1024 dup (?)
  454. disk_buffer_end label byte
  455. BUFFERSEG ENDS
  456.  
  457.     END combine
  458.