;  Program:  TIME
;  Version:  1.1
;  Author:  Richard Conn
;  Date:  6 Mar 82
;  Previous Versions:  1.0 (2 Mar 82)
VERS    equ     11      ;Version Number

;       TIME is invoked by a command line of the form:
;
;               TIME <time> <date> <weekday> <display cmd>
;
;       All parameters are optional and may be present in any order.
;If all parameters are omitted, the time and date are printed.
;The various parameters are:
;       <time> -- Current time as hh:mm (hh and mm are 1-2 digits)
;               hh:mm may be followed by A or P (hh:mmA) for AM or PM
;                       (defaults to current AM or PM)
;       <date> -- Current date as dd/mm/yy (all are 1-2 digits)
;       <weekday> -- Day of week (3 letters are generally required)
;       <display cmd> -- Either:
;               DISPLAY TIME, DISPLAY DATE, XDISK, or PRINT
;                       (only 1st letter of each word required)
;                       DISPLAY Sets Display on Chronograph
;                       PRINT Sends Output to Printer
;                       XDISK Sends Output to Disk File TIME.SYS
;       Each parameter is separated from its predecessor by one or more spaces.
;

;
;  External Routines in SYSLIB Library
;
       ext     cin     ; Console Input
       ext     cout    ; Console Output
       ext     lout    ; List Output
       ext     pout    ; Punch (Clock) Output
       ext     rin     ; Reader (Clock) Input
       ext     crlf    ; New Line
       ext     lcrlf   ; New Line to LST:
       ext     print   ; Print String at Return Address
       ext     lprint  ; Print String at Return Address on LST:
       ext     pstr    ; Print String Pointed to by HL
       ext     lpstr   ; Print String Pointed to by HL on LST:
       ext     f$make  ; Create File
       ext     fo$open ; Open File for Byte-Oriented Output
       ext     fo$close        ; Close File for Byte-Oriented Output
       ext     f$put   ; Put Byte into File

;  ASCII Constants
CR      equ     0dh     ; <CR>
LF      equ     0ah     ; <LF>
CTRLC   equ     3       ; ^C

;
;  CP/M Constants
;
buff    equ     80H     ;Command Line Buffer

;
;  Macros
;
;** Send AT Code and 2-letter command from Stack to Clock **
sendat  macro
       xthl            ;;Point to 1st letter of command
       mvi     a,'A'   ;;Send AT Command Prefix
       call    coclk   ;;Send to Clock
       mvi     a,'T'
       call    coclk
       mov     a,m     ;;Get 1st Command Letter
       call    coclk   ;;Send to Clock
       inx     h       ;;Point to 2nd Command Letter
       mov     a,m     ;;Get it
       call    coclk   ;;Send to Clock
       inx     h       ;;Point to Return Address
       xthl            ;;Save it on Stack
       endm

;
;  TIME Program --
;
       aseg
       org     100H

;
;  Set up for return
;
       lxi     h,0     ;Obtain SP in HL
       dad     sp
       shld    stack   ;Save Return SP Value
       lxi     sp,stack        ;Reset SP

;
;  Check for Help Request
;
       call    helpck

;
;  Extract Data from Clock
;
       call    readclock

;
;  Set New Date or Time if one is specified
;
       call    setclock

;
;  Check Date and Time for Numeric Syntax Error
;
       call    check

;
;  Open Disk File for Output if Requested
;
       call    dskopen

;
;  Print Time/Date/Weekday on CON:, LST:, or Disk
;
       call    prclock
       call    dskclos ;Close Disk if Disk Output Requested
       lda     prflg   ;Check for LST: output and send CRLF if so
       ora     a       ;0=CON: only
       cnz     lcrlf   ;New Line to LST:

;
;  Set Time/Date/Weekday if requested
;
       lda     setit   ;Flag Set?
       ora     a       ;0=no
       cnz     doset

