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