        TITLE   'Prm - RxDOS Command Shell Prompt, Date, and Time'
        PAGE 59, 132
        .LALL

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  RxDOS Command Shell Prompt, Date, and Time                   ;
        ;...............................................................;

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Real Time Dos                                                ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  This material  was created as a published version  of a DOS  ;
        ;  equivalent product.   This program  logically  functions in  ;
        ;  the same way as  MSDOS functions and it  is  internal  data  ;
        ;  structure compliant with MSDOS 6.0                           ;
        ;                                                               ;
        ;  This product is distributed  AS IS and contains no warranty  ;
        ;  whatsoever,   including  warranty  of   merchantability  or  ;
        ;  fitness for a particular purpose.                            ;
        ;                                                               ;
        ;                                                               ;
        ;  (c) Copyright 1990, 1997. Api Software and Mike Podanoffsky  ;
        ;      All Rights Reserved Worldwide.                           ;
        ;                                                               ;
        ;  This product is protected under copyright laws and  may not  ;
        ;  be reproduced  in whole  or in part, in any form  or media,  ;
        ;  included but not limited to source listing, facsimile, data  ;
        ;  transmission, cd-rom, or  floppy disk without the expressed  ;
        ;  written consent of the author.                               ;
        ;                                                               ;
        ;  License  for  distribution  for commercial  use  or  resale  ;
        ;  required from:                                               ;
        ;                                                               ;
        ;  Api Software                                                 ;
        ;  12 South Walker Street                                       ;
        ;  Lowell,  MA   01851                                          ;
        ;                                                               ;
        ;  internet: mikep@world.std.com                                ;
        ;                                                               ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;  Compile with MASM 5.1                                        ;
        ;...............................................................;

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  RxDOS Command Shell                                          ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Programmer's Notes:                                          ;
        ;                                                               ;
        ;  Command Shell consists of  two parts bound  together into a  ;
        ;  single executable load.  There  exists  a  single  resident  ;
        ;  command shell which is accessible by an Int 2Eh.             ;
        ;                                                               ;
        ;...............................................................;

        include rxdosmac.asm
        include rxdosdef.asm
        include rxdoscin.asm

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  RxDOS Command Shell                                          ;
        ;...............................................................;

RxDOSCMD SEGMENT PUBLIC 'CODE'
         assume cs:RxDOSCMD, ds:RxDOSCMD, es:RxDOSCMD, ss:RxDOSCMD

        public DisplayPrompt
        public formatCurrentDate
        public formatCurrentTime

        public _Prompt
        public _Date
        public _Time

        extrn CheckOptOneArg                            : near
        extrn _sprintf                                  : near
        extrn DisplayLine                               : near
        extrn _GetNumber                                : near
        extrn _getStdinLine                             : near
        extrn RxDOS_DefaultPrompt                       : near
        extrn RxDOS_Prompt                              : near
        extrn _CopyString                               : near
        extrn RxDOS_PromptSpec                          : near
        extrn searchEnvVariable                         : near
        extrn deleteEnvVariable                         : near
        extrn insertEnvVariable                         : near
        extrn _PleaseEnterDate                          : near
        extrn _ShowCurrentDate                          : near
        extrn _ShowCurrentTime                          : near
        extrn _PleaseEnterTime                          : near
        extrn CmndError_InvalidDate                     : near
        extrn CmndError_InvalidTime                     : near
        extrn CmndError_OutOfEnvironmentSpace           : near
        extrn DisplayErrorMessage                       : near
        extrn DisplayOutEnvSpace                        : near

        extrn _lowerCase                                : near
        extrn CRLF                                      : near
        extrn RxDOS_Version                             : near
        extrn RxDOSIntl_DateTemplate                    : near
        extrn RxDOSIntl_DayOfWeek                       : near
        extrn RxDOSIntl_TimeTemplate                    : near
        extrn RxDOSIntl_DateTimeTable                   : near

        extrn _EnvSegment                               : word


        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Display Prompt                                               ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Usage:                                                       ;
        ;   $q     =                                                    ;
        ;   $$     $                                                    ;
        ;   $t     time                                                 ;
        ;   $d     date                                                 ;
        ;   $p     drive:path                                           ;
        ;   $v     current rxdos version                                ;
        ;   $n     drive                                                ;
        ;   $g     >                                                    ;
        ;   $l     <                                                    ;
        ;   $b     | (pipe)                                             ;
        ;   $_     cr lf                                                ;
        ;   $e     esc                                                  ;
        ;   $h     backspace                                            ;
        ;...............................................................;

