;
;  TSR Information Shell 1.0.
;  Lorne Kirkland Chartier (1995) - public domain.
;  Turbo Assembler 3.0.
;

; Various definitions
cr      equ     0dh                             ; carriage return
lf      equ     0ah                             ; linefeed
tab     equ     09h                             ; ascii tab
blank   equ     20h                             ; ascii space
quote   equ     22h                             ; ascii quotation
pint    equ     09h                             ; patch interrupt

                .286

cseg            segment 'code'
                assume  cs:cseg,ds:cseg,es:cseg

                org     2ch
envaddr         dw      ?                       ; Environment address

                org     80h                     ; psp cmd line [th]
pspcmdline      dw      ?

                org     100h                    ; program entry point

; *********************************************************
;               Main Routine
; *********************************************************

start:
                mov sp,offset t_stack           ; set up local stack

                call modmem                     ; reduce memory usage
                call setvects                   ; setup tsr vector

                mov dx,offset filenam
                mov cx,offset comline
                call execit                     ; executre the program

                call resvects                   ; restore interrupt vectors

                mov ax,3
                int 10h                         ; force text mode

                mov dx,offset ttitle            ; all done
criterr:
                mov ah,09h
                int 21h

                cmp updated,0                   ; information captured?
                je fini                         ; no, skip
                call dumpinfo

fini:
                mov ah,4ch                      ; terminate process
                int 21h

; ---------------------------------------------
;   modify memory allocation
; ---------------------------------------------
modmem          proc near
                mov bx,offset lastloc           ; bx = program size in
                mov cl,4                        ; paragraphs
                shr bx,cl
                inc bx
                mov ah,4ah                      ; th  deallocate unused memory
                int 21h
                jnc modmem1                     ; if ok, continue

                ; otherwise, we have a fatal error
                mov dx,offset badaloc           ; else load error message
                jmp criterr                     ; jump to critical error

modmem1:        ret
modmem          endp

; ---------------------------------------------
;   execute a program
;   pass:       ds:dx - asciiz filename
;               ds:cx - command tail
;   *** you must!! Have own stack established.
;   returns:    carry flag set on failure
; ---------------------------------------------
execit          proc near

                mov     ax,envaddr              ; th get environment addr
                mov     parmblk,ax              ; stuff in parameter block

                mov     parmblk+2,cx            ; command tail offset

                mov     ax,cs                   ; set segment registers
                mov     parmblk+4,ax            ;  in parameter block
                mov     parmblk+8,ax            ; to our code seg
                mov     parmblk+12,ax

                mov     bx,offset parmblk       ; es:bx = control block
                mov     ax,4b00h                ; service 0, exec

                push    ds                      ; save machine state
                push    es
                mov     savess,ss               ; th
                mov     savesp,sp               ; th
                int     21h                     ; shell to dos

                mov     sp,cs:savesp            ; restore machine state
                mov     ss,cs:savess
                pop     es
                pop     ds

execit1:        ret
execit          endp

; -------------------------------------------
;   Set interrupt vectors
; -------------------------------------------
setvects        proc near
                push es
                mov al,pint                     ; interrupt to patch
                mov ah,35h                      ; get interrupt address
                int 21h
                mov word ptr oldvct,bx          ; save it
                mov word ptr oldvct[2],es

                mov al,pint                     ; interrupt to patch
                mov ah,25h
                mov dx,offset new_int
                int 21h                         ; install our handler
                pop es
                ret
setvects        endp

; -------------------------------------------
;   restore interrupt vectors
; -------------------------------------------
resvects        proc near
                push ds
                mov dx,word ptr oldvct          ; get old interrupt address
                mov ax,word ptr oldvct[2]
                mov ds,ax
                mov al,pint                     ; interrupt to patch
                mov ah,25h
                int 21h                         ; restore old interrupt
                pop ds
                ret
resvects        endp

; -------------------------------------------
;   replacement interrupt handler
; -------------------------------------------
new_int         proc far
                sti                             ; enable interrupts
                push ax                         ; save register

                in al,60h                       ; get scan code
                cmp al,cs:laskey                ; is same as last one? If so,
                je new_intd                     ; assume still down and quit
                mov cs:laskey,al                ; otherwise store value

