home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
assemblr
/
library
/
datetime
/
dat.asm
next >
Wrap
Assembly Source File
|
1991-11-10
|
34KB
|
909 lines
;--------------------------------------------------------------------------;
; Program: DAT .Asm ;
; Purpose: Displays current date and time. ;
; Notes: Compiles under TURBO Assembler, v2.0. Should work on any ;
; machine running MS-DOS, v2.xx or higher. ;
; 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: 06-Mar-90, v1.0, GAT ;
; - initial version. ;
; 13-Mar-90, v1.1, GAT ;
; - added n option to suppress final CR/LF sequence. ;
; 19-Mar-90, GAT ;
; - fixed up on-line help message. ;
; 22-Apr-90, v1.2, GAT ;
; - revised most procedures based on work with ASK. ;
; 05-May-90, GAT ;
; - fixed bug in handling of non-zero return codes. ;
; 12-Jun-90, GAT ;
; - fixed bug in conv_Int2Ascii wrt DI's final value. ;
; 08-Jul-90, GAT ;
; - added macros to push/pop registers. ;
; 28-Aug-90, v1.3a, GAT ;
; - put equates and macros in separate files. ;
; - put common routines in libs. ;
; - added equates for date/time separators. ;
; 12-Oct-91, v1.3b, GAT ;
; - revised include file names. ;
; - replaced references to Push_M and Pop_M macros with ;
; calls to push and pop. ;
; - removed local stack: it's not necessary. ;
;--------------------------------------------------------------------------;
;--------------------------------------------------------------------------;
; 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) ;
;--------------------------------------------------------------------------;
;--------------------------------------------------------------------------;
; 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
TSRMAGIC EQU 424bh ; magic number
STRUC ISR
Entry DW 10EBh ; short jump ahead 16 bytes
OldISR DD ? ; next ISR in chain
Sig DW TSRMAGIC ; magic number
EOIFlag DB ? ; 0 (80) if soft(hard)ware int
Reset DW ? ; short jump to hardware reset
Reserved DB 7 dup (0)
ENDS
STRUC ISRHOOK
Vector DB ? ; vector hooked
Entry DW ? ; offset of TSR entry point
ENDS
STRUC TSRSIG
Company DB 8 dup (" ") ; blank-padded company name
Product DB 8 dup (" ") ; blank-padded product name
Desc DB 64 dup (0) ; ASCIIZ product description
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 find_NextISR : PROC
GLOBAL find_PrevISR : PROC
GLOBAL hook_ISR : PROC
GLOBAL unhook_ISR : PROC
GLOBAL free_Env : PROC
GLOBAL fake_Env : PROC
GLOBAL check_ifInstalled : PROC
GLOBAL install_TSR : PROC
GLOBAL remove_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 memcmp : PROC
GLOBAL strchr : PROC
GLOBAL strcmp : PROC
GLOBAL strlen : PROC
GLOBAL tolower : PROC
GLOBAL toupper : PROC
VERSION equ '1.3b' ; current version of program
ERRH equ 1 ; errorlevel if help given
DATE_SEP equ '/' ; date separator
TIME_SEP equ ':' ; time separator
;--------------------------------------------------------------------------;
; 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
;--------------------------------------------------------------------------;
; D A T A ;
;--------------------------------------------------------------------------;
LABEL ProgName BYTE
db 'dat: ', EOS
LABEL EOL BYTE
db '.', CR, LF, EOS
LABEL HelpMsg BYTE
db CR, LF
db 'TifaWARE DAT, v', VERSION, ', ', ??Date
db ' - displays the current date and time.', CR, LF
db 'Usage: dat [-options] [msg]', CR, LF, LF
db 'Options:', CR, LF
db ' -d = display date', CR, LF
db ' -n = suppress final newline sequence', CR, LF
db ' -t = display time', CR, LF
db ' -? = display this help message', CR, LF, LF
db 'msg is an optional message to display before '
db 'the date or time.', CR, LF, EOS
LABEL Err1Msg BYTE
db 'illegal option -- '
LABEL OptCh BYTE
db ?
db EOS
LABEL TwoDigits BYTE ; space for two digits
db 2 dup (?), EOS
SwitCh db '-' ; char introducing options
HFlag db 0 ; flag for on-line help
DFlag db 0 ; flag for displaying date
NFlag db 0 ; flag for suppressing CR/LF
TFlag db 0 ; flag for displaying time
MsgLen db 0 ; length of message text
MsgTxt dw ? ; near pointer to message text
RCode db 0 ; program return code
;--------------------------------------------------------------------------;
; P R O C E D U R E S ;
;--------------------------------------------------------------------------;
;---- put_TwoDigits -----------------------------------------------------;
; Purpose: Displays a number between 0 and 99 on STDOUT with a leading ;
; 0 as necessary. ;
; Notes: No validity checks are done. ;
; Entry: AL = number to display. ;
; Exit: n/a ;
; Calls: utoa, putchar, fputs ;
; Changes: [TwoDigits] ;
;--------------------------------------------------------------------------;
PROC put_TwoDigits
push ax bx dx di
ZERO ah
mov bx, STDOUT
mov di, OFFSET TwoDigits
call utoa ; treat it as unsigned int
cmp al, 9 ; need a leading 0?
ja SHORT @@WriteIt
mov dl, '0'
call putchar
@@WriteIt:
mov dx, di
call fputs
pop di dx bx ax
ret
ENDP put_TwoDigits
;---- 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], [DFlag], [NFlag], [TFlag], ;
;--------------------------------------------------------------------------;
PROC get_Opt
mov [OptCh], al ; save for later
call tolower ; use only lowercase in cmp.
cmp al, 'd'
jz SHORT @@OptD
cmp al, 'n'
jz SHORT @@OptN
cmp al, 't'
jz SHORT @@OptT
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
jmp SHORT @@Fin
@@OptD:
mov [DFlag], 1 ; display date
jmp SHORT @@Fin
@@OptN:
mov [NFlag], 1 ; no final CR/LF
jmp SHORT @@Fin
@@OptT:
mov [TFlag], 1 ; display time
@@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. ;
; No arguments whatsoever causes help flag to be set. ;
; Entry: n/a ;
; Exit: n/a ;
; Calls: skip_Spaces, get_Opt, get_Arg ;
; Changes: AX, CX, SI, ;
; DX (get_Opt), ;
; [DFlag], [TFlag], ;
; [OptCh], [NFlag] (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 ; yep
mov [DFlag], 1 ; nope, so display date ...
mov [TFlag], 1 ; and time
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: ;
; 0 => program ran successfully ;
; 1 => on-line help requested ;
; Calls: process_CmdLine, fputs, putchar, getdate, put_TwoDigits, ;
; gettime ;
; 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 [RCode], ERRH ; yes, so set return code
mov bx, STDERR
mov dx, OFFSET HelpMsg ; point to help message
call fputs ; display it
jmp SHORT @@Fin ; and jump to end of program
;
; Display any message from commandline then get keypress from user.
;
@@NoHelp:
mov bx, STDOUT ; everything to stdout
cmp [MsgLen], 0 ; anything to print out?
jz SHORT @@Date? ; nope
mov dx, [MsgTxt] ; display message text
call fputs
mov dl, ' ' ; and a space
call putchar
@@Date?:
cmp [DFlag], 0
jz SHORT @@Time?
call getdate
mov al, dh ; dh = month
call put_TwoDigits
mov al, dl ; dl = day
mov dl, DATE_SEP ; now we can use dl for DATE_SEP
call putchar
call put_TwoDigits
call putchar ; dl still holds DATE_SEP
mov ax, cx ; cx = year
sub ax, 1900 ; assume 20th century
call put_TwoDigits
mov dl, ' '
call putchar
@@Time?:
cmp [TFlag], 0 ; display time?
jz SHORT @@FinalEOL? ; no
call gettime
mov al, ch ; ch = hour
call put_TwoDigits
mov dl, TIME_SEP
call putchar
mov al, cl ; cl = minutes
call put_TwoDigits
@@FinalEOL?:
cmp [NFlag], 0 ; suppress final CR/LF?
jnz SHORT @@Fin ; no
mov dx, OFFSET EOL+1
call fputs
;
; Ok, let's terminate the program and exit with proper return code.
;
@@Fin:
mov al, [RCode]
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 es
mov ax, ds
mov es, ax
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:
pop es 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 current system date, based on DOS's internal clock.
; Notes: none
; Requires: 8086-class CPU and DOS v1.0 or better.
; Entry: n/a
; Exit: AL = day of week (0 = Sunday)
; DL = day (1 to 31)
; DH = month (1 to 12)
; CX = year (1980 to 2099)
; Calls: none
; Changes: AX, CX, DX
;-------------------------------------------------------------------------;
PROC getdate
mov ah, 2ah ; MS-DOS get system date function
int DOS
ret
ENDP getdate
;-------------------------------------------------------------------------;
; Purpose: Gets current system time, based on DOS's internal clock.
; Notes: none
; Requires: 8086-class CPU and DOS v1.0 or better.
; Entry: n/a
; Exit: CL = minutes (0 - 59)
; CH = hour (0 - 23)
; DL = hundredths of seconds (0 - 99)
; DH = seconds (0 - 59)
; Calls: none
; Changes: CX, DX
;-------------------------------------------------------------------------;
PROC gettime
push ax
mov ah, 2ch ; MS-DOS get system time function
int DOS
pop ax
ret
ENDP gettime
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