DisplayPrompt:

        Entry
        defbytes _buffer, 128

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  locate init (env) prompt string
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        push di

        mov si, offset RxDOS_PromptSpec
        call searchEnvVariable                          ; locate prompt= spec
        jnz DisplayPrompt_06                            ; if none --> 

        push ds
        add di, dx                                      ; point to env string
        mov si, offset RxDOS_Prompt
        mov ds, word ptr [ _EnvSegment ]                ; seg of env strings
        xchg di, si
        call _CopyString
        pop ds

DisplayPrompt_06:
        mov si, offset RxDOS_Prompt
        lea di, offset [ _buffer ][ bp ]
        mov byte ptr [ di ], 00

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  scan prompt
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DisplayPrompt_08:
        lodsb

DisplayPrompt_10:
        stosb
        or al, al
        ifz DisplayPrompt_48

        cmp al, '$'
        jnz DisplayPrompt_08

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  special case
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        dec di
        lodsb
        or al, al 
        ifz DisplayPrompt_48

        call _lowerCase
        Translate 'q', '=', DisplayPrompt_18
        Translate '$', '$', DisplayPrompt_18
        Translate 'g', '>', DisplayPrompt_18
        Translate 'l', '<', DisplayPrompt_18
        Translate 'b', '|', DisplayPrompt_18
        Translate 'e', '['-40h, DisplayPrompt_18

        cmp al, 't'                             
        ifz DisplayPrompt_Time                          ; $t time -->
        cmp al, 'd'
        ifz DisplayPrompt_Date                          ; $d date -->
        cmp al, 'p'
        ifz DisplayPrompt_Path                          ; $p path -->
        cmp al, 'v'
        ifz DisplayPrompt_Version                       ; $v version -->
        cmp al, 'n'
        ifz DisplayPrompt_Drive                         ; $d drive -->
        cmp al, '_'
        jz DisplayPrompt_CRLF                           ; $_ crlf -->
        cmp al, 'h'
        jz DisplayPrompt_Backspace                      ; $b backspace -->
        jmp DisplayPrompt_10

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  translate 
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DisplayPrompt_18:

        mov al, ah
        stosb                                           ; translated value
        jmp DisplayPrompt_08

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  backspace
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DisplayPrompt_Backspace:
        
        dec di
        jmp DisplayPrompt_08

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  cr lf
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DisplayPrompt_CRLF:

        mov ax, 0a0dh
        stosw
        jmp DisplayPrompt_08

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  time of day
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DisplayPrompt_Time:

        call formatCurrentTime
        jmp DisplayPrompt_08

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  date
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DisplayPrompt_Date:

        call formatCurrentDate
        jmp DisplayPrompt_08

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  path
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DisplayPrompt_Path:

        push si

        Int21 CurrentDisk 
        mov dl, al                                      ; save drive letter
        add al, 'A'                                     ; get drive
        stosb

        mov ax, '\:'
        stosw                                           ; d:\ ...

        inc dl
        mov si, di
        mov byte ptr [ si ], 0
        Int21 GetCurrentDirectory                       ; get current directory

DisplayPrompt_Path_08:
        lodsb
        or al, al
        jnz DisplayPrompt_Path_08

        dec si
        mov di, si

        pop si        
        jmp DisplayPrompt_08
        
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  version
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DisplayPrompt_Version:

        push si
        mov si, offset RxDOS_Version
        call _CopyString
        dec di
        pop si
        jmp DisplayPrompt_08

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  drive letter
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DisplayPrompt_Drive:

        Int21 CurrentDisk
        add al, 'A'                                     ; get drive
        stosb
        jmp DisplayPrompt_08

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  display prompt
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DisplayPrompt_48:
        lea dx, offset [ _buffer ][ bp ]
        call Displayline

        pop di
        Return

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Convert AL To 2 Char Decimal                                 ;
        ;...............................................................;

