1 2SECTION code_clib 3SECTION code_stdio 4 5PUBLIC __stdio_printf_number_tail 6PUBLIC __stdio_printf_number_tail_zero 7 8EXTERN __stdio_printf_sign, asm__memlwr, l_maxu_bc_hl, l_addu_hl_de 9EXTERN __stdio_send_output_buffer, __stdio_printf_padding_width_hl, __stdio_printf_padding_precision_bc 10EXTERN __stdio_printf_padding_precision_hl, __stdio_printf_padding_width_bc 11 12__stdio_printf_number_tail_zero: 13 14 ; ix = FILE * 15 ; hl = 0 16 ; stack = buffer_digits, width, precision 17 ; carry reset 18 19 ld c,l 20 ld b,h ; bc = num_sz = 0 21 22 pop de ; de = internal_spacing = precision 23 24 pop hl ; hl = width 25 sbc hl,de ; hl = external_spacing = width - precision 26 27 jr nc, number_zero 28 29 ld hl,0 ; width field exceeded, external_spacing = 0 30 jr number_zero 31 32__stdio_printf_number_tail: 33 34 or a 35 sbc hl,de 36 ld c,l 37 ld b,h ; bc = num_sz = number of digits written to ascii buffer 38 39 ; common tail code for outputting number on stream 40 ; 41 ; enter : ix = FILE * 42 ; bc = num_sz = number of ascii digits generated in buffer 43 ; stack = void *buffer_digits, width, precision 44 ; 45 ; exit : carry set if stream error 46 ; 47 ; NOTE: (buffer_digits - 3) points at buffer space of three free bytes 48 49 ; determine internal spacing to satisfy precision field 50 51 pop hl ; hl = precision 52 53 ld e,l 54 ld d,h 55 56 call l_maxu_bc_hl 57 ex de,hl ; de = max(precision, num_sz) 58 59 or a 60 sbc hl,bc ; hl = precision - num_sz = internal_spacing 61 jr nc, internal_required 62 63 ld hl,0 ; precision field exceeded 64 65internal_required: 66 67 ; continue computation of output size (num_chars) 68 69 ; ix = FILE * 70 ; hl = internal_spacing 71 ; bc = num_sz 72 ; de = num_chars = max(precision, num_sz) 73 ; stack = buffer_digits, width 74 75 ld a,(ix+5) ; get conversion flags 76 and $e0 ; are any of negative, '+' or ' ' set ? 77 jr z, no_sign ; if no 78 79 inc de ; num_chars++ 80 81no_sign: 82 83 bit 4,(ix+5) ; base indicator flag set ? 84 jr z, no_base_indicator ; if no 85 86 inc de ; num_chars++ 87 88 bit 1,(ix+5) ; is this octal or hex conversion ? 89 jr nz, no_base_indicator ; if octal 90 91 inc de ; num_chars++ 92 93no_base_indicator: 94 95 ; determine external spacing to satisfy width field 96 97 ex (sp),hl 98 99 ; ix = FILE * 100 ; hl = width 101 ; bc = num_sz 102 ; de = num_chars 103 ; stack = buffer_digits, internal_spacing 104 105 sbc hl,de ; hl = width - num_chars 106 jr nc, external_required 107 108 ld hl,0 ; width field exceeded 109 110external_required: 111 112 ; deal with '0' flag 113 114 pop de 115 116number_zero: 117 118 ; ix = FILE * 119 ; hl = external_spacing 120 ; bc = num_sz 121 ; de = internal_spacing 122 ; stack = buffer_digits 123 124 ld a,(ix+5) ; get conversion flags 125 and $0d ; keep '0', '-', precision_specified 126 cp $08 ; is '0' set and '-' reset and 'P' reset ? 127 128 jr nz, spacing_ok 129 130 ; any external_spacing required becomes internal_spacing 131 132 call l_addu_hl_de 133 134 ex de,hl ; de = internal_spacing = external_spacing + internal_spacing 135 ld hl,0 ; hl = external_spacing = 0 136 137spacing_ok: 138 139 push de 140 141 ; ix = FILE * 142 ; bc = num_sz = number of ascii digits in buffer 143 ; hl = external_spacing 144 ; stack = void *buffer_digits, internal_spacing 145 146 bit 2,(ix+5) 147 jr nz, left_justify ; if left justify flag selected 148 149right_justify: 150 151 push bc ; save num_sz 152 153 call __stdio_printf_padding_width_hl ; fill width with spaces 154 155 pop bc ; bc = num_sz 156 pop de ; de = internal_spacing 157 pop hl ; hl = void *buffer_digits 158 159 ret c ; if stream error 160 161out_internal: 162 163 ; bc = num_sz 164 ; de = internal_spacing 165 ; hl = void *buffer_digits 166 167 ld a,b 168 or c 169 jr z, num_is_zero ; if number is zero 170 171 dec hl 172 dec hl 173 dec hl ; hl = buffer_digits - 3 = void *buffer 174 175 ; output precision field 176 ; 177 ; bc = num_sz = number of ascii digits in buffer 178 ; de = internal_spacing = number of 0s to fulfill precision 179 ; hl = void *buffer 180 181 push bc ; save num_sz 182 push de ; save internal_spacing 183 184 ld e,l 185 ld d,h ; de = void *buffer 186 187 bit 6,(ix+4) 188 call nz, __stdio_printf_sign ; if signed conversion, write possible sign to buffer 189 190 bit 4,(ix+5) 191 jr z, no_base_indicator_2 ; if base indicator flag is not selected 192 193 ; write base indicator 194 195 ld (hl),'0' ; for both octal or hex base indicator 196 197 bit 1,(ix+5) 198 jr nz, octal_base ; if octal prefix 199 200hex_base: 201 202 inc hl 203 ld (hl),'x' 204 205 bit 7,(ix+4) 206 jr z, octal_base ; if lower case 207 208 ld (hl),'X' 209 210octal_base: 211 212 inc hl 213 214no_base_indicator_2: 215 216 ; hl = one char past end of buffer 217 ; de = void *buffer 218 ; stack = num_sz, internal_spacing 219 220 or a 221 sbc hl,de 222 223 ld c,l 224 ld b,h ; bc = number of prefix chars 225 226 ex de,hl ; hl = void *buffer 227 push hl ; save buffer 228 229 call __stdio_send_output_buffer 230 231 pop de ; de = void *buffer 232 jr c, stream_error 233 234no_prefix_chars: 235 236 ; de = void *buffer 237 ; stack = num_sz, internal_spacing 238 239 pop bc ; bc = internal_spacing 240 push de ; save buffer 241 242 call __stdio_printf_padding_precision_bc ; output 0s to fulfill precision 243 244stream_error: 245 246 pop hl ; hl = buffer 247 pop bc ; bc = num_sz 248 249 ret c ; if stream error 250 251 inc hl 252 inc hl 253 inc hl ; hl = void *buffer_digits 254 255 bit 7,(ix+4) 256 jp nz, __stdio_send_output_buffer ; if upper case 257 258 push bc ; save num_sz 259 260 call asm__memlwr ; uncapitalize buffer 261 262 pop bc ; bc = num_sz 263 jp __stdio_send_output_buffer 264 265num_is_zero: 266 267 ; for zero, only the precision filler is output 268 269 ; de = internal_spacing = number of 0s to fulfill precision 270 271 ex de,hl 272 jp __stdio_printf_padding_precision_hl 273 274left_justify: 275 276 ; ix = FILE * 277 ; bc = num_sz = number of ascii digits in buffer 278 ; hl = external_spacing 279 ; stack = void *buffer_digits, internal_spacing 280 281 pop de ; de = internal spacing 282 ex (sp),hl ; hl = void *buffer_digits 283 284 call out_internal ; output precision field 285 286 pop bc ; bc = external_spacing 287 288 jp nc, __stdio_printf_padding_width_bc ; if no stream error 289 ret 290