BeRTOS
|
00001 00079 #include "formatwr.h" 00080 00081 #include "cfg/cfg_formatwr.h" /* CONFIG_ macros */ 00082 #include <cfg/debug.h> /* ASSERT */ 00083 00084 #include <cpu/pgm.h> 00085 #include <mware/hex.h> 00086 00087 #ifndef CONFIG_PRINTF_N_FORMATTER 00088 00089 #define CONFIG_PRINTF_N_FORMATTER 0 00090 #endif 00091 00092 #ifndef CONFIG_PRINTF_OCTAL_FORMATTER 00093 00094 #define CONFIG_PRINTF_OCTAL_FORMATTER 0 00095 #endif 00096 00097 /* True if we must keep a count of the number of characters we print. */ 00098 #define CONFIG_PRINTF_COUNT_CHARS (CONFIG_PRINTF_RETURN_COUNT || CONFIG_PRINTF_N_FORMATTER) 00099 00100 #if CONFIG_PRINTF 00101 00102 #if CONFIG_PRINTF > PRINTF_NOFLOAT 00103 #include <float.h> 00104 00105 /* Maximum precision for floating point values */ 00106 typedef long double max_float_t; 00107 00108 #if CONFIG_FRMWRI_BUFSIZE 00109 #define FRMWRI_BUFSIZE CONFIG_FRMWRI_BUFSIZE 00110 #else 00111 /* Conservative estimate. Max float is 3.40282e+038, so %f (but not %e or %g) must have 00112 * space for: sign + all 38 digits + '.' + 6 decimal digits (default) 00113 * Use a high value to avoid unexpected buffer overflows. 00114 */ 00115 #define FRMWRI_BUFSIZE 134 00116 #endif 00117 #else 00118 #if CONFIG_FRMWRI_BUFSIZE 00119 #define FRMWRI_BUFSIZE CONFIG_FRMWRI_BUFSIZE 00120 #else 00121 /* 00122 * Conservative estimate. Should be (probably) 12 (which is the size necessary 00123 * to represent (2^32-1) in octal plus the sign bit. 00124 */ 00125 #define FRMWRI_BUFSIZE 16 00126 #endif 00127 #endif 00128 00129 /* Probably useful for fancy microcontrollers such as the PIC, nobody knows. */ 00130 #ifndef MEM_ATTRIBUTE 00131 #define MEM_ATTRIBUTE 00132 #endif 00133 00134 #if CONFIG_PRINTF > PRINTF_NOMODIFIERS 00135 #define IS_SHORT (h_modifier || (sizeof(int) == 2 && !l_modifier)) 00136 #else 00137 #define IS_SHORT (sizeof(int) == 2) 00138 #endif /* CONFIG_PRINTF > PRINTF_NOMODIFIERS */ 00139 00140 00141 #if CONFIG_PRINTF > PRINTF_NOFLOAT 00142 00143 static char *float_conversion(MEM_ATTRIBUTE max_float_t value, 00144 MEM_ATTRIBUTE short nr_of_digits, 00145 MEM_ATTRIBUTE char *buf, 00146 MEM_ATTRIBUTE char format_flag, 00147 MEM_ATTRIBUTE char g_flag, 00148 MEM_ATTRIBUTE bool alternate_flag) 00149 { 00150 MEM_ATTRIBUTE char *cp; 00151 MEM_ATTRIBUTE char *buf_pointer; 00152 MEM_ATTRIBUTE short n, i, dec_point_pos, integral_10_log; 00153 00154 buf_pointer = buf; 00155 integral_10_log = 0; 00156 00157 if (value >= 1) 00158 { 00159 while (value >= 1e11) /* To speed up things a bit */ 00160 { 00161 value /= 1e10; 00162 integral_10_log += 10; 00163 } 00164 while (value >= 10) 00165 { 00166 value /= 10; 00167 integral_10_log++; 00168 } 00169 } 00170 else if (value) /* Not just 0.0 */ 00171 { 00172 while (value <= 1e-10) /* To speed up things a bit */ 00173 { 00174 value *= 1e10; 00175 integral_10_log -= 10; 00176 } 00177 while (value < 1) 00178 { 00179 value *= 10; 00180 integral_10_log--; 00181 } 00182 } 00183 if (g_flag) 00184 { 00185 if (integral_10_log < nr_of_digits && integral_10_log >= -4) 00186 { 00187 format_flag = 0; 00188 nr_of_digits -= integral_10_log; 00189 } 00190 nr_of_digits--; 00191 if (alternate_flag) 00192 /* %#G - No removal of trailing zeros */ 00193 g_flag = 0; 00194 else 00195 /* %G - Removal of trailing zeros */ 00196 alternate_flag = true; 00197 } 00198 00199 /* %e or %E */ 00200 if (format_flag) 00201 { 00202 dec_point_pos = 0; 00203 } 00204 else 00205 { 00206 /* Less than one... */ 00207 if (integral_10_log < 0) 00208 { 00209 *buf_pointer++ = '0'; 00210 if ((n = nr_of_digits) || alternate_flag) 00211 *buf_pointer++ = '.'; 00212 i = 0; 00213 while (--i > integral_10_log && nr_of_digits) 00214 { 00215 *buf_pointer++ = '0'; 00216 nr_of_digits--; 00217 } 00218 if (integral_10_log < (-n - 1)) 00219 /* Nothing more to do */ 00220 goto CLEAN_UP; 00221 dec_point_pos = 1; 00222 } 00223 else 00224 { 00225 dec_point_pos = - integral_10_log; 00226 } 00227 } 00228 00229 i = dec_point_pos; 00230 while (i <= nr_of_digits ) 00231 { 00232 value -= (max_float_t)(n = (short)value); /* n=Digit value=Remainder */ 00233 value *= 10; /* Prepare for next shot */ 00234 *buf_pointer++ = n + '0'; 00235 if ( ! i++ && (nr_of_digits || alternate_flag)) 00236 *buf_pointer++ = '.'; 00237 } 00238 00239 /* Rounding possible */ 00240 if (value >= 5) 00241 { 00242 n = 1; /* Carry */ 00243 cp = buf_pointer - 1; 00244 do 00245 { 00246 if (*cp != '.') 00247 { 00248 if ( (*cp += n) == ('9' + 1) ) 00249 { 00250 *cp = '0'; 00251 n = 1; 00252 } 00253 else 00254 n = 0; 00255 } 00256 } while (cp-- > buf); 00257 if (n) 00258 { 00259 /* %e or %E */ 00260 if (format_flag) 00261 { 00262 cp = buf_pointer; 00263 while (cp > buf) 00264 { 00265 if (*(cp - 1) == '.') 00266 { 00267 *cp = *(cp - 2); 00268 cp--; 00269 } 00270 else 00271 *cp = *(cp - 1); 00272 cp--; 00273 } 00274 integral_10_log++; 00275 } 00276 else 00277 { 00278 cp = ++buf_pointer; 00279 while (cp > buf) 00280 { 00281 *cp = *(cp - 1); 00282 cp--; 00283 } 00284 } 00285 *buf = '1'; 00286 } 00287 } 00288 00289 CLEAN_UP: 00290 /* %G - Remove trailing zeros */ 00291 if (g_flag) 00292 { 00293 while (*(buf_pointer - 1) == '0') 00294 buf_pointer--; 00295 if (*(buf_pointer - 1) == '.') 00296 buf_pointer--; 00297 } 00298 00299 /* %e or %E */ 00300 if (format_flag) 00301 { 00302 *buf_pointer++ = format_flag; 00303 if (integral_10_log < 0) 00304 { 00305 *buf_pointer++ = '-'; 00306 integral_10_log = -integral_10_log; 00307 } 00308 else 00309 *buf_pointer++ = '+'; 00310 n = 0; 00311 buf_pointer +=10; 00312 do 00313 { 00314 n++; 00315 *buf_pointer++ = (integral_10_log % 10) + '0'; 00316 integral_10_log /= 10; 00317 } while ( integral_10_log || n < 2 ); 00318 for ( i = n ; n > 0 ; n-- ) 00319 *(buf_pointer - 11 - i + n) = *(buf_pointer - n); 00320 buf_pointer -= 10; 00321 } 00322 return (buf_pointer); 00323 } 00324 00325 #endif /* CONFIG_PRINTF > PRINTF_NOFLOAT */ 00326 00332 int 00333 PGM_FUNC(_formatted_write)(const char * PGM_ATTR format, 00334 void put_one_char(char, void *), 00335 void *secret_pointer, 00336 va_list ap) 00337 { 00338 #if CONFIG_PRINTF > PRINTF_REDUCED 00339 MEM_ATTRIBUTE static char bad_conversion[] = "???"; 00340 MEM_ATTRIBUTE static char null_pointer[] = "<NULL>"; 00341 00342 MEM_ATTRIBUTE int precision; 00343 MEM_ATTRIBUTE int n; 00344 #if CONFIG_PRINTF_COUNT_CHARS 00345 MEM_ATTRIBUTE int nr_of_chars; 00346 #endif 00347 MEM_ATTRIBUTE int field_width; 00348 MEM_ATTRIBUTE char format_flag; 00349 enum PLUS_SPACE_FLAGS { 00350 PSF_NONE, PSF_PLUS, PSF_MINUS 00351 }; 00352 enum DIV_FACTOR { 00353 DIV_DEC, DIV_HEX, 00354 #if CONFIG_PRINTF_OCTAL_FORMATTER 00355 DIV_OCT, 00356 #endif 00357 }; 00358 MEM_ATTRIBUTE struct { 00359 enum PLUS_SPACE_FLAGS plus_space_flag : 2; 00360 #if CONFIG_PRINTF_OCTAL_FORMATTER 00361 enum DIV_FACTOR div_factor : 2; 00362 #else 00363 enum DIV_FACTOR div_factor : 1; 00364 #endif 00365 bool left_adjust : 1; 00366 bool l_L_modifier : 1; 00367 bool h_modifier : 1; 00368 bool alternate_flag : 1; 00369 bool nonzero_value : 1; 00370 bool zeropad : 1; 00371 #if CPU_HARVARD 00372 bool progmem : 1; 00373 #endif 00374 } flags; 00375 MEM_ATTRIBUTE unsigned long ulong; 00376 00377 #if CONFIG_PRINTF > PRINTF_NOFLOAT 00378 MEM_ATTRIBUTE max_float_t fvalue; 00379 #endif 00380 00381 MEM_ATTRIBUTE char *buf_pointer; 00382 MEM_ATTRIBUTE char *ptr; 00383 MEM_ATTRIBUTE const char *hex; 00384 MEM_ATTRIBUTE char buf[FRMWRI_BUFSIZE]; 00385 00386 #if CONFIG_PRINTF_COUNT_CHARS 00387 nr_of_chars = 0; 00388 #endif 00389 for (;;) /* Until full format string read */ 00390 { 00391 while ((format_flag = PGM_READ_CHAR(format++)) != '%') /* Until '%' or '\0' */ 00392 { 00393 if (!format_flag) 00394 #if CONFIG_PRINTF_RETURN_COUNT 00395 return (nr_of_chars); 00396 #else 00397 return 0; 00398 #endif 00399 put_one_char(format_flag, secret_pointer); 00400 #if CONFIG_PRINTF_COUNT_CHARS 00401 nr_of_chars++; 00402 #endif 00403 } 00404 if (PGM_READ_CHAR(format) == '%') /* %% prints as % */ 00405 { 00406 format++; 00407 put_one_char('%', secret_pointer); 00408 #if CONFIG_PRINTF_COUNT_CHARS 00409 nr_of_chars++; 00410 #endif 00411 continue; 00412 } 00413 00414 flags.left_adjust = false; 00415 flags.alternate_flag = false; 00416 flags.plus_space_flag = PSF_NONE; 00417 flags.zeropad = false; 00418 #if CPU_HARVARD 00419 flags.progmem = false; 00420 #endif 00421 ptr = buf_pointer = &buf[0]; 00422 hex = HEX_tab; 00423 00424 /* check for leading '-', '+', ' ','#' or '0' flags */ 00425 for (;;) 00426 { 00427 switch (PGM_READ_CHAR(format)) 00428 { 00429 case ' ': 00430 if (flags.plus_space_flag) 00431 goto NEXT_FLAG; 00432 case '+': 00433 flags.plus_space_flag = PSF_PLUS; 00434 goto NEXT_FLAG; 00435 case '-': 00436 flags.left_adjust = true; 00437 goto NEXT_FLAG; 00438 case '#': 00439 flags.alternate_flag = true; 00440 goto NEXT_FLAG; 00441 case '0': 00442 flags.zeropad = true; 00443 goto NEXT_FLAG; 00444 } 00445 break; 00446 NEXT_FLAG: 00447 format++; 00448 } 00449 00450 /* Optional field width (may be '*') */ 00451 if (PGM_READ_CHAR(format) == '*') 00452 { 00453 field_width = va_arg(ap, int); 00454 if (field_width < 0) 00455 { 00456 field_width = -field_width; 00457 flags.left_adjust = true; 00458 } 00459 format++; 00460 } 00461 else 00462 { 00463 field_width = 0; 00464 while (PGM_READ_CHAR(format) >= '0' && PGM_READ_CHAR(format) <= '9') 00465 field_width = field_width * 10 + (PGM_READ_CHAR(format++) - '0'); 00466 } 00467 00468 if (flags.left_adjust) 00469 flags.zeropad = false; 00470 00471 /* Optional precision (or '*') */ 00472 if (PGM_READ_CHAR(format) == '.') 00473 { 00474 if (PGM_READ_CHAR(++format) == '*') 00475 { 00476 precision = va_arg(ap, int); 00477 format++; 00478 } 00479 else 00480 { 00481 precision = 0; 00482 while (PGM_READ_CHAR(format) >= '0' && PGM_READ_CHAR(format) <= '9') 00483 precision = precision * 10 + (PGM_READ_CHAR(format++) - '0'); 00484 } 00485 } 00486 else 00487 precision = -1; 00488 00489 /* At this point, "left_adjust" is nonzero if there was 00490 * a sign, "zeropad" is 1 if there was a leading zero 00491 * and 0 otherwise, "field_width" and "precision" 00492 * contain numbers corresponding to the digit strings 00493 * before and after the decimal point, respectively, 00494 * and "plus_space_flag" is either 0 (no flag) or 00495 * contains a plus or space character. If there was no 00496 * decimal point, "precision" will be -1. 00497 */ 00498 00499 flags.l_L_modifier = false; 00500 flags.h_modifier = false; 00501 00502 /* Optional 'l','L','z' or 'h' modifier? */ 00503 switch (PGM_READ_CHAR(format)) 00504 { 00505 case 'l': 00506 case 'L': 00507 #if SIZEOF_SIZE_T == SIZEOF_LONG 00508 case 'z': 00509 flags.l_L_modifier = true; 00510 #elif SIZEOF_SIZE_T == SIZEOF_INT 00511 flags.l_L_modifier = true; 00512 case 'z': 00513 #endif 00514 format++; 00515 break; 00516 00517 case 'h': 00518 flags.h_modifier = true; 00519 format++; 00520 break; 00521 00522 } 00523 00524 /* 00525 * At exit from the following switch, we will emit 00526 * the characters starting at "buf_pointer" and 00527 * ending at "ptr"-1 00528 */ 00529 switch (format_flag = PGM_READ_CHAR(format++)) 00530 { 00531 #if CONFIG_PRINTF_N_FORMATTER 00532 case 'n': 00533 if (sizeof(short) != sizeof(int)) 00534 { 00535 if (sizeof(int) != sizeof(long)) 00536 { 00537 if (h_modifier) 00538 *va_arg(ap, short *) = nr_of_chars; 00539 else if (flags.l_L_modifier) 00540 *va_arg(ap, long *) = nr_of_chars; 00541 else 00542 *va_arg(ap, int *) = nr_of_chars; 00543 } 00544 else 00545 { 00546 if (h_modifier) 00547 *va_arg(ap, short *) = nr_of_chars; 00548 else 00549 *va_arg(ap, int *) = nr_of_chars; 00550 } 00551 } 00552 else 00553 { 00554 if (flags.l_L_modifier) 00555 *va_arg(ap, long *) = nr_of_chars; 00556 else 00557 *va_arg(ap, int *) = nr_of_chars; 00558 } 00559 continue; 00560 #endif 00561 case 'c': 00562 buf[0] = va_arg(ap, int); 00563 ptr++; 00564 break; 00565 00566 /* Custom formatter for strings in program memory. */ 00567 case 'S': 00568 #if CPU_HARVARD 00569 flags.progmem = true; 00570 #endif 00571 /* Fall trough */ 00572 00573 case 's': 00574 if ( !(buf_pointer = va_arg(ap, char *)) ) 00575 buf_pointer = null_pointer; 00576 if (precision < 0) 00577 precision = 10000; 00578 00579 /* 00580 * Move `ptr' to the last character of the 00581 * string that will be actually printed. 00582 */ 00583 ptr = buf_pointer; 00584 #if CPU_HARVARD 00585 if (flags.progmem) 00586 { 00587 for (n=0; pgm_read_char(ptr) && n < precision; n++) 00588 ++ptr; 00589 } 00590 else 00591 #endif 00592 for (n=0; *ptr && n < precision; n++) 00593 ++ptr; 00594 break; 00595 00596 #if CONFIG_PRINTF_OCTAL_FORMATTER 00597 case 'o': 00598 if (flags.alternate_flag && !precision) 00599 precision++; 00600 #endif 00601 case 'x': 00602 hex = hex_tab; 00603 case 'u': 00604 case 'p': 00605 case 'X': 00606 if (format_flag == 'p') 00607 #if defined(__AVR__) || defined(__I196__) || defined(__MSP430__) /* 16bit pointers */ 00608 ulong = (unsigned long)(unsigned short)va_arg(ap, char *); 00609 #else /* 32bit pointers */ 00610 ulong = (unsigned long)va_arg(ap, char *); 00611 #endif /* 32bit pointers */ 00612 else if (flags.l_L_modifier) 00613 ulong = va_arg(ap, unsigned long); 00614 else if (flags.h_modifier) 00615 ulong = (unsigned long)(unsigned short)va_arg(ap, unsigned int); 00616 else 00617 ulong = va_arg(ap, unsigned int); 00618 00619 flags.div_factor = 00620 #if CONFIG_PRINTF_OCTAL_FORMATTER 00621 (format_flag == 'o') ? DIV_OCT : 00622 #endif 00623 (format_flag == 'u') ? DIV_DEC : DIV_HEX; 00624 flags.plus_space_flag = PSF_NONE; 00625 goto INTEGRAL_CONVERSION; 00626 00627 case 'd': 00628 case 'i': 00629 if (flags.l_L_modifier) 00630 ulong = (unsigned long)(long)va_arg(ap, long); 00631 else 00632 ulong = (unsigned long)(long)va_arg(ap, int); 00633 00634 /* Extract sign */ 00635 if ((signed long)ulong < 0) 00636 { 00637 flags.plus_space_flag = PSF_MINUS; 00638 ulong = (unsigned long)(-((signed long)ulong)); 00639 } 00640 00641 flags.div_factor = DIV_DEC; 00642 00643 /* Now convert to digits */ 00644 INTEGRAL_CONVERSION: 00645 ptr = buf_pointer = &buf[FRMWRI_BUFSIZE - 1]; 00646 flags.nonzero_value = (ulong != 0); 00647 00648 /* No char if zero and zero precision */ 00649 if (precision != 0 || flags.nonzero_value) 00650 { 00651 switch (flags.div_factor) 00652 { 00653 case DIV_DEC: 00654 do 00655 *--buf_pointer = hex[ulong % 10]; 00656 while (ulong /= 10); 00657 break; 00658 00659 case DIV_HEX: 00660 do 00661 *--buf_pointer = hex[ulong % 16]; 00662 while (ulong /= 16); 00663 break; 00664 #if CONFIG_PRINTF_OCTAL_FORMATTER 00665 case DIV_OCT: 00666 do 00667 *--buf_pointer = hex[ulong % 8]; 00668 while (ulong /= 8); 00669 break; 00670 #endif 00671 } 00672 } 00673 00674 /* "precision" takes precedence */ 00675 if (precision < 0) 00676 if (flags.zeropad) 00677 precision = field_width - (flags.plus_space_flag != PSF_NONE); 00678 while (precision > (int)(ptr - buf_pointer)) 00679 *--buf_pointer = '0'; 00680 00681 if (flags.alternate_flag && flags.nonzero_value) 00682 { 00683 if (format_flag == 'x' || format_flag == 'X') 00684 { 00685 *--buf_pointer = format_flag; 00686 *--buf_pointer = '0'; 00687 } 00688 #if CONFIG_PRINTF_OCTAL_FORMATTER 00689 else if ((format_flag == 'o') && (*buf_pointer != '0')) 00690 { 00691 *--buf_pointer = '0'; 00692 } 00693 #endif 00694 } 00695 ASSERT(buf_pointer >= buf); 00696 break; 00697 00698 #if CONFIG_PRINTF > PRINTF_NOFLOAT 00699 case 'g': 00700 case 'G': 00701 n = 1; 00702 format_flag -= 2; 00703 if (! precision) 00704 { 00705 precision = 1; 00706 } 00707 goto FLOATING_CONVERSION; 00708 case 'f': 00709 format_flag = 0; 00710 case 'e': 00711 case 'E': 00712 n = 0; 00713 FLOATING_CONVERSION: 00714 if (precision < 0) 00715 { 00716 precision = 6; 00717 } 00718 00719 if (sizeof(double) != sizeof(max_float_t)) 00720 { 00721 fvalue = flags.l_L_modifier ? 00722 va_arg(ap,max_float_t) : va_arg(ap,double); 00723 } 00724 else 00725 fvalue = va_arg(ap,max_float_t); 00726 00727 if (fvalue < 0) 00728 { 00729 flags.plus_space_flag = PSF_MINUS; 00730 fvalue = -fvalue; 00731 } 00732 ptr = float_conversion (fvalue, 00733 (short)precision, 00734 buf_pointer += field_width, 00735 format_flag, 00736 (char)n, 00737 flags.alternate_flag); 00738 if (flags.zeropad) 00739 { 00740 precision = field_width - (flags.plus_space_flag != PSF_NONE); 00741 while (precision > ptr - buf_pointer) 00742 *--buf_pointer = '0'; 00743 } 00744 break; 00745 00746 #endif /* CONFIG_PRINTF <= PRINTF_NOFLOAT */ 00747 00748 case '\0': /* Really bad place to find NUL in */ 00749 format--; 00750 00751 default: 00752 /* Undefined conversion! */ 00753 ptr = buf_pointer = bad_conversion; 00754 ptr += sizeof(bad_conversion) - 1; 00755 break; 00756 00757 } 00758 00759 /* 00760 * This part emittes the formatted string to "put_one_char". 00761 */ 00762 00763 /* If field_width == 0 then nothing should be written. */ 00764 precision = ptr - buf_pointer; 00765 00766 if ( precision > field_width) 00767 { 00768 n = 0; 00769 } 00770 else 00771 { 00772 n = field_width - precision - (flags.plus_space_flag != PSF_NONE); 00773 } 00774 00775 /* emit any leading pad characters */ 00776 if (!flags.left_adjust) 00777 while (--n >= 0) 00778 { 00779 put_one_char(' ', secret_pointer); 00780 #if CONFIG_PRINTF_COUNT_CHARS 00781 nr_of_chars++; 00782 #endif 00783 } 00784 00785 /* emit flag characters (if any) */ 00786 if (flags.plus_space_flag) 00787 { 00788 put_one_char(flags.plus_space_flag == PSF_PLUS ? '+' : '-', secret_pointer); 00789 #if CONFIG_PRINTF_COUNT_CHARS 00790 nr_of_chars++; 00791 #endif 00792 } 00793 00794 #if CPU_HARVARD 00795 if (flags.progmem) 00796 { 00797 while (--precision >= 0) 00798 { 00799 put_one_char(pgm_read_char(buf_pointer++), secret_pointer); 00800 #if CONFIG_PRINTF_COUNT_CHARS 00801 nr_of_chars++; 00802 #endif 00803 } 00804 } 00805 else 00806 #endif /* CPU_HARVARD */ 00807 { 00808 /* emit the string itself */ 00809 while (--precision >= 0) 00810 { 00811 put_one_char(*buf_pointer++, secret_pointer); 00812 #if CONFIG_PRINTF_COUNT_CHARS 00813 nr_of_chars++; 00814 #endif 00815 } 00816 } 00817 00818 /* emit trailing space characters */ 00819 if (flags.left_adjust) 00820 while (--n >= 0) 00821 { 00822 put_one_char(' ', secret_pointer); 00823 #if CONFIG_PRINTF_COUNT_CHARS 00824 nr_of_chars++; 00825 #endif 00826 } 00827 } 00828 00829 #else /* PRINTF_REDUCED starts here */ 00830 00831 #if CONFIG_PRINTF > PRINTF_NOMODIFIERS 00832 bool l_modifier, h_modifier; 00833 unsigned long u_val, div_val; 00834 #else 00835 unsigned int u_val, div_val; 00836 #endif /* CONFIG_PRINTF > PRINTF_NOMODIFIERS */ 00837 00838 char format_flag; 00839 unsigned int nr_of_chars, base; 00840 char outChar; 00841 char *ptr; 00842 00843 nr_of_chars = 0; 00844 for (;;) /* Until full format string read */ 00845 { 00846 while ((format_flag = PGM_READ_CHAR(format++)) != '%') /* Until '%' or '\0' */ 00847 { 00848 if (!format_flag) 00849 return (nr_of_chars); 00850 put_one_char(format_flag, secret_pointer); 00851 nr_of_chars++; 00852 } 00853 00854 #if CONFIG_PRINTF > PRINTF_NOMODIFIERS 00855 /* 00856 * Optional 'l', 'z' or 'h' modifiers? 00857 */ 00858 l_modifier = h_modifier = false; 00859 switch (PGM_READ_CHAR(format)) 00860 { 00861 case 'l': 00862 #if SIZEOF_SIZE_T == SIZEOF_LONG 00863 case 'z': 00864 l_modifier = true; 00865 #elif SIZEOF_SIZE_T == SIZEOF_INT 00866 l_modifier = true; 00867 case 'z': 00868 #endif 00869 format++; 00870 break; 00871 00872 case 'h': 00873 h_modifier = true; 00874 format++; 00875 break; 00876 } 00877 #endif /* CONFIG_PRINTF > PRINTF_NOMODIFIERS */ 00878 00879 switch (format_flag = PGM_READ_CHAR(format++)) 00880 { 00881 case 'c': 00882 format_flag = va_arg(ap, int); 00883 default: 00884 put_one_char(format_flag, secret_pointer); 00885 nr_of_chars++; 00886 continue; 00887 00888 case 's': 00889 ptr = va_arg(ap, char *); 00890 while ((format_flag = *ptr++)) 00891 { 00892 put_one_char(format_flag, secret_pointer); 00893 nr_of_chars++; 00894 } 00895 continue; 00896 00897 case 'o': 00898 base = 8; 00899 if (IS_SHORT) 00900 div_val = 0x8000; 00901 else 00902 div_val = 0x40000000; 00903 goto CONVERSION_LOOP; 00904 00905 case 'd': 00906 base = 10; 00907 if (IS_SHORT) 00908 div_val = 10000; 00909 else 00910 div_val = 1000000000; 00911 goto CONVERSION_LOOP; 00912 00913 case 'X': 00914 case 'x': 00915 base = 16; 00916 if (IS_SHORT) 00917 div_val = 0x1000; 00918 else 00919 div_val = 0x10000000; 00920 00921 CONVERSION_LOOP: 00922 #if CONFIG_PRINTF > PRINTF_NOMODIFIERS 00923 if (h_modifier) 00924 { 00925 if (format_flag == 'd') 00926 u_val = (short)va_arg(ap, int); 00927 else 00928 u_val = (unsigned short)va_arg(ap, int); 00929 } 00930 else if (l_modifier) 00931 u_val = va_arg(ap, long); 00932 else 00933 { 00934 if (format_flag == 'd') 00935 u_val = va_arg(ap, int); 00936 else 00937 u_val = va_arg(ap, unsigned int); 00938 } 00939 00940 #else /* CONFIG_PRINTF > PRINTF_NOMODIFIERS */ 00941 u_val = va_arg(ap,int); 00942 #endif /* CONFIG_PRINTF > PRINTF_NOMODIFIERS */ 00943 if (format_flag == 'd') 00944 { 00945 if (((int)u_val) < 0) 00946 { 00947 u_val = - u_val; 00948 put_one_char('-', secret_pointer); 00949 nr_of_chars++; 00950 } 00951 } 00952 while (div_val > 1 && div_val > u_val) 00953 { 00954 div_val /= base; 00955 } 00956 do 00957 { 00958 outChar = (u_val / div_val) + '0'; 00959 if (outChar > '9') 00960 { 00961 if (format_flag == 'x') 00962 outChar += 'a'-'9'-1; 00963 else 00964 outChar += 'A'-'9'-1; 00965 } 00966 put_one_char(outChar, secret_pointer); 00967 nr_of_chars++; 00968 u_val %= div_val; 00969 div_val /= base; 00970 } 00971 while (div_val); 00972 00973 } /* end switch(format_flag...) */ 00974 } 00975 #endif /* CONFIG_PRINTF > PRINTF_REDUCED */ 00976 } 00977 00978 #endif /* CONFIG_PRINTF */