;*****   Search & Rescue Memory   *****


OpenLib  = -30-378
CloseLib = -414
ExBase   =  4
Open     = -30
Close    = -30-6
Read     = -30-12
Write    = -30-18
IoErr    = -30-102
FindTask = -$126
WaitPort = -$180
GetMsg   = -$174
Forbid   = -$84
ReplyMsg = -$17a
mode_old =  1005
mode_new =  1006
skey     =  $bfec01

start:                         ;start prg
 move.l  a7,SPinit             ;save SP
 bsr     Wb                    ;link program with Workbench and initialize
 
mloop:                         ;initialize registers
 move.l  #0,a3
 move.l  #0,a4
 moveq   #0,d4
 bsr     menu
 cmp.b   #12,flag
 beq     bsave                 ;save memory
 cmp.b   #15,flag
 beq     quit                  ;bye-bye 
 cmp.b   #7,flag     
 beq     rdmem                 ;read memory
 cmp.b   #6,flag               ;flag <6: Hex
 bcs     hex                   
 move.l  #messA,d2             ;flag >5: ASCII
 bsr     inpt                  ;read string
 move.l  d6,a0                 ;#inbuff in a0
 move.l  a5,a1                 ;#string in a1
copie:
 move.l  (a0)+,(a1)+           ;copy inbuff in string
 tst.b   (a0)
 bne     copie
 bra.s   suite2
hex:
 move.l  #messH,d2              ;print hex message
 bsr     inpt
 bsr     conv
 move.l  d3,(a5)                ;put hex in string
 move.b  #0,+4(a5)              ;put 0 at the end
 cmp.b   #2,flag                ;is it a word?
 bne     suite2
 add.l   #2,a5                  ;then skip 2 bytes
suite2:
 bsr     fromto                 ;get from and to addrresses
 cmp.b   #15,flag               ;return pressed?
 beq     final
 move.l  #messW,d2              ;print Wait...
 bsr     pmsg 
 move.l  a5,a0                  ;#string in a0
 move.l  d4,a1                  ;from addrress in a1 
 clr.l   d2
encore:
 bsr     hunt                   ;get string address 
 cmp.l   #0,d5                  ;is length = zero?
 beq     mloop                  ;then end; start over again
 move.l  a4,a1                  ;place new start add. in a1
 move.l  a5,a0                  ;restore a0
 bra     encore                 ;else search new occurence within range
rdmem:                          ;read memory
 move.l  con2handle,d7          ;switch screen
 move.l  #memmenu,d2
 bsr     pmsg
rdmem2
 bsr      fromto                ;get from and to addresses
 cmp.b    #15,flag              ;return pressed?
 beq      final
 bsr      memoire               ;read memory
 bra.s    rdmem2
final:                          ;exit MemoScope
 move.l  conhandle,d7           ;go to main menu
 move.l  #memmenu,d2
 bsr     pmsg
 bra     mloop                  ;go back other scren

Wb:                             ;link prg with Workbench
 movea.l ExBase,a6
 suba.l  a1,a1
 jsr     FindTask(a6) 
 move.l  d0,task
 movea.l d0,a4
 tst.l   $ac(a4)               ;called from Workbench?
 bne     init                  ;no, from CLI
 lea     $5c(a4),a0            ;get message
 jsr     WaitPort(a6)
 lea     $5c(a4),a0
 jsr     GetMsg(a6)
 move.l  d0,wbmsg
init:                         ;System initialization
 move.l  ExBase,a6            ;Pointer to  EXEC library
 lea     dosname(pc),a1
 moveq   #0,d0
 jsr     OpenLib(a6)          ;Open DOS.Library
 move.l  d0,dosbase
 beq     error
 lea     con2name(pc),a1      ;Con2 Definition
 move.l  #mode_old,d0
 bsr     openfile             ;Console open
 beq     error
 move.l  d0,con2handle
 lea     consolname(pc),a1    ;Console Definition
 move.l  #mode_old,d0
 bsr     openfile             ;Console open
 beq     error
 move.l  d0,conhandle
 move.l  d0,d7                ;current handle in d7
 lea     inbuff,a1             
 move.l  a1,d6                ;#inbuff in d6
 lea     string,a5            ;#string in a5
 rts

