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

                 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

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,'$'

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

;  We found a non-printable
        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
        cmp     cx,8
        jb      loop3           ; if near the end of line, make a new one
        mov     al,20h
        dec     cx
        stosb           ; otherwise, add two spaces and keep scanning
        dec     cx
        xor     bx,bx           ; zero 'printables in-a-row'
        cmp     si,0fff0h
        jb      loop6a
        call    nextsegment        ; call if we're at end of segment
        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
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
        mov     ax,4c00h
        int     21h
nextsegment     endp
endcode label   byte
CODE    ends
        end     start