;
;  Set Display if Requested
;
       lda     disp    ;Flag Set?
       ora     a       ;0=no
       cnz     dodisp

;
;  Return to Caller (CP/M or CP/ZM)
;
return:
       lhld    stack   ;Get original stack pointer
       sphl            ;Load it
       ret

;
;  Clock Input/Output Entry Routines
;
ciclk:
       jmp     rin     ;Clock is on RDR:
coclk:
       jmp     pout    ;Clock is on PUN:

;
;  Open Disk for Output if Requested
;
dskopen:
       lda     dskflg  ;Check flag
       ora     a       ;0=no
       rz
       lxi     d,fcb   ;Pt to FCB
       call    f$make  ;Make File
       lxi     d,fcb   ;Pt to FCB
       call    fo$open ;Open File
       ret

;
;  Close Disk for Output if Requested
;
dskclos:
       lda     dskflg  ;Check flag
       ora     a       ;0=no
       rz
       mvi     a,cr    ;New Line to file
       call    f$put
       mvi     a,lf
       call    f$put
       lxi     d,fcb   ;Pt to FCB
       call    fo$close        ;Close File
       ret

;
;  Print Time/Date/Weekday on CON:
;
prclock:
       call    banner  ;Print Name of Program
       call    prtime  ;Print Time
       call    cprint
       db      ' on ',0
       call    prweek  ;Print Weekday
       call    space   ;Space
       call    prmonth ;Print Month Name
       call    space
       call    prday   ;Print Day Number
       call    pryear  ;Print Year
       ret

;
;  Print Name and Version of Program
;
banner:
       call    print
       db      'TIME  Version '
       db      VERS/10+'0','.',(VERS MOD 10)+'0'
       db      '    ',0
       ret

;
;  Scan Input Buffer of Help Request (Token beginning with /)
;
helpck:

;  Place 0 after last char in command line
       lxi     h,buff  ;Point to char count in command line
       mov     a,m     ;Get char count
       inx     h       ;Point to first char
       add     l       ;Point to after last char in line
       mov     l,a
       mov     a,h
       aci     0
       mov     h,a     ;HL now points to after last char
       mvi     m,0     ;Store 0 after last char

;  Check for Token Beginning with /
       lxi     h,buff+1        ;Pt to 1st char
hckloop:
       call    spskip  ;Skip to next token
       ora     a       ;EOL?
       rz              ;Done if so
       cpi     '/'     ;Help?
       jnz     hckloop ;Fall thru to PRHELP if so

;
;  Print Help Message
;
prhelp:
       call    crlf    ; New Line
       call    banner  ; Print banner
       call    crlf    ; New Line
       call    print
       db      cr,lf,' TIME is invoked by a command line of the form:'
       db      cr,lf
       db      cr,lf,'         TIME <time> <date> <weekday> <display cmd>'
       db      cr,lf
       db      cr,lf,' All parameters are optional and may be present in any'
       db      ' order.'
       db      cr,lf,'If all parameters are omitted, the time and date are'
       db      ' printed.'
       db      cr,lf,'The various parameters are:'
       db      cr,lf,' <time> -- Current time as hh:mm (hh and mm are 1-2'
       db      ' digits)'
       db      cr,lf,'         hh:mm may be followed by A or P (hh:mmA) for'
       db      ' AM or PM '
       db      cr,lf,'                 (defaults to current AM or PM)'
       db      cr,lf,' <date> -- Current date as dd/mm/yy (all are 1-2'
       db      ' digits)'
       db      cr,lf,' <weekday> -- Day of week (3 letters are generally'
       db      ' required)'
       db      cr,lf,' <display cmd> -- Either:'
       db      cr,lf,'         DISPLAY TIME, DISPLAY DATE, XDISK, or PRINT'
       db      cr,lf,'                 (only 1st letter of each word '
       db      'required)'
       db      cr,lf,'                 DISPLAY Sets Display on Chronograph'
       db      cr,lf,'                 PRINT Sends Output to Printer'
       db      cr,lf,'                 XDISK Sends Output to Disk File '
       db      'TIME.SYS'
       db      cr,lf
       db      cr,lf,' Each parameter is separated from its predecessor by'
       db      ' one or more spaces.'
       db      cr,lf,0
       jmp     return

