******************************************************************
*                                                                *
         nam  Setime
         ttl  OS9 Softclock-setting Utility       
*                                                                *
* This is a Y2K-compliant revision of the 'setime' utility       *
* supplied with OS9 Level 2.  It accepts only 4-digit years      *
* in the range 1900 to 2155, and does thorough error-checking    *
* of the dates and times input.  Written by Richard S. Bair on   *
* March 4, 1999.                                                 *
*                                                                *
******************************************************************
*
* include definitions in pass 1
         ifp1
         use  /dd/defs/os9defs
         endc
*
         mod  CSIZE,NAME,TYPE,ATRV,START,DSIZE
NAME     fcs  /Setime/
EDITION  fcb  $09
TYPE     set  Prgrm+Objct   
REVS     set  $02
ATRV     set  ReEnt+REVS
*
* variable storage area
*
ERRFLAG  rmb  1 flag for input errors
STACK    rmb  2 stack location storage
         rmb  250 storage space for stack
         rmb  200 storage space for parameters
DSIZE    equ  .
*
* storage area for constants
*
NOCLKMSG fcb  $0A 
         fcb  $07 
         fcc  "  >> No Clock module found <<"
         fcb  $0A 
LNCLKMSG equ  *-NOCLKMSG
INERRMSG fcb  $0A
         fcb  $07
         fcc  ">> Error in input data;  try again. <<"
         fcb  $0A
LINERMSG equ  *-INERRMSG
GENERMSG fcb  $0A 
         fcb  $07 
         fcc  "  >> Clock Initialization Errors <<"
         fcb  $0A 
LGNERMSG equ  *-GENERMSG
PRMPTSTR fcb  $0A 
         fcc  "       yyyy/mm/dd hh:mm[:ss]"
         fcb  $0A 
         fcc  "Time ? "
LPRPTSTR equ  *-PRMPTSTR
*
* code area
*
START    equ  *
*
         sts  STACK Record stack starting loc.
         cmpd #$0002 Parameter string given?
         bcc  PARSER If so, skip prompt, etc.
RESTART  leas -$15,s Else make space below stack,
         leax PRMPTSTR,pcr point to prompt message,
         ldy  #LPRPTSTR note its length,
         lda  #$01 set path to stdout,
         os9  I$WritLn have OS9 write it to screen.
         leax ,s Point to input string space,
         lda  #$0D put a CR in it
         sta  ,x for now,
         ldy  #$0014 set max length to retrieve,
         clra path to stdin,
         os9  I$ReadLn have OS9 read it in.
PARSER   leas -$06,s Make space for binary data.
         clr  ERRFLAG Reset input error flag.
         lbsr ASCTOBIN Convert century digits to bin
         tst  ERRFLAG check for errors,
         lbne INPUTERR repeat if nec.
         subb #19 Set baseline to 1900,
         cmpb #02 check range.
         lbhi INPUTERR Repeat if necessary.
         lbsr DIGTCNV Convert other
         lbsr DIGTCNV two year digits,
         tst  ERRFLAG check for errors again,
         lbne INPUTERR repeat if nec.
         lbsr DELIMS Else note delimiter,
         stb  ,s and record value.
         lbsr ASCTOBIN convert month,
         tst  ERRFLAG check for errors,
         lbne INPUTERR
         cmpb #12 check range,
         lbhi INPUTERR
         tstb (can't = 0 either)
         lbeq INPUTERR
         stb  $01,s then record it.
         lbsr ASCTOBIN Get day,
         tst  ERRFLAG check for errors,
         lbne INPUTERR
         tstb can't be zero,
         beq  INPUTERR
         cmpb #31 check for range --
         bhi  INPUTERR
         lda  $01,s this will be a bit
         cmpa #07 tedious --
         bhi  SKIP1
         bita #01 Odd months <8
         bne  HOUR are long
         cmpb #30 just check Feb, Apr, Jun.
         bhi  INPUTERR
         cmpa #02 Now for February --
         bne  HOUR
         lda  ,s Get year
         beq  SKIP2 1900's not a leap year
         cmpa #200 nor is 2100
         beq  SKIP2
         bita #04 nor are years that
         bne  SKIP2 aren't a multiple of 4.
         cmpb #29 The rest are.
         bhi  INPUTERR
         bra  HOUR For them, up to 29 = OK.
SKIP2    cmpb #28 Test ordinary February,
         bhi  INPUTERR redo if nec.,
         bra  HOUR else proceed.
SKIP1    bita #01 Even months >7 are long.
         beq  HOUR
         cmpb #30 Test range of others,
         bhi  INPUTERR redo if nec.
HOUR     stb  $02,s Store checked result.
         bsr  ASCTOBIN Get hour,
         tst  ERRFLAG check for errors,
         bne  INPUTERR
         cmpb #23 check for range,
         bhi  INPUTERR
         stb  $03,s if O.K., then record.
         bsr  ASCTOBIN Get minutes,
         tst  ERRFLAG check for errors,
         bne  INPUTERR
         cmpb #59 check for range,
         bhi  INPUTERR
         stb  $04,s record if O.K.
         bsr  ASCTOBIN Get seconds.
         cmpb #59
         bhi  INPUTERR
         stb  $05,s
         leax ,s Point to binary data packet,
         os9  F$STime have OS9 set software clock.
         bcc  EXIT If no errors, go to exit.
         cmpb #$EA Is err "non-existent module"?
         bne  GENERR If not, report general error.
         leax NOCLKMSG,pcr Point to "no clock" msg,
         ldy  #LNCLKMSG note its length,
         bra  ERRPRINT go print it.
*
GENERR   leax GENERMSG,pcr Point to general err msg,
         ldy  #LGNERMSG record its length,
ERRPRINT lda  #$01 set path to stdout,
         os9  I$WritLn have OS9 print it to screen.
EXIT     clrb Report no errors to OS9,
         os9  F$Exit exit.
*
INPUTERR leax INERRMSG,pcr Point to "input error" msg,
         ldy  #LINERMSG note its length,
         lda  #01 set path to stdout,
         os9  I$WritLn have OS9 print it.
         lds  STACK Reset stack pointer,
         lbra RESTART try again with input.
*
ASCTOBIN clrb ASCII-to-bin:  start with 0,
         bsr  DIGTCNV x10 + next digit,
         bsr  DIGTCNV X10 + next digit.
DELIMS   lda  ,x+ Check for delimiter:
         cmpa #$20 a space
         beq  RETURN is O.K.,
         cmpa #$2F or a /,
         beq  RETURN
         cmpa #$3A or :,
         beq  RETURN
         cmpa #$2C or a comma
         beq  RETURN or
         cmpa #$2E a period.
         beq  RETURN
         leax -$01,x Else back up;  it's a digit?
RETURN   rts   
*
DIGTCNV  lda  ,x Get a digit,
         suba #$30 make sure it's
         bcs  EJECT at least 0 ASCII
         cmpa #$09 and not more than
         bhi  EJECT 9 (ASCII). Else abort.
         leax $01,x Advance digit pointer,
         pshs a save the (now binary) value,
         lda  #$0A multiply previous value
         mul (in b register) by 10, then
         addb ,s+ retrieve new value and add.
         bcs  EJECT Check for overflow.
         rts Return (result in b registr).
*
EJECT    inc  ERRFLAG Set error flag
         rts
*
         emod Append CRC bytes.
CSIZE    equ  *