ConvTo2CharDecimal:

        push cx
        xor ah, ah
        mov cl, 10
        div cl
        or ax, '00'
        stosw

        pop cx
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Convert AX To 4 Char Decimal                                 ;
        ;...............................................................;

ConvTo4CharDecimal:

        push cx
        add di, 4
        push di

__4CharDecimal_04:
        xor dx, dx
        mov cx, 10
        div cx

        dec di
        or dl, '0'
        mov byte ptr [ di ], dl

        or ax, ax
        jnz __4CharDecimal_04

        pop di
        pop cx
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Format Date String                                           ;
        ;...............................................................;

formatCurrentDate:
        
        Entry
        defbytes _countryInfo, sizeCOUNTRYINFO

        push si
        push di
        mov si, offset RxDOSIntl_DateTemplate
        call _CopyString

    ; eventually, make this international

        lea dx, offset [ _countryInfo ][ bp ]
        Int21 CountryDependentInfo, 00                  ; get country info

        Int21 GetDate

        pop di
        xor ah, ah
        mov si, ax
        add si, si
        add si, ax                                      ; offset to day of week text
        add si, offset RxDOSIntl_DayOfWeek

        push cx
        mov cx, 3
        rep movsb                                       ; copy 3 bytes

        inc di
        mov al, dh                                      ; mon
        call ConvTo2CharDecimal

        inc di
        mov al, dl                                      ; day
        call ConvTo2CharDecimal

        inc di
        pop ax                                          ; year
        call ConvTo4CharDecimal

        pop si
        Return

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Format Time String                                           ;
        ;...............................................................;

formatCurrentTime:

        Entry
        defbytes _countryInfo, sizeCOUNTRYINFO

        push si
        push di
        mov si, offset RxDOSIntl_TimeTemplate
        call _CopyString

    ; eventually, make this international

        lea dx, offset [ _countryInfo ][ bp ]
        Int21 CountryDependentInfo, 00                  ; get country info

        Int21 GetTime

        pop di
        mov al, ch                                      ; hours
        call ConvTo2CharDecimal

        inc di
        mov al, cl                                      ; minutes
        call ConvTo2CharDecimal

        inc di
        mov al, dh                                      ; seconds
        call ConvTo2CharDecimal

        inc di
        mov al, dh                                      ; hundreths
        call ConvTo2CharDecimal

        pop si
        Return

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Date [ date ]                                                ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Usage:                                                       ;
        ;   ss:di  Arg Array                                            ;
        ;   ax     Number of arguments in array                         ;
        ;...............................................................;

_Date:

        Entry
        def __argarray, di                              ; args array
        defwords _parsedDatePtrs, 3
        defbytes _parsedDate, sizeDATE
        defbytes _buffer, 128                           ; input buffer
        defbytes _printbuffer, 128

      ;  call CheckOptOneArg                             ; see if 1 arg 
      ;  ifc _dateInvalid                                ; if error in args 

        mov si, word ptr [ di ]                         ; get first arg
        or si, si                                       ; if arg, go parse -->
        jnz _date_26

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  display current date
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        lea di, offset [ _buffer ][ bp ]
        push di                                         ; address of 
        call formatCurrentDate                          ; get current date

        mov di, offset _ShowCurrentDate
        push di
        lea di, offset [ _printbuffer ][ bp ]
        push di
        call _sprintf
        add sp, ax                                      ; # args passed
        call DisplayLine

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  please enter date
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_date_12:
        call DisplayPleaseEnterDate

        lea di, offset [ _buffer ][ bp ]
        mov byte ptr [ bufMaxLength ][ di ], 128
        mov word ptr [ bufActualLength ][ di ], 0

        mov dx, di                                      ; where buffer
        call _getStdinLine                              ; read buffer
        call CRLF

        mov bl, byte ptr [ _buffer. bufActualLength ][ bp ]
        and bx, 255
        ifz _dateReturn

        add bx, bp
        mov byte ptr [ _buffer. bufData ][ bx ], 00     ; place a null terminator
        lea si, offset [ _buffer. bufData ][ bp ]       ; parse text
        
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  parse arg at [ si ]
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_date_26:
        push si                                         ; pointer to start of first arg
        lea si, offset [ _parsedDate ][ bp ]            ; start of buffer
        lea di, offset [ _parsedDatePtrs ][ bp ]
        call _GetDateTemplate

        pop si
        call _GetNumber                                 ; get argument
        mov di, word ptr [ _parsedDatePtrs ][ bp ]
        mov word ptr ss:[ di ], dx                      ; store first argument

        cmp byte ptr [ si-1 ], '-'
        jz  _date_28
        cmp byte ptr [ si-1 ], '/'        
        jz  _date_28
        cmp byte ptr [ si-1 ], '.'        
        jnz  _dateInvalid                               ; else invalid -->

