home *** CD-ROM | disk | FTP | other *** search
- ;--------------------------------------------------------------------------;
- ; 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. ;
- ;--------------------------------------------------------------------------;
-
- ;--------------------------------------------------------------------------;
- ; Author: George A. Theall ;
- ; Phone: +1 215 662 0558 ;
- ; SnailMail: TifaWARE ;
- ; 506 South 41st St., #3M ;
- ; Philadelphia, PA. 19104 USA ;
- ; E-Mail: GTHEALL@PENNDRLS.UPENN.EDU (Internet) ;
- ;--------------------------------------------------------------------------;
-
- ;--------------------------------------------------------------------------;
- ; D I R E C T I V E S ;
- ;--------------------------------------------------------------------------;
- DOSSEG
- MODEL tiny
-
- IDEAL
- LOCALS
- JUMPS
-
- ;
- ; This section comes from D:\ASM\INCLUDE\Equates.Inc.
- ;
- EOS EQU 0 ; terminates strings
- 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
-
- ;
- ; This section comes from D:\ASM\INCLUDE\Macros.Inc.
- ;
- MACRO Pop_M RegList ;; Pops registers off stack.
- IRP Reg, <RegList>
- IFIDNI <Reg>, <flags>
- popf
- ELSE
- pop Reg
- ENDIF
- ENDM
- ENDM
- MACRO Push_M RegList ;; Pushes registers onto stack.
- IRP Reg, <RegList>
- IFIDNI <Reg>, <flags>
- pushf
- ELSE
- push Reg
- ENDIF
- ENDM
- ENDM
- MACRO Zero Reg ;; Zeros any register.
- xor Reg, Reg
- ENDM
-
-
- 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, v1.3a, ', ??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
-
-
- ;--------------------------------------------------------------------------;
- ; L O C A L S T A C K ;
- ;--------------------------------------------------------------------------;
- db 16 dup("STACK ") ; 128 bytes for local stack
- StackTop = $
-
-
- ;--------------------------------------------------------------------------;
- ; 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_M <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_M <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, 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:
- mov sp, OFFSET StackTop ; set up local stack
-
- ;
- ; 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
- ;-------------------------------------------------------------------------;
- ; 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
-
-
- EVEN
- ;-------------------------------------------------------------------------;
- ; 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: 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
-
- IF @DataSize EQ 0
- Push_M <ax, cx, di>
- ELSE
- Push_M <ax, cx, di, 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 EQ 0
- Pop_M <di, cx, ax>
- ELSE
- Pop_M <es, di, cx, ax>
- ENDIF
- ret
-
- ENDP fputs
-
-
- EVEN
- ;-------------------------------------------------------------------------;
- ; 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
-
-
- 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_M <bx, dx>
- push dx ; save again calling parameters
- mov bx, STDERR
- mov dx, OFFSET ProgName ; display program name
- call fputs
- pop dx ; recover calling parameters
- call fputs ; display error message
- mov dx, OFFSET EOL
- call fputs
- Pop_M <dx, bx>
- ret
-
- ENDP errmsg
-
-
- 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_M <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_M <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
-
-
- 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_M <ax, di, flags>
- 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_M <di, ax>
- ret
-
- ENDP strlen
-
-
- END
-