| 1145 | kaklik | 1 | /*! \file rprintf.c \brief printf routine and associated routines. */ | 
      
        |  |  | 2 | //***************************************************************************** | 
      
        |  |  | 3 | // | 
      
        |  |  | 4 | // File Name	: 'rprintf.c' | 
      
        |  |  | 5 | // Title		: printf routine and associated routines | 
      
        |  |  | 6 | // Author		: Pascal Stang - Copyright (C) 2000-2002 | 
      
        |  |  | 7 | // Created		: 2000.12.26 | 
      
        |  |  | 8 | // Revised		: 2003.5.1 | 
      
        |  |  | 9 | // Version		: 1.0 | 
      
        |  |  | 10 | // Target MCU	: Atmel AVR series and other targets | 
      
        |  |  | 11 | // Editor Tabs	: 4 | 
      
        |  |  | 12 | // | 
      
        |  |  | 13 | // NOTE: This code is currently below version 1.0, and therefore is considered | 
      
        |  |  | 14 | // to be lacking in some functionality or documentation, or may not be fully | 
      
        |  |  | 15 | // tested.  Nonetheless, you can expect most functions to work. | 
      
        |  |  | 16 | // | 
      
        |  |  | 17 | // This code is distributed under the GNU Public License | 
      
        |  |  | 18 | //		which can be found at http://www.gnu.org/licenses/gpl.txt | 
      
        |  |  | 19 | // | 
      
        |  |  | 20 | //***************************************************************************** | 
      
        |  |  | 21 |  | 
      
        |  |  | 22 | #include <avr/pgmspace.h> | 
      
        |  |  | 23 | //#include <string-avr.h> | 
      
        |  |  | 24 | //#include <stdlib.h> | 
      
        |  |  | 25 | #include <stdarg.h> | 
      
        |  |  | 26 | #include "global.h" | 
      
        |  |  | 27 | #include "rprintf.h" | 
      
        |  |  | 28 |  | 
      
        |  |  | 29 | #ifndef TRUE | 
      
        |  |  | 30 | 	#define TRUE	-1 | 
      
        |  |  | 31 | 	#define FALSE	0 | 
      
        |  |  | 32 | #endif | 
      
        |  |  | 33 |  | 
      
        |  |  | 34 | #define INF     32766	// maximum field size to print | 
      
        |  |  | 35 | #define READMEMBYTE(a,char_ptr)	((a)?(pgm_read_byte(char_ptr)):(*char_ptr)) | 
      
        |  |  | 36 |  | 
      
        |  |  | 37 | #ifdef RPRINTF_COMPLEX | 
      
        |  |  | 38 | 	static unsigned char buf[128]; | 
      
        |  |  | 39 | #endif | 
      
        |  |  | 40 |  | 
      
        |  |  | 41 | // use this to store hex conversion in RAM | 
      
        |  |  | 42 | //static char HexChars[] = "0123456789ABCDEF"; | 
      
        |  |  | 43 | // use this to store hex conversion in program memory | 
      
        |  |  | 44 | //static prog_char HexChars[] = "0123456789ABCDEF"; | 
      
        |  |  | 45 | static char __attribute__ ((progmem)) HexChars[] = "0123456789ABCDEF"; | 
      
        |  |  | 46 |  | 
      
        |  |  | 47 | #define hexchar(x)	pgm_read_byte( HexChars+((x)&0x0f) ) | 
      
        |  |  | 48 | //#define hexchar(x)	((((x)&0x0F)>9)?((x)+'A'-10):((x)+'0')) | 
      
        |  |  | 49 |  | 
      
        |  |  | 50 | // function pointer to single character output routine | 
      
        |  |  | 51 | static void (*rputchar)(unsigned char c); | 
      
        |  |  | 52 |  | 
      
        |  |  | 53 | // *** rprintf initialization *** | 
      
        |  |  | 54 | // you must call this function once and supply the character output | 
      
        |  |  | 55 | // routine before using other functions in this library | 
      
        |  |  | 56 | void rprintfInit(void (*putchar_func)(unsigned char c)) | 
      
        |  |  | 57 | { | 
      
        |  |  | 58 | 	rputchar = putchar_func; | 
      
        |  |  | 59 | } | 
      
        |  |  | 60 |  | 
      
        |  |  | 61 | // *** rprintfChar *** | 
      
        |  |  | 62 | // send a character/byte to the current output device | 
      
        |  |  | 63 | void rprintfChar(unsigned char c) | 
      
        |  |  | 64 | { | 
      
        |  |  | 65 | 	// do LF -> CR/LF translation | 
      
        |  |  | 66 | 	if(c == '\n') | 
      
        |  |  | 67 | 		rputchar('\r'); | 
      
        |  |  | 68 | 	// send character | 
      
        |  |  | 69 | 	rputchar(c); | 
      
        |  |  | 70 | } | 
      
        |  |  | 71 |  | 
      
        |  |  | 72 | // *** rprintfStr *** | 
      
        |  |  | 73 | // prints a null-terminated string stored in RAM | 
      
        |  |  | 74 | void rprintfStr(char str[]) | 
      
        |  |  | 75 | { | 
      
        |  |  | 76 | 	// send a string stored in RAM | 
      
        |  |  | 77 | 	// check to make sure we have a good pointer | 
      
        |  |  | 78 | 	if (!str) return; | 
      
        |  |  | 79 |  | 
      
        |  |  | 80 | 	// print the string until a null-terminator | 
      
        |  |  | 81 | 	while (*str) | 
      
        |  |  | 82 | 		rprintfChar(*str++); | 
      
        |  |  | 83 | } | 
      
        |  |  | 84 |  | 
      
        |  |  | 85 | // *** rprintfStrLen *** | 
      
        |  |  | 86 | // prints a section of a string stored in RAM | 
      
        |  |  | 87 | // begins printing at position indicated by <start> | 
      
        |  |  | 88 | // prints number of characters indicated by <len> | 
      
        |  |  | 89 | void rprintfStrLen(char str[], unsigned int start, unsigned int len) | 
      
        |  |  | 90 | { | 
      
        |  |  | 91 | 	register int i=0; | 
      
        |  |  | 92 |  | 
      
        |  |  | 93 | 	// check to make sure we have a good pointer | 
      
        |  |  | 94 | 	if (!str) return; | 
      
        |  |  | 95 | 	// spin through characters up to requested start | 
      
        |  |  | 96 | 	// keep going as long as there's no null | 
      
        |  |  | 97 | 	while((i++<start) && (*str++)); | 
      
        |  |  | 98 | //	for(i=0; i<start; i++) | 
      
        |  |  | 99 | //	{ | 
      
        |  |  | 100 | //		// keep steping through string as long as there's no null | 
      
        |  |  | 101 | //		if(*str) str++; | 
      
        |  |  | 102 | //	} | 
      
        |  |  | 103 |  | 
      
        |  |  | 104 | 	// then print exactly len characters | 
      
        |  |  | 105 | 	for(i=0; i<len; i++) | 
      
        |  |  | 106 | 	{ | 
      
        |  |  | 107 | 		// print data out of the string as long as we haven't reached a null yet | 
      
        |  |  | 108 | 		// at the null, start printing spaces | 
      
        |  |  | 109 | 		if(*str) | 
      
        |  |  | 110 | 			rprintfChar(*str++); | 
      
        |  |  | 111 | 		else | 
      
        |  |  | 112 | 			rprintfChar(' '); | 
      
        |  |  | 113 | 	} | 
      
        |  |  | 114 |  | 
      
        |  |  | 115 | } | 
      
        |  |  | 116 |  | 
      
        |  |  | 117 | // *** rprintfProgStr *** | 
      
        |  |  | 118 | // prints a null-terminated string stored in program ROM | 
      
        |  |  | 119 | void rprintfProgStr(const prog_char str[]) | 
      
        |  |  | 120 | { | 
      
        |  |  | 121 | 	// print a string stored in program memory | 
      
        |  |  | 122 | 	register char c; | 
      
        |  |  | 123 |  | 
      
        |  |  | 124 | 	// check to make sure we have a good pointer | 
      
        |  |  | 125 | 	if (!str) return; | 
      
        |  |  | 126 |  | 
      
        |  |  | 127 | 	// print the string until the null-terminator | 
      
        |  |  | 128 | 	while((c = pgm_read_byte(str++))) | 
      
        |  |  | 129 | 		rprintfChar(c); | 
      
        |  |  | 130 | } | 
      
        |  |  | 131 |  | 
      
        |  |  | 132 | // *** rprintfCRLF *** | 
      
        |  |  | 133 | // prints carriage return and line feed | 
      
        |  |  | 134 | void rprintfCRLF(void) | 
      
        |  |  | 135 | { | 
      
        |  |  | 136 | 	// print CR/LF | 
      
        |  |  | 137 | 	//rprintfChar('\r'); | 
      
        |  |  | 138 | 	// LF -> CR/LF translation built-in to rprintfChar() | 
      
        |  |  | 139 | 	rprintfChar('\n'); | 
      
        |  |  | 140 | } | 
      
        |  |  | 141 |  | 
      
        |  |  | 142 | // *** rprintfu04 *** | 
      
        |  |  | 143 | // prints an unsigned 4-bit number in hex (1 digit) | 
      
        |  |  | 144 | void rprintfu04(unsigned char data) | 
      
        |  |  | 145 | { | 
      
        |  |  | 146 | 	// print 4-bit hex value | 
      
        |  |  | 147 | //	char Character = data&0x0f; | 
      
        |  |  | 148 | //	if (Character>9) | 
      
        |  |  | 149 | //		Character+='A'-10; | 
      
        |  |  | 150 | //	else | 
      
        |  |  | 151 | //		Character+='0'; | 
      
        |  |  | 152 | 	rprintfChar(hexchar(data)); | 
      
        |  |  | 153 | } | 
      
        |  |  | 154 |  | 
      
        |  |  | 155 | // *** rprintfu08 *** | 
      
        |  |  | 156 | // prints an unsigned 8-bit number in hex (2 digits) | 
      
        |  |  | 157 | void rprintfu08(unsigned char data) | 
      
        |  |  | 158 | { | 
      
        |  |  | 159 | 	// print 8-bit hex value | 
      
        |  |  | 160 | 	rprintfu04(data>>4); | 
      
        |  |  | 161 | 	rprintfu04(data); | 
      
        |  |  | 162 | } | 
      
        |  |  | 163 |  | 
      
        |  |  | 164 | // *** rprintfu16 *** | 
      
        |  |  | 165 | // prints an unsigned 16-bit number in hex (4 digits) | 
      
        |  |  | 166 | void rprintfu16(unsigned short data) | 
      
        |  |  | 167 | { | 
      
        |  |  | 168 | 	// print 16-bit hex value | 
      
        |  |  | 169 | 	rprintfu08(data>>8); | 
      
        |  |  | 170 | 	rprintfu08(data); | 
      
        |  |  | 171 | } | 
      
        |  |  | 172 |  | 
      
        |  |  | 173 | // *** rprintfu32 *** | 
      
        |  |  | 174 | // prints an unsigned 32-bit number in hex (8 digits) | 
      
        |  |  | 175 | void rprintfu32(unsigned long data) | 
      
        |  |  | 176 | { | 
      
        |  |  | 177 | 	// print 32-bit hex value | 
      
        |  |  | 178 | 	rprintfu16(data>>16); | 
      
        |  |  | 179 | 	rprintfu16(data); | 
      
        |  |  | 180 | } | 
      
        |  |  | 181 |  | 
      
        |  |  | 182 | // *** rprintfNum *** | 
      
        |  |  | 183 | // special printf for numbers only | 
      
        |  |  | 184 | // see formatting information below | 
      
        |  |  | 185 | //	Print the number "n" in the given "base" | 
      
        |  |  | 186 | //	using exactly "numDigits" | 
      
        |  |  | 187 | //	print +/- if signed flag "isSigned" is TRUE | 
      
        |  |  | 188 | //	use the character specified in "padchar" to pad extra characters | 
      
        |  |  | 189 | // | 
      
        |  |  | 190 | //	Examples: | 
      
        |  |  | 191 | //	uartPrintfNum(10, 6,  TRUE, ' ',   1234);  -->  " +1234" | 
      
        |  |  | 192 | //	uartPrintfNum(10, 6, FALSE, '0',   1234);  -->  "001234" | 
      
        |  |  | 193 | //	uartPrintfNum(16, 6, FALSE, '.', 0x5AA5);  -->  "..5AA5" | 
      
        |  |  | 194 | void rprintfNum(char base, char numDigits, char isSigned, char padchar, long n) | 
      
        |  |  | 195 | { | 
      
        |  |  | 196 | 	// define a global HexChars or use line below | 
      
        |  |  | 197 | 	//static char HexChars[16] = "0123456789ABCDEF"; | 
      
        |  |  | 198 | 	char *p, buf[32]; | 
      
        |  |  | 199 | 	unsigned long x; | 
      
        |  |  | 200 | 	unsigned char count; | 
      
        |  |  | 201 |  | 
      
        |  |  | 202 | 	// prepare negative number | 
      
        |  |  | 203 | 	if( isSigned && (n < 0) ) | 
      
        |  |  | 204 | 	{ | 
      
        |  |  | 205 | 		x = -n; | 
      
        |  |  | 206 | 	} | 
      
        |  |  | 207 | 	else | 
      
        |  |  | 208 | 	{ | 
      
        |  |  | 209 | 	 	x = n; | 
      
        |  |  | 210 | 	} | 
      
        |  |  | 211 |  | 
      
        |  |  | 212 | 	// setup little string buffer | 
      
        |  |  | 213 | 	count = (numDigits-1)-(isSigned?1:0); | 
      
        |  |  | 214 |   	p = buf + sizeof (buf); | 
      
        |  |  | 215 |   	*--p = '\0'; | 
      
        |  |  | 216 |  | 
      
        |  |  | 217 | 	// force calculation of first digit | 
      
        |  |  | 218 | 	// (to prevent zero from not printing at all!!!) | 
      
        |  |  | 219 | 	*--p = hexchar(x%base); x /= base; | 
      
        |  |  | 220 | 	// calculate remaining digits | 
      
        |  |  | 221 | 	while(count--) | 
      
        |  |  | 222 | 	{ | 
      
        |  |  | 223 | 		if(x != 0) | 
      
        |  |  | 224 | 		{ | 
      
        |  |  | 225 | 			// calculate next digit | 
      
        |  |  | 226 | 			*--p = hexchar(x%base); x /= base; | 
      
        |  |  | 227 | 		} | 
      
        |  |  | 228 | 		else | 
      
        |  |  | 229 | 		{ | 
      
        |  |  | 230 | 			// no more digits left, pad out to desired length | 
      
        |  |  | 231 | 			*--p = padchar; | 
      
        |  |  | 232 | 		} | 
      
        |  |  | 233 | 	} | 
      
        |  |  | 234 |  | 
      
        |  |  | 235 | 	// apply signed notation if requested | 
      
        |  |  | 236 | 	if( isSigned ) | 
      
        |  |  | 237 | 	{ | 
      
        |  |  | 238 | 		if(n < 0) | 
      
        |  |  | 239 | 		{ | 
      
        |  |  | 240 |    			*--p = '-'; | 
      
        |  |  | 241 | 		} | 
      
        |  |  | 242 | 		else if(n > 0) | 
      
        |  |  | 243 | 		{ | 
      
        |  |  | 244 | 	   		*--p = '+'; | 
      
        |  |  | 245 | 		} | 
      
        |  |  | 246 | 		else | 
      
        |  |  | 247 | 		{ | 
      
        |  |  | 248 | 	   		*--p = ' '; | 
      
        |  |  | 249 | 		} | 
      
        |  |  | 250 | 	} | 
      
        |  |  | 251 |  | 
      
        |  |  | 252 | 	// print the string right-justified | 
      
        |  |  | 253 | 	count = numDigits; | 
      
        |  |  | 254 | 	while(count--) | 
      
        |  |  | 255 | 	{ | 
      
        |  |  | 256 | 		rprintfChar(*p++); | 
      
        |  |  | 257 | 	} | 
      
        |  |  | 258 | } | 
      
        |  |  | 259 |  | 
      
        |  |  | 260 | #ifdef RPRINTF_FLOAT | 
      
        |  |  | 261 | // *** rprintfFloat *** | 
      
        |  |  | 262 | // floating-point print | 
      
        |  |  | 263 | void rprintfFloat(char numDigits, double x) | 
      
        |  |  | 264 | { | 
      
        |  |  | 265 | 	unsigned char firstplace = FALSE; | 
      
        |  |  | 266 | 	unsigned char negative; | 
      
        |  |  | 267 | 	unsigned char i, digit; | 
      
        |  |  | 268 | 	double place = 1.0; | 
      
        |  |  | 269 |  | 
      
        |  |  | 270 | 	// save sign | 
      
        |  |  | 271 | 	negative = (x<0); | 
      
        |  |  | 272 | 	// convert to absolute value | 
      
        |  |  | 273 | 	x = (x>0)?(x):(-x); | 
      
        |  |  | 274 |  | 
      
        |  |  | 275 | 	// find starting digit place | 
      
        |  |  | 276 | 	for(i=0; i<15; i++) | 
      
        |  |  | 277 | 	{ | 
      
        |  |  | 278 | 		if((x/place) < 10.0) | 
      
        |  |  | 279 | 			break; | 
      
        |  |  | 280 | 		else | 
      
        |  |  | 281 | 			place *= 10.0; | 
      
        |  |  | 282 | 	} | 
      
        |  |  | 283 | 	// print polarity character | 
      
        |  |  | 284 | 	if(negative) | 
      
        |  |  | 285 | 		rprintfChar('-'); | 
      
        |  |  | 286 | 	else | 
      
        |  |  | 287 | 		rprintfChar('+'); | 
      
        |  |  | 288 |  | 
      
        |  |  | 289 | 	// print digits | 
      
        |  |  | 290 | 	for(i=0; i<numDigits; i++) | 
      
        |  |  | 291 | 	{ | 
      
        |  |  | 292 | 		digit = (x/place); | 
      
        |  |  | 293 |  | 
      
        |  |  | 294 | 		if(digit | firstplace | (place == 1.0)) | 
      
        |  |  | 295 | 		{ | 
      
        |  |  | 296 | 			firstplace = TRUE; | 
      
        |  |  | 297 | 			rprintfChar(digit+0x30); | 
      
        |  |  | 298 | 		} | 
      
        |  |  | 299 | 		else | 
      
        |  |  | 300 | 			rprintfChar(' '); | 
      
        |  |  | 301 |  | 
      
        |  |  | 302 | 		if(place == 1.0) | 
      
        |  |  | 303 | 		{ | 
      
        |  |  | 304 | 			rprintfChar('.'); | 
      
        |  |  | 305 | 		} | 
      
        |  |  | 306 |  | 
      
        |  |  | 307 | 		x -= (digit*place); | 
      
        |  |  | 308 | 		place /= 10.0; | 
      
        |  |  | 309 | 	} | 
      
        |  |  | 310 | } | 
      
        |  |  | 311 | #endif | 
      
        |  |  | 312 |  | 
      
        |  |  | 313 | #ifdef RPRINTF_SIMPLE | 
      
        |  |  | 314 | // *** rprintf1RamRom *** | 
      
        |  |  | 315 | // called by rprintf() - does a simple printf (supports %d, %x, %c) | 
      
        |  |  | 316 | // Supports: | 
      
        |  |  | 317 | // %d - decimal | 
      
        |  |  | 318 | // %x - hex | 
      
        |  |  | 319 | // %c - character | 
      
        |  |  | 320 | int rprintf1RamRom(unsigned char stringInRom, const char *format, ...) | 
      
        |  |  | 321 | { | 
      
        |  |  | 322 | 	// simple printf routine | 
      
        |  |  | 323 | 	// define a global HexChars or use line below | 
      
        |  |  | 324 | 	//static char HexChars[16] = "0123456789ABCDEF"; | 
      
        |  |  | 325 | 	char format_flag; | 
      
        |  |  | 326 | 	unsigned int u_val, div_val, base; | 
      
        |  |  | 327 | 	va_list ap; | 
      
        |  |  | 328 |  | 
      
        |  |  | 329 | 	va_start(ap, format); | 
      
        |  |  | 330 | 	for (;;) | 
      
        |  |  | 331 | 	{ | 
      
        |  |  | 332 | 		while ((format_flag = READMEMBYTE(stringInRom,format++) ) != '%') | 
      
        |  |  | 333 | 		{	// Until '%' or '\0' | 
      
        |  |  | 334 | 			if (!format_flag) | 
      
        |  |  | 335 | 			{ | 
      
        |  |  | 336 | 				va_end(ap); | 
      
        |  |  | 337 | 				return(0); | 
      
        |  |  | 338 | 			} | 
      
        |  |  | 339 | 			rprintfChar(format_flag); | 
      
        |  |  | 340 | 		} | 
      
        |  |  | 341 |  | 
      
        |  |  | 342 | 		switch (format_flag = READMEMBYTE(stringInRom,format++) ) | 
      
        |  |  | 343 | 		{ | 
      
        |  |  | 344 | 			case 'c': format_flag = va_arg(ap,int); | 
      
        |  |  | 345 | 			default:  rprintfChar(format_flag); continue; | 
      
        |  |  | 346 | 			case 'd': base = 10; div_val = 10000; goto CONVERSION_LOOP; | 
      
        |  |  | 347 | //			case 'x': base = 16; div_val = 0x10; | 
      
        |  |  | 348 | 			case 'x': base = 16; div_val = 0x1000; | 
      
        |  |  | 349 |  | 
      
        |  |  | 350 | 			CONVERSION_LOOP: | 
      
        |  |  | 351 | 			u_val = va_arg(ap,int); | 
      
        |  |  | 352 | 			if (format_flag == 'd') | 
      
        |  |  | 353 | 			{ | 
      
        |  |  | 354 | 				if (((int)u_val) < 0) | 
      
        |  |  | 355 | 				{ | 
      
        |  |  | 356 | 					u_val = - u_val; | 
      
        |  |  | 357 | 					rprintfChar('-'); | 
      
        |  |  | 358 | 				} | 
      
        |  |  | 359 | 				while (div_val > 1 && div_val > u_val) div_val /= 10; | 
      
        |  |  | 360 | 			} | 
      
        |  |  | 361 | 			do | 
      
        |  |  | 362 | 			{ | 
      
        |  |  | 363 | 				//rprintfChar(pgm_read_byte(HexChars+(u_val/div_val))); | 
      
        |  |  | 364 | 				rprintfu04(u_val/div_val); | 
      
        |  |  | 365 | 				u_val %= div_val; | 
      
        |  |  | 366 | 				div_val /= base; | 
      
        |  |  | 367 | 			} while (div_val); | 
      
        |  |  | 368 | 		} | 
      
        |  |  | 369 | 	} | 
      
        |  |  | 370 | 	va_end(ap); | 
      
        |  |  | 371 | } | 
      
        |  |  | 372 | #endif | 
      
        |  |  | 373 |  | 
      
        |  |  | 374 |  | 
      
        |  |  | 375 | #ifdef RPRINTF_COMPLEX | 
      
        |  |  | 376 | // *** rprintf2RamRom *** | 
      
        |  |  | 377 | // called by rprintf() - does a more powerful printf (supports %d, %u, %o, %x, %c, %s) | 
      
        |  |  | 378 | // Supports: | 
      
        |  |  | 379 | // %d - decimal | 
      
        |  |  | 380 | // %u - unsigned decimal | 
      
        |  |  | 381 | // %o - octal | 
      
        |  |  | 382 | // %x - hex | 
      
        |  |  | 383 | // %c - character | 
      
        |  |  | 384 | // %s - strings | 
      
        |  |  | 385 | // and the width,precision,padding modifiers | 
      
        |  |  | 386 | // **this printf does not support floating point numbers | 
      
        |  |  | 387 | int rprintf2RamRom(unsigned char stringInRom, const char *sfmt, ...) | 
      
        |  |  | 388 | { | 
      
        |  |  | 389 | 	register unsigned char *f, *bp; | 
      
        |  |  | 390 | 	register long l; | 
      
        |  |  | 391 | 	register unsigned long u; | 
      
        |  |  | 392 | 	register int i; | 
      
        |  |  | 393 | 	register int fmt; | 
      
        |  |  | 394 | 	register unsigned char pad = ' '; | 
      
        |  |  | 395 | 	int flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0; | 
      
        |  |  | 396 | 	int sign = 0; | 
      
        |  |  | 397 |  | 
      
        |  |  | 398 | 	va_list ap; | 
      
        |  |  | 399 | 	va_start(ap, sfmt); | 
      
        |  |  | 400 |  | 
      
        |  |  | 401 | 	f = (unsigned char *) sfmt; | 
      
        |  |  | 402 |  | 
      
        |  |  | 403 | 	for (; READMEMBYTE(stringInRom,f); f++) | 
      
        |  |  | 404 | 	{ | 
      
        |  |  | 405 | 		if (READMEMBYTE(stringInRom,f) != '%') | 
      
        |  |  | 406 | 		{	// not a format character | 
      
        |  |  | 407 | 			// then just output the char | 
      
        |  |  | 408 | 			rprintfChar(READMEMBYTE(stringInRom,f)); | 
      
        |  |  | 409 | 		} | 
      
        |  |  | 410 | 		else  | 
      
        |  |  | 411 | 		{ | 
      
        |  |  | 412 | 			f++;						// if we have a "%" then skip it | 
      
        |  |  | 413 | 			if (READMEMBYTE(stringInRom,f) == '-') | 
      
        |  |  | 414 | 			{ | 
      
        |  |  | 415 | 				flush_left = 1;	// minus: flush left | 
      
        |  |  | 416 | 				f++; | 
      
        |  |  | 417 | 			} | 
      
        |  |  | 418 |             if (READMEMBYTE(stringInRom,f) == '0' | 
      
        |  |  | 419 | 				 || READMEMBYTE(stringInRom,f) == '.') | 
      
        |  |  | 420 | 				{ | 
      
        |  |  | 421 | 					// padding with 0 rather than blank | 
      
        |  |  | 422 | 					pad = '0'; | 
      
        |  |  | 423 | 					f++; | 
      
        |  |  | 424 |             } | 
      
        |  |  | 425 |             if (READMEMBYTE(stringInRom,f) == '*') | 
      
        |  |  | 426 | 				{	// field width | 
      
        |  |  | 427 | 					f_width = va_arg(ap, int); | 
      
        |  |  | 428 | 					f++; | 
      
        |  |  | 429 |             } | 
      
        |  |  | 430 |             else if (Isdigit(READMEMBYTE(stringInRom,f))) | 
      
        |  |  | 431 | 				{ | 
      
        |  |  | 432 | 					f_width = atoiRamRom(stringInRom, (char *) f); | 
      
        |  |  | 433 | 					while (Isdigit(READMEMBYTE(stringInRom,f))) | 
      
        |  |  | 434 | 						f++;        // skip the digits | 
      
        |  |  | 435 |             } | 
      
        |  |  | 436 |             if (READMEMBYTE(stringInRom,f) == '.') | 
      
        |  |  | 437 | 				{	// precision | 
      
        |  |  | 438 | 					f++; | 
      
        |  |  | 439 | 					if (READMEMBYTE(stringInRom,f) == '*') | 
      
        |  |  | 440 | 					{ | 
      
        |  |  | 441 | 						prec = va_arg(ap, int); | 
      
        |  |  | 442 | 						f++; | 
      
        |  |  | 443 | 					} | 
      
        |  |  | 444 | 					else if (Isdigit(READMEMBYTE(stringInRom,f))) | 
      
        |  |  | 445 | 					{ | 
      
        |  |  | 446 | 						prec = atoiRamRom(stringInRom, (char *) f); | 
      
        |  |  | 447 | 						while (Isdigit(READMEMBYTE(stringInRom,f))) | 
      
        |  |  | 448 | 							f++;    // skip the digits | 
      
        |  |  | 449 | 					} | 
      
        |  |  | 450 | 				} | 
      
        |  |  | 451 |             if (READMEMBYTE(stringInRom,f) == '#') | 
      
        |  |  | 452 | 				{	// alternate form | 
      
        |  |  | 453 | 					hash = 1; | 
      
        |  |  | 454 | 					f++; | 
      
        |  |  | 455 |             } | 
      
        |  |  | 456 |             if (READMEMBYTE(stringInRom,f) == 'l') | 
      
        |  |  | 457 | 				{	// long format | 
      
        |  |  | 458 | 					do_long = 1; | 
      
        |  |  | 459 | 					f++; | 
      
        |  |  | 460 |             } | 
      
        |  |  | 461 |  | 
      
        |  |  | 462 | 				fmt = READMEMBYTE(stringInRom,f); | 
      
        |  |  | 463 | 				bp = buf; | 
      
        |  |  | 464 | 				switch (fmt) {		// do the formatting | 
      
        |  |  | 465 | 				case 'd':			// 'd' signed decimal | 
      
        |  |  | 466 | 					if (do_long) | 
      
        |  |  | 467 | 						l = va_arg(ap, long); | 
      
        |  |  | 468 | 					else | 
      
        |  |  | 469 | 						l = (long) (va_arg(ap, int)); | 
      
        |  |  | 470 | 					if (l < 0) | 
      
        |  |  | 471 | 					{ | 
      
        |  |  | 472 | 						sign = 1; | 
      
        |  |  | 473 | 						l = -l; | 
      
        |  |  | 474 | 					} | 
      
        |  |  | 475 | 					do	{ | 
      
        |  |  | 476 | 						*bp++ = l % 10 + '0'; | 
      
        |  |  | 477 | 					} while ((l /= 10) > 0); | 
      
        |  |  | 478 | 					if (sign) | 
      
        |  |  | 479 | 						*bp++ = '-'; | 
      
        |  |  | 480 | 					f_width = f_width - (bp - buf); | 
      
        |  |  | 481 | 					if (!flush_left) | 
      
        |  |  | 482 | 						while (f_width-- > 0) | 
      
        |  |  | 483 | 							rprintfChar(pad); | 
      
        |  |  | 484 | 					for (bp--; bp >= buf; bp--) | 
      
        |  |  | 485 | 						rprintfChar(*bp); | 
      
        |  |  | 486 | 					if (flush_left) | 
      
        |  |  | 487 | 						while (f_width-- > 0) | 
      
        |  |  | 488 | 							rprintfChar(' '); | 
      
        |  |  | 489 | 					break; | 
      
        |  |  | 490 |             case 'o':			// 'o' octal number | 
      
        |  |  | 491 |             case 'x':			// 'x' hex number | 
      
        |  |  | 492 |             case 'u':			// 'u' unsigned decimal | 
      
        |  |  | 493 | 					if (do_long) | 
      
        |  |  | 494 | 						u = va_arg(ap, unsigned long); | 
      
        |  |  | 495 | 					else | 
      
        |  |  | 496 | 						u = (unsigned long) (va_arg(ap, unsigned)); | 
      
        |  |  | 497 | 					if (fmt == 'u') | 
      
        |  |  | 498 | 					{	// unsigned decimal | 
      
        |  |  | 499 | 						do { | 
      
        |  |  | 500 | 							*bp++ = u % 10 + '0'; | 
      
        |  |  | 501 | 						} while ((u /= 10) > 0); | 
      
        |  |  | 502 | 					} | 
      
        |  |  | 503 | 					else if (fmt == 'o') | 
      
        |  |  | 504 | 					{  // octal | 
      
        |  |  | 505 | 						do { | 
      
        |  |  | 506 | 							*bp++ = u % 8 + '0'; | 
      
        |  |  | 507 | 						} while ((u /= 8) > 0); | 
      
        |  |  | 508 | 						if (hash) | 
      
        |  |  | 509 | 							*bp++ = '0'; | 
      
        |  |  | 510 | 					} | 
      
        |  |  | 511 | 					else if (fmt == 'x') | 
      
        |  |  | 512 | 					{	// hex | 
      
        |  |  | 513 | 						do { | 
      
        |  |  | 514 | 							i = u % 16; | 
      
        |  |  | 515 | 							if (i < 10) | 
      
        |  |  | 516 | 								*bp++ = i + '0'; | 
      
        |  |  | 517 | 							else | 
      
        |  |  | 518 | 								*bp++ = i - 10 + 'a'; | 
      
        |  |  | 519 | 						} while ((u /= 16) > 0); | 
      
        |  |  | 520 | 						if (hash) | 
      
        |  |  | 521 | 						{ | 
      
        |  |  | 522 | 							*bp++ = 'x'; | 
      
        |  |  | 523 | 							*bp++ = '0'; | 
      
        |  |  | 524 | 						} | 
      
        |  |  | 525 | 					} | 
      
        |  |  | 526 | 					i = f_width - (bp - buf); | 
      
        |  |  | 527 | 					if (!flush_left) | 
      
        |  |  | 528 | 						while (i-- > 0) | 
      
        |  |  | 529 | 							rprintfChar(pad); | 
      
        |  |  | 530 | 					for (bp--; bp >= buf; bp--) | 
      
        |  |  | 531 | 						rprintfChar((int) (*bp)); | 
      
        |  |  | 532 | 					if (flush_left) | 
      
        |  |  | 533 | 						while (i-- > 0) | 
      
        |  |  | 534 | 							rprintfChar(' '); | 
      
        |  |  | 535 | 					break; | 
      
        |  |  | 536 |             case 'c':			// 'c' character | 
      
        |  |  | 537 | 					i = va_arg(ap, int); | 
      
        |  |  | 538 | 					rprintfChar((int) (i)); | 
      
        |  |  | 539 | 					break; | 
      
        |  |  | 540 |             case 's':			// 's' string | 
      
        |  |  | 541 | 					bp = va_arg(ap, unsigned char *); | 
      
        |  |  | 542 | 					if (!bp) | 
      
        |  |  | 543 | 						bp = (unsigned char *) "(nil)"; | 
      
        |  |  | 544 | 					f_width = f_width - strlen((char *) bp); | 
      
        |  |  | 545 | 					if (!flush_left) | 
      
        |  |  | 546 | 						while (f_width-- > 0) | 
      
        |  |  | 547 | 							rprintfChar(pad); | 
      
        |  |  | 548 | 					for (i = 0; *bp && i < prec; i++) | 
      
        |  |  | 549 | 					{ | 
      
        |  |  | 550 | 						rprintfChar(*bp); | 
      
        |  |  | 551 | 						bp++; | 
      
        |  |  | 552 | 					} | 
      
        |  |  | 553 | 					if (flush_left) | 
      
        |  |  | 554 | 						while (f_width-- > 0) | 
      
        |  |  | 555 | 							rprintfChar(' '); | 
      
        |  |  | 556 | 					break; | 
      
        |  |  | 557 |             case '%':			// '%' character | 
      
        |  |  | 558 | 					rprintfChar('%'); | 
      
        |  |  | 559 | 					break; | 
      
        |  |  | 560 | 			} | 
      
        |  |  | 561 | 			flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0; | 
      
        |  |  | 562 | 			sign = 0; | 
      
        |  |  | 563 | 			pad = ' '; | 
      
        |  |  | 564 | 		} | 
      
        |  |  | 565 | 	} | 
      
        |  |  | 566 |  | 
      
        |  |  | 567 | 	va_end(ap); | 
      
        |  |  | 568 | 	return 0; | 
      
        |  |  | 569 | } | 
      
        |  |  | 570 |  | 
      
        |  |  | 571 | unsigned char Isdigit(char c) | 
      
        |  |  | 572 | { | 
      
        |  |  | 573 | 	if((c >= 0x30) && (c <= 0x39)) | 
      
        |  |  | 574 | 		return TRUE; | 
      
        |  |  | 575 | 	else | 
      
        |  |  | 576 | 		return FALSE; | 
      
        |  |  | 577 | } | 
      
        |  |  | 578 |  | 
      
        |  |  | 579 | int atoiRamRom(unsigned char stringInRom, char *str) | 
      
        |  |  | 580 | { | 
      
        |  |  | 581 | 	int num = 0;; | 
      
        |  |  | 582 |  | 
      
        |  |  | 583 | 	while(Isdigit(READMEMBYTE(stringInRom,str))) | 
      
        |  |  | 584 | 	{ | 
      
        |  |  | 585 | 		num *= 10; | 
      
        |  |  | 586 | 		num += ((READMEMBYTE(stringInRom,str++)) - 0x30); | 
      
        |  |  | 587 | 	} | 
      
        |  |  | 588 | 	return num; | 
      
        |  |  | 589 | } | 
      
        |  |  | 590 |  | 
      
        |  |  | 591 | #endif | 
      
        |  |  | 592 |  | 
      
        |  |  | 593 | //****************************************************************************** | 
      
        |  |  | 594 | // code below this line is commented out and can be ignored | 
      
        |  |  | 595 | //****************************************************************************** | 
      
        |  |  | 596 | /* | 
      
        |  |  | 597 | char* sprintf(const char *sfmt, ...) | 
      
        |  |  | 598 | { | 
      
        |  |  | 599 | 	register unsigned char *f, *bp, *str; | 
      
        |  |  | 600 | 	register long l; | 
      
        |  |  | 601 | 	register unsigned long u; | 
      
        |  |  | 602 | 	register int i; | 
      
        |  |  | 603 | 	register int fmt; | 
      
        |  |  | 604 | 	register unsigned char pad = ' '; | 
      
        |  |  | 605 | 	int     flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0; | 
      
        |  |  | 606 | 	int     sign = 0; | 
      
        |  |  | 607 |  | 
      
        |  |  | 608 | 	va_list ap; | 
      
        |  |  | 609 | 	va_start(ap, sfmt); | 
      
        |  |  | 610 |  | 
      
        |  |  | 611 | 	str = bufstring; | 
      
        |  |  | 612 | 	f = (unsigned char *) sfmt; | 
      
        |  |  | 613 |  | 
      
        |  |  | 614 | 	for (; *f; f++) | 
      
        |  |  | 615 | 	{ | 
      
        |  |  | 616 | 		if (*f != '%') | 
      
        |  |  | 617 | 		{								// not a format character | 
      
        |  |  | 618 | 			*str++ = (*f);			// then just output the char | 
      
        |  |  | 619 | 		} | 
      
        |  |  | 620 | 		else  | 
      
        |  |  | 621 | 		{ | 
      
        |  |  | 622 | 			f++;						// if we have a "%" then skip it | 
      
        |  |  | 623 | 			if (*f == '-') | 
      
        |  |  | 624 | 			{ | 
      
        |  |  | 625 | 				flush_left = 1;	// minus: flush left | 
      
        |  |  | 626 | 				f++; | 
      
        |  |  | 627 | 			} | 
      
        |  |  | 628 |             if (*f == '0' || *f == '.') | 
      
        |  |  | 629 | 				{ | 
      
        |  |  | 630 | 					// padding with 0 rather than blank | 
      
        |  |  | 631 | 					pad = '0'; | 
      
        |  |  | 632 | 					f++; | 
      
        |  |  | 633 |             } | 
      
        |  |  | 634 |             if (*f == '*') | 
      
        |  |  | 635 | 				{	// field width | 
      
        |  |  | 636 | 					f_width = va_arg(ap, int); | 
      
        |  |  | 637 | 					f++; | 
      
        |  |  | 638 |             } | 
      
        |  |  | 639 |             else if (Isdigit(*f)) | 
      
        |  |  | 640 | 				{ | 
      
        |  |  | 641 | 					f_width = atoi((char *) f); | 
      
        |  |  | 642 | 					while (Isdigit(*f)) | 
      
        |  |  | 643 | 						f++;        // skip the digits | 
      
        |  |  | 644 |             } | 
      
        |  |  | 645 |             if (*f == '.') | 
      
        |  |  | 646 | 				{	// precision | 
      
        |  |  | 647 | 					f++; | 
      
        |  |  | 648 | 					if (*f == '*') | 
      
        |  |  | 649 | 					{ | 
      
        |  |  | 650 | 						prec = va_arg(ap, int); | 
      
        |  |  | 651 | 						f++; | 
      
        |  |  | 652 | 					} | 
      
        |  |  | 653 | 					else if (Isdigit(*f)) | 
      
        |  |  | 654 | 					{ | 
      
        |  |  | 655 | 						prec = atoi((char *) f); | 
      
        |  |  | 656 | 						while (Isdigit(*f)) | 
      
        |  |  | 657 | 							f++;    // skip the digits | 
      
        |  |  | 658 | 					} | 
      
        |  |  | 659 | 				} | 
      
        |  |  | 660 |             if (*f == '#') | 
      
        |  |  | 661 | 				{	// alternate form | 
      
        |  |  | 662 | 					hash = 1; | 
      
        |  |  | 663 | 					f++; | 
      
        |  |  | 664 |             } | 
      
        |  |  | 665 |             if (*f == 'l') | 
      
        |  |  | 666 | 				{	// long format | 
      
        |  |  | 667 | 					do_long = 1; | 
      
        |  |  | 668 | 					f++; | 
      
        |  |  | 669 |             } | 
      
        |  |  | 670 |  | 
      
        |  |  | 671 | 				fmt = *f; | 
      
        |  |  | 672 | 				bp = buf; | 
      
        |  |  | 673 | 				switch (fmt) {		// do the formatting | 
      
        |  |  | 674 | 				case 'd':			// 'd' signed decimal | 
      
        |  |  | 675 | 					if (do_long) | 
      
        |  |  | 676 | 						l = va_arg(ap, long); | 
      
        |  |  | 677 | 					else | 
      
        |  |  | 678 | 						l = (long) (va_arg(ap, int)); | 
      
        |  |  | 679 | 					if (l < 0) | 
      
        |  |  | 680 | 					{ | 
      
        |  |  | 681 | 						sign = 1; | 
      
        |  |  | 682 | 						l = -l; | 
      
        |  |  | 683 | 					} | 
      
        |  |  | 684 | 					do	{ | 
      
        |  |  | 685 | 						*bp++ = l % 10 + '0'; | 
      
        |  |  | 686 | 					} while ((l /= 10) > 0); | 
      
        |  |  | 687 | 					if (sign) | 
      
        |  |  | 688 | 						*bp++ = '-'; | 
      
        |  |  | 689 | 					f_width = f_width - (bp - buf); | 
      
        |  |  | 690 | 					if (!flush_left) | 
      
        |  |  | 691 | 						while (f_width-- > 0) | 
      
        |  |  | 692 | 							*str++ = (pad); | 
      
        |  |  | 693 | 					for (bp--; bp >= buf; bp--) | 
      
        |  |  | 694 | 						*str++ = (*bp); | 
      
        |  |  | 695 | 					if (flush_left) | 
      
        |  |  | 696 | 						while (f_width-- > 0) | 
      
        |  |  | 697 | 							*str++ = (' '); | 
      
        |  |  | 698 | 					break; | 
      
        |  |  | 699 |             case 'o':			// 'o' octal number | 
      
        |  |  | 700 |             case 'x':			// 'x' hex number | 
      
        |  |  | 701 |             case 'u':			// 'u' unsigned decimal | 
      
        |  |  | 702 | 					if (do_long) | 
      
        |  |  | 703 | 						u = va_arg(ap, unsigned long); | 
      
        |  |  | 704 | 					else | 
      
        |  |  | 705 | 						u = (unsigned long) (va_arg(ap, unsigned)); | 
      
        |  |  | 706 | 					if (fmt == 'u') | 
      
        |  |  | 707 | 					{	// unsigned decimal | 
      
        |  |  | 708 | 						do { | 
      
        |  |  | 709 | 							*bp++ = u % 10 + '0'; | 
      
        |  |  | 710 | 						} while ((u /= 10) > 0); | 
      
        |  |  | 711 | 					} | 
      
        |  |  | 712 | 					else if (fmt == 'o') | 
      
        |  |  | 713 | 					{  // octal | 
      
        |  |  | 714 | 						do { | 
      
        |  |  | 715 | 							*bp++ = u % 8 + '0'; | 
      
        |  |  | 716 | 						} while ((u /= 8) > 0); | 
      
        |  |  | 717 | 						if (hash) | 
      
        |  |  | 718 | 							*bp++ = '0'; | 
      
        |  |  | 719 | 					} | 
      
        |  |  | 720 | 					else if (fmt == 'x') | 
      
        |  |  | 721 | 					{	// hex | 
      
        |  |  | 722 | 						do { | 
      
        |  |  | 723 | 							i = u % 16; | 
      
        |  |  | 724 | 							if (i < 10) | 
      
        |  |  | 725 | 								*bp++ = i + '0'; | 
      
        |  |  | 726 | 							else | 
      
        |  |  | 727 | 								*bp++ = i - 10 + 'a'; | 
      
        |  |  | 728 | 						} while ((u /= 16) > 0); | 
      
        |  |  | 729 | 						if (hash) | 
      
        |  |  | 730 | 						{ | 
      
        |  |  | 731 | 							*bp++ = 'x'; | 
      
        |  |  | 732 | 							*bp++ = '0'; | 
      
        |  |  | 733 | 						} | 
      
        |  |  | 734 | 					} | 
      
        |  |  | 735 | 					i = f_width - (bp - buf); | 
      
        |  |  | 736 | 					if (!flush_left) | 
      
        |  |  | 737 | 						while (i-- > 0) | 
      
        |  |  | 738 | 							*str++ = (pad); | 
      
        |  |  | 739 | 					for (bp--; bp >= buf; bp--) | 
      
        |  |  | 740 | 						*str++ = ((int) (*bp)); | 
      
        |  |  | 741 | 					if (flush_left) | 
      
        |  |  | 742 | 						while (i-- > 0) | 
      
        |  |  | 743 | 							*str++ = (' '); | 
      
        |  |  | 744 | 					break; | 
      
        |  |  | 745 |             case 'c':			// 'c' character | 
      
        |  |  | 746 | 					i = va_arg(ap, int); | 
      
        |  |  | 747 | 					*str++ = ((int) (i)); | 
      
        |  |  | 748 | 					break; | 
      
        |  |  | 749 |             case 's':			// 's' string | 
      
        |  |  | 750 | 					bp = va_arg(ap, unsigned char *); | 
      
        |  |  | 751 | 					if (!bp) | 
      
        |  |  | 752 | 						bp = (unsigned char *) "(nil)"; | 
      
        |  |  | 753 | 					f_width = f_width - strlen((char *) bp); | 
      
        |  |  | 754 | 					if (!flush_left) | 
      
        |  |  | 755 | 						while (f_width-- > 0) | 
      
        |  |  | 756 | 							*str++ = (pad); | 
      
        |  |  | 757 | 					for (i = 0; *bp && i < prec; i++) | 
      
        |  |  | 758 | 					{ | 
      
        |  |  | 759 | 						*str++ = (*bp); | 
      
        |  |  | 760 | 						bp++; | 
      
        |  |  | 761 | 					} | 
      
        |  |  | 762 | 					if (flush_left) | 
      
        |  |  | 763 | 						while (f_width-- > 0) | 
      
        |  |  | 764 | 							*str++ = (' '); | 
      
        |  |  | 765 | 					break; | 
      
        |  |  | 766 |             case '%':			// '%' character | 
      
        |  |  | 767 | 					*str++ = ('%'); | 
      
        |  |  | 768 | 					break; | 
      
        |  |  | 769 | 			} | 
      
        |  |  | 770 | 			flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0; | 
      
        |  |  | 771 | 			sign = 0; | 
      
        |  |  | 772 | 			pad = ' '; | 
      
        |  |  | 773 | 		} | 
      
        |  |  | 774 | 	} | 
      
        |  |  | 775 |  | 
      
        |  |  | 776 | 	va_end(ap); | 
      
        |  |  | 777 | 	// terminate string with null | 
      
        |  |  | 778 | 	*str++ = '\0'; | 
      
        |  |  | 779 | 	return bufstring; | 
      
        |  |  | 780 | } | 
      
        |  |  | 781 |  | 
      
        |  |  | 782 | */ |