;
;  Set Time/Date/Weekday
;
doset:
       lda     sett    ;Set time?
       ora     a       ;0=no
       jz      doset1
       call    print
       db      cr,lf,'<< Setting Time -- Strike Any Key (^C=Abort) when '
       db      'Ready >>',0
       call    cin     ;Get Response
       call    crlf    ;New Line
       cpi     ctrlc   ;Abort?
       jz      doset1  ;Continue if so
       lxi     h,time  ;Set Time from Buffer
       call    cmdo
       db      'ST'    ;Set Time
doset1:
       lda     setd    ;Set date?
       ora     a       ;0=no
       jz      doset2
       call    print
       db      cr,lf,'<< Setting Date >>',cr,lf,0
       lxi     h,date  ;Set Date from Buffer
       call    cmdo
       db      'SD'    ;Set Date
doset2:
       lda     setw    ;Set weekday?
       ora     a       ;0=no
       rz
       call    print
       db      cr,lf,'<< Setting Weekday >>',cr,lf,0
       lxi     h,week  ;Set Weekday from Buffer
       call    cmdo
       db      'SW'    ;Set Weekday
       ret

;
;  Set Display Date or Time
;
dodisp:
       cpi     'D'     ;Date?
       jz      dod1
       call    cmd     ;Send Command
       db      'DT'    ;Display Time
       ret
dod1:
       call    cmd     ;Send Command
       db      'DD'    ;Display Date
       ret

;
;  Send command pointed to by Return Address and command string pointed
;    to by HL to Clock and get Return Code
;
cmdo:
       sendat          ;Send ATcc
cmdo1:
       mov     a,m     ;Send command string
       ora     a       ;End of string?
       jz      cmdo2
       call    coclk   ;Send to Clock
       inx     h       ;Pt to next
       jmp     cmdo1
cmdo2:
       mvi     a,cr    ;Send CR
       call    coclk   ;To Clock
       call    ciclk   ;Get Response
       mov     b,a     ;Save in B
       call    ciclk   ;Clear CR
       mov     a,b     ;Get Result Code
       sui     '0'     ;Convert to binary
       rz              ;OK
       cpi     9       ;Write Protect?
       jnz     cmderr
       call    print
       db      cr,lf,'** Clock is Write-Protected -- Unprotect it to Set **',0
       jmp     return  ;Immediate Return
cmderr:
       call    print
       db      cr,lf,'** TIME Internal Syntax Error **',0
       jmp     return  ;Immediate Return

;
;  Simply send command at Return Address and check for error code
;
cmd:
       sendat          ;Send ATcc
       jmp     cmdo2   ;Send CR and Check Error Code

;
;  Read Time, Date, and Weekday from Clock
;
readclock:
       lxi     h,time  ;Point to Time Buffer
       call    command
       db      'RT'    ;Read Time
       lxi     h,date  ;Point to Date Buffer
       call    command
       db      'RD'    ;Read Date
       lxi     h,week  ;Point to Weekday Buffer
       call    command
       db      'RW'    ;Read Weekday
       ret

;
;  Print Time on CON: or LST:
;
prtime:
       lxi     h,time  ;Print Time Info
       call    pr2s    ;Print 2 digits
       call    colon   ;Print :
       call    pr2     ;Print 2 digits
       call    colon   ;Print :
       call    pr2     ;Print 2 digits
       call    space   ;Space
       mov     a,m     ;Get A or P
       call    cpout
       mvi     a,'M'   ;Print M
       call    cpout
       ret

