; MemBox 1.0  Copyright (c) 1992  Thomas G. Hanlin III

MEMSIZE   equ  4096    ; size of storage space, in bytes (must be below 32768)

RESLEN    equ  (Start - MemBox + 256 + 15) SHR 4


Sseg          segment        byte stack 'prog'   ; dummy stack segment
Sseg          ends


Cseg          segment        byte public 'prog'
              assume         cs:Cseg, ds:Cseg, es:Cseg, ss:Sseg


              org            100h

MemBox        proc
              jmp            Start          ;   skip code for resident routine
              db MEMSIZE-3 dup(?)           ; storage area
; NOTE that the "JMP Start" code is construed as part of the storage area.
MemBox        endp



INTRmux       proc                     ; multiplex interrupt ------------------
              sti                           ; allow interrupts to occur
              cmp            ah,0CFh        ; is it for us?
              je             IM_OurMux      ;   yep, go process it
IM_NormMux:   db 0EAh                       ; *** self-modifying code
  MUXOFS      dw ?                          ; *** JMP FAR PTR xxxx:yyyy
  MUXSEG      dw ?                          ; (original INT 2Fh vector)

IM_OurMux:    or             al,al          ; status request?
              jnz            IM_OurMux1     ;   no, skip
              dec            al             ; AL=0FFh to show we're here
              iret                          ;   go directly home
IM_OurMux1:   cmp            al,1           ; "remove self" request?
              jne            IM_NormMux     ;   no, exit
              mov            ax,0           ;
              push           ax             ;
              pop            es             ;
              cli                           ; interrupts off
              mov            ax,cs:MUXOFS   ;
              mov            es:[00BCh],ax  ; restore old INT 2Fh vector
              mov            ax,cs:MUXSEG   ;
              mov            es:[00BEh],ax  ; restore old INT 2Fh vector
              sti                           ; interrupts on
              push           cs             ;
              pop            es             ; return current segment in ES
              iret                          ;   return to sender
INTRmux       endp                     ; multiplex interrupt ------------------



Start         proc                     ; main program -------------------------
              cld                           ; set direction forward
              call           ParseCmdLine   ; parse the command line
              jc             _Done          ;   if invalid, take error exit

_Start1:      cmp            TSR_OFF,0      ; remove TSR?
              jz             _Start2        ;   no, skip it
              mov            ax,0CF00h      ; check for TSR...
              int            2Fh            ; ...on the multiplex interrupt
              inc            al             ; is it installed?
              jnz            _Start1A       ;   no, skip
              mov            ax,0CF01h      ; tell it to remove itself
              int            2Fh            ; (returns TSR segment in ES)
              mov            ah,49h         ; free up TSRs memory
              int            21h            ;
              jmp            _Done          ;
_NotInstMsg   db "MemBox is not resident",13,10,"$"
_Start1A:     mov            ah,9           ; display a string
              mov            dx,offset _NotInstMsg ; ptr to "Not installed"
              int            21h            ;
              mov            ERRCODE,1      ; set error code
              jmp            _Done          ;

_Start2:      mov            ax,0CF00h      ; check for TSR...
              int            2Fh            ; ...on the multiplex interrupt
              inc            al             ; is it installed?
              jz             _Start2A       ;   yep, skip out

              mov            es,ds:[002Ch]  ;
              mov            bx,1           ; one paragraph
              mov            ah,4Ah         ; shrink the environment
              int            21h            ;

              cld                           ; set direction forward
              mov            si,offset PROCNAME ; install name in mini-envirn
              xor            di,di          ;
              mov            cx,8           ; 16 bytes maximum
              rep            movsw          ;

              mov            ds:[0080h],MEMSIZE ; store memory size for later

              mov            ax,352Fh       ; get multiplex int vect (INT 2Fh)
              int            21h            ;
              mov            MUXOFS,bx      ; save old misc system services
              mov            MUXSEG,es      ;
              mov            ax,252Fh       ; install new multiplex int vector
              mov            dx,offset INTRmux ; ptr to our routine
              int            21h            ;

              mov            dx,RESLEN      ; size of TSR in paragraphs
              mov            ax,3100h       ; terminate and stay resident
              int            21h            ;

