cr  equ 13
lf  equ 10
bptr  equ byte ptr
ofs  equ offset

jmps            macro   loc
                jmp     short loc
                endm

code  segment
  assume cs:code

  org 100h
begin:  jmp start

numblocks dw ?  ; store number of 16k blocks for search
searchstr dw ?  ; store address of search string
strlen  dw ?  ; store length of search string

h2a  proc near  ; clever code that converts 0 - f in al
  add al,90h  ;   into ASCII 0 - 9, A - F in al
  daa
  adc al,40h
  daa
  ret
h2a  endp

write_al proc near  ; write hex contents of al to screen
  push ax  ; save registers used
  push cx
  push dx
  push ax  ; save lower nybble
  mov cl,4  ; shift 4 bits
  shr al,cl  ; move high nybble to low nybble
  call h2a  ; convert to ASCII
  mov dl,al  ; send character to output device
  mov ah,2  ;   with DOS function 2
  int 21h
  pop ax  ; get lower nybble
  and al,0fh  ; isolate nybble
  call h2a  ; convert to ASCII
  mov dl,al  ; send character to output device
  mov ah,2  ;   with DOS function 2
  int 21h
  pop dx  ; restore registers
  pop cx
  pop ax
  ret
write_al endp

write_ax proc near  ; write hex contents of ax to screen
  push ax  ; save register
  mov al,ah  ; write high byte first
  call write_al ; ASCII value of high byte to std out
  pop ax  ; recover
  call write_al ; ASCII value of low byte to std out
  ret
write_ax endp

syntax  db cr,lf,'   LOOK version 1.0',cr,lf,cr,lf
  db '   The correct syntax for LOOK is "LOOK something",'
  db ' where "something" is a',cr,lf,'   string (any string'
  db ' at all) to be searched for in DOS memory.  DOS keeps'
  db cr,lf,'   a record of the command line in several '
  db 'places so LOOK will list several',cr,lf,'   addresses'
  db ' at least; more if matches are found in other memory '
  db 'locations.',cr,lf,'$'

start:  mov si,80h  ; get command line character count
  cmp bptr[si],0 ; anything on command line
  jnz do_look  ; yes, look for item
do_syntax: mov dx,ofs syntax ; point to syntax message
  mov ah,9  ; send it to console
  int 21h
  jmp exit  ; done, leave

do_look: int 12h  ; get system memory
  mov cl,4  ; compute number of 16k blocks
  shr ax,cl
  mov numblocks,ax ; store as number of blocks for search
  mov si,81h  ; address command line
next_char: lodsb   ; get character from command line
  cmp al,' '  ; a space?
  je next_char ; yes, ignore
  cmp al,9  ; a tab char?
  je next_char ; again ignore
  dec si  ; point again to first string char
  mov searchstr,si ; store point of string origin
  mov di,si  ; search for cr at end of command line
  mov al,cr
  mov cx,128
  repne scasb
  sub di,si  ; compute search string length
  dec di  ; (not to include cr)
  jz do_syntax
  mov strlen,di
  mov dl,cr  ; print crlf
  mov ah,2
  int 21h
  mov dl,lf
  int 21h
  xor ax,ax  ; zero
  mov es,ax  ;   to es
  xor di,di  ; start search at 0:0
  mov bx,strlen ; length of search string to bx
  mov dx,searchstr ; search string address to dx

lookagain: cmp di,16384 ; search offset at or beyond 16k?
  jae bumpseg  ; yes, move to next search segment
  mov si,dx  ; load address of search string
  mov cx,bx  ;   and its length
  repe cmpsb  ; is it a match?
  jne lookagain ; no, not found; try again

  mov dl,' '  ; print two spaces
  mov ah,2
  int 21h
  int 21h
  sub di,bx  ; yes, point again to matched string
  mov bx,di  ; compute normalized segment of match:
  mov cl,4  ;   divide offset by 16
  shr bx,cl  ;   to get paragraphs in bx
  mov ax,es
  add ax,bx
  call write_ax ; print normalized segment
  mov dl,':'  ; print colon
  mov ah,2
  int 21h
  mov ax,di  ; compute normalized offset of match:
  shl bx,cl  ;   multiply paragraphs by 16
  sub ax,bx  ;   so get offset within paragraph
  call write_ax ; print normalized offset
  mov dl,cr  ; print crlf
  mov ah,2
  int 21h
  mov dl,lf
  int 21h
  mov bx,strlen ; reload length of search string
  mov dx,searchstr ; reload search string address
  add di,bx  ; restore di value
  jmps lookagain ; continue search

exit:  mov ax,4c00h ; exit with error level of 0
  int 21h

bumpseg: sub di,16384 ; reduce offset by 16k for next segment
  mov ax,es  ; last used search segment
  add ax,400h  ; compute next used search segment
  dec numblocks ; looked far enough yet?
  jz exit  ; yes, done
  mov es,ax  ; no, try next segment
  jmps lookagain ; continue looking

code  ends
  end begin

