programming-examples/assembly/Assembly language program which shows the current date and time in a form identical to that used by Posix ctime() .asm
2019-11-15 12:59:38 +01:00

325 lines
9.7 KiB
NASM

; showdate.asm
;
; prints the date and time to stdout
; equivalent to the following C++ program:
;
;#include <iostream.h>
;#include <time.h>
;
;int main()
;{
; time_t t;
; time(&t); // get the current time
; cout << ctime(&t); // convert to string and print
; return 0;
;}
;
; This code may be assembled and linked using Borland's TASM:
; tasm /la /m2 showdate
; tlink /Tdc showdate
;
STDOUT equ 01h ; handle of standard output device
DOS_GET_DATE equ 02ah ; get system date
DOS_GET_TIME equ 02ch ; get system time
DOS_WRITE_HANDLE equ 040h ; write to handle
DOS_TERMINATE equ 04ch ; terminate with error code
DOSINT macro function, subfunction
IFB <subfunction>
mov ah,(function AND 0ffh)
ELSE
mov ax,(function SHL 8) OR (subfunction AND 0ffh)
ENDIF
int 21h ; invoke DOS function
endm
MODEL tiny
;.STACK 100h
.CODE
;****************************************************************************
; main
;
; calls showdate routne and exists with 00 error code
;
; Entry:
;
; Exit:
;
; Trashed:
; none
;
;****************************************************************************
main proc far
.STARTUP ; sets up DS and stack
call showdate ;
.EXIT 0 ; return with errcode=0
main endp
;****************************************************************************
; showdate
;
; fetches the DOS system date, prints it to stdout and exits
; the format of the output is identical to that of the Posix ctime()
; function:
;
; Thu May 11 16:11:30 2000
;
; The day of week and month are always 3 characters long. The time of
; day is in 24hour form (e.g. 16:11:30 is a few minutes after four in
; the afternoon) and the year is always four digits. The whole thing is
; followed by a newline character (line feed = 0ah), making 25
; characters total.
;
; Note that ctime() returns 26 characters which is all of the above,
; followed by a terminating NUL char but this program does not emit a
; NUL.)
;
; Entry:
; DS points to segment for our data tables
;
; Exit:
; carry may be set if last write failed
;
; Trashed:
; none
;
;****************************************************************************
showdate proc
push ax bx cx dx ;
DOSINT DOS_GET_DATE ;
; returns the following
; cx = year (1980-2099)
; dh = month (1-12) == (Jan..Dec)
; dl = day (1-31)
; al = day of week (0-6) == (Sun..Sat)
push cx ;
push dx ; save the return values
; write the day of week
mov dx, offset dayname ;
mov cx,3 ; number of bytes to write
call WriteSubstring ;
; write the month
pop ax ; recall month/day
push ax ; and save it again
mov al,ah ; isolate just month
mov dx, offset monthname - 3 ; monthname array is 1-based
mov cx,3 ; number of bytes to write
call WriteSubstring ;
; write the day of the month
pop ax ;
call WriteNumber ;
call WriteSpace ;
; write the hour
DOSINT DOS_GET_TIME ; ch = hour, cl = min,
; dh = sec, dl = hundredths
push dx ; save seconds
push cx ; save minutes
mov al,ch ;
call WriteNumber ;
call WriteColon ;
; write the minutes
pop ax ;
call WriteNumber ;
call WriteColon ;
; write the seconds
pop ax ;
mov al,ah ;
call WriteNumber ;
call WriteSpace ;
; write the year (century first)
pop ax ;
xor dx,dx ; clear other reg before divide
mov cx,100 ; ax = ax/100, dx = remainder
div cx ;
push dx ; save remainder
call WriteNumber ;
; write the year (year within century)
pop ax ;
call WriteNumber ;
mov dx,offset newlinechar
call PrintOne ;
pop dx cx bx ax ; restore stack
ret ;
showdate endp
;****************************************************************************
; WriteSubstring
;
; writes a short substring to stdout
; specifically, prints CL characters, starting at DS:(DX+CL*AL)
;
; Entry:
; DS:DX ==> pointer to base of string array
; CL = size of each string
; AL = string selector (i.e. which string)
;
; Exit:
; CY set if there was an error writing last byte
; if CY clear,
; AX = 1 (number of bytes written)
; else
; AX = error code
;
; Trashed:
; BX CX DX
;
;****************************************************************************
WriteSubstring proc
mul cl ; ax = cl * al
add dx,ax ; offset now points to appropriate day string
call PrintIt ;
WriteSubstring endp
; deliberately fall through
;****************************************************************************
; WriteSpace
;
; writes a single space character (20h) to stdout
;
; Entry:
; DS points to data table segment
;
; Exit:
; CY set if there was an error writing last byte
; if CY clear,
; AX = 1 (number of bytes written)
; else
; AX = error code
;
; Trashed:
; BX CX DX
;
;****************************************************************************
WriteSpace proc
mov dx,offset spacechar;
WriteSpace endp
; deliberately fall through
;****************************************************************************
; PrintOne
;
; prints a single character pointed to by DS:DX
;
; Entry:
; DS:DX ==> points to the character to be printed
;
; Exit:
; CY set if there was an error writing last byte
; if CY clear,
; AX = 1 (number of bytes written)
; else
; AX = error code
;
; Trashed:
; BX CX DX
;
;****************************************************************************
PrintOne proc
mov cx,1 ;
PrintOne endp
; deliberately fall through
;****************************************************************************
; PrintIt
;
; prints the passed string to stdout
;
; Entry:
; DS:DX ==> points to string to be printed
; CX = number of bytes to be printed
;
; Exit:
; CY set if there was an error writing to stdout
; if CY clear,
; AX = number of bytes written
; else
; AX = error code
;
; Trashed:
; none
;
;****************************************************************************
PrintIt proc
mov bx,STDOUT ;
DOSINT DOS_WRITE_HANDLE ; write to the file
ret ;
PrintIt endp
;****************************************************************************
; WriteColon
;
; writes a colon character to stdout
;
; Entry:
; DS points to data segment
;
; Exit:
; CY set if there was an error writing to stdout
; if CY clear,
; AX = 1 (number of bytes written)
; else
; AX = error code
;
; Trashed:
; none
;
;****************************************************************************
WriteColon proc
mov dx,offset colonchar;
jmp PrintOne ;
WriteColon endp
;****************************************************************************
; WriteNumber
;
; prints the number in AL to stdout as two decimal digits
;
; Entry:
; AL = number to be printed. It must be in the range 00-99
;
; Exit:
; CY set if there was an error writing to stdout
; if CY clear,
; AX = 2 (number of bytes written)
; else
; AX = error code
;
; Trashed:
; BX CX DX
;
;****************************************************************************
WriteNumber proc
xor ah,ah ; clear out high half
mov cl,10 ; prepare to convert to decimal (base 10)
div cl ; divide it out
or ax,3030h ; convert to ASCII digits
push ds ; remember DS for later
push ax ; push converted chars on stack
mov dx,ss ;
mov ds,dx ; ds = ss
mov dx,sp ; print data from stack
mov cx,2 ; two characters only
call PrintIt ;
pop bx ; fix stack
pop ds ; restore ds pointer
ret ;
WriteNumber endp
;.DATA
dayname db "SunMonTueWedThuFriSat"
monthname db "JanFebMarAprMayJunJulAugSepOctNovDec"
spacechar db " "
colonchar db ":"
newlinechar db 0ah ; in C this is \n
end