;
;  Print Weekday on CON: or LST:
;
prweek:
       lda     week    ;Get week day number
       sui     '0'     ;Convert to Binary
       inr     a       ;Add 1
       lxi     d,dlen  ;Length of Day Strings
       lxi     h,days  ;Beginning of Day Strings
       call    offset  ;Compute offset to desired string
       call    cpstr   ;Print Day Name
       ret

;
;  Print Month Name
;
prmonth:
       lxi     h,date+2        ;Convert month number
       mov     a,m     ;Get first digit
       sui     '0'     ;Convert to Binary
       mov     b,a     ;Save in B
       add     a       ;*2
       add     a       ;*4
       add     b       ;*5
       add     a       ;*10
       inx     h       ;Point to next digit
       mov     b,a     ;Value in B
       mov     a,m     ;Get Digit
       sui     '0'     ;Convert to Binary
       add     b       ;Add in
       lxi     d,mlen  ;Length of Month Strings
       lxi     h,months        ;Beginning of Month Strings
       call    offset  ;Compute Offset to Desired String
       call    cpstr   ;Print Month Name
       ret

;
;  Print Day Number
;
prday:
       lxi     h,date+4        ;Point to Day Digits
       call    pr2s    ;Print as 2 Digits
       ret

;
;  Print Year
;
pryear:
       call    cprint  ;Print Year Prefix
       db      ', 19',0
       lxi     h,date  ;Point to Year
       call    pr2     ;Print 2 Digits
       ret

;
;  Print colon or space
;
colon:
       mvi     a,':'   ;Print colon
       jmp     cpout
space:
       mvi     a,' '   ;Print space
       jmp     cpout

;
;  Command -- Issue 2-letter command pointed to by Return Address to Clock
;    and copy response into buffer pointed to by HL; affect all registers
;
command:
       sendat          ;Send ATcc
       mvi     a,CR    ;Send <CR>
       call    coclk   ;Send to Clock
;  Collect Response Chars
cmdloop:
       call    ciclk   ;Get letter
       cpi     CR      ;End of Response?
       jz      cmddone
       mov     m,a     ;Store in Buffer
       inx     h       ;Point to next position
       jmp     cmdloop
cmddone:
       mvi     m,0     ;Store ending zero
       ret

;
;  PR2S -- Print chars pointed to by HL and HL+1; if first character is '0',
;    print only one char; affect all registers; on exit, HL points to byte
;    after 2nd char printed
;  PR2 -- PR2S but always print 2 digits
;
pr2:
       mov     a,m     ;Get first char
       jmp     pr2a
pr2s:
       mov     a,m     ;Get first char
       cpi     '0'     ;Leading zero?
       jz      pr2b
pr2a:
       call    cpout   ;Print char
pr2b:
       inx     h       ;Point to next
       mov     a,m     ;Get it
       call    cpout
       inx     h       ;Point to next
       ret

;
;  Compute Offset to selected string; on input, HL points to first
;    string, DE=string length, A=Number of String desired (first string = 1)
;
offset:
       dcr     a       ;Count down
       rz
       dad     d       ;Point to next
       jmp     offset

;
;  Check Date and Time for Numeric Error (Range)
;
check:
       lda     setit   ;Any Change?
       ora     a       ;0=no
       rz
       lxi     h,time  ;Hours can't exceed 12
       call    get2    ;Get 2 digits
       cpi     12+1    ;Range ok?
       jnc     chkerr  ;Error
       lxi     h,time+2        ;Minutes can't exceed 60
       call    get2    ;Get 2 digits
       cpi     60+1    ;Range ok?
       jnc     chkerr  ;Error
       lxi     h,date+2        ;Month can't exceed 12
       call    get2    ;Get 2 digits
       cpi     12+1    ;Range ok?
       jnc     chkerr  ;Error
       lxi     h,date+4        ;Day can't exceed 31
       call    get2    ;Get 2 digits
       cpi     31+1    ;Range ok?
       rc              ;Done if so
