        TITLE   me

_TEXT   SEGMENT
        ASSUME  cs:_TEXT, ds:_TEXT, ss:_TEXT, es:_TEXT
        ORG     100h


ESC_CHR         EQU     '$'             ; Escape character

;
; Command line escape sequence characters
;

DOLLAR          EQU     '$'             ; $ character
TIME            EQU     't'             ; Time
DATE            EQU     'd'             ; Date
CUR_DIR         EQU     'p'             ; Current directory
DOS_VER         EQU     'v'             ; DOS Version number
DRIVE           EQU     'n'             ; Default drive letter
GREATER         EQU     'g'             ; > character
LESS            EQU     'l'             ; < character
PIPE            EQU     'b'             ; | character
EQUAL           EQU     'q'             ; = character
BS              EQU     'h'             ; Backspace
ESCAPE          EQU     'e'             ; ESCape character
CR_LF           EQU     '_'             ; CR LF sequence

;
; Miscellanious equates
;

CR              EQU     0Ah
LF              EQU     0Dh

char_ptr        EQU     [bx+82h]

;
; Macro declarations
;

out_chr         MACRO   p1              ;; Display a character
                mov     ah, 02h
                mov     dl, p1          ;; Character to be displayed
                int     21h             ;; DOS interrupt
                ENDM

out_str         MACRO   p1              ;; Display a $ terminated string
                mov     ah, 09h
                mov     dx, offset p1
                int     21h
                ENDM

is_it           MACRO   p1, p2          ;; Compare characters
                cmp     byte ptr p2, p1 ;; Compare supplied values
                ENDM

tolower         MACRO   p1
                LOCAL   no_conversion           ;; Local label name
                cmp     byte ptr p1, 'A'
                jl      no_conversion
                cmp     byte ptr p1, 'Z'
                jg      no_conversion
                or      byte ptr p1, 20h        ;; Convert to lowercase
no_conversion:
                ENDM

ascii_z         MACRO   p1                      ;; Output a zero terminated string
                LOCAL   loop, done
                mov     si, 0
loop:
                cmp     p1[si], 0
                je      done
                out_chr p1[si]
                inc     si
                jmp     loop
done:
                ENDM

pr_byte         MACRO   p1

                mov     ah, p1
                mov     save, ah                ;; Save value of AH
                mov     al, save                ;; Restore to AL
                mov     ah, 0                   ;; Zero AH
                cwd
                mov     bl, 10                  ;; Divide by 10
                div     bl                      ;; Integer divide
                add     al, '0'                 ;; Make ASCII
                mov     temp, al                ;; Move to print area
                add     ah, '0'                 ;; NEW
                mov     save, ah                ;; NEW
                out_chr temp                    ;; Print character
                out_chr save                    ;; NEW

;               mov     ah, 0                   ;; Zero AH
;               mov     al, save                ;; Restore saved value
;               cwd
;               mov     bl, 10
;               div     bl
;               add     ah, '0'                 ;; Make remainder ASCII
;               mov     temp, ah                ;; More to print area
;               out_chr temp                    ;; Print character

                ENDM

start:  jmp     begin                   ; Jump over data

;
; Data declarations
;

tm_fmt  db      3                       ; Time format
                                        ; 1 - MM/DD/YYYY
                                        ; 2 - MM/DD/YY
                                        ; 3 - DDD MM/DD/YYYY

sun     db      'Sun$'
mon     db      'Mon$'
tue     db      'Tue$'
wed     db      'Wed$'
thu     db      'Thu$'
fri     db      'Fri$'
sat     db      'Sat$'

day_num db      0

temp    db      0
save    db      0

month   db      0
day     db      0
century db      0
year    db      0

hours   db      0
minutes db      0
seconds db      0

save_bx dw      ?
save_cx dw      ?

major   db      0
minor   db      0

huh     db      CR, LF, 7, 'Unknown escape sequence - $'
dir     db      67 dup (?)
not_yet db      CR, LF, 7, 'Escape sequence not implemented - $', CR, LF