menu:                         ;set the flag 
 move.l #menumess,d2
 bsr    pmsg
 move.l #80,d3
 bsr    getchr
 move.l d6,a1
 move.b (a1),d0
 cmp.b  #'a',d0
 beq    sort1
 cmp.b  #'w',d0
 beq    sort2
 cmp.b  #'l',d0
 beq    sort4
 cmp.b  #'s',d0
 beq    sort5
 cmp.b  #'q',d0
 beq    sort6
 cmp.b  #'m',d0
 beq    sort7
 bra.s  menu
sort1:
 move.b #10,flag               ;ASCII
 rts
sort2:
 move.b #2,flag                ;Hex Word
 rts
sort5:
 move.b #12,flag               ;Save
 rts
sort6:
 move.b #15,flag               ;Quit
 rts
sort7:
 move.b #7,flag                ;Read Memory
 rts
sort4:
 move.b #1,flag
 rts                           ;Hex Long Word

openfile:                      ;Open File
 move.l a1,d1                  ;Pointer to I/O-Definition
 move.l d0,d2
 move.l dosbase,a6
 jsr    Open(a6)
 tst.l  d0
 rts
openfileD:                     ;open disk file
 move.l  #mode_new,d2
 movea.l d6,a1
 move.l  a1,d1
 move.l  dosbase,a6 
 jsr     Open(a6)
 move.l  d0,filehd
 rts
closefileD:                    ;close disk file
 move.l  dosbase,a6
 move.l  filehd,d1
 jsr     Close(a6)
 rts

fromto:                        ;get from and to addresses
 move.l  #mess2,d2
 bsr     inpt                  ;read start address
 cmp.b   #15,flag              ;is it single CR?
 beq     retour                ;then exit 
 bsr     conv                  ;convert to hex
 move.l  d3,d4                 ;save it in d4
 move.l  #mess3,d2
 bsr     inpt                  ;read end address
 cmp.b   #15,flag              ;is it single CR?
 beq     retour                ;then exit 
 bsr     conv                  ;convert to hex
 sub.l   d4,d3                 ;compute length in d3
 move.l  d3,d5                 ;copy length in d5
retour:
 rts
 
pmsg:                          ;print message to screen
 movem.l d0-d7/a0-a6,-(sp)     ;save registers to stack
 move.l  d2,a0 
 clr.l   d3
boucle:
 tst.b   (a0)+
 beq     psuite
 addq.l  #1,d3
 bra     boucle                ;compute length in d3
psuite:
 move.l  d7,d1
 move.l  dosbase,a6
 jsr     Write(a6)
 movem.l (sp)+,d0-d7/a0-a6     ;reload registers from stack
 rts

inpt:                          ;output message & input string
 bsr      pmsg
 move.l   #80,d3
 bsr      getchr               ;get string
 move.l   d6,a1                
 move.b   (a1),d0
 cmp.b    #10,d0               ;is it single CR?
 beq      putflag              ;then flag it
place0:
 add.l    d5,a1
 clr.l    d5
 move.b   #0,-(a1)             ;place '00' over '0a'
 rts
putflag:                       ;put #15 in flag 
 move.b   #15,flag
 bra.s    place0

getchr:                        ;get string for keyboard
 move.l  d7,d1                 ;curent screen handle in d1
 move.l  d6,d2                 ;put #inbuff in d2
 move.l  dosbase,a6
 jsr     Read(a6)
 move.l  d0,d5                 ;string length in d5
 rts

hunt:                          ;search string in memory
 clr.l  d2
 cmpm.b (a0)+,(a1)+            ;compare byte to byte
 beq    ste1
 move.l a5,a0                  ;restore  string address
 sub.l  #1,d5                  ;decrement length
 tst.l  d5                     ;is it zero?
 bne    hunt                   ;no: then go back
 move.l #mess4,d2              ;yes: print message & exit
 bra.s  rien 