_Done:        mov            ah,4Ch         ; terminate program w/ error code
              mov            al,ERRCODE     ; get the error code
              int            21h            ;

_Start2A:     mov            dx,offset _AlrInstMsg ; ptr to "Already installed"
_Start2Z:     mov            ah,9           ; display a string
              int            21h            ;
              mov            ERRCODE,1      ; set error code
              jmp            _Done          ;   go exit

_AlrInstMsg   db "MemBox is already resident",13,10,"$"

Start         endp                     ; main program -------------------------



ParseCmdLine  proc           near      ; parse the command line for parms -----
              mov            si,0080h       ; ptr to length of command line
              mov            ax,si          ; zero AH
              lodsb                         ; length of command line
              cmp            al,1           ; is it null or nearly so?
              jbe            PCL_Help       ;   yep, go help 'em
              mov            cx,ax          ; length of command line

PCL_ScanParms:
              mov            di,si          ; update ptr to command line
              mov            al,"/"         ; switch character
              repne          scasb          ; see if we can find it
              mov            si,di          ;
              jne            PCL_Done       ;   no, go exit
              jcxz           PCL_Done       ;   exit if no parms left
              lodsb                         ; get option character
              dec            cx             ; account for it
              and            al,0DFh        ; convert it to uppercase
              cmp            al,"D"         ; D>einstall?
              je             PCL_Remove     ;   yep, take care of it
              cmp            al,"I"         ; I>nstall?
              jne            PCL_BadParm    ;   nope, error

PCL_Install:  mov            TSR_ON,1       ; set /Install flag
              jmp            PCL_ScanParms  ;   go try for another parm

PCL_Remove:   mov            TSR_OFF,1      ; set /Deinstall flag
              jmp            PCL_ScanParms  ;   go try for another parm

PCL_Done:     cmp            TSR_OFF,0      ; did we get an option?
              jne            PCL_GoodExit   ;   yep, it's good
              cmp            TSR_ON,0       ; did we get an option?
              jne            PCL_GoodExit   ;   yep, it's good

PCL_Help:     mov            si,offset INFO ; ptr to info about MemBox
PCL_ShowInfo: lodsb                         ; get a char
              or             al,al          ; end of text?
              jz             PCL_BadExit    ;   yep, go exit
              cmp            al,0FFh        ; unprintable char?
              jne            PCL_SI1        ;   no, go display it
              mov            al," "         ; convert to space
PCL_SI1:      mov            dl,al          ; get char ready to display
              mov            ah,2           ; display a character
              int            21h            ;
              jmp            PCL_ShowInfo   ;   go for all chars

PCL_BadParm:  mov            ah,9           ; display a string
              mov            dx,offset PCL_BadParmMsg ; ptr to "Invalid parm"
              int            21h            ;
              mov            ERRCODE,2      ; set error code
              jmp            PCL_BadExit    ;   go exit
PCL_BadParmMsg   db "Error: invalid parameter",13,10,"$"

PCL_BadExit:  stc                           ; set error flag
              ret                           ;   return to sender

PCL_GoodExit: clc                           ; clear error flag
              ret                           ;   return to sender

ParseCmdLine  endp                     ; parse the command line for parms -----



; -------------------------- transient data area ------------------------------



INFO  db "MemBox 1.0  Copyright (c) 1992  Thomas G. Hanlin III",13,10
      db 13,10
      db "This TSR provides a fixed block of RAM for use as a data transfer area.",13,10
      db 13,10
      db "Syntax:",13,10
      db "  MEMBOX       display info on MemBox",13,10
      db "  MEMBOX /I    install MemBox",13,10
      db "  MEMBOX /D    deinstall MemBox",13,10
      db 0



; These are flags set by ParseCmdLine according to the switches it finds.

TSR_OFF    db 0      ; whether to remove TSR from memory    /D
TSR_ON     db 0      ; whether to install TSR               /I



; The original environment will be discarded by the MemBox TSR, since it won't
; be needed and takes up space.  We'll install the following as the new name
; in a tiny environment, though, for the benefit of MAP utilities.

PROCNAME  db 0,0,1,0,"MEMBOX.COM",0,0



ERRCODE   db 0    ; number to return as ErrorLevel when program exits

Cseg          ends
              end            MemBox