usage   db              'MyEcho - Version 1.00 (Production)'
        db      CR, LF, 'Copyright (C) 1988, 1989 by Mark G. Plancke'
        db      CR, LF, 'To form an escape sequence you must first specify the escape character - "$",'
        db      CR, LF, 'followed by one of the characters listed below.'
        db      CR, LF
        db      CR, LF, 'ESC Sequence   Description'
        db      CR, LF, '    $          The escape character'
        db      CR, LF, '    $$         Print the dollar sign'
        db      CR, LF, '    $T         Print the time'
        db      CR, LF, '    $D         Print the date'
        db      CR, LF, '    $P         Print the current directory'
        db      CR, LF, '    $V         Print the DOS version'
        db      CR, LF, '    $N         Print the default drive'
        db      CR, LF, '    $G         Print the > character'
        db      CR, LF, '    $L         Print the < character'
        db      CR, LF, '    $B         Print the | character'
        db      CR, LF, '    $Q         Print the = character'
        db      CR, LF, '    $H         Print the back space character'
        db      CR, LF, '    $E         Print the escape character'
        db      CR, LF, '    $_         Print a CR/LF sequence'
        db      CR, LF
        db      CR, LF, 'For example, the command line - "$P$GHello" would result in "C:\DIR>Hello"'
        db      CR, LF, 'being printed. This program can be used to enter ANSI escape sequences as well.'
        db      0


begin:
        mov     si, 80h                 ; Offset command line length
        mov     cl, es:[si]             ; Get command line length
        xor     ch, ch                  ; Test for null
        cmp     cx, 0
        jne     commands_there
        call    pr_usage                ; Print help screen
        jmp     exit_prog

commands_there:
        dec     cl                      ; Subtract one byte - for leading blank

        mov     bx, 0                   ; Initialize counter

main_loop:
        mov     al, ESC_CHR
        cmp     byte ptr char_ptr, al   ; Is this an escape sequence?

        je      escape_seq              ; Yes, process it

        out_chr char_ptr                ; Display character

resume:
        inc     bx                      ; Increment character pointer
        cmp     bx, cx                  ; End of string?
        jnz     main_loop               ; No, get next character

        mov     al, 0                   ; Set exit code
exit_prog:
        mov     ah, 4ch                 ; DOS exit
        int     21h                     ; Terminate

;
; Evaluate escape sequences
;

escape_seq:
        inc     bx                      ; Advance to next character
        cmp     bx, cx                  ; Are we past the end of line?
        jnz     esc_DOLLAR              ; No, evaluate next character
        jmp     esc_UNKNOWN             ; Yes, display error message

esc_DOLLAR:
        tolower char_ptr                ; Convert to lowercase
        is_it   DOLLAR, char_ptr        ; Is it a dollar escape?
        jne     esc_TIME                ; No, check next in line
        out_chr '$'                     ; Display a dollar sign
        jmp     resume                  ; Get next character

esc_TIME:
        is_it   TIME, char_ptr
        jne     esc_DATE
        call    disp_time
        jmp     resume

esc_DATE:
        is_it   DATE, char_ptr
        jne     esc_CUR_DIR
        call    disp_date
        jmp     resume

esc_CUR_DIR:
        is_it   CUR_DIR, char_ptr
        jne     esc_DOS_VER
        call    disp_cur_dir
        jmp     resume

esc_DOS_VER:
        is_it   DOS_VER, char_ptr
        jne     esc_DRIVE
        call    disp_dos_ver
        jmp     resume

esc_DRIVE:
        is_it   DRIVE, char_ptr
        jne     esc_GREATER
        call    disp_drive
        jmp     resume

esc_GREATER:
        is_it   GREATER, char_ptr
        jne     esc_LESS
        out_chr '>'
        jmp     resume

esc_LESS:
        is_it   LESS, char_ptr
        jne     esc_PIPE
        out_chr '<'
        jmp     resume


esc_PIPE:
        is_it   PIPE, char_ptr
        jne     esc_EQUAL
        out_chr '|'
        jmp     resume

esc_EQUAL:
        is_it   EQUAL, char_ptr
        jne     esc_BS
        out_chr '='
        jmp     resume

esc_BS:
        is_it   BS, char_ptr
        jne     esc_ESCAPE
        out_chr 09h
        jmp     resume