chkerr:
       call    print
       db      cr,lf,'Argument Range Error -- Value in Error is ',0
       mov     a,m     ;Get 1st digit
       call    cout
       inx     h       ;Pt to 2nd
       mov     a,m     ;Get 2nd digit
       call    cout
       call    print
       db      cr,lf,'Aborting to CP/M',0
       jmp     return
;
;  Get two ASCII chars pted to by HL and convert them to integer in A
;
get2:
       push    h       ;Save ptr
       mov     a,m     ;Get 10's digit
       sui     '0'     ;Convert to binary
       mov     b,a     ;Save in B
       add     a       ;*2
       add     a       ;*4
       add     b       ;*5
       add     a       ;*10
       mov     b,a     ;Result in B
       inx     h       ;Pt to next
       mov     a,m     ;Get 1's digit
       sui     '0'     ;Convert to binary
       add     b       ;Add in
       pop     h       ;Get ptr
       ret

;
;  Set Time, Date, or Weekday
;
setclock:
;  Assume no Display Change and no Time/Date/Weekday Set
       xra     a       ;A=0
       sta     disp    ;No Display
       sta     setit   ;No Set
       sta     sett    ;No Set Time
       sta     setd    ;No Set Date
       sta     setw    ;No Set Weekday
       sta     prflg   ;No Print
       sta     dskflg  ;No Disk Output

;  Skip to first non-blank char
       lxi     h,buff+1        ;Point to first char
       call    spskip  ;Skip to EOL or first token
       ora     a       ;EOL?
       rz
       jmp     nxt1

;  Skip to next token in command line
nxtoken:
       call    spskip  ;HL now points to first non-blank char; A is char
       ora     a       ;Check for EOL
       jnz     nxt1    ;Continue if not
       mvi     a,0ffh  ;Set flag
       sta     setit   ;Clock Set Flag
       ret

;  Main Token Processing Loop
nxt1:

;  Check for Number (Date or Time)
       mov     a,m     ;Get next char
       call    digit   ;Digit?
       jz      wdchk   ;If not, check for Print, Weekday, or Display Command

;  It is a number -- Determine if date or time
       call    dtchk   ;Scan for ':' or '/' or ' ' or <NULL>
       cpi     ' '+1   ;Error if no ':' or '/'
       jnz     nxt2    ;Print error message and then Help message
       call    print
       db      cr,lf,'** Numeric Argument contains no Date (/) or Time (:)'
       db      ' Separator **',0
       jmp     prhelp
nxt2:
       cpi     ':'     ;Time?
       jz      setime  ;Set Time

;  Set Date
       mvi     a,0ffh  ;Set flag
       sta     setd    ;Set Date
       call    number  ;Extract token as number char string
       cpi     6       ;Must be 6 digits
       jz      nxt3    ;Date error if not
       call    print
       db      cr,lf,'** Invalid Date Specification **',0
       jmp     prhelp
nxt3:
       push    h       ;Save ptr
       lxi     h,numbuf+4      ;Extract year digits
       lxi     d,date  ;1st 2 in date buffer
       call    copy2
       lxi     h,numbuf+2      ;Extract month digits
       call    copy2
       lxi     h,numbuf        ;Extract day digits
       call    copy2
       pop     h       ;Get ptr
       jmp     nxtoken ;Get next token

;  Set Time
setime:
       mvi     a,0ffh  ;Set flag
       sta     sett    ;Set Time
       call    number  ;Extract token as number char string
       cpi     4       ;Must be 4 digits
       jz      nxt4
       jc      timerr  ;OK if more than 4 digits
       call    print
       db      cr,lf,'Warning -- Seconds Specified in Time Argument Ignored',0
       jmp     nxt4
timerr:
       call    print
       db      cr,lf,'** Invalid Time Specification **',0
       jmp     prhelp
