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