home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS - Coast to Coast
/
simteldosarchivecoasttocoast.iso
/
pcmag
/
vol11n01.zip
/
TRACKR.ZIP
/
TRACKR.ASM
next >
Wrap
Assembly Source File
|
1991-11-18
|
81KB
|
2,555 lines
;============================================================================
; TRACKR.COM keeps logs of time spent on individual tasks
;
; Revision History:
;
; Version 1.0 Initial Release
;
;============================================================================
Code segment byte public 'code'
assume cs:code
assume ds:code
org 100h
LGo: jmp Init
Drive db 79 dup (0) ;full pathname of .LOG files
NameOff dw offset Drive ;offset where filename goes onto path
TaskOff dw 0 ;offset of current task in TaskList
SrchName db '*'
Extension db '.LOG',0
ScanCode db 13h ;Hot key scan code (R)
ShiftState db 4 ;hot key shift state (Ctrl)
Space db ' '
HAt db 1Fh ;hi-lite screen attribute
NAt db 31h ;normal screen attribute
Vec09 dd 0 ;original BIOS interupt address
Vec13 dd 0
Vec08 dd 0
Vec28 dd 0
OrgCursor dw 0 ;cursor location when popped up
VidPage db 0 ;video page during pop-up
Up? db 0 ;1 if Tracker is popped up
MsgUp? db 0 ;1 if Reminder msg is up
Minutes dw 0 ;# of minutes task has been active
Min_Ticks dw 0444h ;ticks in a minute
Display? db 1 ;1 if reminder is to be displayed
WaitTicks dw 444h ;interval between reminders (ticks)
Rem_Ticks dw 0 ;interval between reminders (ticks)
MsgTicks db 5Ah ;clock ticks reminder stays up
Timer? db 0 ;1 if timer is activated
Resume db 'Resume'
Msg db ' hh:mm '
FileName db 14 dup (0)
db 0Dh,0Ah,'$'
PauseMsg db ' Timer on Pause '
ScrnMsg db ' : '
Tick dw 0
OurPSP dw 0 ;Trackr's PSP segment
ParentPSP dw 0 ;parent program's PSP segment
OrgVidSeg dw 0B000h ;video segment
VidSeg dw 0 ;OrgVidSeg adjusted for screen offset
Pausing? db 0 ;1 if pausing
Message db 'TrackerPro'
Pause db 'PAUSE'
DayTot dw 0 ;day total of time
Total dw 0 ;grand total of time
DayTotMsg db '* Day Total: :'
db ' ',0Dh,0Ah,0Dh,0Ah
TotalMsg db '========== Task Total: : ',0Dh,0Ah
VidMode db 0 ;video mode
StrSize db 0 ;size of string inputted
TopPage db 0 ;first task of current display
NumTasks db 0 ;# of tasks
NumClients db 0 ;# of Clients
Update? db 0 ;1 if updating
ThisFile db 'TRACKR.COM',0
Menu db 'P',1,'ause',2
db 'L',1,'og off',2
db 'S',1,'witch',2
Menu2 db 'C',1,'reate new task',2
db 'U',1,'pdate task log'
MenuEnd db 3
db 'L',1,'og in new task',3
SelectTask db ' Task #:',0
InpClient db ' Client #:',0
TaskMsg db 'Tasks ─'
Status db ' Active task: Elapsed time: '
Screen db ' Active task: Elapsed time: '
db '┌ Tasks ──────────────────┬ Press: ─────────────┐'
db '│ 0 NEW 5 │ │'
db '│ 1 6 │ │'
db '│ 2 7 │ │'
db '│ 3 8 │ │'
db '│ 4 9 │ │'
db '└────────────── Press Escape to Exit ───────────┘'
; Note: "Screen" is also used to store screen characters overwritten by
; Trackr when it pops up
Attributes db 398 dup (0) ;stores overwritten screen attributes
DTA db 49 dup (0) ;disk transfer area
DiskOp? db 0 ;1 if disk ops in progress
DBOff dw 0 ;DOS busy byte offset
DBSeg dw 0 ;DOS busy byte segment
Request? db 0 ;1=request to pop-up
TryCnt db 5Bh ;clock ticks to try to pop-up
NameMsg db 'Task name:',0
DupNameMsg db 'Task already exists. Press any key.',0
InvNameMsg db 'Invalid file name. Press any key.',0
TooManyMsg db 'Ignoring extra clients. Press any key.',0
StackPtr dw 0
HoldSP dw 0
ClientFH dw 0FFFh ;CLIENT.DAT file handle
LogFH dw 0FFFh ;log file handle
TempFH dw 0FFFh ;temp file's file handle
HoldFH dw 0 ;temporarily holds file handle
Flag db 0 ;procedure flag
Client? db 0 ;procedure flag
Client db 21 dup (0) ;first 21 bytes of Client info
Rate dw 0 ;billing rate
Units dw 0 ;billing increments
CTopPage db 0 ;first client of current display
ClientFN db 'CLIENT.DAT',0
TempFN db 'TEMP',0
BytesRead dw 0 ;# of bytes read
EndRec dw 0 ;signal end of record
EoF db 0 ;signals end of file
Date db 8 dup (0)
Today db ' / / ',0
LogIn dw 0 ;time logged in
LogOut dw 0 ;time logged out
LogOff? db 0 ;1 if logging out
CListPtr dw 0
ClientArray dw 30 dup (0) ;30 clients
TaskList db 650 dup (0) ;50 entries 13 bytes each
RecOff dw 0 ;file offset of desired record
db ' '
Comments db 30 dup (0)
CommentMsg db ' Comment: ',0
FirstRec? db 0
Temp dw 0
EndStr dw 0 ;sets max lenght of input string
Cursor dw 0 ;current cursor location
ErrInfo dw 3 dup (0) ;extended error info of parent
;============================================================================
; Int08 processes BIOS timer interrupt (Int 08h)
;============================================================================
Int08 proc
pushf
call cs:Vec08 ;call original interupt
sti
cmp cs:Timer?,1
je A1
cmp cs:Pausing?,1
je A1
A0: cmp cs:Request?,1
jne A05
jmp Readyet? ;okay to pop-up yet?
A05: iret
A1: dec cs:Min_Ticks ;count down ticks per minute
jnz A11
inc cs:Minutes ;another minute has passed
mov cs:Min_Ticks,0444h ;reset counter
A11: cmp cs:MsgUp?,1
jne A12
;reminder message is up
dec cs:MsgTicks
jz DisTimer ;if up for 5 secs then remove
jmp A0
;reminder message not up
A12: dec cs:Rem_Ticks
jnz A0
;time to display reminder
mov ax,cs:WaitTicks
mov cs:Rem_Ticks,ax
;displays or removes reminder
DisTimer: cmp cs:Up?,1 ;is TRACKR popped up?
je A0
cmp cs:Display?,1 ;don't want to re-enter
jne A0
mov cs:Display?,0 ;make sure we don't re-enter
push ax
push bx
push cx
push dx
push si
push di
push ds
push es
push cs
pop ds
A15: mov ax,40h
mov es,ax
mov al,es:49h ;bios mode
cmp al,7
je A2
cmp al,3
ja RetInt ;if not text mode return
A2: call AdjVidSeg
mov es,VidSeg
mov di,32h ;offset into screen of stuff to grab
mov cx,36h ;number of words to grab
mov si,offset Buffer
cld
cmp MsgUp?,1
jne A3
;restore background
mov cx,5
repe cmpsw ;are previous 5 characters same
jne Bally ;nope? then don't restore original
mov cx,31h
rep movsw
jmp Bally
;save background
A3: xchg si,di
push es
pop ds
push cs
pop es
rep movsw ;save screen
push cs
pop ds
;display reminder message
mov di,3Dh
mov si,offset Attributes
mov cx,31h
call DisStr
mov MsgTicks,5Ah
call DisStatus ;display reminder
Bally: xor MsgUp?,1
RetInt: pop es
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
mov cs:Display?,1
cmp cs:Request?,1
jne RY0
;checks to see if it's safe to pop-up
Readyet?: dec cs:TryCnt ;how many times have we tried?
jnz RY1
mov cs:Request?,0 ;if tried for 5 secs then give up
RY0: iret
RY1: push ax
;check DOS busy byte
push es
push si
mov es,cs:DBseg
mov si,cs:DBoff
cmp byte ptr es:[si],0 ;DOS busy byte
pop si
pop es
jne T1 ;can't pop-up if DOS is busy
;DOS not busy
cmp cs:Diskop?,0
je T2
;unable to accomodate request (DOS busy or disk ops in progress)
T1: pop ax
iret
;DOS not busy and no disk ops, let's do it
T2: pop ax
jmp MainStuff
Int08 endp
;============================================================================
; Int09 processes BIOS keyboard interrupt (Int 09h)
;============================================================================
Int09 proc
sti
push ax
push es
mov ax,40h
mov es,ax
mov al,es:17h
and al,0Fh
cmp al,cs:ShiftState ;check shift state
je R1
R0: pop es ;chain to original interupt
pop ax
cli
jmp cs:Vec09
R1: in al,60h
cmp al,cs:ScanCode ;check scan code
jne R0
;hot key has been pressed, ask to pop-up
mov cs:Request?,1
mov cs:TryCnt,5Bh
cli
mov al,20h ;reset interupts
out 20h,al
sti
pop es
pop ax
iret
Int09 endp
;============================================================================
; Int28 processes undocumented DOS interrupt "keyboard busy loop" (Int 28h)
;============================================================================
Int28 proc
pushf
call cs:Vec28
sti
cmp cs:Request?,1
je I28b
I28a: iret
I28b: cmp cs:Diskop?,1
je I28a
;no disk ops, and in Int28, let's do it
jmp MainStuff
Int28 endp
;============================================================================
; Int13 processes BIOS disk services interrupt (Int 13h)
;============================================================================
Int13 proc
;won't let you pop-up during BIOS disk operations
sti
mov cs:Diskop?,1
pushf
call cs:Vec13 ;call original interupt
mov cs:Diskop?,0
retf 2
Int13 endp
;============================================================================
; Start logs in a new task
;============================================================================
Start proc
call GetTime ;get log-in time
mov LogIn,ax
mov Timer?,1 ;we're on, ignore further requests
mov Pausing?,0 ;we're not pausing
mov ax,WaitTicks ;set up Rem_Ticks
mov Rem_Ticks,ax
ret
Start endp
;============================================================================
; GetTime returns with seconds since midnight in AX
;============================================================================
GetTime proc
push es
mov ax,40h
mov es,ax
mov ax,es:6Ch
mov dx,es:6Eh
mov bx,0444h
div bx ;ax=minutes since midnight
pop es
ret
GetTime endp
;============================================================================
; Stop logs-off
;============================================================================
Stop proc
call GetTime
mov LogOut,ax ;get log-out time
mov Timer?,0 ;we're off
mov Minutes,0 ;reset elapsed time
ret
Stop endp
;============================================================================
; Encode puts time in HHH:MM format
; Entry: AX = minutes
; DI = offset HHH:MM string goes
;============================================================================
Encode proc
mov cx,3030h
mov bx,3Ch
xor dx,dx
div bx
xchg dx,ax ;put minutes in ax
aam
xchg ah,al
or ax,cx
mov [di+4],ax ;minutes
mov ax,dx ;put hours in ax
mov bl,64h
div bl ;divide by 100
mov bl,al
mov al,ah
aam
xchg ah,al
or ax,cx
mov [di+1],ax ;hours mod 100
cmp bl,0
je E1
mov al,bl
aam
or ax,cx
mov [di],al ;hundreds of hours value
E1: mov byte ptr [di+3],':' ;stick in colon
ret
Encode endp
;============================================================================
; Decode takes time value in HH:MM and returns AX=minutes
; Entry: SI = offset of HH:MM value
; Exit: AX = minutes
;============================================================================
Decode proc
cmp byte ptr [si],' '
jne DD1
mov byte ptr [si],'0'
DD1: mov ax,[si]
xor ax,3030h
xchg ah,al
aad
mov bl,3Ch
mul bl
mov dx,ax
mov ax,[si+3]
xor ax,3030h
xchg ah,al
aad
add ax,dx
ret
Decode endp
;============================================================================
; MainStuff prepares for popping up by saving registers, cursor location,
; extended error information, getting and setting the PSP, getting the video
; segment and offsets, saving the background, and displaying Trackr's main
; screen.
;============================================================================
MainStuff proc
mov cs:Request?,0
mov cs:Up?,1
push ax
push bx
push cx
push dx
push si
push di
push ds
push es
mov ax,cs
mov ds,ax
mov es,ax
mov ah,51h
int 21h ;get parent PSP
mov ParentPSP,bx
mov ah,50h
mov bx,OurPSP
int 21h ;set our PSP
mov ah,59h
int 21h ;get extended error information
mov ErrInfo,ax
mov ErrInfo[2],bx
mov ErrInfo[4],cx
call AdjVidSeg ;get video segment
cmp MsgUp?,1
jne MS1
;remove reminder if currently displayed
push es
mov es,VidSeg
mov di,3Ch
mov cx,31h
mov si,offset Buffer
cld
rep movsw
mov MsgUp?,0
pop es
MS1: mov ah,0Fh
int 10h
mov VidPage,bh
mov ah,3
int 10h
mov OrgCursor,dx ;save cursor position
mov ax,sp
mov StackPtr,ax ;save stack ptr
call SwapScreen ;save background and display Trackr
call MakeDate
cmp NumTasks,0
jne Main
;if no tasks then jump to Create Task
jmp M51
;============================================================================
; Main procedure
;============================================================================
Main proc
mov Client?,0
mov Update?,0
;display Menus
mov ah,2
mov bh,VidPage
mov dx,1900h
int 10h ;move cursor off screen
mov si,offset TaskMsg
mov cx,7
mov di,0E0h
call DisStr ;display TaskMsg
mov si,offset Menu
mov MenuEnd,3
cmp TaskOff,0
jne Mt
mov si,offset Menu2
dec MenuEnd
Mt: call DisMenu ;display appropriate Menu
cmp Pausing?,1
jne Mu
mov di,01B4h
mov si,offset Resume
mov cx,6
call DisStr ;display Pausing message
Mu: call DisStatus ;display task status
call DisList ;display list of tasks
;fall thru to GetKey
Main endp
MainStuff endp
;============================================================================
; GetKey gets menu keystrokes and directs efforts as appropriate
;============================================================================
GetKey proc
M0: xor ah,ah
int 16h
cmp ah,1
jne M2
jmp Returnn ;Escape? then exit
M2: cmp ah,49h ;PgUp
je M3
cmp ah,51h ;PgDn
jne M4
M3: call Chk_PgUp
jmp M0
M4: cmp Update?,1
jne M41
jmp M9 ;if Updating then jmp M9
M41: cmp ah,26h ;Log-Off
jne M5
cmp TaskOff,0
je M8
call LogOff
mov TaskOff,0
jmp Returnn
M5: cmp ah,2Eh ;Create new task?
jne M6
cmp Pausing?,1
je M51
cmp TaskOff,0
je M51
call LogOff ;if logged on then log-off first
M51: call NewTask
jmp M36
M6: cmp ah,19h ;Pause?
jne M7
cmp TaskOff,0
je M8
call LogOff
mov Pausing?,1
jmp Returnn
M7: cmp ah,13h ;Resume?
jne M8
call Start ;log back on
jmp Returnn
M8: cmp ah,16h ;Update?
jne M9
mov Update?,1
push TaskOff ;save TaskOff
call Update
pop TaskOff ;restore TaskOff
mov Update?,0
jmp Returnn
M9: cmp ah,1Fh ;Switch
je M10
cmp ah,26h ;Log-on
je M10
jmp M0
M10: mov si,offset SelectTask
mov Client?,0
call GetNumber ;returns task # in al
;number has been pressed
mov bl,0Dh
mul bl
add ax,offset TaskList ;offset of task name
push ax
cmp Pausing?,1
je M35a
cmp TaskOff,0
je M35a
call LogOff ;if logged on then log-off (switch)
;log on to task whose # was pressed
M35a: pop ax
mov TaskOff,ax
M36: call GetComment ;get comment
call Start ;log-on
jmp Returnn ;exit
GetKey endp
;============================================================================
; GetNumber returns with client (if Client?=1) or task number in AL
; Entry: SI = offset of prompt message
; Client? = 1 if getting client number else 0
; Exit: AL = client or task number
;============================================================================
GetNumber proc
GN0: push si
mov ax,2 ;limit input to 2 characters
call GetInput
pop si
mov al,Buffer ;convert to binary number
sub al,'0'
cmp al,9
ja GN0
cmp StrSize,1
je GN1
mov bl,0Ah
mul bl
mov bl,Buffer+1
sub bl,'0'
cmp bl,9
ja GN0
add al,bl
GN1: mov cl,NumTasks
cmp Client?,0
je GN2
mov cl,NumClients
GN2: cmp al,cl
jae GN0 ;check to see if number is out of limits
mov Client?,0
ret
GetNumber endp
;============================================================================
; Returnn exits Trackr and restores everything as it was before popping up
;============================================================================
Returnn proc
push cs
pop ds
call CloseFiles ;close any open files
mov bx,ParentPSP
mov ah,50h
int 21h ;restore parent PSP
call SwapScreen
mov ax,5D0Ah
mov dx,offset ErrInfo
int 21h ;restore extended error info
mov ah,2
mov dx,OrgCursor
mov bh,VidPage
int 10h ;restore cursor
mov ax,StackPtr
mov sp,ax ;restore stackptr
pop es
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
mov cs:Up?,0
iret
Returnn endp
;============================================================================
; CloseFiles closes any open files
;============================================================================
CloseFiles proc
mov cx,3
mov si,offset ClientFH
Ret1: mov bx,[si]
cmp bx,0FFFh
je Ret2
mov word ptr [si],0FFFh
mov ah,3Eh
int 21h
Ret2: inc si
inc si
loop Ret1
ret
CloseFiles endp
;============================================================================
; DisStatus displays task name and elapsed time (or pausing message)
;============================================================================
DisStatus proc
mov al,' '
mov di,offset Status+14
push di
mov cx,8
rep stosb ;clear task name
add di,18
mov cx,5
rep stosb ;clear elapsed time
pop di
mov si,TaskOff
cmp si,0
je ST3
;insert task name
ST0: mov al,[si]
cmp al,'.'
je ST1
mov [di],al
inc si
inc di
jmp ST0
ST1: mov di,offset Status+40
cmp Pausing?,1
jne ST2
inc di
mov si,offset Pause
mov cx,5
rep movsb ;insert "Pausing" if appropriate
jmp ST3
ST2: mov ax,Minutes
call Encode ;convert elapsed time into ASCII
ST3: mov si,offset Status
mov cx,31h
mov di,3Ch
jmp DisStr ;display status message
DisStatus endp
;============================================================================
; DisList displays the list of tasks
;============================================================================
DisList proc
DLz: call ClrList
mov di,180h
mov al,TopPage
mov bl,0Dh
mul bl
add ax,offset TaskList
mov si,ax ;first task name on page
mov dl,TopPage
mov cl,NumTasks
sub cl,dl
cmp cl,0Ah
jbe DL1
mov cx,0Ah
DL1: push si
push di
mov al,dl
aam
xor ax,'00'
mov es:[di],ah
mov es:[di+2],al
inc dl
add di,6
DL2: mov al,[si]
cmp al,'.'
je DL3
mov es:[di],al
inc si
inc di
inc di
jmp DL2
DL3: pop di
pop si
add si,0Dh
add di,0A0h
cmp di,04A0h
jb DL4
mov di,019Ah
DL4: loop DL1
push ds
pop es
ret
DisList endp
;============================================================================
; ClrList clears the screen where the task list goes
;============================================================================
ClrList proc
mov ah,NAt
mov al,' '
mov es,VidSeg
mov di,180h
mov cx,5
DL0: push cx
push di
mov cx,18h
rep stosw
pop di
add di,0A0h
pop cx
loop DL0
ret
ClrList endp
;============================================================================
; MakeDate gets date and converts to DD/MM/YR format in "Today" variable
;============================================================================
MakeDate proc
mov ah,2Ah
int 21h ;dh=month,dl=day,cx=yr
mov al,dh
aam
xchg al,ah
add ax,3030h
mov word ptr Today,ax
mov al,dl
aam
xchg al,ah
add ax,3030h
mov word ptr Today[3],ax
sub cx,076Ch
D1: cmp cx,64h
jae D1
mov al,cl
aam
xchg al,ah
add ax,3030h
mov word ptr Today[6],ax
ret
MakeDate endp
;============================================================================
; LogOff logs off the current task and updates the task file
;============================================================================
LogOff proc
call Stop ;get log-off time
cmp Pausing?,1
jne LO1
mov Pausing?,0
ret
LO1: mov LogOff?,1
jmp FixLog ;update task file
LogOff endp
;============================================================================
; SwapScreen moves data in the "Screen" and "Attributes" buffers back onto
; the screen and vice versa.
;============================================================================
SwapScreen proc
;swaps screen to "Screen" buffer
mov es,VidSeg
mov si,offset Screen
mov di,3Ch
mov cx,8
SW1: push cx
push di
mov cx,31h
SW2: mov ax,es:[di]
mov bl,[si]
mov bh,[si+188h]
mov es:[di],bx
mov [si],al
mov [si+188h],ah
inc si
inc di
inc di
loop SW2
pop di
pop cx
add di,0A0h
loop SW1
push ds
pop es
ret
SwapScreen endp
;============================================================================
; AdjVidSeg adjusts VidSeg for offset into the screen (pages)
;============================================================================
AdjVidSeg proc
push es
mov ax,40h
mov es,ax
mov ax,es:4Eh ;screen offset
mov cl,4
shr ax,cl ;divided by 16
add ax,OrgVidSeg
mov VidSeg,ax ;add to original video segment
pop es
ret
AdjVidSeg endp
;============================================================================
; Update gets task number and then updates the task file to incorporate
; additions or changes
;============================================================================
Update proc
mov HoldSP,sp
mov si,offset SelectTask
mov Client?,0
call GetNumber ;returns with task number in al
mov bl,0Dh
mul bl
add ax,offset TaskList
mov TaskOff,ax
call FixLog ;fix the task file
mov sp,HoldSP
ret
Update endp
;============================================================================
; LoadLog opens the task file with LogFH=file handle
; moves to first data location
; gets Units and Rate info
;============================================================================
LoadLog proc
mov di,NameOff
mov si,TaskOff
mov cx,0Dh
rep movsb
mov ax,3D02h
mov dx,offset Drive
int 21h ;open file
jnc S1
S0: push cs ;unable to open file
pop ds
jmp TaskErr
S1: mov LogFH,ax ;file handle
mov bx,ax
mov LogFH,ax
mov al,2
mov RecOff,0
;fall through to GetHeader
LoadLog endp
;============================================================================
; GetHeader loads in Units and Rate information and returns with file at start
; of next entry and AX=offset into file of next entry
; Entry: AL = 0 if task, 1 if making Client array, 2 if making new task
; BX = file handle (LogFH or ClientFH)
; Exit: AX = file offset of next entry
;============================================================================
GetHeader proc
mov Flag,al
mov HoldFH,bx
mov EoF,0
H1: mov dx,RecOff
xor cx,cx
mov ax,4200h
int 21h ;mov to file ptr to RecOff
;read 10 more than scanning to account for unit message length overrun
mov ah,3Fh
mov cx,50h
mov dx,offset Buffer
int 21h ;read
mov cx,ax ;bytes read
cmp Flag,1
jne H2
;making client array
push di
push cx
mov si,dx
;go past tabs, spaces, linefeeds and carraige returns
H14: mov al,[si]
cmp al,7
je H15
cmp al,' '
je H15
cmp al,0Ah
je H15
cmp al,0Dh
jne H16
H15: inc si
jmp H14
H16: mov di,offset Client
mov cx,15h
rep movsb ;move in client name
pop cx
pop di
mov Flag,0
H2: cmp cx,50h ;bytes read
je H3
mov EoF,1 ;set EoF if bytes read less than requested
H3: mov di,dx
mov cx,46h
H31: mov al,'\'
repne scasb ;look for start of rate info
cmp cx,0
je H34
;check to see if '\' is first character in line
cmp di,offset Buffer+1
je H4
push di
dec di
H32: dec di
mov al,[di]
cmp al,' '
je H32
cmp al,0Ah
je H33
cmp al,0Dh
je H33
pop di ;'\' isn't first character in line
jmp H31 ;so keep looking
H33: pop di
jmp H4
;haven't found '\' yet
H34: cmp EoF,1
je H4 ;if end of file then goto H4
add RecOff,46h ;else read in more and try again
cmp Flag,2
je H34a
jmp H1
H34a: mov bx,TempFH ;if making new task then write info to
;TEMP file first
mov ah,40h
mov cx,46h
int 21h ;write info to TEMP file
jnc H35
jmp TaskErr
H35: mov bx,HoldFH ;restore original file handle
jmp H1 ;go read in more and continue search
H4: call GetVal
mov Rate,ax ;get Rate Value
call GetVal
mov Units,ax ;get Units value (billing increment)
S3: mov al,[di] ;go past end of line
cmp al,0Dh
je S4
cmp al,0Ah
jne S5
S4: inc di
jmp S3
S5: sub di,offset Buffer
cmp Flag,2
jne S6
mov cx,di ;if creating new task then write info
;to TEMP file
mov bx,TempFH
mov ah,40h
int 21h
jnc S6
jmp TaskErr
S6: mov dx,di ;change RecOff to next record's offset
add dx,RecOff
mov RecOff,dx
xor cx,cx
mov ax,4200h
mov bx,HoldFH
int 21h ;move file pos to next record
ret
GetHeader endp
;============================================================================
; GetVal takes ASCII # pointed to by DI and returns a binary number in AX
; and DI pointing to the next ASCII # or carraige return. Used for
; decoding task files or CLIENT.DAT.
; Entry: DI = offset of ASCII number
; Exit: AX = binary number
; DI = offset of next ASCII # or CR
;============================================================================
GetVal proc
xor ax,ax
mov cx,ax
mov bl,0Ah
G1: mov cl,[di]
cmp cl,0Dh
je G2
cmp cl,'\'
je G2
sub cl,'0'
cmp cl,9
ja G15
mul bl
add ax,cx
G15: inc di
jmp G1
G2: inc di
ret
GetVal endp
;============================================================================
; NewTask
;============================================================================
NewTask proc
mov si,offset SelectTask-1
call DisMenu ;display "Select task" menu
call GetClients ;get clients from CLIENT.DAT
mov CTopPage,0
NT0: call DisClients ;display client list
mov si,offset InpClient
mov Client?,1
call GetNumber ;get client #
call MovPtr ;move file ptr to client
;create new task file
NT8a: mov si,offset NameMsg
mov ax,8
call GetInput ;get task file name
mov si,offset Buffer
mov di,NameOff
NT9: mov al,[si]
cmp al,0Dh
je NT11
cmp al,' ' ;no spaces allowed
je NT11c
cmp al,'.' ;ignore extension
je NT11
cmp al,'a'
jb NT10
cmp al,'z'
ja NT10
sub al,20h ;change to upper case
NT10: mov [di],al
inc si
inc di
jmp NT9
NT11: mov si,offset Extension
mov cx,5
rep movsb ;add .LOG extension
mov dx,offset Drive
mov ax,3D02h
int 21h ;check for duplicate file
jc NT11b
mov bx,ax
mov ah,3Eh
int 21h ;file already exists so close file
mov si,offset DupNameMsg
NT11a: call DisErrMsg
jmp NT8a
;create new file
NT11b: mov ah,3Ch
xor cx,cx
mov dx,offset Drive
int 21h ;create new task file
jnc NT12
NT11c: mov si,offset InvNameMsg
jmp NT11a ;invalid file name, try again
NT12: mov TempFH,ax ;file handle of task file
mov si,NameOff
call PutTask ;add task name to task list
mov bx,ClientFH
mov al,2 ;flag
call GetHeader ;get info from CLIENT.DAT and create
;task file
mov bx,ClientFH
mov ClientFH,0FFFh
mov ah,3Eh ;close CLIENT.DAT
int 21h
mov bx,TempFH
mov TempFH,0FFFh
mov ah,3Eh ;close TEMP file
int 21h
ret
NewTask endp
;============================================================================
; DisClients displays the list of clients starting with CTopPage as the first
; client
;============================================================================
DisClients proc
call ClrList ;clear the screen
push ds
pop es
mov al,CTopPage
mov Flag,al
mov di,186h
mov cx,5
NT1: mov al,5
sub al,cl
add al,CTopPage
cmp al,NumClients
jb NT13
ret
NT13: push cx
push di
mov bx,ClientFH
call MovPtr
mov dx,offset Client
mov cx,15h
mov ah,3Fh
int 21h ;read in first 21 bytes of client data
pop di
push di
mov es,VidSeg
mov al,Flag
aam
or ax,'00'
mov es:[di-6],ah
mov es:[di-4],al ;display client number
inc Flag
mov cx,15h
mov si,offset Client
NT15: mov al,[si]
cmp al,0Ah
je NT2
cmp al,0Dh
je NT2
cmp al,7
je NT2
cmp al,' '
jne NT3
NT2: inc si
dec cx
jmp NT15
NT3: call DisStr ;display 15 bytes of client info
pop di
add di,0A0h
pop cx
loop NT1
ret
DisClients endp
;============================================================================
; MovPtr takes client number in AL and returns with file ptr at client's
; record
; Entry: AL = # of client
;============================================================================
MovPtr proc
xor ah,ah
shl ax,1
add ax,offset ClientArray
mov di,ax
mov dx,[di]
mov RecOff,dx
xor cx,cx
mov ax,4200h
mov bx,ClientFH
int 21h ;move file ptr to first entry
ret
MovPtr endp
;============================================================================
; FixLog updates task log pointed to by TaskOff
;
; Entry: TaskOff pointing to desired task
;============================================================================
FixLog proc
mov DayTot,0
mov di,NameOff
mov si,offset TempFN
mov cx,5
rep movsb ;make full pathname for TEMP
mov dx,offset Drive
mov ah,3Ch
xor cx,cx
int 21h ;create TEMP file
jnc FL1
jmp TaskErr
FL1: mov bx,ax ;file handle
mov TempFH,ax
mov Flag,2
call LoadLog
cmp LogOff?,1
jne FL4
;if logging off add new entry to file
mov di,offset Buffer+2
mov al,' '
mov cx,50h
push di
rep stosb
pop di
mov si,offset Today
mov cx,8
rep movsb ;mov in today's date
mov ax,LogIn
mov di,offset Buffer+11
call Encode ;add log in time
mov ax,LogOut
mov di,offset Buffer+18
call Encode ;add log out time
mov di,offset Buffer+31
mov si,offset Comments-2
FL2: mov al,[si] ;add comments
cmp al,0Dh
je FL3
mov [di],al
inc di
inc si
jmp FL2
FL3: mov ax,0A0Dh
mov [di],ax
mov word ptr Buffer,ax ;add carraige return, line feed
sub di,offset Buffer-4
xor cx,cx
mov dx,cx
mov ax,4202h
mov bx,LogFH
int 21h ;move to end of task file
mov dx,offset Buffer
mov cx,di
mov ah,40h
int 21h ;write entry
jnc FL35
jmp TaskErr
FL35: mov ax,4200h
mov dx,RecOff
xor cx,cx
int 21h ;return to first record
mov LogOff?,0
mov EoF,0
FL4: mov FirstRec?,1
FL5: mov bx,LogFH
mov cx,50h
mov ah,3Fh
mov dx,offset Buffer
int 21h ;read in 80 bytes from task file
cmp ax,0 ;ax=bytes read
jne FL6
jmp FL22
FL6: mov BytesRead,ax
mov cx,ax
add ax,offset Buffer
mov EndRec,ax
;search for 13 then go until not 10 or 13, this is next record
mov di,offset buffer
mov al,0Dh
repne scasb
cmp cx,0
jne FL7
mov EoF,1
FL7: mov al,[di]
cmp al,0Dh
je FL8
cmp al,0Ah
jne FL9
FL8: inc di
cmp di,EndRec
jb FL7
FL9: sub di,offset Buffer
mov dx,di
add dx,RecOff
mov RecOff,dx ;RecOff points to next record
xor cx,cx
mov ax,4200h
int 21h ;mov source file to next record
cmp di,20h
jae FL10
dec di
dec di
mov cx,1Eh
sub cx,di
mov al,' '
add di,offset Buffer
rep stosb
mov word ptr [di],0A0Dh
FL10: cmp Buffer+0Ch,':'
jne FL11
cmp Buffer+13h,':'
je FL12
FL11: jmp FL21
FL12: cmp FirstRec?,1
jne FL13
mov FirstRec?,0
jmp FL16
FL13: cmp Buffer,' ' ;no date
jne FL14
jmp FL18
FL14: mov di,offset Buffer
mov si,offset Date
mov cx,8
repe cmpsb ;compare entry date with last entry
jz FL17
;new date
call DayTally
FL16: mov si,offset Buffer
mov di,offset Date
mov cx,8
rep movsb
jmp FL18
;dates are same
FL17: mov al,' '
mov cx,8
mov di,offset Buffer
rep stosb
FL18: mov si,offset Buffer+0Ah
call Decode
push ax ;log in time
mov si,offset Buffer+11h
call Decode ;log off time
pop bx
sub ax,bx ;elapsed minutes
cmp ax,0
jne FL19
inc ax
FL19: jg FL191
add ax,05A0h ;minutes in 24 hours
FL191: mov bx,Units
cmp bx,1
je FL20
xor dx,dx
div bx
inc ax
mul bx ;elapsed time in billing increments
FL20: add DayTot,ax ;add to day total
add Total,ax ;add to grand total
mov di,offset Buffer+23
call Encode ;encode and add to log entry string
mov dx,offset Buffer
call WrtEntry ;write log entry string
FL21: cmp EoF,1
je FL22
jmp FL5
;construct and display summary
FL22: call DayTally
mov ax,Total
mov di,offset TotalMsg+23
call Encode
cmp Rate,0
jne FL23
mov di,offset TotalMsg+31
mov al,' '
mov cx,10
rep stosb
jmp FL24
FL23: mov ax,Total
mov di,offset TotalMsg+40
call EncBucks
FL24: mov dx,offset TotalMsg
call WrtEntry
mov Total,0
mov bx,TempFH
mov TempFH,0FFFh
mov ah,3Eh
int 21h ;close TEMP file
mov bx,LogFH
mov LogFH,0FFFh
mov ah,3Eh
int 21h ;close .LOG file
mov di,NameOff
mov si,TaskOff
mov cx,0Dh
rep movsb ;make complete pathname for task file
mov si,offset Drive ;contains task's complete pathname
mov di,offset Buffer
mov cx,50h
rep movsb ;move task name to buffer
mov di,NameOff
mov si,offset TempFN
mov cx,5
rep movsb ;make full pathname for TEMP
mov dx,offset Buffer
mov ah,41h
int 21h ;delete original task file
jnc FL25
jmp TaskErr
FL25: mov di,offset Buffer
mov dx,offset Drive
mov ah,56h
int 21h ;rename TEMP to task file
ret
FixLog endp
;============================================================================
; DayTally makes the daily total entry for the task log
;============================================================================
DayTally proc
mov ax,DayTot
cmp ax,0
jne DT1
ret
DT1: mov di,offset DayTotMsg+23
call Encode
mov di,offset DayTotMsg+31
mov al,' '
mov cx,10
rep stosb
cmp Rate,0
je DT4
DT2: mov ax,DayTot
mov di,offset DayTotMsg+40
call EncBucks
DT4: mov DayTot,0
mov dx,offset DayTotMsg
mov cx,2Dh
jmp WriteEntry
DayTally endp
;============================================================================
; WrtEntry takes a log entry pointed to by DX and writes it to the file whose
; file handle is in TempFH
; Entry: DX - pointing to log entry string
; TempFH - holding file handle
;============================================================================
WrtEntry proc
mov di,dx
mov al,0Ah
mov cx,50h
repne scasb
sub di,dx
mov cx,di
WriteEntry proc
mov bx,TempFH
mov ah,40h
int 21h
jc Err
ret
Err: jmp TaskErr
WriteEntry endp
WrtEntry endp
;============================================================================
; EncBucks displays flush right at DI, minutes (in AX) times Rate
; Entry: AX = minutes
; DI = where rightmost character goes
;============================================================================
EncBucks proc
mov bx,di
mov cx,8
sub bx,cx
EB00: mov byte ptr [bx],' '
inc bx
loop EB00 ;clear display area
mov bx,Rate
mul bx ;hourly rate times minutes
mov bx,3Ch
div bx ;divided by 60
mov cx,ax ;dollars
mov ax,dx ;remainder
mov bl,64h
mul bl ;multiplied by 100
mov bl,3Ch
div bl ;and divided by 60, al=cents
aam
xchg ah,al
add ax,3030h
dec di
mov [di],ax ;display cents
dec di
mov byte ptr [di],'.'
mov ax,cx ;ax = dollars
EB2: dec di
cmp ax,0
je EB3
xor dx,dx
mov bx,0Ah
div bx
add dl,'0'
mov [di],dl ;display dollars
jmp EB2
EB3: dec di
mov byte ptr [di],'$'
ret
EncBucks endp
NeedDATAmsg db ' Unable to open CLIENT.DAT.',0
WriteErrMsg db ' Unable to create, open, or modify .LOG file. ',0
;============================================================================
; TaskErr handles errors with the task (.LOG) file
;============================================================================
TaskErr proc
mov TaskOff,0
mov si,offset WriteErrMsg
TaskErr endp
;============================================================================
; DisErr displays the error message in SI, waits for keypress and return to
; the "Main" procedure
;============================================================================
DisErr proc
call ClrLine
mov di,3Ch
call DisStrZ
xor ah,ah
int 16h
Abort: push cs
pop ds
call CloseFiles
AB0: mov ax,StackPtr
mov sp,ax
cmp NumTasks,0
jne AB1
jmp Returnn
AB1: jmp Main
DisErr endp
;============================================================================
; DisErrMsg displays the Error message pointed at by SI and waits for keypress
;============================================================================
DisErrMsg proc
call ClrLine
mov di,3Eh
call DisStrZ
xor ah,ah
int 16h
ret
DisErrMsg endp
;============================================================================
; Chk_PgUp chks for PgUp and PgDn while at a menu and acts accordingly
;============================================================================
Chk_PgUp proc
GI1: cmp ah,49h
jne GI3
;PgUp
cmp Client?,1
jne GI2
cmp CTopPage,0
jne GI1b
GI1a: ret
GI1b: sub CTopPage,5
jmp GI4
GI2: cmp TopPage,0
je GI1a
sub TopPage,0Ah
jmp GI6
;PgDn
GI3: cmp Client?,1
jne GI5
mov al,NumClients
sub al,CTopPage
cmp al,5
jbe GI1a
add CTopPage,5
GI4: push di
call DisClients
pop di
ret
GI5: mov al,NumTasks
sub al,TopPage
cmp al,0Ah
jbe GI6
add TopPage,0Ah
GI6: push di
call DisList
pop di
ret
Chk_PgUp endp
;============================================================================
; GetInput displays prompt message and then gets keyboard input which it puts
; in "Buffer"
; Entry: SI = pointer to prompt message
; AX = max length of input
; Exit: Buffer - holds keyboard input string
;============================================================================
GetInput proc
add ax,offset Buffer
mov EndStr,ax
call ClrLine ;clear the input area on screen
mov di,3Ch
call DisStrZ ;display prompt
mov di,offset Buffer
mov Cursor,28h
jmp J1
;get input
J0: xor ah,ah
int 16h
cmp ah,1 ;escape?
jne J02
jmp Abort
J02: cmp ah,49h ;PgUp?
je J03
cmp ah,51h ;PgDn?
jne J05
J03: call Chk_PgUp
jmp J0
J05: cmp ah,0Eh ;BS
je J2
cmp al,0Dh ;return
je J9
cmp al,80h ;no values >127
jae J0
cmp di,EndStr
jae J0
mov ah,0Ah
mov cx,1
int 10h ;display value
mov [di],al
inc di
J1: inc Cursor
mov ah,2
xor bh,bh
mov dx,Cursor
int 10h ;advance cursor
jmp J0
;backspace
J2: cmp Cursor,29h
jne J3
jmp J0
J3: dec Cursor
dec di
mov byte ptr [di],0
mov ah,2
mov dx,Cursor
int 10h
mov al,' '
mov ah,0Ah
mov cx,1
int 10h
jmp J0
J9: mov ah,2
mov dx,2000h
mov bh,VidPage
int 10h
mov byte ptr [di],0Dh ;add carraige return
mov ax,di
sub ax,offset Buffer
mov StrSize,al
push ds
pop es
ret
GetInput endp
;============================================================================
; ClrLine clears top line of Trackr's screen
;============================================================================
ClrLine proc
mov di,3Ch
mov cx,31h
mov ax,word ptr Space
mov es,VidSeg
rep stosw ;clear line
push ds
pop es
ret
ClrLine endp
;============================================================================
; DisStrZ displays ASCIIZ string
; Entry: SI = offset of string
; DI = offset of destination
;============================================================================
DisStrZ proc
mov cx,255 ;fall through to DisStr
;============================================================================
; DisStr displays string
; Entry: SI = offset of string
; CX = string length
; DI = destination offset
;============================================================================
DisStr proc
;enter with di pointing to destination, cx=str len, si point to str
mov es,VidSeg
DS1: mov al,[si]
cmp al,0
je DS3
cmp al,0Dh
jne DS2
mov al,' '
dec si
DS2: mov es:[di],al
inc si
inc di
inc di
loop DS1
push ds
pop es
DS3: ret
DisStr endp
DisStrZ endp
;============================================================================
; DisMenu displays the menu options
; Entry: SI = offset of Menu string
;============================================================================
DisMenu proc
;clear the screen
mov ah,NAt
mov al,' '
mov di,01B4h
push di
mov es,VidSeg
mov cx,5
DMx: push cx
push di
mov cx,13h
rep stosw
pop di
pop cx
add di,0A0h
loop DMx
pop di
push di
DM0: mov al,[si] ;menu string
cmp al,3
jne DM1
pop di ;if al=3 then return
push ds
pop es
ret
DM1: cmp al,1 ;if al=1 then hi-lite last value
jne DM2
mov al,HAt
mov es:[di-1],al
inc si
jmp DM0
DM2: cmp al,2 ;if al=2 then go to next line
jne DM3
inc si
mov al,[si]
pop di
add di,0A0h
push di
DM3: mov es:[di],al ;else display character
inc si
inc di
inc di
jmp DM0
DisMenu endp
;============================================================================
; GetComment gets log on comments for task entry
;============================================================================
GetComment proc
mov si,offset CommentMsg
mov ax,1Eh
call GetInput
mov cl,StrSize
mov ch,0
inc cx
mov si,offset Buffer
mov di,offset Comments
rep movsb
mov byte ptr [di],0
jmp DisStatus
GetComment endp
;============================================================================
; PutTask inserts task information into task list in alphebetical order
; Entry: SI = offset of task name
; Exit: TaskOff pointing to desired task
; task list in alphabetical order
;============================================================================
PutTask proc
;enter with si pointing to task name
;returns with TaskOff and task list in alpha order
mov Temp,si
mov di,offset TaskList-0Dh
mov cl,NumTasks
cmp cl,32h
jb PT1
dec cl
mov NumTasks,cl ;ignore tasks if more than 50
PT1: xor ch,ch
inc cx
CR11: add di,0Dh
push di
push cx
mov cx,0Dh
mov si,Temp
cmp word ptr [di],0
je CR11a
repe cmpsb
CR11a: pop cx
pop di
jbe CR12
loop CR11 ;doesn't go here, keep trying
CR12: mov ax,di
mov di,offset TaskList+289h
cmp ax,di
jae CR13
mov si,di
sub si,0Dh
mov cx,si
sub cx,ax
inc cx
std
rep movsb ;make room for new entry by moving
;other tasks up
cld
CR13: mov di,ax
mov TaskOff,di
mov si,Temp
mov cx,0Dh
rep movsb ;move in new task
inc NumTasks
ret
PutTask endp
;============================================================================
; GetClients makes Client array from CLIENT.DAT file
;============================================================================
GetClients proc
xor ax,ax
mov RecOff,ax
mov NumClients,0
mov di,offset ClientArray
mov cx,1Eh
rep stosw ;zero out ClientArray
;make Client Array
mov di,NameOff
mov si,offset ClientFN
mov cx,11
push es
push ds
pop es
rep movsb ;make full pathname for CLIENT.DAT
pop es
mov ax,3D00h
mov dx,offset Drive
int 21h ;open CLIENT.DAT
jnc K31
mov si,offset NeedDATAmsg
jmp DisErr ;if no CLIENT.DAT file then abort
K31: mov bx,ax ;file handle
mov ClientFH,ax
mov di,offset ClientArray+2
K4: push di
mov al,1
mov bx,ClientFH
call GetHeader ;get client info
inc NumClients
pop di
cmp NumClients,30
jb K5
mov si,offset TooManyMsg
jmp DisErrMsg ;more than 30 clients
K5: mov ax,RecOff
mov [di],ax ;store in ClientArray
inc di
inc di
cmp EoF,1 ;End of CLIENT.DAT file?
jne K4
ret
GetClients endp
Buffer db 98 dup (0)
;----------------------------------------------------------------------------
; Non-TSR portion
;----------------------------------------------------------------------------
CodeSeg dw 0
RemovedMsg db 0Dh,0Ah,'TRACKR is removed.',0Dh,0Ah,'$'
UnableMsg db 0Dh,0Ah,'Unable to remove TRACKR.',0Dh,0Ah,'$'
InHereMsg db 0Dh,0Ah,'TRACKR is already loaded',0Dh,0Ah,'$'
Copyright db 0Ah,'TRACKR 1.0 Copyright (c) 1991 Ziff '
db 'Communications Co.',0Dh,0Ah
db 'PC Magazine ■ Scott Chaney',0Dh,0Ah,0Ah
Syntax db 'Syntax: TRACKR [/#] [/U] [/I D:\PATH]',0Dh,0Ah
db ' /# = Minutes between reminders '
db '(1-9, 0=disable)',0Dh,0Ah
db ' /U = Uninstall',0Dh,0Ah
db ' /I = Sets path for .LOG files',0Dh,0Ah,0Ah
ActMsg db 'Activation Hot Key: '
HKmsg db 'Ctrl-R ',0Dh,0Ah,'$'
Init proc
push cs
pop es
B4: mov ax,cs
mov ds,ax
mov es,ax
;check for DOS 3.0 or greater
mov ah,30h
int 21h
cmp al,3
jae B5
mov dx,offset WrongVerMsg
jmp P32b
;get our PSP
B5: mov ah,51h
int 21h
mov OurPSP,bx
;move NAt into attribute array
mov al,HAt
mov cx,31h
mov di,offset Attributes
rep stosb
mov cx,157h
mov al,NAt
rep stosb
;check for command line
In0: mov bx,80h
mov cl,[bx] ;number of characters in command line
cmp cl,0
jne In2
In1: jmp P4
In2: mov si,81h
Parse: mov al,[si]
inc si
cmp al,0Dh
je In1
cmp al,'/'
je Parse
P01: cmp al,' '
je Parse
cmp al,'?'
jne P012
;asking for help: display copyright and exit
mov dx,offset Syntax
mov ah,9
mov ActMsg,'$'
int 21h
mov ah,4Ch
int 21h
P012: cmp al,'0'
jb P015
cmp al,'9'
ja P015
;adjusting reminder interval
sub al,'0'
jnz P013
mov Display?,0
jmp P4 ;if 0 then no reminders
P013: mov bl,al
mov ax,0444h
mul bx ;multiply reminder interval by clock
;ticks per minute
mov WaitTicks,ax
jmp P4
P015: or al,20h
cmp al,'u' ;uninstall?
jne P3
jmp UnInstall
P3: cmp al,'i' ;initialize path for .LOG files?
jne Parse
mov di,offset Drive
P31: lodsb
cmp al,' '
je P31
cmp al,0Dh
je P32
stosb ;store path in "Drive"
jmp P31
P32: mov al,'\' ;add '\' to end
stosb
mov NameOff,di ;put offset in NameOff
;get full pathname of TRACKR.COM
mov ax,cs:2Ch
mov es,ax
xor ax,ax
mov di,ax
mov cx,1024
GP0: cmp word ptr es:[di],ax
je GP1
inc di
loop GP0
mov dx,offset ThisFile
jmp GP2
GP1: add di,4
mov dx,di
push es
pop ds
GP2: mov ax,3D02h
int 21h ;open TRACKR.COM
push cs
pop ds
jnc P33
;can't find TRACKR.COM
P32a: mov dx,offset CantInitMsg
P32b: mov ah,9
int 21h
mov ah,4Ch
int 21h ;end
P33: mov bx,ax ;file handle
mov cx,54h
mov dx,100h
mov ah,40h
int 21h ;write task and client directory info
jc P32a
mov ah,3Eh
int 21h ;close file
P4: call Loaded? ;Trackr loaded already?
jne P45
mov dx,offset InHereMsg ;if so, say so and quit
mov ah,9
int 21h
mov ah,4Ch
int 21h
P45: mov ah,0Fh ;get video mode
int 10h
xor ah,ah
cmp al,7
je L1
mov al,3
mov OrgVidSeg,0B800h ;set video segment (0B000 by default)
L1: mov dx,offset DTA
mov ah,1Ah
int 21h ;set DTA
;make task list
push cs
pop es
mov di,NameOff
mov si,offset SrchName
mov cx,6
rep movsb
mov dx,offset Drive
mov cx,0
mov ah,4Eh
int 21h ;find first .LOG file
jc K3
K1: mov si,offset DTA+1Eh
call PutTask
cmp NumTasks,32h
jb K2
mov dx,offset Warning
mov ah,9
int 21h
jmp K3
K2: mov ah,4Fh
int 21h ;find next .LOG file
jnc K1
K3: mov TaskOff,0
mov ah,9
mov dx,offset Copyright
int 21h ;print copyright
M1: mov ax,cs:2Ch
mov es,ax
mov ah,49h
int 21h ;free environment memory
mov ax,3509h
int 21h ;get int 09 vector
mov word ptr Vec09,bx
mov word ptr Vec09[2],es
mov ax,3513h
int 21h ;get int vec 13
mov word ptr Vec13,bx
mov word ptr Vec13[2],es
mov ax,3508h
int 21h ;get int vec 1C
mov word ptr Vec08,bx
mov word ptr Vec08[2],es
mov ax,3528h
int 21h ;get int vec 28
mov word ptr Vec28,bx
mov word ptr Vec28[2],es
mov ah,34h
int 21h ;location of DOS busy byte
mov DBseg,es
mov DBoff,bx
mov dx,offset Int09
mov ax,2509h
int 21h ;set vector for Int 09
mov dx,offset Int13
mov ax,2513h
int 21h ;set vector for Int 13
mov dx,offset Int08
mov ax,2508h
int 21h ;set vector for Int 1C
mov dx,offset Int28
mov ax,2528h
int 21h ;set vector for Int 28
mov ax,offset CodeSeg
mov cl,4
shr ax,cl
inc ax
mov dx,ax ;paragraphs to remain resident
mov ax,3100h
int 21h ;go TSR
Init endp
UnInstall proc
call Loaded?
je UI1
jmp U2
UI1: mov CodeSeg,es
;check to see if anyone else has taken our interupts
mov ax,es
xor si,si
mov ds,si
cmp [si+26h],ax ;Int 09
jne Unable
cmp [si+4Eh],ax ;Int 13h
jne Unable
cmp [si+22h],ax ;Int 08h
jne Unable
cmp [si+0A2h],ax ;Int 28h
je U1
Unable: mov ah,9
mov dx,offset UnableMsg
push cs
pop ds
int 21h
mov ah,4Ch
int 21h
U1: inc es:Message+2 ;change message
;reset interupts to original values
mov dx,word ptr es:Vec09
mov ax,word ptr es:Vec09[2]
mov ds,ax
mov ax,2509h ;reset int 09
int 21h
mov dx,word ptr es:Vec13
mov ax,word ptr es:Vec13[2]
mov ds,ax
mov ax,2513h ;reset int 13
int 21h
mov dx,word ptr es:Vec08
mov ax,word ptr es:Vec08[2]
mov ds,ax
mov ax,2508h ;reset int 1C
int 21h
mov dx,word ptr es:Vec28
mov ax,word ptr es:Vec28[2]
mov ds,ax
mov ax,2528h ;reset int 28
int 21h
mov ah,49h
int 21h ;free memory block
push cs
pop ds
mov dx,offset RemovedMsg
mov ah,9
int 21h ;print message
U2: mov ah,4Ch
int 21h ;end
UnInstall endp
Loaded? proc
;checks to see if TSR already is loaded. If it is then zf set upon
;return and es:di points to offset info in TSR
mov bx,offset Message
inc Message ;avoid disk cache match
mov ax,cs
mov dx,0A000h-1
NextPara: inc dx ;next paragraph
mov es,dx
cmp dx,ax
je NotHere ;If our seg then search is done
mov si,bx ;else check for match
mov di,bx
mov cx,0Ah
rep cmpsb ;a match?
jnz NextPara ;if no match, keep looking
ret
NotHere: inc ax
cmp ax,dx ;return with not equal
ret
Loaded? endp
CantInitMsg db 'Unable to locate TRACKR.COM. Aborting.$'
Warning db 0Dh,0Ah,'WARNING: Number of tasks exceeds limit'
db ' of 50. Extras will be ignored.',7,0Dh,0Ah,'$'
WrongVerMsg db 'Sorry, TRACKR needs DOS 3.0 or greater.',7,'$'
;data needed for CONFIG program
Preface db 255,'*RsE*',128
Method db 1
Colors db 2
ColorOff dw offset HAt
NumKeys db 1
NumEtc db 0
SSoff dw offset ShiftState
SCoff dw offset ScanCode
DesOff dw offset HKmsg
Code ends
end LGo