; Copyright 1996 Acorn Computers Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;     http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
        TTL     => Convrsions : various number to string routines

despatchConvert ROUT

        ; Pick off the non table driven ones
        CMP     R11, #OS_ConvertVariform
        BNE     %FT10
        Push    "lr"
        BL      VariformInternal
        Pull    "lr"
        B       SLVK_TestV
10
        CMP     R11, #OS_ConvertStandardDateAndTime
        BEQ     StandardDateTime_Code
        CMP     R11, #OS_ConvertDateAndTime
        BEQ     DateTime_Code

        ASSERT  OS_ConvertFixedFileSize > OS_ConvertFixedNetStation
        CMP     R11, #OS_ConvertFixedFileSize
        BGE     FileSize_Code
        CMP     R11, #OS_ConvertFixedNetStation
        BGE     NetStation_Code

        ; Use SWI number as index into tables mapping to OS_ConvertVariform
        Push    "r0, r3-r4, lr"
        MOV     r0, sp

        SUB     r4, r11, #OS_ConvertHex1 - 3
        ADR     r14, ConvertSizesTable
        LDRB    r3, [r14, r4]
        ADR     r14, ConvertTypesTable
        LDRB    r4, [r14, r4, LSR #2]

        BL      VariformOutput
        ADD     sp, sp, #4
        Pull    "r3-r4, lr"
        B       SLVK_TestV

ConvertSizesTable
        DCB     0, 0, 0, 1, 2, 4, 6, 8, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4
        ASSERT  (. - ConvertSizesTable) :AND: 3 = 0
ConvertTypesTable
        DCB     ConvertToHex, ConvertToHex, ConvertToCardinal, ConvertToInteger
        DCB     ConvertToBinary, ConvertToSpacedCardinal, ConvertToSpacedInteger
        ALIGN

TenTimesTable
        DCD     1                       ; 10^0
        DCD     10
        DCD     100
        DCD     1000
        DCD     10000
        DCD     100000
        DCD     1000000
        DCD     10000000
        DCD     100000000
        DCD     1000000000              ; 10^9
TenTimesBigTable
        DCQ     10000000000             ; 10^10
        DCQ     100000000000
        DCQ     1000000000000
        DCQ     10000000000000
        DCQ     100000000000000
        DCQ     1000000000000000
        DCQ     10000000000000000
        DCQ     100000000000000000
        DCQ     1000000000000000000     ; 10^18

CommaPositions
        DCD     2_01001001001001001001001001001000

SuffixSI
        DCB     "byte"
PrefixSI
        DCB     " kMGTPE"               ; units/kilo/mega/giga/tera/peta/exa
        ALIGN

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; VariformInternal
; ----------------
; The guts behind OS_ConvertVariform but callable as a subroutine
; In  : R0 pointer to input value (word alignment)
;       R1 pointer to buffer
;       R2 max buffer length, or -ve to read space required
;       R3 bytes to use from input value (or nybbles if hex output reqd)
;       R4 type to convert to
; Out : R0 pointer to buffer
;       R1 pointer to terminator
;       R2 free bytes in buffer, or NOT space required if R2 -ve on entry
;       V Set if buffer overflow

VariformInternal
        ; Check if it's a read space operation
        MOVS    r2, r2
        BPL     VariformOutput

VariformCount
        ; Some of them are calculable
        TEQ     r4, #ConvertToBinary
        MOVEQ   r2, r3, LSL #3          ; 8 output chars for every 1 input byte
        BEQ     %FT30
        TEQ     r4, #ConvertToHex
        TEQNE   r4, #ConvertToHexLowercase
        MOVEQ   r2, r3, LSL #1          ; 2 output chars for every 1 input nybble
        BEQ     %FT30
        TEQ     r4, #ConvertToFixedFileSize
        MOVEQ   r2, #4 + 1 + 1 + 5      ; Always '1234 kbytes'
        BEQ     %FT30
        TEQ     r4, #ConvertToEUI
        ADDEQ   r2, r3, r3, LSL #1      ; 3 output chars for every 1 input byte (inc term)
        SUBEQ   r2, r2, #1              ; Don't count the terminator
        BEQ     %FT30
10
        ; A hard length to know, just do it
        Push    "r1, lr"
        SUB     sp, sp, #44             ; Longest is currently IPv6 output
        MOV     r1, sp
        MOV     r2, #44
        BL      VariformOutput
        SUB     r2, r1, r0              ; Length = term - start
        ADD     sp, sp, #44
        Pull    "r1, lr"
        ; Fall through
30
        MVN     r2, r2
40
        ADRL    r0, ErrorBlock_BuffOverflow
      [ International
        Push    "lr"
        BL      TranslateError
        Pull    "pc"
      |
        SETV
        MOV     pc, lr
      ]

VariformOutputChar
        TEQ     r2, #0
        BEQ     %BT40
        CMP     r0, #0                  ; Clears V too
        STREQB  r0, [r1]
        STRNEB  r0, [r1], #1            ; Adjust pointers except for terminating null
        SUBNE   r2, r2, #1
        MOV     pc, lr

VariformOutput ROUT
        Push    "lr"
        TEQ     r3, #0                  ; Ask for nothing, get a null string
        BNE     %FT10
        MOV     r0, #0
        BL      VariformOutputChar
        MOVVC   r0, r1
        Pull    "pc"
10
        ASSERT  ConvertToHex = 0
        CMP     r4, #(VariformHighest - VariformLowest) / 4
        ADDCC   pc, pc, r4, LSL #2
        BCS     VariBadConv
VariformLowest
        B       VariformOutputBinHex    ; ConvertToHex
        B       VariformOutputDec       ; ConvertToCardinal
        B       VariformOutputDec       ; ConvertToInteger
        B       VariformOutputBinHex    ; ConvertToBinary
        B       VariformOutputDecSpaced ; ConvertToSpacedCardinal
        B       VariformOutputDecSpaced ; ConvertToSpacedInteger
        B       VariformOutputDecPunct  ; ConvertToPunctCardinal
        B       VariformOutputDecPunct  ; ConvertToPunctInteger
        B       VariformOutputFileSize  ; ConvertToFixedFileSize
        B       VariformOutputFileSize  ; ConvertToFileSize
        B       VariformOutputDotColon  ; ConvertToIPv4
        B       VariformOutputDotColon  ; ConvertToEUI
        B       VariformOutputIPv6      ; ConvertToIPv6
        B       VariformOutputShortIPv6 ; ConvertToShortestIPv6
        B       VariformOutputBinHex    ; ConvertToHexLowercase
VariformHighest

VariBadConv
        ADR     r0, ErrorBlock_UnConv   ; Unsupported conversion
        B       %FT20
        MakeErrorBlock UnConv

VariBadNumb
        ADRL    r0, ErrorBlock_BadNumb  ; Bad number
20
      [ International
        BL      TranslateError
      |
        SETV
      ]
        Pull    "pc"

VariformOutputDecPunct ROUT
        Push    "r0-r1"
        MOV     r0, #-1
        MOV     r1, #1
        SWI     XTerritory_ReadSymbols
        STRVS   r0, [sp]
        Pull    "r0-r1, pc", VS
        LDRB    r10, [r0]               ; Thousands separator
        Pull    "r0-r1"
        B       %FT10

VariformOutputDecSpaced
        MOV     r10, #' '               ; Spaces between 1000's
        B       %FT10

VariformOutputDec
        MOV     r10, #0                 ; No gaps between 1000's
10
        CMP     r3, #8                  ; Deal with up to 2^(8*8) or 64 bit
        BHI     VariBadNumb

        Push    "r1, r5-r9"
        ADD     r12, r0, r3             ; Input block
        MOV     r14, r3
        MOV     r5, #0
        MOV     r6, #0
20
        LDRB    r0, [r12, #-1]!
        CMP     r14, #4
        ORRHI   r6, r0, r6, LSL #8      ; Hi input word
        ORRLS   r5, r0, r5, LSL #8      ; Lo input word
        SUBS    r14, r14, #1
        BNE     %BT20

        TEQ     r4, #ConvertToInteger
        TEQNE   r4, #ConvertToSpacedInteger
        TEQNE   r4, #ConvertToPunctInteger
        BNE     %FT40                   ; Treat unsigned

        TEQ     r3, #4
        MOVEQ   r6, r5, ASR #31         ; Extend lo to hi
        ANDS    r11, r3, #3
        BEQ     %FT30                   ; For 4 & 8, no further action
        RSB     r11, r11, #4
        MOV     r11, r11, LSL #3        ; Sign extend shift of (4 - (length MOD 4)) * 8 bit
        CMP     r3, #4
        MOVHI   r6, r6, LSL r11
        MOVHI   r6, r6, ASR r11
        MOVLS   r5, r5, LSL r11
        MOVLS   r5, r5, ASR r11
        MOVLS   r6, r5, ASR #31         ; Extend lo to hi too
30
        CMP     r6, #0                  ; Is it overall negative?
        BPL     %FT50
        MOV     r0, #'-'
        BL      VariformOutputChar
        Pull    "r1, r5-r9, pc", VS
        MVN     r5, r5
        MVN     r6, r6
        ADDS    r5, r5, #1
        ADC     r6, r6, #0              ; Take ABS(r5,r6)
40
        TEQ     r6, #0
50
        MOVEQ   r11, #9                 ; Maximum power of 10 to consider
        MOVNE   r11, #18
        MOV     r9, #0                  ; Supress leading zeros
60
        MOV     r0, #'0'                ; This digit
        CMP     r11, #10
        ADRCC   r12, TenTimesTable
        LDRCC   r7, [r12, r11, LSL #2]
        MOVCC   r8, #0
        ADRCS   r12, TenTimesBigTable - (10 * 8)
        LDRCS   r7, [r12, r11, LSL #3]!
        LDRCS   r8, [r12, #4]
70
        SUBS    r5, r5, r7
        SBCS    r6, r6, r8
        ADDPL   r0, r0, #1              ; Subtracted OK
        BPL     %BT70

        ADDS    r5, r5, r7
        ADC     r6, r6, r8              ; Correct the undershoot
        TEQ     r9, #0
        SUBEQS  r9, r0, #'0'            ; Reevaluate supression if supressing
        BEQ     %FT80
        BL      VariformOutputChar
        Pull    "r1, r5-r9, pc", VS
        MOV     r14, #1
        MOV     r14, r14, LSL r11
        LDR     r0, CommaPositions
        TST     r14, r0                 ; V still clear
        MOVNE   r0, r10
        BLNE    VariformOutputChar
        Pull    "r1, r5-r9, pc", VS
80
        SUBS    r11, r11, #1
        BNE     %BT60

        ADD     r0, r5, #'0'            ; Units column is simple
        BL      VariformOutputChar
        MOVVC   r0, #0
        BLVC    VariformOutputChar
        Pull    "r1, r5-r9, pc", VS
        Pull    "r0, r5-r9, pc"

VariformOutputFileSize ROUT
        CMP     r3, #8                  ; Deal with up to 2^(8*8) or 64 bit
        BHI     VariBadNumb

        Push    "r1, r5-r6"
        ADD     r12, r0, r3             ; Input block
        MOV     r14, r3
        MOV     r5, #0
        MOV     r6, #0
10
        LDRB    r0, [r12, #-1]!
        CMP     r14, #4
        ORRHI   r6, r0, r6, LSL #8      ; Hi input word
        ORRLS   r5, r0, r5, LSL #8      ; Lo input word
        SUBS    r14, r14, #1
        BNE     %BT10

        MOV     r10, #0                 ; SI unit index
20
        CMP     r6, #1
        CMPCC   r5, #4096               ; Keep dividing until < 4096
        BCC     %FT30
        MOV     r14, r6, LSL #22
        MOV     r6, r6, LSR #10
        MOVS    r5, r5, LSR #10
        ORR     r5, r14, r5
        ADCS    r5, r5, #0              ; Round up lost bit
        ADC     r6, r6, #0
        ADD     r10, r10, #1            ; Next 10^3 up
        B       %BT20
30
        TEQ     r4, #ConvertToFileSize
        BEQ     %FT50                   ; Don't do leading spaces

        MOV     r0, #' '                ; Do leading spaces
        CMP     r5, #1000
        BLCC    VariformOutputChar
        CMP     r5, #100
        BLCC    VariformOutputChar
        CMP     r5, #10
        BLCC    VariformOutputChar
        Pull    "r1, r5-r6, pc", VS
50
        Push    "r3-r5, r10"
        ADD     r0, sp, #8              ; Use R5
        MOV     r3, #2
        MOV     r4, #ConvertToCardinal
        BL      VariformOutput
        Pull    "r3-r5, r10"

        MOVVC   r0, #' '                ; Always need that space
        BLVC    VariformOutputChar
        Pull    "r1, r5-r6, pc", VS

        ADR     r14, PrefixSI
        LDRB    r0, [r14, r10]
        TEQ     r4, #ConvertToFileSize
        MOVNE   r10, #' '
        MOVEQ   r10, #0
        TEQEQ   r0, #' '
        MOVEQ   r0, #0                  ; Supress padding SI unit too
        BL      VariformOutputChar      ; Catch overflows when doing the suffix

        LDR     r0, SuffixSI
60
        BL      VariformOutputChar
        Pull    "r1, r5-r6, pc", VS
        MOVS    r0, r0, LSR #8
        BNE     %BT60

        CMP     r5, #1                  ; I am the one and only
        MOVNE   r0, #'s'
        MOVEQ   r0, r10
        BL      VariformOutputChar

        MOVVC   r0, #0                  ; Terminate
        BLVC    VariformOutputChar
        Pull    "r1, r5-r6, pc", VS
        Pull    "r0, r5-r6, pc"

VariformOutputShortIPv6 ROUT
        TST     r3, #1                  ; Must be a halfword multiple
        BNE     VariBadNumb

        Push    "r1, r3-r9"
        MOV     r12, r0                 ; Input block
        MOV     r10, #0                 ; Index loop
        MOV     r5, #0                  ; Set thisstart = 0
        MOV     r6, #0                  ;     thisrun = 0
        MOV     r7, #0                  ; Set maxstart = length
        MOV     r8, #0                  ;     maxrun = 0
        MOV     r9, #2_10               ; Set last != 0, current = 0
10
        LDRB    r11, [r12], #1          ; Hi
        LDRB    r14, [r12], #1          ; Lo
        ORRS    r14, r14, r11, LSL #8

        ORRNE   r9, r9, #2_01
        ANDS    r9, r9, #3
        ADDEQ   r6, r6, #1              ; Case 2_00 : last & current zero -> in a run
                                        ; Case 2_01 : last is zero, current is not -> end of a run
        CMP     r9, #2_10               ; Case 2_10 : last is nonzero, current is -> start of a run
        MOVEQ   r6, #1                  ; Case 2_11 : not interesting
        MOVEQ   r5, r10

        CMP     r6, r8                  ; max = MAX(max, this)
        MOVCS   r8, r6
        MOVCS   r7, r5

        MOV     r9, r9, LSL #1          ; last = current
        ADD     r10, r10, #2
        TEQ     r10, r3
        BNE     %BT10

        MOV     r4, #ConvertToIPv6
        MOV     r5, r0                  ; Keep original start
        CMP     r8, #1                  ; Longest run was only 1, don't compact this
        MOVLS   r7, r3                  ; Make maxstart = length
        BLS     %FT30

        ADD     r8, r7, r8, LSL #1      ; maxstart + maxcount

        SUB     r3, r3, r8              ; Do length - (maxstart + maxcount) to the end
        ADD     r0, r0, r8              ; At original start + (maxstart + maxcount)
        BL      VariformOutput

        MOVVC   r0, #':'                ; Skip maxcount, abbreviate to '::'
        BLVC    VariformOutputChar
        BLVC    VariformOutputChar
30
        MOVVC   r3, r7                  ; Lowest maxstart bytes
        MOVVC   r0, r5                  ; From original start
        BLVC    VariformOutput

        Pull    "r1, r3-r9, pc", VS
        Pull    "r0, r3-r9, pc"

VariformOutputIPv6
        TST     r3, #1                  ; Must be a halfword multiple
        BNE     VariBadNumb

        Push    "r1, r3"
        ADD     r12, r0, r3             ; Input block
10
        LDRB    r11, [r12, #-1]!        ; Hi
        LDRB    r0, [r12, #-1]!         ; Lo
        ORR     r0, r0, r11, LSL #8

        Push    "r3-r4, r12"
        MOV     r3, #1                  ; Must output at least 1 digit
        MOVS    r0, r0, LSR #4
        ADDNE   r3, r3, #1
        MOVS    r0, r0, LSR #4
        ADDNE   r3, r3, #1
        MOVS    r0, r0, LSR #4
        ADDNE   r3, r3, #1
        MOV     r4, #ConvertToHexLowercase
        MOV     r0, r12
        BL      VariformOutput          ; Up to 4 nybbles please
        Pull    "r3-r4, r12"
        Pull    "r1, r3, pc", VS

        SUBS    r3, r3, #2
        MOVNE   r0, #':'                ; Separator
20
        MOVEQ   r0, #0                  ; Terminator
        BL      VariformOutputChar
        Pull    "r1, r3, pc", VS

        TEQ     r3, #0
        Pull    "r0, r3, pc", EQ        ; Done
        B       %BT10                   ; More

VariformOutputDotColon ROUT
        Push    "r1, r3-r4"
        ADD     r12, r0, r3             ; Input block
        TEQ     r4, #ConvertToIPv4
        MOVEQ   r4, #ConvertToCardinal
        MOVEQ   r10, #'.'
        MOVNE   r4, #ConvertToHex
        MOVNE   r10, #':'
10
        LDRB    r11, [r12, #-1]!        ; Not actually used

        Push    "r3, r10, r12"
        TEQ     r4, #ConvertToHex
        MOVEQ   r3, #2                  ; Two nybbles please
        MOVNE   r3, #1                  ; One octet please
        MOV     r0, r12
        BL      VariformOutput
        Pull    "r3, r10, r12"
        Pull    "r1, r3-r4, pc", VS

        SUBS    r3, r3, #1
        MOVNE   r0, r10                 ; Separator
        MOVEQ   r0, #0                  ; Terminator
        BL      VariformOutputChar
        Pull    "r1, r3-r4, pc", VS

        TEQ     r3, #0
        Pull    "r0, r3-r4, pc", EQ     ; Done
        B       %BT10                   ; More

VariformOutputBinHex ROUT
        Push    "r1, r5"
        TEQ     r4, #ConvertToBinary
        MOVEQ   r5, #1                  ; Step size in bits
        MOVNE   r5, #4
        ADDEQ   r12, r0, r3             ; Input block
        ADDNE   r12, r3, #1
        ADDNE   r12, r0, r12, LSR #1    ; Input block adjusted for nybbles and bytes
        MOVEQ   r10, r3, LSL #3
        MOVNE   r10, r3, LSL #2         ; Total bit count
10
        TEQ     r10, #0
        BNE     %FT20
        MOV     r0, #0
        BL      VariformOutputChar      ; Terminate even if nothing
        Pull    "r1, r5, pc", VS
        Pull    "r0, r5, pc"
20
        LDRB    r11, [r12, #-1]!        ; Current byte
        TST     r10, #7
        MOVEQ   r11, r11, LSL #24       ; Work at top for LSL and LSR
        MOVNE   r11, r11, LSL #28       ; Partial nybble
30
        RSB     r0, r5, #32             ; Shift of 8 - step + 24
        MOV     r0, r11, LSR r0
        CMP     r0, #10
        ADDCC   r0, r0, #'0'
        ADDCS   r0, r0, #'A' - 10
        TEQ     r4, #ConvertToHexLowercase
        ORREQ   r0, r0, #&20            ; Lowercasify (0-9 unaffected)
        BL      VariformOutputChar
        Pull    "r1, r5, pc", VS

        MOV     r11, r11, LSL r5
        SUB     r10, r10, r5
        TST     r10, #7
        BNE     %BT30
        B       %BT10                   ; Either the end or need a new byte

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; OS_BinaryToDecimal
; ------------------
; Convert int32_t to string SWI (with no terminator)
; prefixed '-' if negative, leading zeros always stripped.
; In  : R0 signed 32-bit integer
;       R1 pointer to buffer
;       R2 max buffer length
; Out : R0, R1 unmodified
;       R2 actual chars given
;       V Set if buffer overflow

BinaryToDecimal_Code ROUT
        Push    "R0, R3-R5"
        MOV     R12, R2                 ; Keep buffer length
        MOV     R2, #0
        CMP     R0, #0
        BPL     %FT01
        SUBS    R12, R12, #1            ; Check enough buffer for '-'
        BMI     %FT10
        MOV     R11, #"-"
        STRB    R11, [R1]               ; Place the '-'
        MOV     R2, #1
        RSB     R0, R0, #0

        ; now do digits.
01      RSB     R0, R0, #0              ; get negative so minint works.
        ADRL    R3, TenTimesTable
        MOV     R10, #9                 ; max entry 10^9
        MOV     R4, #0                  ; non-0 had flag
02      LDR     R11, [R3, R10, LSL #2]
        MOV     R5, #-1                 ; digit value
03      ADDS    R0, R0, R11
        ADD     R5, R5, #1
        BLE     %BT03
        SUB     R0, R0, R11
        CMP     R5, #0
        CMPEQ   R4, #0
        BNE     %FT05                   ; put digit
04      SUBS    R10, R10, #1
        BPL     %BT02                   ; next digit
        CMP     R4, #0
        BEQ     %FT05                   ; finished, nothing output, must be '0'
        Pull    "R0, R3-R5"
        B       SLVK

05      SUBS    R12, R12, #1
        BMI     %FT10                   ; naff Exit
        ADD     R5, R5, #"0"
        MOV     R4, #-1                 ; set flag, a non-zero had
        STRB    R5, [R1, R2]
        ADD     R2, R2, #1
        B       %BT04
10
        ADRL    R0, BufferOFloError
    [ International
        Push    "lr"
        BL      TranslateError
        Pull    "lr"
    ]
        ADD     SP, SP, #4              ; discard R0 in
        Pull    "R3-R5"
        B       SLVK_SetV

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; OS_ConvertFileSize
; OS_ConvertFixedFileSize
; -----------------------
; Do length as xxxx bytes or xxxx kbytes or xxxx Mbytes
; In  : R0 file size in bytes
;       R1 pointer to buffer
;       R2 max buffer length
; Out : R0 pointer to buffer
;       R1 pointer to terminator
;       R2 free bytes in buffer
;       V Set if buffer overflow

FileSize_Code ROUT
        Push    "r0, r3-r4, lr"
        MOV     r0, sp

        MOVEQ   r4, #ConvertToFixedFileSize
        MOVNE   r4, #ConvertToFileSize

        MOV     r3, #4                  ; Always 4 bytes

        BL      VariformOutput
        ADD     sp, sp, #4
        Pull    "r3-r4, lr"
        B       SLVK_TestV

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; OS_ConvertNetStation
; OS_ConvertFixedNetStation
; -------------------------
; EcoNet conversions of the form 'nnn.sss' for the fixed variant, or shorter
; In  : R0 pointer to two word net/station number block
;       R1 pointer to buffer
;       R2 max buffer length
; Out : R0 pointer to buffer
;       R1 pointer to terminator
;       R2 free bytes in buffer
;       V Set if buffer overflow

rStn    RN      10
rNet    RN      12
NetStation_Code ROUT
        Push    "r1, r9, lr"

        ASSERT  rStn < rNet
        LDMIA   r0, { rStn, rNet }
        CMP     rNet, #256
        ADRCS   r0, ErrorBlock_BadNetwork
        BCS     %FT40

        CMP     rStn, #0
        CMPNE   rStn, #256
        ADRCS   r0, ErrorBlock_BadStation
        BCS     %FT40

        TEQ     r11, #OS_ConvertNetStation
        MOVNE   r9, #' '                ; Select padding
        MOVEQ   r9, #0
        BL      NetToDec
        BVS     %FT30

        MOV     r0, #'.'                ; Dot normally
        CMP     rNet, #1                ; Prepare carry
        TEQ     r11, #OS_ConvertNetStation
        BNE     %FT10
        MOVCC   r0, #0                  ; Nothing for net of zero
        MOV     r9, #0                  ; Then no padding regardless
        B       %FT20
10
        MOVCC   r0, #' '                ; Space next if net of zero
        MOVCC   r9, #' '                ; Prepad with space
        MOVCS   r9, #'0'                ; or 0
20
        BL      VariformOutputChar
        MOVVC   rNet, rStn
        BLVC    NetToDec                ; Includes terminator
30
        Pull    "r0, r9, lr", VC
        Pull    "r1, r9, lr", VS
        B       SLVK_TestV
40
      [ International
        BL      TranslateError
        Pull    "r1, r9, lr"
        B       SLVK_SetV
      |
        Pull    "r1, r9, lr"
        B       SLVK_SetV
      ]

NetToDec
        Push    "lr"
        MOV     r0, r9
        CMP     rNet, #100
        BLCC    VariformOutputChar
        CMP     rNet, #10
        BLCC    VariformOutputChar

        TEQ     rNet, #0                ; Can't have a station of zero anyway
        BNE     %FT50
        BL      VariformOutputChar      ; Pad instead of "0"
        Pull    "pc"
50
        MOV     r0, rNet
        SWI     XOS_ConvertCardinal1
        Pull    "pc"

        MakeInternatErrorBlock BadNetwork,,BadNet

        MakeInternatErrorBlock BadStation,,BadStn

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; OS_ConvertStandardDateAndTime
; -----------------------------
; Convert from 5-byte cs representation to format specified in <SYS$DateFormat>
; In  : R0 -> time block
;       R1 -> buffer to accept conversion
;       R2 = size of buffer
;
; Out : R0 = input value of R1, or error block
;       R1 = updated pointer to buffer
;       R2 = updated size of buffer
;       V Set if error

StandardDateTime_Code ROUT
        Push    "R3, R14"
        MOVS    R3, R2                  ; Territory SWI wants things one register up
        BMI     %FT10                   ; Actively reject unlikely buffer sizes
        MOV     R2, R1
        MOV     R1, R0
        MOV     R0, #-1                 ; Use configured territory
        SWI     XTerritory_ConvertStandardDateAndTime
        Pull    "R3, R14"
        B       SLVK_TestV

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; OS_ConvertDateAndTime
; ---------------------
; Convert from 5-byte cs representation to format specified by user
; In  : R0 -> time block
;       R1 -> buffer to accept conversion
;       R2 = size of buffer
;       R3 -> format string
;
; Out : R0 = input value of R1, or error block
;       R1 = updated pointer to buffer
;       R2 = updated size of buffer
;       V Set if error

DateTime_Code
        Push    "R3-R4, R14"
        MOV     R4, R3                  ; Territory SWI wants things one register up.
        MOVS    R3, R2
        BMI     %FT10                   ; Actively reject unlikely buffer sizes
        MOV     R2, R1
        MOV     R1, R0
        MOV     R0, #-1                 ; Use configured territory.
        SWI     XTerritory_ConvertDateAndTime
        Pull    "R3-R4, R14"
        B       SLVK_TestV
10
        ADRL    R0, ErrorBlock_BuffOverflow
      [ International
        BL      TranslateError
      ]
        B       SLVK_SetV

        END