ste1:
 sub.l  #1,d5                  ;decrement length
 tst.b  (a0)                   ;end of string?
 beq    exit
 add.l  #1,d2                  ;increment string counter
 cmpm.b (a0)+,(a1)+            ;check next byte
 beq    ste1
 sub.l  #1,d5                  ;decrement length
 move.l a5,a0                  ;restore string address
 bra.s  hunt
exit:
 add.l  #1,d2
 move.l a1,a3        
 move.l a1,a4                  ;copy found address in a4
 sub.l  d2,a3                  ;beginning of found address in a3
 bsr     conv2                 ;place converted address in inbuff
 move.l  d6,d2                 ;#inbuff in d2
rien:
 bsr     pmsg                  ;print address or Not found
 rts

bsave:                         ;save memory in a file
 move.l  #messF,d2
 bsr     inpt                  ;read filename
 bsr     openfileD             ;open disk file
 beq     error
 bsr     fromto                ;get from and to addresses
 move.l  d4,d2                 ;put start add in d2
 move.l  filehd,d1
 move.l  dosbase,a6
 jsr     Write(a6)
 bsr     closefileD            ;close file
 bra     mloop

memoire:                       ;read memory
 moveq   #0,d5
 move.l  d3,long               ;save length
 moveq   #4,d3
 swap    d4                    ;align start address (d4) 
 move.l  d4,stad
 clr.w   d4
 swap    d4
 divu    d3,d4
 swap    d4
 clr.w   d4
 swap    d4
 mulu    d3,d4
 move.w  d4,stad               ;save start address 
 move.l  stad,d4
 swap    d4
mem1:
 move.l  d4,a3                 ;start address in a3
 bsr     conv2                 ;convert in ASCII
 move.l  d6,d2 
 bsr     pmsg                  ;print start address
 move.l  #points,d2         
 bsr     pmsg                  ;print spacer
 move.l  d4,a4                 ;copy st. add. in a4
 move.l  #15,d5
 lea     string,a5
cop2:                          ;copy 4 long words in 2nd buffer
 move.l  (a4)+,(a5)+
 dbra    d5,cop2
 lea     string,a5 
 move    #3,d5                 ;3 in counter (d5)
quatre:
 move.l  (a5)+,a3              ;load a3
 bsr     conv2                 ;convert in ASCII
 move.l  d6,d2
 bsr     pmsg
 dbra    d5,quatre             ;print 4 long words
 move.l  #points,d2
 bsr     pmsg                  ;print spacer
 lea     string,a5             ;restore a5             
 move    #15,d5                ;restore 15 in counter (d5)
 move.l  #1,d3                 ;1 in d3
 lea     string,a5             ;restore a5
seize:
 bsr    ctrl                   ;check for unprintable char.
 bsr    pchar                  ;print one char.
 dbra   d5,seize               ;print 16 char.
 move.l #cr,d2              
 bsr    pmsg                   ;print a CR 
 move.l long,d3 
 sub.l  #16,d3                 ;update lenght
 move.l d3,long
 cmp.b  #$39,skey              ;CTRL pressed?
 beq    finboucle
 add.l  #16,d4                 ;update address to read
 cmp.w  #$f000,d3              ;lenght = 0?
 bcs    mem1                   ;next 16 bytes
finboucle:
 rts
ctrl:                       
 cmp.b  #32,(a5)               ;change control characters (<32)
 bcs    efface
 cmp.b  #126,(a5)            
 bcc    eff2
cont:
 move.l a5,d2
 add.l  #1,a5                  ;update counter
 rts
efface:
 move.b #'.',(a5)
 bra.s  cont
eff2:                          ;change invisible char. (127-159)
 cmp.b #161,(a5)
 bcc   out
 move.b #'.',(a5)
out:
 bra.s  cont
pchar:                         ;print message to screen
 movem.l d0-d7/a0-a6,-(sp)
 move.l  d2,a0
 move.l  d7,d1
 jsr     Write(a6)
 movem.l (sp)+,d0-d7/a0-a6
 rts 

conv:                          ;convert ASCII to hex
 clr.l     d3                  ;input = d3
 move.l    d6,a0               ;inbuff
 jsr       hexinloop
 rts
