home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1993 May / SIMTEL_0593.ISO / msdos / sysutl / u.asm < prev    next >
Assembly Source File  |  1989-01-03  |  18KB  |  402 lines

  1. Date: Sunday, 1 January 1989  11:43-MST
  2. From: <MULTI%TRIUMFCL.BITNET@CORNELLC.CIT.CORNELL.EDU>
  3. Re:   TSR program that "unhooks" itself, see Issues 49,57 of 1988 digest
  4.  
  5. Title   U
  6. Page    80,132
  7. BUFLEN  =64                             ; Length of command save
  8. ;DBG    =1                              ; Define for printout
  9. GUARD   =0                              ; Length of guard band
  10. INTDOS  =21h*4                          ; Address of DOS vector
  11. PSPOFF  =5Ch                            ; PSP above here overlaid
  12. RELOC   =100h-PSPOFF                    ; Distance code shuffled
  13. ;
  14.  .SFCOND                                ; Suppress false conditionals
  15. ;
  16. Code    Segment
  17.         ORG     100h
  18. Assume  cs:code,ds:code
  19. start   label   byte
  20. count:  jmp     u                       ; Command being recalled
  21. punt:   db      0EAh                    ; Far jump to DOS
  22. chain   dw      2 dup(?)                ;  ...int 21h entry
  23. ;
  24. begin:  cmp     ah,0Ah                  ; Buffered keyboard input request?
  25.         jne     punt                    ;  ...no, pass to DOS
  26.         push    ax
  27.         push    bx
  28.         push    cx
  29.         push    dx
  30.         push    si
  31.         push    di
  32.         push    es
  33.         push    ds
  34.         pop     es
  35.         mov     di,dx                   ; DS:DI --> user's buffer
  36.         inc     di                      ; Skip maximum  byte count
  37.         inc     di                      ; Skip returned byte count
  38.         mov     bx,dx                   ; Load into index register
  39.         cld                             ; Strings advance forwards
  40. retry:  mov     byte ptr [bx]+1,0       ; Zero returned byte count
  41. ;
  42. loop:   call    in                      ; Read char into AL reg
  43. loop1:  cmp     al,0Dh                  ; Entry process char in AL reg
  44.         je      done
  45.         or      al,al                   ; Function key?
  46.         je      f_key                   ;  ...begins with null
  47.         cmp     al,"H"-64               ; Backspace
  48.         je      erase
  49.         cmp     al,"U"-64               ; ^U
  50.         je      erall
  51.         cmp     al,27                   ; Escape
  52.         je      erall
  53.         mov     dx,[bx]                 ; Get both byte counts
  54.         cmp     dh,dl                   ;  ...full if equal
  55.         je      bell                    ;  ...ignore,bell if so
  56.         stosb                           ; Save character
  57.         call    echo                    ;  ...echo it
  58.         cmp     byte ptr [di]-1,"C"-64  ; ^C character
  59.         je      break                   ;  ...causes interrupt
  60.         inc     byte ptr [bx]+1         ; End of checking, accept char.
  61.         jmp     loop                    ;  ...back for more
  62. ;
  63. f_key:  call    in                      ; AL contains 2nd char
  64.         or      al,al                   ; Zero is break
  65.         je      break
  66.         cmp     al,61                   ; F3 = Function Recall
  67.         je      recal
  68.         cmp     al,72                   ; Cursor up,, same thing
  69.         je      recal
  70.         cmp     al,65                   ; F7 = Function Recall Backwards
  71.         je      rbc
  72.         cmp     al,80                   ; Cursor Down, same thing
  73.         je      rbc
  74.         cmp     al,64                   ; F6 = Control-Z
  75.         je      ctrl_z
  76.         jmp     loop                    ; Ignore the remainder
  77. ;
  78. ctrl_z: mov     al,"Z"-64               ; F6 is Control-Z
  79.         jmp     loop1                   ;  ...pretend from keyboard
  80. ;
  81. recal:  jmp     recall
  82. rbc:    jmp     rbck
  83. ;
  84. break:  int     23h                     ; Control_Break
  85.         call    crlf                    ;  ...as per documentation
  86.         jnc     retry                   ;  ...carry clear, retry
  87.         mov     ax,4C00h                ; Else do a kosher terminate
  88.         int     21h                     ;  ...do not know his PSP
  89. ;
  90. done:   stosb                           ; Success, save 0Dh terminator
  91.         call    store                   ; Store the command
  92.         pop     es                      ; Done, restore reg. and exit
  93.         pop     di
  94.         pop     si
  95.         pop     dx
  96.         pop     cx
  97.         pop     bx
  98.         pop     ax
  99.         iret
  100. ;
  101. erase:  call    delete
  102.         jmp     loop
  103. ;
  104. erall:  call    delete
  105.         cmp     Byte ptr [bx]+1,0
  106.         jne     erall
  107.         jmp     loop
  108. ;
  109. bell:   mov     al,7
  110.         call    out
  111.         jmp     loop
  112. ;
  113. recall: call    delete                  ; Attempt to delete char.
  114.         cmp     Byte ptr [bx+1],0       ;  ...any left to delete
  115.         jne     recall                  ;  ...yes, loop around
  116. ;
  117.         push    ds                      ; Save user's DS
  118.         push    bx                      ;  ...and BX reg
  119.         push    cs                      ; Make DS the same
  120.         pop     ds                      ;  ...as code seg
  121. ;
  122.         xor     bx,bx                   ; Go to start of buffer
  123.         mov     dx,word ptr count-RELOC ; DX is count of comands
  124.         inc     word ptr count-RELOC    ; One more in stack
  125. ;
  126. rec0:   dec     dx                      ; This command
  127.         je      extrct                  ;  ...yes
  128. ;
  129.         mov     cl,[save-RELOC+bx]      ; Get saved byte count
  130.         mov     ch,0                    ;  ...make word
  131.         jcxz    rec90                   ; End of commands
  132.         inc     cx                      ;  ...skip past char count
  133.         add     bx,cx                   ;  ...and string
  134.         cmp     bx,BUFLEN               ; Buffer overflowed
  135.         jae     rec90
  136.         jmp     rec0                    ;  ...and continue
  137.  
  138. rec90:  xor     bx,bx                   ; Back to start of buffer
  139.         mov     word ptr count-RELOC,2  ; Say one command there
  140. extrct: mov     cl,[save-RELOC+bx]      ;  ...get char count
  141.         mov     ch,0                    ;  ...be safe
  142.         lea     si,[save+1-RELOC+bx]    ; ds:SI --> input buffer
  143.         inc     bx                      ; Add in character counter
  144.         add     bx,cx                   ; Length of line
  145.         cmp     bx,BUFLEN               ;  ...will it fit?
  146.         jae     rec90                   ;  ...no, so restart
  147.         pop     bx
  148.         cmp     cl,es:[bx]              ; Compare with new buffer
  149.         jbe     fit                     ;  ...will fit
  150.         mov     cl,es:[bx]              ;  ...copy what will fit
  151. fit:    mov     es:[bx]+1,cl            ; Get saved byte count
  152.         jcxz    nul                     ;  ...all done
  153.         lea     di,[bx]+2               ; ES:DI --> user  buffer
  154. ;
  155. l:      lodsb                           ; Load AL from input  buffer
  156.         stosb                           ; Dump AL into output buffer
  157.         call    echo                    ; Echo AL on   print  screen
  158.         loop    l                       ;  ...loop until CX=0
  159. ;
  160. nil:    pop     ds                      ; Restore user's DS
  161.         jmp     loop                    ;  ...back for more
  162. ;
  163. nul:    cmp     save-RELOC,0            ; Buffer really empty?
  164.         je      nil                     ;  ...yes, nothing to recall
  165.         push    bx                      ; Else save BX
  166.         jmp     rec90                   ;  ...EOB, go back to start
  167. ;
  168. rbck:   sub     word ptr cs:count-RELOC,2; Back two commands
  169.         jle     toofar
  170. bckr:   jmp     recall                  ;  ...and recall
  171. toofar: push    ds                      ; Must scan for the
  172.         push    bx                      ;  ...end of buffer
  173.         push    cs                      ; Make DS the same
  174.         pop     ds                      ;  ...as code seg.
  175.         xor     bx,bx                   ; Beginning of buffer
  176.         mov     word ptr count-RELOC,0  ; Start at command 0
  177. bck1:   mov     cl,[save-RELOC+bx]      ; Get saved byte count
  178.         mov     ch,0                    ;  ...be safe
  179.         jcxz    bck90                   ; Not very nice, null string
  180.         inc     cx                      ; Include char. count
  181.         add     bx,cx                   ; Now point at next string
  182.         cmp     bx,BUFLEN               ; Buffer overflowed
  183.         jae     bck90                   ; Not very nice
  184.         inc     word ptr count-RELOC    ; Another kosher stored command
  185.         jmp     bck1
  186. ;
  187. bck90:  cmp     word ptr count-RELOC,0  ; Too small?
  188.         ja      bck91                   ;  ...no
  189.         mov     word ptr count-RELOC,1  ; Must have one command
  190. bck91:  pop     bx                      ; Got our answer
  191.         pop     ds                      ;  ...restore
  192.         jmp     bckr                    ; Go to find command routine
  193. ;
  194. delete: cmp     Byte ptr [bx]+1,0       ; Anything to delete
  195.         je      delret                  ;  ...no, then nop
  196.         dec     di                      ; Back up pointer
  197.         mov     al,[di]                 ;  ...AL has char
  198.         dec     Byte ptr [bx]+1         ; One less in buffer
  199.         mov     cx,1                    ; Assume takes one print pos.
  200.         cmp     al," "                  ;  ...space and above OK
  201.         jae     norm                    ;  ...blank out one position
  202.         inc     cx                      ; Control char blank out two
  203. ;
  204. norm:   mov     al,"H"-64               ; Backspace over char.
  205.         call    out                     ;  ...print backspace
  206.         mov     al," "                  ; Destructive overprint
  207.         call    out                     ;  ...print space
  208.         mov     al,"H"-64               ; Backspace to one before
  209.         call    out                     ;  ...print backspace
  210.         loop    norm                    ; Destroy one or two char.
  211. delret: ret                             ;  ...all done
  212. ;
  213. in:     mov     ah,7                    ; Read/no echo
  214.         int     21h                     ; AL contains char
  215.         ret                             ;  ...back to user
  216. ;
  217. out:    push    dx                      ; Save register
  218.         mov     dl,al                   ; Get character to print
  219.         mov     ah,2                    ;  ...on print screen
  220.         int     21h                     ;  ...do DOS call supposed
  221.         pop     dx                      ;  ...restore reg.
  222.         ret                             ;  ...to check for break
  223. ;
  224. echo:   cmp     al,32                   ; Char in AL destroyed
  225.         jae     nocntl                  ;  ...is space or above
  226.         push    ax                      ; Else save a copy
  227.         mov     al,"^"                  ;  ...print ^ arrow
  228.         call    out                     ;  ...this way
  229.         pop     ax                      ; Restore char in AL
  230.         add     al,"A"-1                ;  ...map control to letter
  231. nocntl: call    out                     ; Print the character
  232.         ret                             ;  ...back to DOS
  233. ;
  234.  
  235. store:  mov     cl,[bx]+1               ; Char. count for new command
  236.         mov     ch,0                    ;  ...null hi order
  237.         jcxz    null                    ;  ...no command
  238.         inc     cx                      ;  ...include Count in string
  239.         cmp     cx,BUFLEN               ; String too long
  240.         ja      null                    ;  ...yes, don't save
  241.         push    cx                      ;  ...save a copy
  242.         neg     cx                      ;  ...negate length
  243.         lea     di,save+BUFLEN-RELOC-1  ; Source for shuffle
  244.         lea     si,save+BUFLEN-RELOC-1  ; Target for shuffle
  245.         add     si,cx                   ;  ...back up source
  246.         add     cx,BUFLEN               ;  ...size of buffer to shuffle
  247.         js      null                    ;  ...too big
  248.         push    ds                      ; Save old DS segment
  249.         push    cs
  250.         pop     ds                      ; DS = CS
  251.         push    cs
  252.         pop     es                      ; ES = CS
  253.         std                             ;  ...shuffle backwards
  254. ;
  255.         rep     movsb                   ;  ...push old commands
  256.         mov     word ptr count-RELOC,1  ;  ...reset buffer pointer
  257. ;
  258.         pop     ds                      ; Restore data segment
  259.         pop     cx                      ; Restore line length
  260.         lea     si,[bx]+1               ; Get address of counted line
  261.         lea     di,save-RELOC           ; ES:DI --> Save buffer
  262.         cld                             ;  ...save forwards
  263.         rep     movsb                   ;  ...save into local buffer
  264. Ifdef   DEB
  265.         call    debug                   ; *** DEBUG ***
  266. endif
  267. null:   ret                             ;  ...back to caller
  268. ;
  269. crlf:   push    ax
  270.         mov     al,13
  271.         call    out
  272.         mov     al,10
  273.         call    out
  274.         pop     ax
  275.         ret
  276. ;
  277. Ifdef   DEB
  278. number: push    ax
  279.         push    cx
  280.         mov     cx,4
  281. num:    rol     bp,1
  282.         rol     bp,1
  283.         rol     bp,1
  284.         rol     bp,1
  285.         mov     ax,bp
  286.         and     ax,0Fh
  287.         add     ax,"0"
  288.         cmp     ax,"9"
  289.         jbe     num1
  290.         add     ax,"A"-"9"-1
  291. num1:   call    out
  292.         loop    num
  293.         pop     cx
  294.         pop     ax
  295.         ret
  296. ;
  297. debug:  push    ax
  298.         push    bx
  299.         push    ds
  300.         push    cs
  301.         pop     ds
  302.         xor     bx,bx
  303. deb0:   test    bx,63
  304.         jne     deb1
  305.         call    crlf
  306.         mov     bp,cs
  307.         call    number
  308.         mov     al,":"
  309.         call    out
  310.         lea     bp,[save-RELOC+bx]
  311.         call    number
  312.         mov     al," "
  313.         call    out
  314. deb1:   mov     al,[save-RELOC+bx]
  315.         inc     bx
  316.         cmp     al," "
  317.         jae     deb2
  318.         mov     al,"."
  319. deb2:   call    out
  320.         cmp     bx,BUFLEN+GUARD         ; *** DEBUG ***
  321.         jb      deb0
  322.         pop     ds
  323.         pop     bx
  324.         pop     ax
  325.         ret
  326. Endif
  327. ;
  328. impure  label   byte                    ; End of area to check for install
  329. ;
  330. save    db      ?                       ; Token null for buffer
  331. ;
  332. quit    label   byte                    ; End of permanent region
  333. ;
  334. u:      xor     dx,dx                   ; Get vector segment
  335.         mov     es,dx                   ;  ...and load into ES
  336.         lds     si,dword ptr es:INTDOS  ; DS:SI --> DOS interrupt routine
  337.         mov     cx,offset impure-begin  ;  ...this is pure code to compare
  338.         push    cs                      ; Save code      segment
  339.         pop     es                      ; ES same as code seg.
  340.         lea     di,begin                ; ES:DI --> our interrupt service
  341.         rep     cmpsb                   ; Are they the same?
  342.         push    cs                      ; Set data segment same as
  343.         pop     ds                      ; the code segment
  344.         jz      remove                  ;  ...code compares, remove
  345. ;
  346.         lea     si,start                ; DS:SI --> Code segment
  347.         mov     di,PSPOFF               ; ES:DI --> Where relocates to
  348.         mov     cx,offset quit-start    ; CX = bytes to relocate
  349.         rep     movsb                   ;  ...shuffle section down
  350. ;
  351.         mov     ds,dx                   ; Reload vector segment
  352.         mov     si,INTDOS               ; DS:SI --> DOS  vector
  353.         lea     di,chain-RELOC          ; ES:DI --> JMPF address
  354.         movsw                           ; Move the offset
  355.         movsw                           ; Move the segment
  356.         push    cs                      ; Equivalence code and
  357.         pop     ds                      ;  ...data segments
  358.         mov     es,dx                   ; ES:DI --> DOS  vector
  359.         mov     di,INTDOS
  360.         lea     ax,begin-RELOC          ; AX is entry offset
  361.         stosw                           ;  ...store as DOS vector
  362.         mov     ax,cs                   ; CS is entry segment
  363.         stosw                           ;  ...store as DOS vector
  364. ;
  365.         mov     word ptr count-RELOC,1  ;  ...reset count
  366. ;
  367.         lea     dx,msg1                 ; Say editor installed
  368.         mov     ah,9h                   ;  ...print string
  369.         int     21h                     ;  ...like so
  370. ;
  371.         push    ds:2Ch                  ; Get environ. segment
  372.         pop     es                      ;  ...into ES register
  373.         mov     ah,49h                  ;  ...then free
  374.         int     21h                     ;  ...the memory
  375. ;
  376.         lea     dx,save+BUFLEN-RELOC    ; Last address to save
  377.         int     27h                     ;  ...terminate, stay resident
  378. ;
  379. remove: lea     dx,msg2                 ; Code already was installed
  380.         mov     ah,9h                   ;  ...print string
  381.         int     21h                     ;  ...is function
  382.         xor     dx,dx                   ; Point to vector area
  383.         mov     es,dx                   ;  ...to restore DOS
  384.         lds     si,dword ptr es:INTDOS  ; Get saved dos interrupt
  385.         mov     di,INTDOS+4             ; Where to restore old DOS entry
  386.         std                             ;  ...copy backwards
  387.         cmpsw                           ; Backspace SI and DI
  388.         movsw                           ;  ...restore segment
  389.         movsw                           ;  ...restore offset
  390.         mov     bx,ds                   ; Get PSP of stored program
  391.         dec     bx                      ; BX --> storage block
  392.         mov     ds,bx                   ; DS --> storage block
  393.         mov     word ptr ds:1,0         ; This deletes the PSP
  394.         ret                             ;  ...back to caller
  395. ;
  396. msg1:   db      "[Editor Installed]$"   ; Hooked to DOS, resident
  397. msg2:   db      "[Editor Removed]$"     ; Unhooked, gone from memory
  398. ;
  399. code    ends
  400. ;
  401. End     count
  402.