home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
batch
/
library
/
errlvl12
/
errlvl.asm
next >
Wrap
Assembly Source File
|
1991-10-15
|
32KB
|
847 lines
;--------------------------------------------------------------------------;
; Program: ErrLvl .Asm ;
; Purpose: Displays value of previous ERRORLEVEL. ;
; Notes: Compiles under TURBO Assembler, v2.0. Tested under ;
; MS/PC-DOS v3.30, v4.0, and v5.0. ;
; Status: Released into the public domain. Enjoy! If you use it, ;
; let me know what you think. You don't have to send ;
; any money, just comments and suggestions. ;
; Updates: 13-Jun-89, v1.0, GAT ;
; - initial version. ;
; 08-Jul-90, GAT ;
; - added macros to push/pop registers. ;
; 28-Aug-90, v1.1a, GAT ;
; - put equates and macros in separate files. ;
; - put common routines in libs. ;
; 28-Dec-90, v1.2a, GAT ;
; - added support for DOS v4.0. ;
; 15-Oct-91, v1.2b, GAT ;
; - revised include file names. ;
; - added support for DOS v5.0. ;
;--------------------------------------------------------------------------;
;--------------------------------------------------------------------------;
; Author: George A. Theall ;
; Phone: +1 215 662 0558 ;
; SnailMail: TifaWARE ;
; 506 South 41st St., #3M ;
; Philadelphia, PA. 19104 USA ;
; E-Mail: theall@gdalsrv.sas.upenn.edu (Internet) ;
;--------------------------------------------------------------------------;
%NEWPAGE
;--------------------------------------------------------------------------;
; D I R E C T I V E S ;
;--------------------------------------------------------------------------;
DOSSEG
MODEL tiny
IDEAL
LOCALS
JUMPS
;
; This section comes from Misc.Inc.
;
@16BIT EQU (@CPU AND 8) EQ 0
@32BIT EQU (@CPU AND 8)
MACRO ZERO RegList ;; Zeros registers
IRP Reg, <RegList>
xor Reg, Reg
ENDM
ENDM
;
; This section comes from DOS.Inc.
;
BELL EQU 7
BS EQU 8
TAB EQU 9
CR EQU 13
LF EQU 10
ESCAPE EQU 27 ; nb: ESC is a TASM keyword
SPACE EQU ' '
KEY_F1 EQU 3bh
KEY_F2 EQU 3ch
KEY_F3 EQU 3dh
KEY_F4 EQU 3eh
KEY_F5 EQU 3fh
KEY_F6 EQU 40h
KEY_F7 EQU 41h
KEY_F8 EQU 42h
KEY_F9 EQU 43h
KEY_F10 EQU 44h
KEY_HOME EQU 47h
KEY_UP EQU 48h
KEY_PGUP EQU 49h
KEY_LEFT EQU 4bh
KEY_RIGHT EQU 4dh
KEY_END EQU 4fh
KEY_DOWN EQU 50h
KEY_PGDN EQU 51h
KEY_INS EQU 52h
KEY_DEL EQU 53h
KEY_C_F1 EQU 5eh
KEY_C_F2 EQU 5fh
KEY_C_F3 EQU 60h
KEY_C_F4 EQU 61h
KEY_C_F5 EQU 62h
KEY_C_F6 EQU 63h
KEY_C_F7 EQU 64h
KEY_C_F8 EQU 65h
KEY_C_F9 EQU 66h
KEY_C_F10 EQU 67h
KEY_C_LEFT EQU 73h
KEY_C_RIGHT EQU 74h
KEY_C_END EQU 75h
KEY_C_PGDN EQU 76h
KEY_C_HOME EQU 77h
KEY_C_PGUP EQU 84h
KEY_F11 EQU 85h
KEY_F12 EQU 86h
KEY_C_F11 EQU 89h
KEY_C_F12 EQU 8ah
DOS EQU 21h ; main MSDOS interrupt
STDIN EQU 0 ; standard input
STDOUT EQU 1 ; standard output
STDERR EQU 2 ; error output
STDAUX EQU 3 ; COM port
STDPRN EQU 4 ; printer
STRUC HOOK
Vector DB ? ; vector hooked into
OldISR DD ? ; entry point to old ISR
NewISR DD ? ; entry point to new ISR
ENDS
GLOBAL at : PROC
GLOBAL errmsg : PROC
GLOBAL ProgName : BYTE ; needed for errmsg()
GLOBAL EOL : BYTE ; ditto
GLOBAL fgetc : PROC
GLOBAL fputc : PROC
GLOBAL fputs : PROC
GLOBAL getchar : PROC
GLOBAL getdate : PROC
GLOBAL getswtch : PROC
GLOBAL gettime : PROC
GLOBAL getvdos : PROC
GLOBAL getvect : PROC
GLOBAL isatty : PROC
GLOBAL kbhit : PROC
GLOBAL pause : PROC
GLOBAL putchar : PROC
GLOBAL setvect : PROC
GLOBAL sleep : PROC
GLOBAL fake_Env : PROC
GLOBAL install_TSR : PROC
GLOBAL uninstall_TSR : PROC
;
; This section comes from Math.Inc.
;
GLOBAL atoi : PROC
GLOBAL atou : PROC
GLOBAL utoa : PROC
;
; This section comes from String.Inc.
;
EOS EQU 0 ; terminates strings
GLOBAL isdigit : PROC
GLOBAL islower : PROC
GLOBAL isupper : PROC
GLOBAL iswhite : PROC
GLOBAL strchr : PROC
GLOBAL strcmp : PROC
GLOBAL strlen : PROC
GLOBAL tolower : PROC
GLOBAL toupper : PROC
VERSION equ '1.2b' ; current version of program
ERRH equ 1 ; return code if help given
ERRVDOS equ 10 ; return code if bad DOS version
%NEWPAGE
;--------------------------------------------------------------------------;
; C O D E S E G M E N T ;
;--------------------------------------------------------------------------;
CODESEG
ORG 80h ; commandline
LABEL CmdLen BYTE
db ?
LABEL CmdLine BYTE
db 127 dup (?)
ORG 100h ; start of .COM file
STARTUPCODE
jmp main ; skip over data and stack
%NEWPAGE
;--------------------------------------------------------------------------;
; D A T A ;
;--------------------------------------------------------------------------;
LABEL ProgName BYTE
db 'errlvl: ', EOS
LABEL EOL BYTE
db '.', CR, LF, EOS
LABEL HelpMsg BYTE
db CR, LF
db 'TifaWARE ERRLVL, v', VERSION, ', ', ??Date
db ' - displays previous ERRORLEVEL.', CR, LF
db 'Usage: errlvl [-options] [msg]', CR, LF, LF
db 'Options:', CR, LF
db ' -? = display this help message', CR, LF, LF
db 'msg is an optional message to display before'
db ' the errorlevel.', CR, LF, EOS
LABEL Err1Msg BYTE
db 'illegal option -- '
LABEL OptCh BYTE
db ?
db EOS
LABEL Err2Msg BYTE
db 'unable to locate errorlevel', EOS
LABEL Value BYTE ; errorlevel in char form
db 4 dup (?) ; 3 chars plus EOS
STRUC ERRLOC ; structure holding addresses
vDos DW ? ; minor SHL 8 + major
Loc DW ? ; offset within segment
ENDS
ErrLocTbl ERRLOC <30 SHL 8 + 3, 0beaH> ; for DOS v3.30
ERRLOC <00 SHL 8 + 4, 0f2bH> ; for DOS v4.0
ERRLOC <00 SHL 8 + 5, 02a3H> ; for DOS v5.0
ERRLOC <0, 0> ; >>>must be last<<<
SwitCh db '-' ; char introducing options
HFlag db 0 ; flag for on-line help
MsgLen db 0 ; length of message text
MsgTxt dw ? ; near pointer to message text
%NEWPAGE
;--------------------------------------------------------------------------;
; P R O C E D U R E S ;
;--------------------------------------------------------------------------;
;---- get_ErrLvl --------------------------------------------------------;
; Purpose: Gets errorlevel from previously executed program. ;
; Notes: Thanks to Josep Fortiana Gregori (D3ESJFG0@EB0UB011) for ;
; providing a code sample from which this proc was ;
; derived and to Yan Juras for suggesting at which ;
; offset to look for this value. ;
; Requires: 8086-class CPU and DOS v3.30 or v4.0 (as sold in USA). ;
; Entry: DS = PSP address of program (OK if not changed since ;
; program started. ;
; Exit: AL = errorlevel, ;
; cf = 1 if DOS version is unsupported or DOS not found. ;
; Calls: getvdos ;
; Changes: AX, ;
; flags ;
;--------------------------------------------------------------------------;
PROC get_ErrLvl
push bp dx es
; Make sure a supported version of DOS is being used.
call getvdos ; AL = major version
mov bp, OFFSET ErrLocTbl
@@NextVer:
cmp [(ERRLOC PTR bp).vDOS], ax ; supported version?
je SHORT @@FindPSP ; yes
add bp, SIZE ErrLocTbl ; no
cmp [(ERRLOC PTR bp).vDOS], 0 ; at end of table?
je SHORT @@NoCanDo ; yes
jmp SHORT @@NextVer ; no
; Find the PSP for the version of COMMAND.COM which called us.
; This approach relies on the observation that COMMAND.COM
; assigns its own PSP as the calling PSP at offset 16h.
;
;
; NB: Abort if calling PSP is above current PSP. This happens
; when running under an alternate shell like MKS Toolkit.
@@FindPSP:
mov ax, ds
@@LoopBack:
mov es, ax
mov dx, [es:16h] ; get caller's PSP (undocumented)
xchg ax, dx
cmp ax, dx
jb @@LoopBack
ja SHORT @@NoCanDo ; avoid infinite loop if no DOS
clc ; signal no error
mov bp, [(ERRLOC PTR bp).Loc]
mov al, [es:bp]
jmp SHORT @@Fin
@@NoCanDo:
stc ; signal an error
@@Fin:
pop es dx bp
ret
ENDP get_ErrLvl
;---- skip_Spaces -------------------------------------------------------;
; Purpose: Skips past spaces in a string. ;
; Notes: Scanning stops with either a non-space *OR* CX = 0. ;
; Entry: DS:SI = start of string to scan. ;
; Exit: AL = next non-space character, ;
; CX is adjusted as necessary, ;
; DS:SI = pointer to next non-space. ;
; Calls: none ;
; Changes: AL, CX, SI ;
;--------------------------------------------------------------------------;
PROC skip_Spaces
jcxz SHORT @@Fin
@@NextCh:
lodsb
cmp al, ' '
loopz @@NextCh
jz SHORT @@Fin ; CX = 0; don't adjust
inc cx ; adjust counters if cx > 0
dec si
@@Fin:
ret
ENDP skip_Spaces
;---- get_Opt -----------------------------------------------------------;
; Purpose: Get a commandline option. ;
; Notes: none ;
; Entry: AL = option character. ;
; Exit: n/a ;
; Calls: tolower, errmsg ;
; Changes: AX, DX, ;
; [OptCh], [HFlag] ;
;--------------------------------------------------------------------------;
PROC get_Opt
mov [OptCh], al ; save for later
call tolower ; use only lowercase in cmp.
cmp al, '?'
jz SHORT @@OptH
mov dx, OFFSET Err1Msg ; unrecognized option
call errmsg ; then *** DROP THRU *** to OptH
; Various possible options.
@@OptH:
mov [HFlag], 1 ; set help flag
@@Fin:
ret
ENDP get_Opt
;---- get_Arg -----------------------------------------------------------;
; Purpose: Gets a non-option from the set of commandline arguments. ;
; Notes: Anything left on the commandline is user's message text. ;
; Entry: CX = count of characters left in commandline, ;
; DS:SI = pointer to argument to process. ;
; Exit: CX = zero ;
; DS:SI = points to CR after commandline. ;
; Calls: none ;
; Changes: CX, SI ;
; [MsgLen], [MsgTxt] ;
;--------------------------------------------------------------------------;
PROC get_Arg
mov [MsgLen], cl ; for safekeeping
mov [MsgTxt], si
add si, cx ; adjust so nothing's left
ZERO cl
mov [BYTE PTR si], EOS ; finish off string
ret
ENDP get_Arg
;---- process_CmdLine ---------------------------------------------------;
; Purpose: Processes commandline arguments. ;
; Notes: A switch character by itself is ignored. ;
; Entry: n/a ;
; Exit: n/a ;
; Calls: skip_Spaces, get_Opt, get_Arg ;
; Changes: AX, CX, SI, ;
; DX (get_Opt), ;
; [OptCh], [HFlag], (get_Opt), ;
; [MsgLen], [MsgTxt] (get_Arg), ;
; Direction flag is cleared. ;
;--------------------------------------------------------------------------;
PROC process_CmdLine
cld ; forward, march!
ZERO ch
mov cl, [CmdLen] ; length of commandline
mov si, OFFSET CmdLine ; offset to start of commandline
call skip_Spaces ; check if any args supplied
or cl, cl
jnz SHORT @@ArgLoop
jmp SHORT @@Fin
; For each blank-delineated argument on the commandline...
@@ArgLoop:
lodsb ; next character
dec cl
cmp al, [SwitCh] ; is it the switch character?
jnz SHORT @@NonOpt ; no
; Isolate each option and process it. Stop when a space is reached.
@@OptLoop:
jcxz SHORT @@Fin ; abort if nothing left
lodsb
dec cl
cmp al, ' '
jz SHORT @@NextArg ; abort when space reached
call get_Opt
jmp @@OptLoop
; Process the current argument, which is *not* an option.
; Then, *drop thru* to advance to next argument.
@@NonOpt:
dec si ; back up one character
inc cl
call get_Arg
; Skip over spaces until next argument is reached.
@@NextArg:
call skip_Spaces
or cl, cl
jnz @@ArgLoop
@@Fin:
ret
ENDP process_CmdLine
;--------------------------------------------------------------------------;
; E N T R Y P O I N T ;
;--------------------------------------------------------------------------;
;---- main --------------------------------------------------------------;
; Purpose: Main section of program. ;
; Notes: none ;
; Entry: Arguments as desired ;
; Exit: Return code as follows: ;
; 1 => on-line help requested ;
; 10 => errorlevel not found ;
; or errorlevel from previous program. ;
; Calls: process_CmdLine, fputs, get_ErrLvl, errmsg, fputc, utoa ;
; Changes: n/a ;
;--------------------------------------------------------------------------;
main:
; Process commandline arguments. If the variable HFlag is set, then
; on-line help is displayed and the program immediately terminates.
call process_CmdLine ; process commandline args
cmp [HFlag], 0 ; is help needed?
jz SHORT @@NoHelp ; no
mov bx, STDERR ; yes, write to STDERR
mov dx, OFFSET HelpMsg
call fputs
mov al, ERRH ; set return code
jmp SHORT @@Fin ; and jump to end of program
; Get errorlevel. Display error message and abort on failure.
@@NoHelp:
call get_ErrLvl ; get earlier errorlevel in AL
jnc SHORT @@ShowText ; continue; no problems
mov dx, OFFSET Err2Msg ; can't find errorlevel
call errmsg
mov al, ERRVDOS
jmp SHORT @@Fin
; Display any message text supplied by user. Follow it with a space.
@@ShowText:
mov bx, STDOUT ; everything to stdout
cmp [MsgLen], 0 ; anything to print out?
jz SHORT @@ShowErrLvl ; nope
mov dx, [MsgTxt] ; yes, display message text
call fputs
push ax
mov al, ' '
call fputc
pop ax
; Display errorlevel and end off with CR/LF.
@@ShowErrLvl:
ZERO ah ; only AL matters
mov di, OFFSET Value ; point to storage area
call utoa ; convert errlvl to string
mov dx, di ; display it
call fputs
mov dx, OFFSET EOL ; finish off display with CR/LF
inc dx
call fputs
; Ok, let's terminate the program and exit with proper return code in AL.
@@Fin:
mov ah, 4ch
int DOS
EVEN
Buffer db ? ; space for single character
; nb: shared by fgetc() & fputc()
;-------------------------------------------------------------------------;
; Purpose: Reads a character from specified device.
; Notes: No checks are done on BX's validity.
; Buffer is shared by fputc(). Do *NOT* use in a
; multitasking environment like DESQview.
; Requires: 8086-class CPU and DOS v2.0 or better.
; Entry: BX = device handle.
; Exit: AL = character,
; Carry flag set on error (AX holds error code).
; Calls: none
; Changes: AX
; flags
;-------------------------------------------------------------------------;
PROC fgetc
push cx dx
IF @DataSize NE 0
push ds
mov ax, @data
mov ds, ax
ENDIF
mov dx, OFFSET Buffer ; point to storage
mov cx, 1 ; only need 1 char
mov ah, 3fh
int DOS ; get it
jc SHORT @@Fin ; abort on error
mov al, [Buffer]
@@Fin:
IF @DataSize NE 0
pop ds
ENDIF
pop dx cx
ret
ENDP fgetc
;-------------------------------------------------------------------------;
; Purpose: Writes a character to specified device.
; Notes: No checks are done on BX's validity.
; Buffer is shared by fputc(). Do *NOT* use in a
; multitasking environment like DESQview.
; Requires: 8086-class CPU and DOS v2.0 or better.
; Entry: AL = character to display,
; BX = device handle.
; Exit: AL = 1 if successful,
; Carry flag set on error (AX holds error code).
; Calls: none
; Changes: AX
;-------------------------------------------------------------------------;
PROC fputc
push cx dx
IF @DataSize NE 0
push ds
mov dx, @data
mov ds, ax
ENDIF
mov dx, OFFSET Buffer ; point to storage
mov [Buffer], al ; save char
mov cx, 1 ; only write 1 char
mov ah, 40h
int DOS
IF @DataSize NE 0
pop ds
ENDIF
pop dx cx
ret
ENDP fputc
;-------------------------------------------------------------------------;
; Purpose: Reads a character from STDIN.
; Notes: Character is echoed to display.
; Requires: 8086-class CPU and DOS v1.0 or better.
; Entry: n/a
; Exit: AL = character.
; Calls: none
; Changes: AX
;-------------------------------------------------------------------------;
PROC getchar
mov ah, 1
int DOS
ret
ENDP getchar
;-------------------------------------------------------------------------;
; Purpose: Writes a character to STDOUT device.
; Notes: none
; Requires: 8086-class CPU and DOS v1.0 or better.
; Entry: DL = character to display.
; Exit: n/a
; Calls: none
; Changes: none
;-------------------------------------------------------------------------;
PROC putchar
push ax
mov ah, 2
int DOS
pop ax
ret
ENDP putchar
;-------------------------------------------------------------------------;
; Purpose: Checks if a character is ready for input from STDIN.
; Notes: none
; Requires: 8086-class CPU and DOS v1.0 or better.
; Entry: n/a
; Exit: zf = 1 if character available.
; Calls: none
; Changes: flags
;-------------------------------------------------------------------------;
PROC kbhit
push ax
mov ah, 0bh
int DOS
cmp al, 0ffh ; AL = FFh if character ready
pop ax
ret
ENDP kbhit
EVEN
;-------------------------------------------------------------------------;
; Purpose: Writes an ASCIIZ string to specified device.
; Notes: A zero-length string doesn't seem to cause problems when
; this output function is used.
; Requires: 8086-class CPU and DOS v2.0 or better.
; Entry: BX = device handle,
; DS:DX = pointer to string.
; Exit: Carry flag set if EOS wasn't found or handle is invalid.
; Calls: strlen
; Changes: none
;-------------------------------------------------------------------------;
PROC fputs
push ax cx di
IF @DataSize NE 0
push es
mov ax, ds
mov es, ax
ENDIF
mov di, dx
call strlen ; set CX = length of string
jc SHORT @@Fin ; abort if problem finding end
mov ah, 40h ; MS-DOS raw output function
int DOS
@@Fin:
IF @DataSize NE 0
pop es
ENDIF
pop di cx ax
ret
ENDP fputs
EVEN
;-------------------------------------------------------------------------;
; Purpose: Writes an error message to stderr.
; Notes: none
; Requires: 8086-class CPU and DOS v2.0 or better.
; Entry: DS:DX = pointer to error message.
; Exit: n/a
; Calls: fputs
; Changes: none
;-------------------------------------------------------------------------;
PROC errmsg
push bx dx
mov bx, STDERR
mov dx, OFFSET ProgName ; display program name
call fputs
pop dx ; recover calling parameters
push dx ; and save again to avoid change
call fputs ; display error message
mov dx, OFFSET EOL
call fputs
pop dx bx
ret
ENDP errmsg
EVEN
;-------------------------------------------------------------------------;
; Purpose: Gets version of DOS currently running.
; Notes: none
; Requires: 8086-class CPU and DOS v2.0 or better.
; Entry: n/a
; Exit: AL = major version number,
; AH = minor version number (2.1 = 10).
; Calls: none
; Changes: AX
;-------------------------------------------------------------------------;
PROC getvdos
push bx cx ; DOS destroys bx and cx!
mov ah, 30h
int DOS
pop cx bx
ret
ENDP getvdos
EVEN
;-------------------------------------------------------------------------;
; Purpose: Converts an *unsigned* integer in range [0, 65535] to
; an ASCIIZ string of digits.
; Notes: No checks are made to ensure storage area is big enough.
; A terminating null is added.
; Requires: 8086-class CPU.
; Entry: AX = unsigned integer value,
; ES:DI = pointer to string storage area.
; Exit: ES:DI = pointer to start of string.
; Calls: none
; Changes: DI
;-------------------------------------------------------------------------;
PROC utoa
push ax bx cx dx di
mov bx, 10 ; conversion factor
ZERO cx ; track # digits in string
@@NewDigit: ; for each character
ZERO dx ; dx:ax is dividend so make dx 0
div bx ; ax = dx:ax / 10
push dx ; dx = dx:ax mod 10
inc cl ; one more digit processed
or ax, ax ; anything left?
jnz @@NewDigit
@@NextChar: ; for each power of ten
pop ax
add al, '0'
mov [BYTE PTR di], al
inc di
loop @@NextChar
mov [BYTE PTR di], EOS ; don't forget to end it!
pop di dx cx bx ax
ret
ENDP utoa
EVEN
;-------------------------------------------------------------------------;
; Purpose: Converts character to lowercase.
; Notes: none
; Requires: 8086-class CPU.
; Entry: AL = character to be converted.
; Exit: AL = converted character.
; Calls: none
; Changes: AL
; flags
;-------------------------------------------------------------------------;
PROC tolower
cmp al, 'A' ; if < 'A' then done
jb SHORT @@Fin
cmp al, 'Z' ; if > 'Z' then done
ja SHORT @@Fin
or al, 20h ; make it lowercase
@@Fin:
ret
ENDP tolower
;-------------------------------------------------------------------------;
; Purpose: Converts character to uppercase.
; Notes: none
; Requires: 8086-class CPU.
; Entry: AL = character to be converted.
; Exit: AL = converted character.
; Calls: none
; Changes: AL
; flags
;-------------------------------------------------------------------------;
PROC toupper
cmp al, 'a' ; if < 'a' then done
jb SHORT @@Fin
cmp al, 'z' ; if > 'z' then done
ja SHORT @@Fin
and al, not 20h ; make it lowercase
@@Fin:
ret
ENDP toupper
EVEN
;-------------------------------------------------------------------------;
; Purpose: Calculates length of an ASCIIZ string.
; Notes: Terminal char is _not_ included in the count.
; Requires: 8086-class CPU.
; Entry: ES:DI = pointer to string.
; Exit: CX = length of string,
; cf = 0 and zf = 1 if EOS found,
; cf = 1 and zf = 0 if EOS not found within segment.
; Calls: none
; Changes: CX,
; flags
;-------------------------------------------------------------------------;
PROC strlen
push ax di
pushf
cld ; scan forward only
mov al, EOS ; character to search for
mov cx, di ; where are we now
not cx ; what's left in segment - 1
push cx ; save char count
repne scasb
je SHORT @@Done
scasb ; test final char
dec cx ; avoids trouble with "not" below
@@Done:
pop ax ; get original count
sub cx, ax ; subtract current count
not cx ; and invert it
popf ; restore df
dec di
cmp [BYTE PTR es:di], EOS
je SHORT @@Fin ; cf = 0 if equal
stc ; set cf => error
@@Fin:
pop di ax
ret
ENDP strlen
END