esc_ESCAPE:
        is_it   ESCAPE, char_ptr
        jne     esc_CRLF
        out_chr 1Bh
        jmp     resume

esc_CRLF:
        is_it   CR_LF, char_ptr
        jne     esc_UNKNOWN
        out_chr CR
        out_chr LF
        jmp     resume

esc_UNKNOWN:
        out_str huh                     ; Display error message
        out_chr '$'                     ; Display escape sequence...
        out_chr char_ptr
        out_chr CR
        out_chr LF
        call    pr_usage
        mov     al, 1                   ; Set exit code
        jmp     exit_prog               ; Terminate program

;
; Subroutines
;

;
; Pr_Usage
;
pr_usage        proc
        ascii_z usage
        ret
pr_usage        endp

;
; Display time
;
disp_time       proc
        mov     save_bx, bx
        mov     save_cx, cx

        mov     ah, 2Ch
        int     21h

        mov     hours, ch
        mov     minutes, cl
        mov     seconds, dh

        pr_byte hours
        out_chr ':'
        pr_byte minutes
        out_chr ':'
        pr_byte seconds

        mov     bx, save_bx
        mov     cx, save_cx

        ret
disp_time       endp
;
; Display date
;
disp_date       proc

        mov     save_bx, bx
        mov     save_cx, cx

        mov     ah, 2Ah                 ; Get current date
        int     21h                     ; Time of day service

        mov     day_num, al
        mov     month, dh
        mov     day, dl
        mov     ax, cx
        cwd
        mov     bl, 100
        div     bl

        mov     century, al
        mov     year, ah

        cmp     tm_fmt, 3
        jnz     skip_day


        cmp     day_num, 0
        jnz     mon_chk
        out_str sun
        jmp     done_day

mon_chk:
        cmp     day_num, 1
        jnz     tue_chk
        out_str mon
        jmp     done_day

tue_chk:

        cmp     day_num, 2
        jnz     wed_chk
        out_str tue
        jmp     done_day

wed_chk:
        cmp     day_num, 3
        jnz     thu_chk
        out_str wed
        jmp     done_day

thu_chk:
        cmp     day_num, 4
        jnz     fri_chk
        out_str thu
        jmp     done_day

fri_chk:
        cmp     day_num, 5
        jnz     sat_chk
        out_str fri
        jmp     done_day

sat_chk:
        out_str sat

done_day:
        out_chr ' '

skip_day:

        pr_byte month
        out_chr '/'
        pr_byte day
        out_chr '/'

        cmp     tm_fmt, 2
        jz      disp_year

        pr_byte century

disp_year:

        pr_byte year

        mov     bx, save_bx
        mov     cx, save_cx
        ret

disp_date       endp
;
; Display current directory
;
disp_cur_dir    proc
        mov     ah,19h                  ; Get default drive code
        int     21h                     ; DOS interrupt
        mov     dir[0], al              ; Move to display area
        add     dir[0], 'A'             ; Make into drive letter
        mov     dir[1], ':'             ; Assign colon and
        mov     dir[2], '\'             ; Slash
        mov     ah, 47h                 ; DOS function - current directory
        mov     dl, 0                   ; Current drive
        mov     si, offset dir + 3      ; Address of receiveing string
        int     21h                     ; DOS interrupt
        ascii_z dir                     ; Display string
        ret
disp_cur_dir    endp
;
; Display DOS version
;
disp_dos_ver    proc
        mov     save_bx, bx
        mov     save_cx, cx

        mov     ah, 030h
        int     21h

        mov     major, al
        mov     minor, ah

        pr_byte major
        out_chr '.'
        pr_byte minor

        mov     bx, save_bx
        mov     cx, save_cx

        ret
disp_dos_ver    endp
;
; Display drive
;
disp_drive      proc
        mov     ah,19h                  ; Get default drive code
        int     21h                     ; DOS interrupt
        mov     dir[0], al              ; Move to display area
        add     dir[0], 'A'             ; Make into drive letter
        out_chr dir[0]                  ; Display string
        ret
disp_drive      endp

_TEXT   ends
        end     start