_date_28:
        call _GetNumber                                 ; get argument
        mov di, word ptr [ _parsedDatePtrs + 2 ][ bp ]
        mov word ptr ss:[ di ], dx                      ; store second argument

        cmp byte ptr [ si-1 ], '-'
        jz  _date_32
        cmp byte ptr [ si-1 ], '/'        
        jz  _date_32
        cmp byte ptr [ si-1 ], '.'        
        jnz  _dateInvalid                               ; else invalid -->

_date_32:
        call _GetNumber                                 ; get last argument
        mov di, word ptr [ _parsedDatePtrs + 4 ][ bp ]
        mov word ptr ss:[ di ], dx                      ; store third argument

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  parse Year
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        mov ax, word ptr [ _parsedDate. _YEAR ][ bp ]   ; start of buffer
        cmp ax, 1980                                    ; greater than 1980 ?
        jnc _date_42                                    ; valid -->
        cmp ax, 80                                      ; less than 80 ?
        jnc _date_36                                    ; 
        add ax, 2000                                    ; must be between 2000 - 2099

_date_36:
        cmp ax, 100                                     ; between 80 and 100 ?
        jnc _date_38                                    ; no -->
        add ax, 1900

_date_38:
        cmp ax, 1980
        jc _dateInvalid                                 ; if invalid -->
        cmp ax, 2100
        jnc _dateInvalid                                ; if invalid -->

_date_42:
        mov cx, ax                                      ; year
        mov dh, byte ptr [ _parsedDate. _MONTH ][ bp ]  ; month
        mov dl, byte ptr [ _parsedDate. _DAY   ][ bp ]  ; day
        Int21 SetDate
        or al, al                                       ; date valid ?
        jnz _dateInvalid                                ; no -->

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  return
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_dateReturn:
        Return

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  invalid date
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_dateInvalid:
        mov dx, offset CmndError_InvalidDate
        call DisplayLine
        jmp _date_12

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Prompt                                                       ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Usage:                                                       ;
        ;   ss:di  Arg Array                                            ;
        ;   ax     Number of arguments in array                         ;
        ;...............................................................;

_Prompt:

        mov si, word ptr [ di ]                         ; get pointer to arg
        or si, si
        jnz _prompt_08
        mov si, offset RxDOS_DefaultPrompt

_prompt_08:
        mov di, offset RxDOS_Prompt
        call _CopyString

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  insert prompt=
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        mov si, offset RxDOS_PromptSpec                 ; locate PROMPT=
        call searchEnvVariable                          ; env variable located ?
        jnz _prompt_12                                  ; if no arg located -->
        call deleteEnvVariable

_prompt_12:
        mov si, offset RxDOS_PromptSpec                 ; insert PROMPT=
        call insertEnvVariable
        call DisplayOutEnvSpace                         ; if error, display message
        jc _prompt_18                                   ; if error -->

        mov si, offset RxDOS_Prompt
        call insertEnvVariable
        call DisplayOutEnvSpace                         ; if error, display message

_prompt_18:
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Time [ time ]                                                ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Usage:                                                       ;
        ;   ss:di  Arg Array                                            ;
        ;   ax     Number of arguments in array                         ;
        ;...............................................................;