new_int1:       cmp al,58h                      ; is f12?
                jne new_intd                    ; if not, skip

                ; get current information
                push es
                push bx
                push ax

                mov ax,0
                mov es,ax                       ; address bios segment

                mov cs:[updated],1              ; set information captured

                mov ah,0fh                      ; get video info
                int 10h
                mov ah,0
                mov cs:[vmode],ax

                mov bx,044ah                    ; save screen cols
                mov ax,word ptr es:[bx]
                mov cs:[vcols],ax

                mov bx,0484h
                mov ah,0
                mov al,byte ptr es:[bx]
                inc ax
                mov cs:[vrows],ax               ; save screen rows

                pop ax
                pop bx
                pop es

new_intd:       pop ax                          ; restore register
                jmp cs:dword ptr oldvct
new_int         endp

dumpinfo        proc near

                mov ah,09h
                mov dx,offset mvmode
                int 21h
                mov ax,vmode
                mov si,offset ttitle
                mov cx,10
                call itoa
                mov ah,09h
                mov dx,si
                int 21h
                mov dx,offset crlf
                int 21h

                mov ah,09h
                mov dx,offset mvcols
                int 21h
                mov ax,vcols
                mov si,offset ttitle
                mov cx,10
                call itoa
                mov ah,09h
                mov dx,si
                int 21h
                mov dx,offset crlf
                int 21h

                mov ah,09h
                mov dx,offset mvrows
                int 21h
                mov ax,vrows
                mov si,offset ttitle
                mov cx,10
                call itoa
                mov ah,09h
                mov dx,si
                int 21h
                mov dx,offset crlf
                int 21h

                ret
dumpinfo        endp

; -------------------------------------------
; ITOA.ASM --- Convert 16-bit integer to ASCII string
;
; Copyright (C) 1989 Ray Duncan
;
; Call with:    AX    = 16-bit integer
;               DS:SI = buffer to receive string,
;                       must be at least 6 bytes long
;               CX    = radix
;
; Returns:      DS:SI = address of converted string
;               AX    = length of string
;
; Destroy:      Nothing
; -------------------------------------------
itoa            proc    near

                add     si,6                    ; advance to end of buffer
                mov     byte ptr [si],'$'
                push    si                      ; and save that address.
                or      ax,ax                   ; test sign of 16-bit value,
                pushf                           ; and save sign on stack.
                jns     itoa1                   ; jump if value was positive.
                neg     ax                      ; find absolute value.

itoa1:          cwd                             ; divide value by radix to extract
                div     cx                      ; next digit for forming string
                add     dl,'0'                  ; convert remainder to ASCII digit
                cmp     dl,'9'                  ; in case converting to hex ASCII,
                jle     itoa2                   ; jump if in range 0-9,
                add     dl,'A'-'9'-1            ; correct digit if in range A-F

itoa2:          dec     si                      ; back up through buffer
                mov     [si],dl                 ; store this character into string
                or      ax,ax
                jnz     itoa1                   ; no, convert another digit

                popf                            ; was original value negative?
                jns     itoa3                   ; no, jump
                dec     si                      ; yes, store sign into output
                mov     byte ptr [si],'-'

itoa3:          pop     ax                      ; calculate length of string
                sub     ax,si
                ret                             ; back to caller

itoa            endp


; *********************************************************
;               Data
; *********************************************************

savess          dw      0                       ; Holders for ss:sp
savesp          dw      0

oldvct          dd      ?                       ; old interrupt handler
laskey          db      0                       ; last key scan code

; information holders
updated         dw      0                       ; information captured?
vmode           dw      0
vcols           dw      0
vrows           dw      0

; various messages
ttitle          db cr,lf,'TSRINFO 1.0 - Information TSR.',cr,lf
                db 'Lorne Kirkland Chartier (1995) - public domain.',cr,lf
                db '<F12> To get status at time of hotkey press.',cr,lf,'$'
badaloc         db 13,10,'error: bad memory allocation',13,10,'$'
badexec         db 13,10,'error: bad program execution',13,10,'$'
mvmode          db 13,10,'video mode is:  $'
mvcols          db 'columns:        $'
mvrows          db 'rows:           $'
crlf            db 13,10,'$'

filenam         db 'starprt2.exe',0             ; file to run

        even                                    ; th for faster access?

; parameter block for executing a child process
parmblk dw      00                      ; environment block - 00 = use parent's
        dw      00,00                   ; command tail
        dw      5ch,00                  ; fcb1
        dw      6ch,00                  ; fcb2

comline db      0
        db      cr

        db      128  dup (?)                    ; stack
t_stack label   byte

; ---------------------------------------------------------
;  *** warning!!! - Discardable marker ***
;  every thing past this point will be discarded
;  when the modmem() function is called.
; ---------------------------------------------------------
lastloc label   byte                            ; end of program

cseg            ends
                end     start

