summaryrefslogtreecommitdiff
path: root/v4.0/src/INC/PRINTF.ASM
diff options
context:
space:
mode:
Diffstat (limited to 'v4.0/src/INC/PRINTF.ASM')
-rw-r--r--v4.0/src/INC/PRINTF.ASM415
1 files changed, 415 insertions, 0 deletions
diff --git a/v4.0/src/INC/PRINTF.ASM b/v4.0/src/INC/PRINTF.ASM
new file mode 100644
index 0000000..bc871b4
--- /dev/null
+++ b/v4.0/src/INC/PRINTF.ASM
@@ -0,0 +1,415 @@
1TITLE PRINTF ROUITNE FOR MS-DOS
2;
3; PRINTF(Control String, arg1, arg2,...,argn-1,argn)
4;
5; Characters are output to PFHandle according to the
6; specifications contained in the Control String.
7;
8; The conversion characters are as follow:
9;
10; %c - output the next argument as a character
11; %s - output the next argument as a string
12; %x - output the next argument as a hexidecimal number
13; using abcedf
14; %X - output the next argument as a hexidecimal number
15; using ABCDEF
16; %d - output the next argument as a decimal number
17;
18;
19; Other format specifiers that may precede the conversion character are:
20;
21; - (minus sign) - causes the field to be left-adjusted
22; + (plus sign) - causes the field to be right-adjusted (default)
23; n - digit specifing the minimum field width (default to 1)
24; L - specifing a long integer
25;
26; On entry to PRINTF the stack contains the return address and a pointer
27; to an argument list.
28;
29; ____________________
30; | Ret Addr | <= SP
31; --------------------
32; | Ptr to Arg List |
33; --------------------
34;
35; And the argument list contains the following:
36;
37; String_ptr (a pointer to the control string)
38; Arg 1
39; Arg 2
40; .
41; .
42; .
43; Arg n-1
44; Arg n
45;
46; If the argument is a %s or %c the arg contains a pointer to the string
47; or character.
48;
49; The arguments are used in one-to-one correspondence to % specifiers.
50
51.xlist
52.xcref
53 INCLUDE dossym.asm
54.cref
55.list
56
57printf_CODE SEGMENT public byte
58ASSUME CS:PRINTF_CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING
59
60 PUBLIC PRINTF, PFHandle
61 PUBLIC PRINTF_LAST
62
63PFHandle DW 1
64PRINTF_LEFT DB 0
65PRINTF_LONG DB 0
66PRINTF_HEX DB 0
67TABLE_INDEX DB 0
68S_FLAG DB 0
69PRINTF_WIDTH DW 0
70PRINTF_BASE DW 0
71PAD_CHAR DB " "
72
73PRINTF_TABLE DB "0123456789ABCDEFabcdef"
74
75PRINTF_STACK STRUC
76OLDES DW ?
77OLDDS DW ?
78OLDSI DW ?
79OLDDI DW ?
80OLDAX DW ?
81OLDBX DW ?
82OLDCX DW ?
83OLDDX DW ?
84OLDBP DW ?
85OLDCS DW ?
86OLDIP DW ?
87STRING DW ?
88PRINTF_STACK ENDS
89
90PRINTF_ARGS STRUC
91CONSTR DW ?
92ARG DW ?
93PRINTF_ARGS ENDS
94
95RET_ADDR1 DW ?
96RET_ADDR2 DW ?
97
98BUFSIZ = 20
99PRINTF_BUF DB BUFSIZ DUP (?)
100 db 0 ;This buffer is always nul terminated
101BUFEND DW $-PRINTF_BUF
102
103PRINTF proc far
104 PUSH BP ;Save the callers' registers
105 PUSH DX
106 PUSH CX
107 PUSH BX
108 PUSH AX
109 PUSH DI
110 PUSH SI
111 PUSH ES
112 PUSH DS
113 MOV BP,SP
114 PUSH CS
115 POP ES ;ES points to Printf segment
116 MOV DI,OFFSET PRINTF_BUF ;DI points to the output buffer
117 MOV BP,[BP.STRING] ;BP points to the argument list
118 MOV SI,DS:[BP] ;SI points to the control string
119 XOR BX,BX ;BX is the index into the arg list
120 CALL Clear_flags ; initialize the world
121GET_CHAR:
122 LODSB ;Get a character
123 CMP AL,"%" ;Is it a conversion specifier?
124 JZ CONV_CHAR ;Yes - find out which one
125 OR AL,AL ;Is it the end of the control string?
126 JZ PRINTF_DONE ;Yes - then we're done
127 CALL OUTCHR ;Otherwise store the character
128 JMP SHORT GET_CHAR ;And go get another
129
130PRINTF_DONE:
131 CALL FLUSH
132 POP DS
133 POP ES
134 POP SI
135 POP DI
136 POP AX
137 POP BX
138 POP CX
139 POP DX
140 POP BP
141 POP CS:[RET_ADDR1] ;Fix up the stack
142 POP CS:[RET_ADDR2]
143 POP AX
144 PUSH CS:[RET_ADDR2]
145 PUSH CS:[RET_ADDR1]
146 RET
147
148printf endp
149
150PRINTF_PERCENT:
151 CALL OUTCHR
152 JMP GET_CHAR
153
154CONV_CHAR:
155 ;Look for any format specifiers preceeding the conversion character
156 LODSB
157 CMP AL,"%" ;Just print the %
158 JZ PRINTF_PERCENT
159 CMP AL,"-" ;Right justify the field
160 JZ LEFT_ADJ
161 CMP AL,"+" ;Left justify the field
162 JZ NXT_CONV_CHAR
163 CMP AL,"L" ;Is it a long integer
164 JZ LONG_INT
165 CMP AL,"l"
166 JZ LONG_INT
167 CMP AL,"0" ;Is it a precision specification
168 JB LOOK_CONV_CHAR
169 CMP AL,"9"
170 JA LOOK_CONV_CHAR
171 CMP AL,"0"
172 JNZ NOT_PAD
173 CMP CS:[PRINTF_WIDTH],0
174 JNZ NOT_PAD
175 MOV CS:BYTE PTR [PAD_CHAR],"0"
176NOT_PAD:
177 PUSH AX ;Adjust decimal place on precision
178 MOV AX,10
179 MUL CS:[PRINTF_WIDTH]
180 MOV CS:[PRINTF_WIDTH],AX
181 POP AX
182 XOR AH,AH
183 SUB AL,"0"
184 ADD CS:[PRINTF_WIDTH],AX ;And save the total
185 JMP SHORT NXT_CONV_CHAR
186
187 ;Set the correct flags for the options in a conversion
188
189LEFT_ADJ:
190 INC CS:BYTE PTR[PRINTF_LEFT]
191 JMP SHORT NXT_CONV_CHAR
192
193LONG_INT:
194 INC CS:BYTE PTR[PRINTF_LONG]
195NXT_CONV_CHAR:
196 JMP CONV_CHAR
197
198 ;Look for a conversion character
199
200LOOK_CONV_CHAR:
201 CMP AL,"X"
202 JZ HEX_UP
203
204 ;Make all other conversion characters upper case
205
206 CMP AL,"a"
207 JB CAPS
208 CMP AL,"z"
209 JG CAPS
210 AND AL,0DFH
211CAPS:
212 CMP AL,"X"
213 JZ HEX_LO
214 CMP AL,"D"
215 JZ DECIMAL
216 CMP AL,"C"
217 JZ C_PUT_CHAR
218 CMP AL,"S"
219 JZ S_PUT_STRG
220
221 ;Didn't find any legal conversion character - IGNORE it
222
223 call clear_flags
224 jmp get_char
225
226HEX_LO:
227 MOV CS:[TABLE_INDEX],6 ;Will print lower case hex digits
228HEX_UP:
229 MOV CS:[PRINTF_BASE],16 ;Hex conversion
230 JMP CONV_TO_NUM
231
232DECIMAL:
233 MOV CS:[PRINTF_BASE],10 ;Decimal conversion
234 JMP CONV_TO_NUM
235
236S_PUT_STRG:
237 INC CS:[S_FLAG] ;It's a string specifier
238C_PUT_CHAR:
239 PUSH SI ;Save pointer to control string
240 MOV SI,BX
241 ADD BX,2
242 MOV SI,ds:[BP+SI.ARG] ;Point to the % string or character
243 CMP BYTE PTR CS:[S_FLAG],0
244 JNZ S_PUT_1
245 LODSB
246 cmp al,0
247 jz short c_s_end
248 CALL OUTCHR ;Put it into our buffer
249 JMP SHORT C_S_END
250
251S_PUT_1:
252 mov cx,cs:[printf_width]
253 or cx,cx
254 jz s_put_2
255 cmp cs:byte ptr[printf_left],0
256 jnz s_put_2
257 push si
258 call Pad_string
259 pop si
260s_put_2:
261 push si
262s_put_3:
263 LODSB ;Put them all in our buffer
264 CMP AL,0
265 jz s_put_4
266 CALL OUTCHR
267 jmp short S_PUT_3
268s_put_4:
269 pop si
270 cmp byte ptr[printf_left],0
271 jz c_s_end
272 mov cx,cs:[printf_width]
273 or cx,cx
274 jz c_s_end
275 call Pad_string
276C_S_END:
277 call clear_flags
278 POP SI ;Restore control string pointer
279 JMP GET_CHAR ;Go get another character
280
281pad_string:
282 xor dx,dx
283count_loop:
284 lodsb
285 or al,al
286 jz count_done
287 inc dx
288 jmp short count_loop
289count_done:
290 sub cx,dx
291 jbe count_ret
292 call pad
293count_ret:
294 ret
295
296CONV_TO_NUM:
297
298 PUSH SI ;Save pointer to control string
299 MOV SI,BX ;Get index into argument list
300 ADD BX,2 ;Increment the index
301 MOV AX,ds:[BP+SI.ARG] ;Lo word of number in SI
302 CMP BYTE PTR CS:[PRINTF_LONG],0 ;Is this is a short or long integer?
303 JZ NOT_LONG_INT
304 MOV SI,BX ;Copy index
305 ADD BX,2 ;Increment the index
306 MOV DX,ds:[BP+SI.ARG] ;Hi word of number in BP
307 JMP SHORT DO_CONV
308NOT_LONG_INT:
309 XOR DX,DX ;Hi word is zero
310DO_CONV:
311 PUSH BX ;Save index into arguemnt list
312 MOV si,CS:[PRINTF_BASE]
313 MOV cx,CS:[PRINTF_WIDTH]
314 CALL PNUM
315 CALL PAD
316CONV_DONE:
317 call clear_flags
318 POP BX
319 POP SI
320 jmp get_char
321
322PNUM:
323 DEC CX
324 PUSH AX
325 MOV AX,DX
326 XOR DX,DX
327 DIV SI
328 MOV BX,AX
329 POP AX
330 DIV SI
331 XCHG BX,DX
332 PUSH AX
333 OR AX,DX
334 POP AX
335 JZ DO_PAD
336 PUSH BX
337 CALL PNUM
338 POP BX
339 JMP SHORT REM
340DO_PAD:
341 CMP CS:BYTE PTR[PRINTF_LEFT],0
342 JNZ REM
343 CALL PAD
344REM:
345 MOV AX,BX
346 CMP AL,10
347 JB NOT_HEX
348 CMP CS:BYTE PTR [PRINTF_HEX],0
349 JNZ NOT_HEX
350 ADD AL,CS:BYTE PTR [TABLE_INDEX]
351NOT_HEX:
352 MOV BX,OFFSET PRINTF_TABLE
353 PUSH DS
354 PUSH CS
355 POP DS
356 XLAT 0
357 POP DS
358 push cx
359 CALL OUTCHR
360 pop cx
361 RET
362
363PAD:
364 OR CX,CX
365 JLE PAD_DONE
366 MOV AL,CS:BYTE PTR [PAD_CHAR]
367PAD_LOOP:
368 push cx
369 CALL OUTCHR
370 pop cx
371 LOOP PAD_LOOP
372PAD_DONE:
373 RET
374
375OUTCHR:
376 STOSB
377 CMP DI,offset bufend-1 ;Don't count the nul
378 RETNZ
379 MOV CX,BUFSIZ
380WRITE_CHARS:
381 push bx
382 MOV BX,PFHandle
383 push ds
384 PUSH CS
385 POP DS
386 MOV DX,OFFSET PRINTF_BUF
387 MOV AH,WRITE
388 INT 21H
389 pop ds
390 pop bx
391 MOV DI,OFFSET PRINTF_BUF
392 RET
393
394FLUSH:
395 CMP DI,OFFSET PRINTF_BUF
396 RETZ
397 SUB DI,OFFSET PRINTF_BUF
398 MOV CX,DI
399 call write_chars
400 ret
401
402CLEAR_FLAGS:
403 XOR ax,ax
404 MOV BYTE PTR CS:[PRINTF_LEFT],al ;Reset justifing flag
405 MOV BYTE PTR CS:[PRINTF_LONG],al ;Reset long flag
406 MOV BYTE PTR CS:[TABLE_INDEX],al ;Reset hex table index
407 MOV CS:[PRINTF_WIDTH],ax ;Reinitialize width to 0
408 MOV BYTE PTR CS:[PAD_CHAR]," " ;Reset padding character
409 MOV BYTE PTR CS:[S_FLAG],al ;Clear the string flag
410 ret
411
412PRINTF_LAST LABEL WORD
413printf_CODE ENDS
414 END
415 \ No newline at end of file