_Time:

        Entry
        def __argarray, di                              ; args array
        defbytes _parsedTime, sizeTIME                  ; time struc
        defbytes _buffer, 128                           ; input buffer
        defbytes _printbuffer, 128

        call CheckOptOneArg                             ; see if 1 arg 
        ifc _timeInvalid                                ; if error in args 

        mov si, word ptr [ di ]                         ; get first arg
        or si, si                                       ; if arg, go parse -->
        jnz _time_26

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  display current time
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        lea di, offset [ _buffer ][ bp ]
        push di
        call formatCurrentTime                          ; get current time

        mov di, offset _ShowCurrentTime
        push di
        lea di, offset [ _printbuffer ][ bp ]
        push di
        call _sprintf
        add sp, ax                                      ; # args passed
        call DisplayLine

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  please enter time
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_time_12:
        mov dx, offset _PleaseEnterTime
        call DisplayLine

        lea di, offset [ _buffer ][ bp ]
        mov byte ptr [ bufMaxLength ][ di ], 128
        mov word ptr [ bufActualLength ][ di ], 0

        mov dx, di                                      ; where buffer
        call _getStdinLine                              ; read buffer
        
        call CRLF

        mov bl, byte ptr [ _buffer. bufActualLength ][ bp ]
        and bx, 255
        ifz _timeReturn

        add bx, bp
        mov byte ptr [ _buffer. bufData ][ bx ], 00     ; place a null terminator
        lea si, offset [ _buffer. bufData ][ bp ]       ; parse text
        
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  parse arg at [ si ]       ** must internationalize by matching template **
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_time_26:
        xor ax, ax
        mov word ptr [ _parsedTime. _HOURS      ][ bp ], ax
        mov word ptr [ _parsedTime. _MINUTES    ][ bp ], ax
        mov word ptr [ _parsedTime. _SECONDS    ][ bp ], ax
        mov word ptr [ _parsedTime. _HUNDREDTHS ][ bp ], ax

        call _GetNumber                                 ; get hours
        mov word ptr [ _parsedTime. _HOURS ][ bp ], dx

        call _checkSeparator
        jc _timeInvalid
        jz _time_36
        call _GetNumber                                 ; get mins
        mov word ptr [ _parsedTime. _MINUTES ][ bp ], dx

        call _checkSeparator
        jc _timeInvalid
        jz _time_36
        call _GetNumber                                 ; get seconds
        mov word ptr [ _parsedTime. _SECONDS ][ bp ], dx

        call _checkSeparator
        jc _timeInvalid
        jz _time_36
        call _GetNumber                                 ; get hundreths of seconds
        mov word ptr [ _parsedTime. _HUNDREDTHS ][ bp ], dx

_time_36:
        mov dl, byte ptr [ _parsedTime. _HUNDREDTHS ][ bp ]
        mov dh, byte ptr [ _parsedTime. _SECONDS    ][ bp ]
        mov cl, byte ptr [ _parsedTime. _MINUTES    ][ bp ]
        mov ch, byte ptr [ _parsedTime. _HOURS      ][ bp ]
        Int21 SetTime
        or al, al                                       ; date valid ?
        jnz _timeInvalid                                ; no -->

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  return
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_timeReturn:
        Return

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  invalid time
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_timeInvalid:
        mov dx, offset CmndError_InvalidTime
        call DisplayLine
        jmp _time_12

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Test Time Separator                                          ;
        ;...............................................................;

_checkSeparator:

        mov al, byte ptr [ si-1 ]                       ; get last character processed
        or al, al                                       ; if end of line -->
        jz _checkSeparator_24                           ; return end of line -->

        cmp al, ' '
        jnz _checkSeparator_06                          ; skip any spaces -->

        inc si
        jmp _checkSeparator

_checkSeparator_06:
        call _lowerCase

        cmp al, ':'
        jz _checkSeparator_24                           ; return end of line -->
        cmp al, '.'        
        jz _checkSeparator_24                           ; return end of line -->

        cmp al, 'a'                                     ; am / pm ?
        jz _checkSeparator_12                           ; yes -->
        cmp al, 'p'                                     ; am / pm ?
        jz _checkSeparator_10                           ; yes -->

        stc                                             ; anything else is an error
        ret

_checkSeparator_10:
        cmp byte ptr [ _hours ][ bp ], 12
        jge _checkSeparator_12
        add byte ptr [ _hours ][ bp ], 12

_checkSeparator_12:
        xor ax, ax