hexinloop:
 bsr       nibblein
 cmp       $10,d0
 bcc       hexinok             ; Test if good
 lsl.l     #4,d3               ; Shift result
 or.b      d0,d3               ; Insert nibble
 bra       hexinloop           ; And continue
hexinok:
 rts
nibblein:                      ; Convert the nibble from (A0)
 clr.l     d0                  ; Erase D0
 move.b    (a0)+,d0            ; Get digit, increment A0
 sub       #'a',d0             ; Subtract $61
 bcc       ischar              ; No problem, in the range a-f
 add       #39,d0              ; Else correct value
ischar:
 add       #10,d0              ; Correct value
 rts 

conv2:                         ;convert hex to ASCII
 move.l   d6,a0                ;#inbuff in a0
 clr.l    d3
 clr.l    d2
 move     #7,d3                ; Counter in d3
 move.l   a3,d1                ; address to convert in d1
lp:
 rol.l    #4,d1                ; Move upper nibble into lower
 move     d1,d2                ; Write in d2
 bsr      nibble               ; And convert it
 move.b   d2,(a0)+             ; Character in buffer
 dbra     d3,lp                ; Repeat 8 times
 move.w   #$2000,(a0)          ; Put space + 0 at the end of the string
 rts
nibble:
 and      #$0F,d2              ; Just keep low byte
 add      #$30,d2              ; Add $30
 cmp      #$3A,d2              ; Was it a digit?
 bcs      ok                   ; Yes, done
 add      #39,d2               ; Else add 39
ok:
 rts                           ; Bye-bye

error: 
 move.l  dosbase,a6
 jsr     IoErr(a6)
 move.l  d0,d6

quit:
 move.l  con2handle,d1         ;window close
 move.l  dosbase,a6 
 jsr     Close(a6)
 move.l  conhandle,d1          ;window close
 move.l  dosbase,a6
 jsr     Close(a6)
 move.l  dosbase,a1            ;DOS.Lib close
 move.l  ExBase,a6
 jsr     CloseLib(a6)
 tst.l  wbmsg                  ;close Workbench if opened
 beq.s  fin
 jsr    Forbid(a6)
 move.l wbmsg,a1
 jsr    ReplyMsg(a6)
fin:
 moveq  #0,d0
 move.l SPinit,a7
 rts 

SPinit:     dc.l 0
task:       dc.l 0
wbmsg:      dc.l 0
long:       dc.l 0
inbuff:     ds.l 20
 even
string:     ds.l 20
 even
dosname:    dc.b "dos.library",0,0
 even
dosbase:    dc.l 0
con2name: dc.b "CON:0/0/600/100/** MemoScope - Enter [CTRL] to stop, [RETURN] to exit **",0
 even
consolname: dc.b "CON:0/100/600/100/** Search & Rescue **",0
 even
conhandle:  dc.l 0
con2handle: dc.l 0
filehd:     dc.l 0
flag:       dc.l 0
stad:       dc.l 0
memmenu:    dc.w $1b63
            dc.b '[33mClick this screen on.[31m',10,0
 even
menumess:   dc.b ' ',10
            dc.b '** Search & Rescue v1.0 [33m * THE UNCRASHER * [31m  M. Laliberté, oct. 88 **',10
            dc.b '    * [A]SCII * [W]ord * [L]ong Word * [S]ave * [M]emory * [Q]uit *',10
            dc.b '-',0
 even
messA:      dc.b "Enter ASCII string, max. 40 characters (case sensitive)",10
            dc.b '-',0
 even
messH       dc.b 'Enter HEX     :-------- 4 or 8 digits, a-f lower case only.',10
            dc.b '             -$',0
 even
mess2:      dc.b 'From address:-$',0
 even
mess3:      dc.b 'To address  :-$',0
 even
messW:      dc.b 'Wait...  ',0
 even
mess4:      dc.b 'End Hunt',10,0
 even
messF:      dc.b 'Filename (full path): -',0
 even
points:     dc.b ': ',0
 even
cr:         dc.b ' ',10,0
 even

 end