nxt4:
       push    h       ;Save ptr
       lxi     h,numbuf        ;Place number in time buffer
       lxi     d,time
       call    copy4   ;Copy into buffer
       mvi     a,'0'   ;Store ending 0's for seconds
       stax    d
       inx     d
       stax    d
       lda     letter  ;Get trailing letter, if any
       cpi     'A'     ;AM?
       cz      setlet  ;Set Letter
       cpi     'P'     ;PM?
       cz      setlet
       pop     h       ;Get ptr
       jmp     nxtoken

;
;  Set Time Letter
;
setlet:
       sta     time+6  ;6th position
       ret

;  Check for Print, Weekday, or Display Command and Set it if so
wdchk:
       mov     a,m     ;Get 1st letter of command
       cpi     'P'     ;Print?
       jz      setpr
       cpi     'X'     ;Disk Output?
       jz      setdsk
       cpi     'D'     ;Display Time or Date?
       jz      display
       mvi     a,0ffh  ;Set flag
       sta     setw    ;Set Weekday
       mov     a,m     ;Get Letter back
       cpi     'T'     ;Tuesday or Thursday?
       jnz     wdchk0
       inx     h       ;Point to next char
       mov     a,m     ;Get it
       jmp     wdchk1
wdchk0:
       cpi     'S'     ;Saturday or Sunday?
       jnz     wdchk1
       inx     h       ;Point to next char
       mov     a,m     ;Get it
       cpi     ' '+1   ;In range?
       jc      wderr
       inx     h       ;Point to 3rd char
       mov     a,m     ;Get it
wdchk1:
       push    h       ;Save ptr
       lxi     h,daytab        ;Point to table of single letters (reverse)
       mov     b,a     ;Char in B
       mvi     c,7     ;Scan for 7 entries
wdchk2:
       mov     a,m     ;Get letter
       cmp     b       ;Match?
       jz      wdmatch
       inx     h       ;Pt to next
       dcr     c       ;Count down
       jnz     wdchk2
       pop     h       ;Get ptr
wderr:
       call    print   ;Error
       db      cr,lf,'** Invalid Weekday Specification **',0
       jmp     prhelp
wdmatch:
       pop     h       ;Get ptr
       mov     a,c     ;Get weekday number +1
       dcr     a       ;Adjust
       adi     '0'     ;Convert to ASCII
       sta     week    ;Set Day
       jmp     nxtoken ;Continue processing

;  Display Time or Date
display:
       call    spskip  ;Skip to next token
       cpi     'D'     ;Date?
       jz      disp1
       cpi     'T'     ;Time?
       jz      disp1
       call    print
       db      cr,lf,'** Invalid Display Option -- Not Time or Date **',0
       jmp     prhelp
disp1:
       sta     disp    ;Set Display Command
       jmp     nxtoken ;Continue

;
;  Set Print Flag
;
setpr:
       mvi     a,0ffh  ;Set flag
       sta     prflg
       jmp     nxtoken ;Continue

;
;  Set Disk Output
;
setdsk:
       mvi     a,0ffh  ;Set flag
       sta     dskflg
       jmp     nxtoken ;Continue

;
;  Copy HL to DE for 2 or 4 bytes
;
copy2:
       mvi     b,2     ;2 Bytes
       jmp     copyl
copy4:
       mvi     b,4     ;4 Bytes
copyl:
       mov     a,m     ;Get byte
       stax    d       ;Put byte
       inx     h       ;Pt to next
       inx     d
       dcr     b       ;Count down
       jnz     copyl
       ret

;
;  Scan for Date or Time separator; terminate scan if found or <SP> or <NULL>
;    encountered; Do NOT affect HL
;
dtchk:
       push    h       ;Save HL
dtchk1:
       mov     a,m     ;Get char
       inx     h       ;Pt to next
       ora     a       ;<NULL>?
       jz      dtchk2
       cpi     ' '     ;<SP>?
       jz      dtchk2
       cpi     ':'
       ;Time?
       jz      dtchk2
       cpi     '/'     ;Date?
       jnz     dtchk1  ;Continue if not