_checkSeparator_24:
        or al, al
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Get International Date Template                              ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Usage:                                                       ;
        ;   si     pointer to DayMonthYear buffer                       ;
        ;   di     pointer to DayMonthYear array of pointers to be      ;
        ;           returned.                                           ;
        ;...............................................................;

_GetDateTemplate:

        Entry
        def _DayMonthYear, si
        def _DayMonthYearPtrs, di

        mov word ptr ss:[ di ], si
        mov word ptr ss:[ di + 2 ], si
        mov word ptr ss:[ di + 4 ], si                  ; initialize pointers to base

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  scan date template
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        call returnDateTimeTemplate

        xor bx, bx                                      ; argument order
        getarg di, _DayMonthYearPtrs                    ; start with arg array 

_GetDateTemplate_14:
        lodsw                                           ; get characters
        Goto 'd', _GetDateTemplate_Day                  ; if day   -->
        Goto 'm', _GetDateTemplate_Month                ; if month -->
        Goto 'y', _GetDateTemplate_Year                 ; if year  -->
        jmp short _GetDateTemplate_Done

_GetDateTemplate_Day:
        add word ptr ss:[ di + bx ], _DAY
        jmp short _GetDateTemplate_SkipToSeparator
        
_GetDateTemplate_Month:
        add word ptr ss:[ di + bx ], _MONTH
        jmp short _GetDateTemplate_SkipToSeparator

_GetDateTemplate_Year:
        add word ptr ss:[ di + bx ], _YEAR
      ; jmp short _GetDateTemplate_SkipToSeparator

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  skip to next argument
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_GetDateTemplate_SkipToSeparator:
        lodsb
        or al, al                                       ; end of string ?
        jz _GetDateTemplate_Done                        ; yes, done -->
        cmp al, 'a'                                     ; none text ?
        jnc _GetDateTemplate_SkipToSeparator            ; still on text -->

        inc bx
        inc bx                                          ; advance reference pointer
        jmp _GetDateTemplate_14                         ; continue -->
        
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  done
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_GetDateTemplate_Done:

        Return

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Display Get Date Prompt                                      ;
        ;...............................................................;

DisplayPleaseEnterDate:

        mov dx, offset _PleaseEnterDate
        call DisplayLine

        mov dl, '('
        Int21 DisplayOutput

        call returnDateTimeTemplate
        mov cx, bx
        sub cx, si                                      ; length of string.
        dec cx

DisplayPleaseEnterDate_08:
        lodsb
        mov dl, al
        Int21 DisplayOutput
        loop DisplayPleaseEnterDate_08

        mov dl, ')'
        Int21 DisplayOutput
        mov dl, ':'
        Int21 DisplayOutput
        mov dl, ' '
        Int21 DisplayOutput

        ret        

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Find International Date /Time Template                       ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Returns:                                                     ;
        ;   si     pointer to Date Template                             ;
        ;   bx     pointer to Time Template                             ;
        ;   ax     country code                                         ;
        ;...............................................................;

returnDateTimeTemplate:

        Entry
        def _countryCode
        def _dateTemplate
        def _timeTemplate
        defbytes _countryInfo, sizeCOUNTRYINFO

        push di
        lea dx, offset [ _countryInfo ][ bp ]
        Int21 CountryDependentInfo, 00                  ; get country info
        mov word ptr [ _countryCode ][ bp ], bx         ; save value.

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  locate international template
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        mov di, offset RxDOSIntl_DateTimeTable

returnTemplate_08:
        inc di
        inc di
        cmp bx, word ptr [ di - 2 ]                     ; is it current entry ?
        jz returnTemplate_12                            ; yes -->

        mov cx, -1
        xor ax, ax
        repnz scasb                                     ; scan for null terminator

        cmp word ptr [ di ], 0000                       ; end of table ?
        jnz returnTemplate_08                           ; no, continue looking -->

        mov di, offset RxDOSIntl_DateTimeTable          ; assume USA if no valid entry

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  compute time template
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

returnTemplate_12:
        storarg _dateTemplate, di

        mov al, ' '
        mov cx, -1
        repnz scasb                                     ; search for space delimeter

        mov bx, di                                      ; time template address
        getarg si, _dateTemplate                        ; date template address
        getarg ax, _countrycode                         ; country code

        pop di
        Return

RxDOSCMD                        ENDS
                                END

