home *** CD-ROM | disk | FTP | other *** search
- ;=============================================================================
- ; LOG maintains a log of system usage in an ASCII file. Syntax is:
- ; LOG [filespec] [/U]
- ; where filespec = Name of and/or path to log file, /U = Uninstall
- ;=============================================================================
- CODE SEGMENT PARA PUBLIC 'CODE'
- ASSUME CS:CODE
- ORG 100H
- BEGIN: JMP INITIALIZE
-
- PROGRAM DB "LOG 1.0 "
- COPYRIGHT DB "(c) 1988 Ziff Communications Co.",13,10
- AUTHOR DB "PC Magazine ",254," Jeff Prosise",13,10,"$",26
- HANDLE DW ? ;file handle
- DOSVERSION DW ? ;DOS version number
- INT21H DD ? ;interrupt 21h vector
- LEVEL DW 0 ;EXEC reentrancy level
- EXECFLAG DW 0 ;EXEC flag
- XERROR_AX DW ? ;extended error information
- XERROR_BX DW ?
- XERROR_CX DW ?
- XERROR_DX DW ?
- XERROR_SI DW ?
- XERROR_DI DW ?
- XERROR_DS DW ?
- XERROR_ES DW ?
- DW 3 DUP (0)
- ;=============================================================================
- ; DOSINT intercepts calls to interrupt 21h.
- ;=============================================================================
- DOSINT PROC FAR
- CMP AX,4B00H ;exit immediately if this
- JNE EXEC0 ; isn't a call to EXEC
- CMP CS:[LEVEL],9 ;exit if we've exceeded
- JB EXEC1 ; reentrancy limits
- EXEC0: JMP INT21H
- ;--Save registers passed to EXEC by the parent program.
- EXEC1: STI ;interrupts on
- PUSH AX ;save registers
- PUSH BX
- PUSH CX
- PUSH DX
- PUSH SI
- PUSH DI
- PUSH BP
- PUSH DS
- PUSH ES
- ;--Record the program start/end time and write an entry to the log.
- PUSH BX ;save registers set for
- PUSH DX ; EXEC call
- PUSH DS
- PUSH ES
- PUSH CS ;point DS to code segment
- POP DS
- ASSUME DS:CODE
- INC LEVEL ;increment reentrancy count
- CALL RECORD_TIME ;record the current time
- MOV DX,OFFSET FILESPEC
- CALL OPENFILE ;open the log file
- MOV SI,LEVEL ;point SI to start time and
- DEC SI ; DI to end time
- SHL SI,1
- SHL SI,1
- ADD SI,OFFSET TIMES
- MOV DI,SI
- ADD DI,4
- MOV AL,BYTE PTR LEVEL ;put previous level number
- DEC AL ; in AL
- CALL WRITE_ENTRY ;write log entry
- CALL CLOSEFILE ;close the log file
- MOV EXECFLAG,1 ;set EXEC flag
- ASSUME DS:NOTHING
- POP ES ;restore EXEC register
- POP DS ; parameters
- POP DX
- POP BX
- ;--Record the name of the program just EXECed.
- PUSH ES ;save ES and BX for later
- PUSH BX
- PUSH DS ;set ES equal to DS
- POP ES
- MOV DI,DX ;scan for terminating zero
- XOR AL,AL ; in ASCIIZ filename
- MOV CX,128
- CLD
- REPNE SCASB
- MOV BX,127 ;transfer string length
- SUB BX,CX ; to CX
- MOV CX,BX
- MOV SI,DI ;get ending address in SI
- SUB SI,2 ;set SI to last character
- STD ;set DF for reverse string ops
- EXEC2: LODSB ;scan backwards for first
- CMP AL,"\" ; character in filename
- JE EXEC3
- CMP AL,":"
- JE EXEC3
- LOOP EXEC2
- DEC SI
- EXEC3: ADD SI,2 ;point SI to first character
- SUB BX,CX ;calculate length of filename
- MOV CX,BX ;transfer length to CX
- CLD ;clear DF again
- PUSH CS ;set ES to code segment
- POP ES
- MOV AL,13 ;calculate offset into table
- MOV DL,BYTE PTR CS:[LEVEL] ; of program names
- MUL DL
- MOV DI,AX
- ADD DI,OFFSET NAMES
- MOV AL,CL ;write filename character
- STOSB ; count into table
- EXEC5: LODSB ;convert lowercase characters
- CMP AL,"a" ; to upper and copy filename
- JB EXEC6 ; into table
- CMP AL,"z"
- JA EXEC6
- AND AL,0DFH
- EXEC6: STOSB
- LOOP EXEC5
- ;--Record the command line passed to the program just EXECed.
- POP BX ;restore ES and BX
- POP ES
- LDS SI,ES:[BX+2] ;load parm string address
- MOV CL,[SI] ;get length
- XOR CH,CH
- INC CX
- PUSH CS ;point ES:DI to command line
- POP ES ; buffer in code segment
- MOV DI,OFFSET COMLINE
- REP MOVSB ;copy command line
- ;--Restore register values originally passed by the parent program.
- POP ES
- POP DS
- POP BP
- POP DI
- POP SI
- POP DX
- POP CX
- POP BX
- POP AX
- ;--Save registers again since the DOS 2.X EXEC function destroys them.
- PUSH AX
- PUSH BX
- PUSH CX
- PUSH DX
- PUSH SI
- PUSH DI
- PUSH BP
- PUSH DS
- PUSH ES
- ;--Save the values of SS and SP, call EXEC, and restore the stack.
- MOV CS:[HANDLE],BX ;calculate an index into
- MOV BX,CS:[LEVEL] ; the STACKSEG and
- DEC BX ; STACKPTR tables
- SHL BX,1
- CLI ;disable interrupts and
- MOV WORD PTR CS:[STACKSEG][BX],SS ; save the SS and SP
- MOV WORD PTR CS:[STACKPTR][BX],SP ; registers
- MOV BX,CS:[HANDLE]
- PUSHF ;PUSH the flags register and
- CALL INT21H ; call DOS EXEC
- LAHF ;store flags temporarily in AH
- MOV BX,CS:[LEVEL] ;recalculate table index
- DEC BX
- SHL BX,1
- CLI ;disable interrupts and
- MOV SS,WORD PTR CS:[STACKSEG][BX] ; restore SS and SP
- MOV SP,WORD PTR CS:[STACKPTR][BX]
- STI
- SAHF ;restore flags
- ;--Restore the registers to their conditions before EXEC was called.
- POP ES
- POP DS
- POP BP
- POP DI
- POP SI
- POP DX
- POP CX
- POP BX
- POP AX
- ;--Save registers again while post-processing is performed.
- PUSHF ;then save it for exit
- PUSH AX ;save general registers
- PUSH BX
- PUSH CX
- PUSH DX
- PUSH SI
- PUSH DI
- PUSH BP
- PUSH DS
- PUSH ES
- ;--Save extended error information if DOS version is 3.10 or later.
- PUSH CS ;set DS to code segment
- POP DS
- ASSUME DS:CODE
- CMP DOSVERSION,030AH ;skip if not 3.10 or later
- JB EXEC7
- PUSH DS ;save DS
- MOV AH,59H ;get extended error
- XOR BX,BX ; information
- INT 21H
- MOV CS:[XERROR_DS],DS ;save return value of DS
- POP DS ;set DS to code segment again
- MOV XERROR_AX,AX ;save remaining register
- MOV XERROR_BX,BX ; values in XERROR array
- MOV XERROR_CX,CX
- MOV XERROR_DX,DX
- MOV XERROR_SI,SI
- MOV XERROR_DI,DI
- MOV XERROR_ES,ES
- ;--Record the program start/end time and write an entry to the log.
- EXEC7: DEC LEVEL ;decrement reentrancy count
- CALL RECORD_TIME ;record the current time
- MOV DX,OFFSET FILESPEC
- CALL OPENFILE ;open the log file
- MOV SI,LEVEL ;point SI to start time and
- INC SI ; DI to end time
- SHL SI,1
- SHL SI,1
- ADD SI,OFFSET TIMES
- MOV DI,SI
- SUB DI,4
- MOV AL,BYTE PTR LEVEL ;put previous level number
- INC AL ; in AL
- CALL WRITE_ENTRY ;write log entry
- CALL CLOSEFILE ;close the log file
- MOV EXECFLAG,0 ;clear EXEC flag
- ;--Restore extended error information if DOS version is 3.10 or later.
- CMP DOSVERSION,030AH ;skip if not 3.10 or later
- JB EXEC8
- MOV AX,5D0AH ;restore information with
- MOV DX,OFFSET XERROR_AX ; undocumented function 5Dh
- INT 21H
- ;--Restore registers a final time and exit to the parent program.
- ASSUME DS:NOTHING
- EXEC8: POP ES ;restore registers
- POP DS
- POP BP
- POP DI
- POP SI
- POP DX
- POP CX
- POP BX
- POP AX
- POPF
- DOSEXIT: IRET
- DOSINT ENDP
- ;-----------------------------------------------------------------------------
- ; OPENFILE opens an existing log file or creates a new one.
- ; Entry: DS - code segment
- ; Exit: CF: clear-opened/created, set-file could not be opened/created
- ;-----------------------------------------------------------------------------
- ADDRSPEC DW ?
- CALLFLAG DB 0
-
- OPENFILE PROC NEAR
- ASSUME DS:CODE
- MOV ADDRSPEC,DX ;save filespec address
- MOV AX,3D02H ;attempt to open an existing
- INT 21H ; log file
- JC OPEN3 ;branch if call failed
- MOV HANDLE,AX ;store file handle
- MOV BX,AX ;transfer it to BX
- MOV AX,4202H ;position file pointer at
- XOR CX,CX ; the end of the file
- XOR DX,DX
- INT 21H
- CMP CALLFLAG,0 ;write date to log file
- JNE OPEN1 ; if this is the first
- INC CALLFLAG ; call to OPENFILE
- OPEN0: CALL WRITE_DATE
- CALL WRITE_HEADER ;then write header line
- OPEN1: CLC ;clear CF for exit
- OPEN2: RET ;exit
- ;--Call to open an existing file failed. Create a new one and initialize it.
- OPEN3: MOV AH,3CH ;attempt to create a new
- XOR CX,CX ; file of the same name
- MOV DX,ADDRSPEC
- INT 21H
- JC OPEN2 ;exit on error
- MOV HANDLE,AX ;store file handle
- MOV BX,AX ;transfer it to BX
- MOV CALLFLAG,1 ;set entry flag
- MOV AH,40H ;write copyright text
- MOV CX,70
- MOV DX,OFFSET PROGRAM
- INT 21H
- JMP OPEN0 ;exit
- OPENFILE ENDP
- ;-----------------------------------------------------------------------------
- ; CLOSEFILE closes the log file.
- ;-----------------------------------------------------------------------------
- CLOSEFILE PROC NEAR
- ASSUME DS:CODE
- MOV AH,3EH
- MOV BX,HANDLE
- INT 21H
- RET
- CLOSEFILE ENDP
- ;-----------------------------------------------------------------------------
- ; WRITE_ENTRY writes a one-line entry to the log file.
- ; Entry: DS:SI - start time
- ; DS:DI - end time
- ; AL - last reentrancy level
- ;-----------------------------------------------------------------------------
- LASTLEVEL DB ?
-
- WRITE_ENTRY PROC NEAR
- ASSUME DS:CODE
- MOV LASTLEVEL,AL ;store last level number
- CALL WRITE_TIME ;write start time
- MOV CX,4
- CALL WRITE_SPACES
- PUSH SI ;save start time
- MOV SI,DI ;write end time
- CALL WRITE_TIME
- MOV CX,3
- CALL WRITE_SPACES
- POP SI ;retrieve start time
- CALL WRITE_DIFF ;write elapsed time
- MOV CX,5
- CALL WRITE_SPACES
- MOV AL,LASTLEVEL ;write reentrancy level
- MOV BL,1
- CALL WRITE_NUM
- MOV CX,6
- CALL WRITE_SPACES
- MOV AL,13 ;calculate offset into
- MUL LASTLEVEL ; program name table
- MOV DX,AX
- ADD DX,OFFSET NAMES
- MOV AH,40H ;write program name
- MOV BX,DX
- MOV CL,[BX]
- XOR CH,CH
- PUSH CX
- MOV BX,HANDLE
- INC DX
- INT 21H
- POP BX
- CMP EXECFLAG,0 ;exit now if this entry is
- JE NOPARMS ; a return from EXEC
- MOV CX,12 ;calculate number of spaces
- SUB CX,BX ; to skip
- ADD CX,5
- CALL WRITE_SPACES
- MOV BX,OFFSET COMLINE ;write command line passed
- MOV CL,[BX] ; to the last program
- XOR CH,CH ; EXECed to the log file
- JCXZ NOPARMS
- MOV AH,40H
- MOV BX,HANDLE
- MOV DX,OFFSET COMLINE+1
- INT 21H
- NOPARMS: CALL WRITE_CRLF ;end line with CR/LF
- RET
- WRITE_ENTRY ENDP
- ;-----------------------------------------------------------------------------
- ; WRITE_DATE writes the current date to the log file.
- ;-----------------------------------------------------------------------------
- MONTHS DB "JanFebMarAprMayJunJulAugSepOctNovDec"
- CENTURY DB "19"
-
- WRITE_DATE PROC NEAR
- ASSUME DS:CODE
- CALL WRITE_CRLF ;skip one line
- MOV AH,2AH ;get date from DOS
- INT 21H
- PUSH CX ;save it
- PUSH DX
- MOV AL,DL ;write day of the month to
- XOR BL,BL ; the log file
- CALL WRITE_NUM
- MOV CX,1 ;skip a space
- CALL WRITE_SPACES
- POP DX ;retrieve month from stack
- DEC DH ;calculate offset into MONTH
- MOV CL,DH ; table of text for the
- XOR CH,CH ; current month
- MOV DX,OFFSET MONTHS
- JCXZ WRDATE2
- WRDATE1: ADD DX,3
- LOOP WRDATE1
- WRDATE2: MOV AH,40H ;write month to log file
- MOV BX,HANDLE
- MOV CX,3
- INT 21H
- MOV CX,1 ;skip a space
- CALL WRITE_SPACES
- MOV AH,40H ;write "19" portion of year
- MOV CX,2
- MOV DX,OFFSET CENTURY
- INT 21H
- POP CX ;retrieve year from stack
- SUB CX,1900 ;subtract century portion
- MOV AL,CL ;write year to the log file
- XOR BL,BL
- CALL WRITE_NUM
- CALL WRITE_CRLF ;finish with CRLF pairs
- CALL WRITE_CRLF
- RET
- WRITE_DATE ENDP
-
- ;-----------------------------------------------------------------------------
- ; WRITE_TIME writes the time to the log file. Entry: DS:SI - time
- ;-----------------------------------------------------------------------------
- COLON DB ":"
-
- WRITE_TIME PROC NEAR
- ASSUME DS:CODE
- MOV AL,[SI+1] ;write hours to log file
- MOV BL,1
- CALL WRITE_NUM
- MOV AH,40H ;write ":" to separate
- MOV BX,HANDLE ; hours and minutes
- MOV CX,1
- MOV DX,OFFSET COLON
- INT 21H
- MOV AL,[SI] ;write minutes to log file
- XOR BL,BL
- CALL WRITE_NUM
- RET
- WRITE_TIME ENDP
- ;-----------------------------------------------------------------------------
- ; WRITE_DIFF writes the elapsed time to the log file.
- ; Entry: DS:SI - start time, DS:DI - end time
- ;-----------------------------------------------------------------------------
- DELTA DB 3 DUP (?)
-
- WRITE_DIFF PROC NEAR
- ASSUME DS:CODE
- MOV AL,[DI] ;retrieve starting and ending
- MOV BL,[SI] ; seconds, minutes, and
- MOV CL,[DI+1] ; hours
- MOV DL,[SI+1]
- MOV AH,[DI+2]
- MOV BH,[SI+2]
- CMP AH,BH ;if ending seconds is less
- JAE WRDIFF1 ; than starting, add 60 to
- ADD AH,60 ; ending seconds and
- DEC AL ; decrement ending minutes
- WRDIFF1: CMP AL,BL ;if ending minutes is less
- JGE WRDIFF2 ; than starting, add 60 to
- ADD AL,60 ; ending minutes and
- DEC CL ; decrement ending hours
- WRDIFF2: CMP CL,DL ;if ending hours is less
- JGE WRDIFF3 ; than starting, add 24
- ADD CL,24 ; to ending hours
- WRDIFF3: SUB AH,BH ;calculate seconds difference
- MOV DELTA+2,AH ;store it
- SUB AL,BL ;calculate minutes difference
- MOV DELTA,AL ;store it
- SUB CL,DL ;calculate hours difference
- MOV DELTA+1,CL ;store it
- MOV SI,OFFSET DELTA ;write hours and minutes to
- CALL WRITE_TIME ; the log file
- MOV AH,40H ;write ":" to log file
- MOV BX,HANDLE
- MOV CX,1
- MOV DX,OFFSET COLON
- INT 21H
- MOV AL,[SI+2] ;write seconds to log file
- XOR BL,BL
- CALL WRITE_NUM
- RET
- WRITE_DIFF ENDP
- ;-----------------------------------------------------------------------------
- ; WRITE_NUM converts a binary byte value to ASCII and writes it to the log
- ; file. Value must be between 0 and 99, inclusive.
- ; Entry: AL - byte value, BL - 0 = include leading zeroes, 1 = don't include
- ;-----------------------------------------------------------------------------
- FILEWORD DW ?
-
- WRITE_NUM PROC NEAR
- ASSUME DS:CODE
- AAM ;convert to BCD in AX
- ADD AX,3030H ;convert to ASCII
- OR BL,BL ;convert leading zero to
- JZ WRNUM1 ; space if BL = 1 on
- CMP AH,30H ; entry
- JNE WRNUM1
- MOV AH,20H
- WRNUM1: XCHG AH,AL ;swap bytes
- MOV FILEWORD,AX ;store them
- MOV AH,40H ;then write them to the
- MOV BX,HANDLE ; log file
- MOV CX,2
- MOV DX,OFFSET FILEWORD
- INT 21H
- RET
- WRITE_NUM ENDP
- ;-----------------------------------------------------------------------------
- ; WRITE_HEADER writes the column titles to the log file.
- ;-----------------------------------------------------------------------------
- TITLES DB "START",5 DUP (32),"END",5 DUP (32)
- DB "ELAPSED",4 DUP (32),"LEVEL",4 DUP (32)
- DB "PROGRAM",10 DUP (32),"PARAMETERS",13,10
- EQUALSIGN DB "="
-
- WRITE_HEADER PROC NEAR
- ASSUME DS:CODE
- MOV AH,40H ;write column titles
- MOV BX,HANDLE
- MOV CX,67
- MOV DX,OFFSET TITLES
- INT 21H
- MOV CX,79 ;write row of "=" symbols
- WRHEAD1: PUSH CX
- MOV AH,40H
- MOV CX,1
- MOV DX,OFFSET EQUALSIGN
- INT 21H
- POP CX
- LOOP WRHEAD1
- CALL WRITE_CRLF ;end it with a CR/LF pair
- RET
- WRITE_HEADER ENDP
- ;-----------------------------------------------------------------------------
- ; WRITE_CRLF writes a carriage return / line feed to the log file.
- ;-----------------------------------------------------------------------------
- CRLF DB 13,10
-
- WRITE_CRLF PROC NEAR
- ASSUME DS:CODE
- MOV AH,40H
- MOV BX,HANDLE
- MOV CX,2
- MOV DX,OFFSET CRLF
- INT 21H
- RET
- WRITE_CRLF ENDP
- ;-----------------------------------------------------------------------------
- ; WRITE_SPACES writes CX spaces to the log file.
- ;-----------------------------------------------------------------------------
- SPACE DB 32
-
- WRITE_SPACES PROC NEAR
- ASSUME DS:CODE
- PUSH CX ;save counter
- MOV AH,40H ;write one space
- MOV BX,HANDLE
- MOV CX,1
- MOV DX,OFFSET SPACE
- INT 21H
- POP CX ;retrieve count
- LOOP WRITE_SPACES ;loop until done
- RET
- WRITE_SPACES ENDP
- ;-----------------------------------------------------------------------------
- ; RECORD_TIME records the current time in the slot designated by LEVEL.
- ;-----------------------------------------------------------------------------
- RECORD_TIME PROC NEAR
- ASSUME DS:CODE
- MOV AH,2CH ;get current time
- INT 21H
- MOV BX,LEVEL ;calculate offset into table
- SHL BX,1 ; of start/end times
- SHL BX,1
- MOV WORD PTR TIMES[BX],CX ;store current time
- MOV BYTE PTR TIMES[BX+2],DH
- RET
- RECORD_TIME ENDP
- ;=============================================================================
- ; 418-byte buffer area used after LOG becomes resident.
- ;=============================================================================
- PC = $
- FILESPEC = PC ;filespec buffer
- PC = PC + 80
- NAMES = PC ;storage array for program
- PC = PC + 130 ; names
- TIMES = PC ;storage array for program
- PC = PC + 40 ; start/end times
- STACKSEG = PC ;storage array for SS
- PC = PC + 20 ; register values
- STACKPTR = PC ;storage array for SP
- PC = PC + 20 ; register values
- COMLINE = PC ;command line parameter buffer
- PC = PC + 128
- LASTBYTE = PC
- ;=============================================================================
- ; INITIALIZE installs or uninstalls the program.
- ;=============================================================================
- ERRMSG1 DB "Usage: LOG [filespec] [/U]$"
- ERRMSG2 DB "Not Installed$"
- ERRMSG3 DB "Cannot Uninstall$"
- ERRMSG4 DB "Already Installed$"
- ERRMSG5 DB "Invalid Filespec$"
- OUTTEXT DB "Uninstalled$"
- DEFNAME DB "\USAGE.LOG",13
- IDLETEXT DB 6,"<idle>"
- INSTALLED DB 0
-
- INITIALIZE PROC NEAR
- ASSUME CS:CODE, DS:CODE
- ;--See if a copy of LOG is already resident in memory.
- CLD ;clear DF for string ops
- MOV WORD PTR [BEGIN],0 ;initialize fingerprint
- XOR BX,BX ;zero BX for start
- MOV AX,CS ;keep CS value in AX
- INIT1: INC BX ;increment search segment value
- MOV ES,BX
- CMP AX,BX ;not installed if current
- JE PARSE1 ; segment is reached
- MOV SI,OFFSET BEGIN ;search this segment for ASCII
- MOV DI,SI ; fingerprint
- MOV CX,16
- REPE CMPSB
- JNE INIT1 ;loop back if not found
- MOV INSTALLED,1 ;set installed flag
- ;--Parse the command line for entries.
- PARSE1: MOV SI,81H ;point SI to command line
- PARSE2: LODSB ;get a character
- CMP AL,20H ;skip it if it's a space
- JE PARSE2
- CMP AL,0DH ;exit loop when a carriage
- JE NOSPEC ; return is encountered
- CMP AL,"/" ;check for forward slash
- JNE QUALIFY ;anything else is a filespec
- LODSB ;get the next character
- AND AL,0DFH ;capitalize it
- CMP AL,"U" ;branch to uninstall code if
- JE UNINSTALL ; character is a "U"
- ;--An error was encountered in parsing. Display error message and exit.
- MOV DX,OFFSET ERRMSG1 ;load message address
- ERROR_EXIT: MOV AH,9 ;display error message
- INT 21H
- MOV AX,4C01H ;exit with ERRORLEVEL = 1
- INT 21H
- ;--Uninstall the program.
- UNINSTALL: MOV DX,OFFSET ERRMSG2 ;error if program isn't
- CMP INSTALLED,0 ; installed
- JE ERROR_EXIT
- CALL REMOVE ;call uninstall routine
- MOV DX,OFFSET ERRMSG3 ;error if uninstall failed
- JC ERROR_EXIT
- MOV DX,OFFSET OUTTEXT ;display "Uninstalled"
- MOV AH,9 ; message
- INT 21H
- MOV AX,4C00H ;exit with ERRORLEVEL = 0
- INT 21H
- ;--Convert the filespec into a fully qualified filename.
- NOSPEC: MOV SI,OFFSET DEFNAME+1 ;Use default filespec
- QUALIFY: MOV DX,OFFSET ERRMSG4 ;error if program is already
- CMP INSTALLED,0 ; installed
- JNE ERROR_EXIT
- DEC SI ;point DS:SI to filespec
- PUSH CS ;point ES:DI to temporary
- POP ES ; filespec buffer
- MOV DI,OFFSET CWDIR+80
- CALL GENSPEC ;generate complete filespec
- MOV DX,OFFSET ERRMSG5 ;exit if error flag is set
- JC ERROR_EXIT ; on return
- MOV DI,OFFSET CWDIR+80 ;find the terminating zero in
- XOR AL,AL ; the ASCIIZ string
- MOV CX,80
- REPNE SCASB
- DEC DI
- CMP BYTE PTR [DI-1],"\" ;append default filename if
- JNE TESTSPEC ; last character is a
- MOV SI,OFFSET DEFNAME+1 ; backslash
- MOV CX,9
- REP MOVSB
- XOR AL,AL ;write ASCIIZ terminator
- STOSB
- ;--Test the filespec and create the log file if it doesn't already exist.
- TESTSPEC: MOV DX,OFFSET CWDIR+80
- CALL OPENFILE ;open/create log file
- MOV DX,OFFSET ERRMSG5 ;error if file could not
- JC ERROR_EXIT ; be opened
- CALL CLOSEFILE ;close log file
- CALL RECORD_TIME ;record starting time
- MOV AX,3000H ;record version of DOS
- INT 21H ; LOG is running under
- XCHG AH,AL
- MOV DOSVERSION,AX
- ;--Hook into interrupt 21h and deallocate the program's environment block.
- MOV AX,3521H ;save old interrupt vector
- INT 21H
- MOV WORD PTR INT21H,BX
- MOV WORD PTR INT21H[2],ES
- MOV AX,2521H ;then set the new vector
- MOV DX,OFFSET DOSINT
- INT 21H
- MOV AX,DS:[2CH] ;deallocate the program's
- MOV ES,AX ; environment block
- MOV AH,49H
- INT 21H
- ;--Initialize buffer areas.
- PUSH CS ;point ES to code segment
- POP ES
- MOV SI,OFFSET CWDIR+80 ;copy filepsec string to
- MOV DI,OFFSET FILESPEC ; filespec buffer
- COPYLOOP: LODSB
- STOSB
- OR AL,AL
- JNZ COPYLOOP
- MOV SI,OFFSET IDLETEXT ;copy "<idle>" string to
- MOV DI,OFFSET NAMES ; program names buffer
- MOV CX,7
- REP MOVSB
- ;--Display copyright notice, then terminate and remain resident in memory.
- MOV AH,9 ;display copyright
- MOV DX,OFFSET PROGRAM
- INT 21H
- MOV AX,3100H
- MOV DX,(OFFSET LASTBYTE - OFFSET CODE + 15) SHR 4
- INT 21H
- INITIALIZE ENDP
- ;-----------------------------------------------------------------------------
- ; REMOVE deallocates the memory block addressed by ES and restores the
- ; interrupt vector displaced on installation.
- ; Entry: ES - segment to release
- ; Exit: CF clear - program uninstalled, CF set - can't uninstall
- ;-----------------------------------------------------------------------------
- REMOVE PROC NEAR
- MOV CX,ES ;abort if the interrupt 21h
- MOV AX,3521H ; vector has been altered
- INT 21H ; since installation
- MOV AX,ES
- CMP AX,CX
- JNE REMOVE_ERROR
- MOV ES,CX
- MOV AH,49H ;free memory given to
- INT 21h ; original program block
- JC REMOVE_ERROR ;branch on error
- PUSH DS ;restore interrupt vector
- ASSUME DS:NOTHING
- MOV AX,2521H
- LDS DX,ES:[INT21H]
- INT 21H
- POP DS
- ASSUME DS:CODE
- NOT WORD PTR ES:[BEGIN] ;destroy ASCII fingerprint
- CLC ;clear CF for exit
- RET
- REMOVE_ERROR: STC ;set CF to indicate program
- RET ; couldn't be uninstalled
- REMOVE ENDP
- ;-----------------------------------------------------------------------------
- ; GENSPEC generates a fully qualified filename.
- ; Entry: DS:SI - filename, ES:DI - filespec buffer
- ; Exit: CF clear - drive/directory valid, CF set - drive/directory invalid
- ;-----------------------------------------------------------------------------
- ADDRIN DW ? ;input string address
- ADDROUT DW ? ;output string address
- DEFDRIVE DB ? ;default drive
- ADDRSLASH DW ? ;address of last backslash
-
- GENSPEC PROC NEAR
- MOV ADDROUT,DI ;save output buffer address
- ;--Save the current drive and directory.
- PUSH SI ;save SI
- MOV AH,19H ;get current drive and
- INT 21H ; save it
- MOV DEFDRIVE,AL
- MOV AH,47H ;get current directory and
- XOR DL,DL ; save it
- MOV SI,OFFSET CWDIR+1
- INT 21H
- POP SI ;restore SI
- ;--Check for a drive designator and supply default drive code if needed.
- CMP BYTE PTR [SI+1],":" ;see if drive designator
- JNE GEN1 ; appears in filespec
- LODSW ; buffer and capitalize
- AND AL,0DFH ; drive letter if it does
- JMP SHORT GEN2
- GEN1: MOV AL,DEFDRIVE ;get default drive letter
- ADD AL,"A" ;convert to ASCII
- MOV AH,":" ;append colon
- GEN2: STOSW ;and output drive spec
- ;--Scan the input filespec for the rightmost backslash character.
- MOV ADDRIN,SI ;save filespec address
- XOR CX,CX ;initialize counter
- GEN3: LODSB ;get next byte
- CMP AL,0DH ;scan finished if character
- JE GEN4 ; is a carriage return or
- CMP AL,20H ; space
- JE GEN4
- CMP AL,"\" ;loop back if it's anything
- JNE GEN3 ; but a backslash
- MOV CX,SI ;save address of backslash
- DEC CX ; character and return to
- JMP GEN3 ; scan loop
- ;--Copy everything up to the last backslash to the output buffer.
- GEN4: MOV ADDRSLASH,CX ;save backslash address
- MOV SI,ADDRIN ;point SI back to filespec
- OR CX,CX ;terminate string if no
- JZ GEN6 ; backslashes found
- CMP SI,CX ;copy leading backslash if
- JE GEN5 ; if it was the only one
- SUB CX,SI ;otherwise copy everything
- DEC CX ; up to the last backslash
- JCXZ GEN5
- REP MOVSB
- GEN5: MOVSB
- GEN6: XOR AL,AL ;append binary zero to form
- STOSB ; ASCIIZ string
- ;--Change to the drive and directory specified and get a full pathname.
- MOV AH,0EH ;switch current drive
- MOV DI,ADDROUT
- MOV DL,[DI]
- SUB DL,"A"
- INT 21H
- CMP BYTE PTR [DI+2],0
- JE GEN7
- MOV AH,3BH ;set current directory to
- MOV DX,ADDROUT ; the one just formulated
- ADD DX,2 ; and exit if the call fails
- INT 21H
- JC GEN_EXIT
- GEN7: MOV AH,47H ;now request a complete
- MOV SI,ADDROUT ; directory string from
- MOV DL,[SI] ; DOS
- SUB DL,40H
- ADD SI,3
- MOV BYTE PTR [SI-1],"\"
- INT 21H
- JC GEN_EXIT ;exit on error
- ;--Reset the default drive and directory.
- MOV AH,0EH ;reset default drive
- MOV DL,DEFDRIVE
- INT 21H
- MOV AH,3BH ;finish up by setting the
- MOV DX,OFFSET CWDIR ; current directory to what
- INT 21H ; it was when we started
- JC GEN_EXIT
- ;--Append the filename to the directory specification if one was entered.
- MOV DI,ADDROUT ;find ASCIIZ terminator byte
- XOR AL,AL ; in output buffer
- MOV CX,80
- REPNE SCASB
- DEC DI
- CMP BYTE PTR [DI-1],"\" ;insert a backslash if
- JE GEN8 ; there's not one at the
- MOV AL,"\" ; end of the string
- STOSB
- GEN8: MOV SI,ADDRSLASH ;point SI to the first
- OR SI,SI ; character in the
- JNZ GEN9 ; input filename
- MOV SI,ADDRIN
- JMP SHORT GEN10
- GEN9: INC SI
- GEN10: LODSB ;copy characters until a
- CMP AL,0DH ; carriage return or space
- JE GEN11 ; delimiter is reached
- CMP AL,20H
- JE GEN11
- STOSB
- JMP GEN10
- GEN11: XOR AL,AL ;append terminating zero byte
- STOSB ; to string
- CLC ;clear CF and exit
- GEN_EXIT: RET
- GENSPEC ENDP
- CWDIR DB "\" ;directory string buffer
- CODE ENDS
- END BEGIN
-