diff options
Diffstat (limited to 'v4.0/src/INC/PRINTF.ASM')
| -rw-r--r-- | v4.0/src/INC/PRINTF.ASM | 415 |
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 @@ | |||
| 1 | TITLE 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 | |||
| 57 | printf_CODE SEGMENT public byte | ||
| 58 | ASSUME CS:PRINTF_CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING | ||
| 59 | |||
| 60 | PUBLIC PRINTF, PFHandle | ||
| 61 | PUBLIC PRINTF_LAST | ||
| 62 | |||
| 63 | PFHandle DW 1 | ||
| 64 | PRINTF_LEFT DB 0 | ||
| 65 | PRINTF_LONG DB 0 | ||
| 66 | PRINTF_HEX DB 0 | ||
| 67 | TABLE_INDEX DB 0 | ||
| 68 | S_FLAG DB 0 | ||
| 69 | PRINTF_WIDTH DW 0 | ||
| 70 | PRINTF_BASE DW 0 | ||
| 71 | PAD_CHAR DB " " | ||
| 72 | |||
| 73 | PRINTF_TABLE DB "0123456789ABCDEFabcdef" | ||
| 74 | |||
| 75 | PRINTF_STACK STRUC | ||
| 76 | OLDES DW ? | ||
| 77 | OLDDS DW ? | ||
| 78 | OLDSI DW ? | ||
| 79 | OLDDI DW ? | ||
| 80 | OLDAX DW ? | ||
| 81 | OLDBX DW ? | ||
| 82 | OLDCX DW ? | ||
| 83 | OLDDX DW ? | ||
| 84 | OLDBP DW ? | ||
| 85 | OLDCS DW ? | ||
| 86 | OLDIP DW ? | ||
| 87 | STRING DW ? | ||
| 88 | PRINTF_STACK ENDS | ||
| 89 | |||
| 90 | PRINTF_ARGS STRUC | ||
| 91 | CONSTR DW ? | ||
| 92 | ARG DW ? | ||
| 93 | PRINTF_ARGS ENDS | ||
| 94 | |||
| 95 | RET_ADDR1 DW ? | ||
| 96 | RET_ADDR2 DW ? | ||
| 97 | |||
| 98 | BUFSIZ = 20 | ||
| 99 | PRINTF_BUF DB BUFSIZ DUP (?) | ||
| 100 | db 0 ;This buffer is always nul terminated | ||
| 101 | BUFEND DW $-PRINTF_BUF | ||
| 102 | |||
| 103 | PRINTF 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 | ||
| 121 | GET_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 | |||
| 130 | PRINTF_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 | |||
| 148 | printf endp | ||
| 149 | |||
| 150 | PRINTF_PERCENT: | ||
| 151 | CALL OUTCHR | ||
| 152 | JMP GET_CHAR | ||
| 153 | |||
| 154 | CONV_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" | ||
| 176 | NOT_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 | |||
| 189 | LEFT_ADJ: | ||
| 190 | INC CS:BYTE PTR[PRINTF_LEFT] | ||
| 191 | JMP SHORT NXT_CONV_CHAR | ||
| 192 | |||
| 193 | LONG_INT: | ||
| 194 | INC CS:BYTE PTR[PRINTF_LONG] | ||
| 195 | NXT_CONV_CHAR: | ||
| 196 | JMP CONV_CHAR | ||
| 197 | |||
| 198 | ;Look for a conversion character | ||
| 199 | |||
| 200 | LOOK_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 | ||
| 211 | CAPS: | ||
| 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 | |||
| 226 | HEX_LO: | ||
| 227 | MOV CS:[TABLE_INDEX],6 ;Will print lower case hex digits | ||
| 228 | HEX_UP: | ||
| 229 | MOV CS:[PRINTF_BASE],16 ;Hex conversion | ||
| 230 | JMP CONV_TO_NUM | ||
| 231 | |||
| 232 | DECIMAL: | ||
| 233 | MOV CS:[PRINTF_BASE],10 ;Decimal conversion | ||
| 234 | JMP CONV_TO_NUM | ||
| 235 | |||
| 236 | S_PUT_STRG: | ||
| 237 | INC CS:[S_FLAG] ;It's a string specifier | ||
| 238 | C_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 | |||
| 251 | S_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 | ||
| 260 | s_put_2: | ||
| 261 | push si | ||
| 262 | s_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 | ||
| 268 | s_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 | ||
| 276 | C_S_END: | ||
| 277 | call clear_flags | ||
| 278 | POP SI ;Restore control string pointer | ||
| 279 | JMP GET_CHAR ;Go get another character | ||
| 280 | |||
| 281 | pad_string: | ||
| 282 | xor dx,dx | ||
| 283 | count_loop: | ||
| 284 | lodsb | ||
| 285 | or al,al | ||
| 286 | jz count_done | ||
| 287 | inc dx | ||
| 288 | jmp short count_loop | ||
| 289 | count_done: | ||
| 290 | sub cx,dx | ||
| 291 | jbe count_ret | ||
| 292 | call pad | ||
| 293 | count_ret: | ||
| 294 | ret | ||
| 295 | |||
| 296 | CONV_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 | ||
| 308 | NOT_LONG_INT: | ||
| 309 | XOR DX,DX ;Hi word is zero | ||
| 310 | DO_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 | ||
| 316 | CONV_DONE: | ||
| 317 | call clear_flags | ||
| 318 | POP BX | ||
| 319 | POP SI | ||
| 320 | jmp get_char | ||
| 321 | |||
| 322 | PNUM: | ||
| 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 | ||
| 340 | DO_PAD: | ||
| 341 | CMP CS:BYTE PTR[PRINTF_LEFT],0 | ||
| 342 | JNZ REM | ||
| 343 | CALL PAD | ||
| 344 | REM: | ||
| 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] | ||
| 351 | NOT_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 | |||
| 363 | PAD: | ||
| 364 | OR CX,CX | ||
| 365 | JLE PAD_DONE | ||
| 366 | MOV AL,CS:BYTE PTR [PAD_CHAR] | ||
| 367 | PAD_LOOP: | ||
| 368 | push cx | ||
| 369 | CALL OUTCHR | ||
| 370 | pop cx | ||
| 371 | LOOP PAD_LOOP | ||
| 372 | PAD_DONE: | ||
| 373 | RET | ||
| 374 | |||
| 375 | OUTCHR: | ||
| 376 | STOSB | ||
| 377 | CMP DI,offset bufend-1 ;Don't count the nul | ||
| 378 | RETNZ | ||
| 379 | MOV CX,BUFSIZ | ||
| 380 | WRITE_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 | |||
| 394 | FLUSH: | ||
| 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 | |||
| 402 | CLEAR_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 | |||
| 412 | PRINTF_LAST LABEL WORD | ||
| 413 | printf_CODE ENDS | ||
| 414 | END | ||
| 415 | \ No newline at end of file | ||