dtchk2:
       pop     h       ;Found delimiter - Return with it in A
       ret

;
;  Skip to next space or <NULL>
;
tosp:
       mov     a,m     ;Get char
       cpi     ' '     ;<SP>?
       rz
       ora     a       ;<NULL>?
       rz
       inx     h       ;Pt to next char
       jmp     tosp

;
;  Skip to next non-blank char after current token
;
spskip:
       call    tosp    ;Skip to white space
spsk1:
       mov     a,m     ;Get char
       cpi     ' '     ;<SP>?
       rnz
       inx     h       ;Pt to next
       jmp     spsk1

;
;  Extract Number pted to by HL into numbuf; if number is followed by a letter,
;    return letter in 'letter' buffer; on exit, HL points to <SP> or <NULL>
;    after argument
;
number:
       lxi     d,numbuf        ;Pt to buffer
       call    num2    ;Get 2 digits
       mvi     c,0     ;0 so far
       ora     a       ;No 1st digit?
       jz      numb1
       call    sepchk  ;Check for ':' or '/' separator and adv HL if so
       mvi     c,2     ;2 so far
       call    num2    ;Get 2 more digits
       ora     a       ;No 1st digit?
       jz      numb1
       call    sepchk  ;Separator check
       mvi     c,4     ;4 so far
       call    num2    ;Get 2 more digits
       ora     a       ;No 1st digit?
       jz      numb1
       mvi     c,6     ;6 so far
numb1:
       mov     a,m     ;Get terminating char
       cpi     ' '+1   ;Letter?
       jc      numb2
       sta     letter  ;Set letter
       call    tosp    ;Skip to <SP> or <NULL>
numb2:
       mov     a,c     ;Get digit count
       ret

;  Check to see that char pted to by HL is ':' or '/'; HL=HL+1 if so
sepchk:
       mov     a,m     ;Get char
       cpi     ':'     ;':'?
       jz      sepadv
       cpi     '/'     ;'/'?
       rnz
sepadv:
       inx     h       ;Inc HL
       ret

;  Extract at most 2 digits; on return, A=0 if no 1st digit; on return, A<>0
;    if 1st digit, DE=DE+2, HL pts to after digits
num2:
       mov     a,m     ;Get first char
       call    digit   ;Digit?
       rz              ;A=0
       push    h       ;Save ptr
       mvi     c,1     ;Assume 1 digit
       mov     a,m     ;Get char
       call    digit   ;Digit?
       jnz     num2a   ;Continue if so
num2err:
       call    print
       db      cr,lf,'** Invalid Digit Form in Numeric Argument **',0
       jmp     prhelp
num2a:
       inx     h       ;Pt to next
       mov     a,m     ;Get it
       call    digit   ;Digit?
       jz      num2b   ;Continue if not -- 1 digit
       mvi     c,2     ;2 Digits
       inx     h       ;Pt to next
       mov     a,m     ;Get it
       call    digit   ;Should NOT be digit
       jnz     num2err ;Error if it is
num2b:
       pop     h       ;Pt to first digit
       mov     a,c     ;Get number of digits
       cpi     2       ;2?
       jz      numb2c  ;Skip if 2 digits
       mvi     a,'0'   ;Store leading zero
       stax    d
       inx     d       ;Pt to next
numb2c:
       mov     a,m     ;Get digit
       stax    d       ;Put digit
       inx     h       ;Pt to next
       inx     d
       dcr     c       ;Count down
       jnz     numb2c
       mvi     a,1     ;Set OK
       ret

;  Determine if byte in A is ASCII digit; return with A=0 and Z if not
digit:
       cpi     '0'     ;Less than '0'?
       jc      nodig
       cpi     '9'+1   ;Greater than '9'?
       jnc     nodig
       mvi     a,0ffh  ;Set OK
       ora     a       ;Set flags
       ret
