SPRAY.ASM


comment }
  SPRAY.COM      program copyright Dave Angel  71046,1567.
                 free for anybody, as long as it's not included with
                 commercial software.  Nominal charge (under $6) okay.

  SPRAY.ASM      This file serves as both documentation and source code.
                 The program was written in response to a message by
                 Joe Wallace 21550,6003, who wanted a program to dump
                 memory after an accidental abort of some other program.

                 The program was entered with KEDIT, assembled with MASM
                 5.1, and debugged with SYMDEB.  There are several known
                 simplifications, to keep it small.

                 It only parses the command line to the extent that if the
                 command line is non-blank it gives the copyright message.
                 If run with a blank line, it dumps memory from its own end
                 to the 640k boundary.  If you have some other amount of
                 memory, change the line below containing '**memory' as
                 appropriate.

                 It outputs to standard out, and you have to redirect it if
                 you want it in a disk file.  So you'd run   SPRAY>C:\temp
                 to get it to dump to a file on C: called temp.

                 Finally, it will go somewhat beyond the (640k) limit, as
                 much as 63.9 k beyond.  This is no problem on most
                 systems, you just may get a bit of garbage at the end.
                 But on a few systems you may get funny errors accessing
                 that memory.  If so, the 'nextsegment' logic needs to be
                 tightened up, to handle the final, partial segment.

                 Good luck.  Any suggestions or improvements welcome.
                 Dave Angel  Compuserve 71046,1456    or    Genie   D.Angel
                 July 27, 1989

}
CGROUP  group  CODE
CODE    segment
        org     100h
     assume  cs:CODE, DS:CODE
start   proc    near
        mov     sp,100h
        cmp     byte ptr ds:[80h],0
        jz      start2
        mov     dx,offset CGROUP:helpmessage
        mov     ah,9
        int     21h
        jmp     next2
helpmessage     db    'SPRAY  copyright 1989 by Dave Angel 71046,1567',13,10
                db    '   free software to dump memory to stdout',13,10,'$'

start2:
        mov     di,offset CGROUP:endcode
        mov     si,offset CGROUP:endcode+5  ; source starting address
        cld
        mov     cx,78
        xor     bx,bx           ; bx is count of printables 'in-a-row'
loop1:
        cmp     si,0fff0h
        jb      loop1a
        call    nextsegment        ; call if we're at end of segment
loop1a:
        lodsb                   ; retrieve one byte
        cmp     al,20h
        jb      loop5
        cmp     al,7fh
        ja      loop5           ; skip if unprintable character
;  found a printable character
loop2:
        stosb
        inc     bx
        loop    loop1
; we've printed enough on this line, go to next
loop3:
        mov     al,0dh
        stosb
        mov     al,0ah
        stosb
        call    flushoutput             ; write the data so far
        xor     bx,bx
        loop    loop1

;  We found a non-printable
loop5:
        cmp     bx,3
        ja      loop5a          ; skip if at least 3 printables in a row
        sub     di,bx
        add     cx,bx           ; back up over them, if 3 or less
        jmp     loop5b
loop5a:
        cmp     cx,8
        jb      loop3           ; if near the end of line, make a new one
        mov     al,20h
        stosb
        dec     cx
        stosb           ; otherwise, add two spaces and keep scanning
loop5b:
        dec     cx
loop6:
        xor     bx,bx           ; zero 'printables in-a-row'
        cmp     si,0fff0h
        jb      loop6a
        call    nextsegment        ; call if we're at end of segment
loop6a:
        lodsb
        cmp     al,20h
        jb      loop6
        cmp     al,7fh
        ja      loop6           ; ignore any more unprintables
        jmp     loop2
start   endp

flushoutput     proc    near
;  DI points one beyond last character of buffer.  So write from
;    endcode to one less than DI
        mov     cx,di
        mov     dx,offset CGROUP:endcode            ; address
        sub     cx,dx           ; count
        mov     bx,1            ; standard out
        mov     ah,40h
        push    ds
        push    cs
        pop     ds
        int     21h             ; write the line to stdout
        pop     ds
     ; ignore errors
        mov     di,offset cgroup:endcode
        mov     cx,78
        ret
flushoutput     endp


nextsegment     proc    near
;  this routine is only called when SI exceeds FFF0
;  here's where we move to another segment, and check for 640k.  We adjust
;  DS and SI, and return, if still more to do.

        push    bx              ; save bx
        mov     bx,0a000h       ; end of **memory assumed to be A000
        mov     ax,ds
        add     ax,0fffh
        sub     si,0fff0h
        mov     ds,ax
; notice, we're being sloppy here, and dumping as much as 63.9k beyond 640k
        cmp     ax,bx
        jae     next2
        pop     bx              ; restore bx
        ret                     ; return if still more memory to go
next2:
        mov     ax,4c00h
        int     21h
nextsegment     endp
endcode label   byte
CODE    ends
        end     start