!************************************************************************** !* !* Boot-ROM-Code to load an operating system across a TCP/IP network. !* !* Module: printf.S !* Purpose: Print a formatted string !* Entries: _printf !* !************************************************************************** !* !* Copyright (C) 1995-2003 Gero Kuhlmann !* !* This program is free software; you can redistribute it and/or modify !* it under the terms of the GNU General Public License as published by !* the Free Software Foundation; either version 2 of the License, or !* any later version. !* !* This program is distributed in the hope that it will be useful, !* but WITHOUT ANY WARRANTY; without even the implied warranty of !* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the !* GNU General Public License for more details. !* !* You should have received a copy of the GNU General Public License !* along with this program; if not, write to the Free Software !* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. !* !* $Id: printf.S,v 1.4 2003/01/25 23:29:41 gkminix Exp $ !* ! !************************************************************************** ! ! Include assembler macros: ! #include #include "libpriv.inc" ! !************************************************************************** ! ! Select the appropriate output routine according to the preprocessor ! flags: ! #ifdef USEANSI #define DOPRINT prnansi #else #define DOPRINT prnchar #endif ! !************************************************************************** ! ! BSS segment: ! .bss BUFSIZE equ 12 ! size of number buffer .lcomm numbuf,BUFSIZE ! buffer for number conversion ! !************************************************************************** ! ! Start code segment. ! .text public _printf ! define entry points extrn DOPRINT ! external print routine ! !************************************************************************** ! ! Print formatted string. ! Input: 1. arg - format string ! ... - arguments according to format string ! Output: none ! _printf: penter (0) ! setup standard stack frame push si push di getcarg (si,0) ! get pointer to format string mov bx,#1 ! BX = argument counter cld ! The following is the basic printing routine. It checks, wether there ! is a special character in the format string. If it is not, the current ! character just gets printed out. print1: lodsb print5: or al,al ! at end of string? jz print3 cmp al,#CHR_PERCENT ! print argument? je prna1 print2: cmp al,#CHR_LF ! convert linefeed into newline jne print4 call DOPRINT mov al,#CHR_CR print4: CALL DOPRINT ! print character jmp print1 ! and check for next character print3: jmp near print9 ! jump to end of routine ! Handle argument format. This is a bit simpler than usually implemented ! in a C library. If the first character after the initial % is another ! %, print this as a single % character. Otherwise the argument format ! is as follows: ! ! %[width]indicator ! ! with indicator being one of the following: ! ! c - character ! s - string ! d - decimal number (signed) ! u - decimal number (unsigned) ! o - octal number (unsigned) ! x - unsigned hexadecimal number (unsigned) ! ! The width field can be missing, or be the character 'l', which means a ! long argument for integer numbers, or a pointer to a string followed ! by a length argument for a string argument. prna1: lodsb ! get next character or al,al jz print3 cmp al,#CHR_PERCENT je print4 ! print % character xor ah,ah cmp al,#$6C ! long argument indicator? jne prna2 inc ah lodsb or al,al jz print3 prna2: mov dl,#10 ! check for decimal number cmp al,#$64 je prna3 cmp al,#$75 je prna3 mov dl,#8 ! check for octal number cmp al,#$6F je prna3 mov dl,#16 ! check for hexdecimal number cmp al,#$78 je prna3 cmp al,#$63 ! check for character argument jne prna6 getrarg (ax,bx) inc bx jmp print4 ! print character prna3: push dx getrarg (cx,bx) ! get next argument inc bx xor dx,dx cmp al,#$64 ! is it a signed number? jne prnaA xchg ax,cx cwd ! expand word to double word if signed xchg cx,ax prnaA: or ah,ah ! is it a long argument? jz prna4 getrarg (dx,bx) ! get high word of long argument inc bx prna4: cmp al,#$64 ! the number is now in (DX,AX):CX mov ax,dx jne prnaB ! if its negative, print a minus or dx,dx ! sign, and then convert it into jns prnaB ! a positive number mov al,#$2D call DOPRINT ! print minus sign xor ax,ax neg cx ! make the number positive sbb ax,dx prnaB: pop dx xchg ax,cx ! the argument is now in CX:AX call prnum ! print the number jmp prna9 prna6: cmp al,#$73 ! check for string argument jne prna9 push si getrarg (si,bx) ! get pointer to string inc bx mov cx,#-1 ! check for length argument or ah,ah jz prna7 getrarg (cx,bx) ! get maximum length of string inc bx prna7: lodsb ! print string or al,al jz prna8 call DOPRINT ! print the character loop prna7 prna8: pop si prna9: jmp near print1 ! Return to caller after cleaning up the stack. print9: pop di pop si pleave ret ! !************************************************************************** ! ! Print a number onto the screen. ! Input: CX:AX - number ! DL - base ! Output: none ! Registers changed: AX, CX, DX ! prnum: push bx mov bx,#numbuf + BUFSIZE - 1 prnum1: xchg cx,ax mov dh,al mov al,ah xor ah,ah div dl xchg dh,al ! divide the number in CX:AX by div dl ! the number base xchg al,ch div dl xchg al,cl div dl and ah,#$0F add ah,#$30 cmp ah,#$39 ! the division remainder gets converted jbe prnum2 ! into an ascii character add ah,#7 prnum2: mov [bx],ah dec bx cmp bx,#numbuf ! store character into temporary buffer jbe prnum3 mov ah,cl mov cl,ch ! put quotient back into CX:AX mov ch,dh or dh,cl or dh,ah or dh,al ! check if number got completely or dh,dh ! converted jnz prnum1 prnum3: inc bx mov al,[bx] ! print all characters call DOPRINT cmp bx,#numbuf + BUFSIZE - 1 jb prnum3 pop bx ret ! !************************************************************************** ! end