nodig:
       xra     a       ;Not digit
       ret

;
;  Send output to CON: or LST: depending on PRFLG
;
cpout:
       call    cout    ;Output to CON:
       push    psw     ;Save char
       lda     prflg   ;Check flag
       ora     a       ;0=CON:
       jz      cpout1
       pop     psw     ;Get char
       push    psw     ;Save char
       call    lout    ;LST:
cpout1:
       lda     dskflg  ;Check flag
       ora     a       ;<>0 = Disk
       jz      cpout2
       pop     psw     ;Get char
       push    psw     ;Save char
       call    f$put   ;Disk
cpout2:
       pop     psw     ;Get char
       ret

;
;  Print string pted to by return address on CON: or LST:
;
cprint:
       xthl            ;Pt to string
cpr1:
       mov     a,m     ;Get char
       inx     h       ;Pt to next
       ora     a       ;Done?
       jz      cpr2
       call    cpout   ;Print to CON: or LST:
       jmp     cpr1
cpr2:
       xthl            ;Restore HL and Ret Adr
       ret

;
;  Print string pted to by HL on CON: or LST:
;
cpstr:
       push    h       ;Save ptr
       push    psw     ;Save char
cpstr1:
       mov     a,m     ;Get next char
       inx     h       ;Pt to next char
       ora     a       ;Done?
       jz      cpstr2
       call    cpout   ;Print char
       jmp     cpstr1
cpstr2:
       pop     psw     ;Get char
       pop     h       ;Get ptr
       ret

;
;  Disk Output FCB
;
fcb:
       db      0,'TIME    SYS',0,0,0,0
       db      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
       db      0,0,0

;
;  Day Strings
;
days:
       db      'Monday',0,0,0,0
days2:
       db      'Tuesday',0,0,0
       db      'Wednesday',0
       db      'Thursday',0,0
       db      'Friday',0,0,0,0
       db      'Saturday',0,0
       db      'Sunday',0,0,0,0
dlen    equ     days2-days      ;Number of Bytes in Each Entry

;
;  Quick-Reference Day Table (in Reverse Order)
;
daytab:
       db      'N'     ; suNday
       db      'T'     ; saTurday
       db      'F'     ; Friday
       db      'H'     ; tHursday
       db      'W'     ; Wednesday
       db      'U'     ; tUesday
       db      'M'     ; Monday

;
;  Month Strings
;
months:
       db      'January',0,0,0
month1:
       db      'February',0,0
       db      'March',0,0,0,0,0
       db      'April',0,0,0,0,0
       db      'May',0,0,0,0,0,0,0
       db      'June',0,0,0,0,0,0
       db      'July',0,0,0,0,0,0
       db      'August',0,0,0,0
       db      'September',0
       db      'October',0,0,0
       db      'November',0,0
       db      'December',0,0
mlen    equ     month1-months   ;Number of Bytes in Each Entry

;
;  Stack Area
;
       ds      40      ;20-Elt Stack
stack:  ds      2       ;Return SP Value

;
;  Input Buffers
;
time:
       ds      10      ; Time Buffer
date:
       ds      10      ; Date Buffer
week:
       ds      10      ; Weekday Buffer
numbuf:
       ds      10      ; Number Input Buffer
disp:
       ds      1       ; Display Flag (0=Don't change Chronograph Display,
                       ;   D=Display Date, T=Display Time)
letter:
       ds      1       ; Optional Letter after Time (A/P)
setit:
       ds      1       ; Set Time/Date/Weekday Flag (0=no)
sett:
       ds      1       ; Set Time (0=no)
setd:
       ds      1       ; Set Date (0=no)
setw:
       ds      1       ; Set Weekday (0=no)
prflg:
       ds      1       ; Print (0=no)
dskflg:
       ds      1       ; Disk Output (0=no)

       end