Sistema l'errore da me commesso in fase di conversione...
[bertos.git] / mware / formatwr.c
old mode 100755 (executable)
new mode 100644 (file)
index dc590b9..f8df352
@@ -1,8 +1,8 @@
-/*!
+/**
  * \file
  * <!--
- * Copyright 2003, 2004 Develer S.r.l. (http://www.develer.com/)
- * This file is part of DevLib - See devlib/README for information.
+ * Copyright 2003, 2004, 2005 Develer S.r.l. (http://www.develer.com/)
+ * This file is part of DevLib - See README.devlib for information.
  * -->
  *
  * \version $Id$
 
 /*#*
  *#* $Log$
- *#* Revision 1.11  2005/02/16 16:51:29  bernie
- *#* Simplify float code.
+ *#* Revision 1.19  2006/09/20 13:58:17  marco
+ *#* Added z modifier in string format.
  *#*
- *#* Revision 1.10  2004/10/26 09:01:35  bernie
- *#* Fix spacing.
+ *#* Revision 1.18  2006/07/19 12:56:27  bernie
+ *#* Convert to new Doxygen style.
  *#*
- *#* Revision 1.9  2004/09/14 21:06:23  bernie
- *#* Spelling fix.
+ *#* Revision 1.17  2005/11/04 17:43:27  bernie
+ *#* Fix for LP64 architectures; Add some more tests.
  *#*
- *#* Revision 1.8  2004/08/25 14:12:09  rasky
- *#* Aggiornato il comment block dei log RCS
+ *#* Revision 1.16  2005/07/19 07:25:46  bernie
+ *#* Use appconfig.h instead of cfg/config.h.
  *#*
- *#* Revision 1.7  2004/08/04 15:53:47  rasky
- *#* Nuove opzioni di configurazione per formatted_write e ridotto maggiormente l'utilizzo dellos tack
+ *#* Revision 1.15  2005/04/11 19:10:28  bernie
+ *#* Include top-level headers from cfg/ subdir.
  *#*
- *#* Revision 1.6  2004/07/30 14:34:10  rasky
- *#* Vari fix per documentazione e commenti
- *#* Aggiunte PP_CATn e STATIC_ASSERT
+ *#* Revision 1.14  2005/03/01 23:26:22  bernie
+ *#* Use shared hextab.
  *#*
- *#* Revision 1.5  2004/07/29 22:57:09  bernie
- *#* Switch to new-style config handling.
+ *#* Revision 1.13  2005/02/18 12:33:25  bernie
+ *#* Avoid strlen().
  *#*
- *#* Revision 1.4  2004/07/21 00:20:20  bernie
- *#* Allow completely disabling printf()-like formatter.
+ *#* Revision 1.12  2005/02/16 20:28:03  bernie
+ *#* Add %S formatter.
  *#*
- *#* Revision 1.3  2004/07/18 22:00:15  bernie
- *#* Reorganize configuration parameters to match DevLib's convention.
+ *#* Revision 1.11  2005/02/16 16:51:29  bernie
+ *#* Simplify float code.
  *#*
- *#* Revision 1.2  2004/06/03 11:27:09  bernie
- *#* Add dual-license information.
+ *#* Revision 1.10  2004/10/26 09:01:35  bernie
+ *#* Fix spacing.
  *#*
- *#* Revision 1.1  2004/05/23 15:43:16  bernie
- *#* Import mware modules.
+ *#* Revision 1.9  2004/09/14 21:06:23  bernie
+ *#* Spelling fix.
  *#*
+ *#* Revision 1.8  2004/08/25 14:12:09  rasky
+ *#* Aggiornato il comment block dei log RCS
  *#*/
 
 #include "formatwr.h"
-#include <compiler.h> /* progmem macros */
-#include <config.h> /* CONFIG_ macros */
-#include <debug.h> /* ASSERT */
+#include <mware/pgm.h>
+#include <mware/hex.h>
+#include <cfg/debug.h> /* ASSERT */
+#include <appconfig.h> /* CONFIG_ macros */
 
 #ifndef CONFIG_PRINTF_N_FORMATTER
-       /*! Disable the arcane %n formatter. */
+       /** Disable the arcane %n formatter. */
        #define CONFIG_PRINTF_N_FORMATTER 0
 #endif
 
 #ifndef CONFIG_PRINTF_OCTAL_FORMATTER
-       /*! Disable the %o formatter. */
+       /** Disable the %o formatter. */
        #define CONFIG_PRINTF_OCTAL_FORMATTER 0
 #endif
 
 #if CONFIG_PRINTF
 
 #if CONFIG_PRINTF > PRINTF_NOFLOAT
-#include <float.h>
-#endif /* CONFIG_PRINTF > PRINTF_NOFLOAT */
+       #include <float.h>
 
-#if CONFIG_PRINTF > PRINTF_NOFLOAT
-/*bernie: save some memory, who cares about floats with lots of decimals? */
+       /* Maximum precision for floating point values */
+       typedef long double max_float_t;
+
+       /*bernie: save some memory, who cares about floats with lots of decimals? */
        #define FRMWRI_BUFSIZE 134
        #warning 134 is too much, the code must be fixed to have a lower precision limit
 #else
 
 #if CONFIG_PRINTF > PRINTF_NOFLOAT
 
-static char *float_conversion(MEM_ATTRIBUTE long double value,
+static char *float_conversion(MEM_ATTRIBUTE max_float_t value,
                MEM_ATTRIBUTE short nr_of_digits,
                MEM_ATTRIBUTE char *buf,
                MEM_ATTRIBUTE char format_flag,
@@ -228,7 +231,7 @@ static char *float_conversion(MEM_ATTRIBUTE long double value,
        i = dec_point_pos;
        while (i <= nr_of_digits )
        {
-               value -= (long double)(n = (short)value); /* n=Digit value=Remainder */
+               value -= (max_float_t)(n = (short)value); /* n=Digit value=Remainder */
                value *= 10; /* Prepare for next shot */
                *buf_pointer++ = n + '0';
                if ( ! i++ && (nr_of_digits || alternate_flag))
@@ -323,7 +326,7 @@ CLEAN_UP:
 
 #endif /* CONFIG_PRINTF > PRINTF_NOFLOAT */
 
-/*!
+/**
  * This routine forms the core and entry of the formatter.
  *
  * The conversion performed conforms to the ANSI specification for "printf".
@@ -354,24 +357,27 @@ PGM_FUNC(_formatted_write)(const char * PGM_ATTR format,
                DIV_OCT,
 #endif
        };
-       struct {
-               MEM_ATTRIBUTE enum PLUS_SPACE_FLAGS plus_space_flag : 2;
+       MEM_ATTRIBUTE struct {
+               enum PLUS_SPACE_FLAGS plus_space_flag : 2;
 #if CONFIG_PRINTF_OCTAL_FORMATTER
-               MEM_ATTRIBUTE enum DIV_FACTOR div_factor : 2;
+               enum DIV_FACTOR div_factor : 2;
 #else
-               MEM_ATTRIBUTE enum DIV_FACTOR div_factor : 1;
+               enum DIV_FACTOR div_factor : 1;
+#endif
+               bool left_adjust : 1;
+               bool l_L_modifier : 1;
+               bool h_modifier : 1;
+               bool alternate_flag : 1;
+               bool nonzero_value : 1;
+               bool zeropad : 1;
+#if CPU_HARVARD
+               bool progmem : 1;
 #endif
-               MEM_ATTRIBUTE bool left_adjust : 1;
-               MEM_ATTRIBUTE bool l_L_modifier : 1;
-               MEM_ATTRIBUTE bool h_modifier : 1;
-               MEM_ATTRIBUTE bool alternate_flag : 1;
-               MEM_ATTRIBUTE bool nonzero_value : 1;
-               MEM_ATTRIBUTE bool zeropad : 1;
        } flags;
        MEM_ATTRIBUTE unsigned long ulong;
 
 #if CONFIG_PRINTF >  PRINTF_NOFLOAT
-       MEM_ATTRIBUTE long double fvalue;
+       MEM_ATTRIBUTE max_float_t fvalue;
 #endif
 
        MEM_ATTRIBUTE char *buf_pointer;
@@ -411,8 +417,11 @@ PGM_FUNC(_formatted_write)(const char * PGM_ATTR format,
                flags.alternate_flag = false;
                flags.plus_space_flag = PSF_NONE;
                flags.zeropad = false;
+#if CPU_HARVARD
+               flags.progmem = false;
+#endif
                ptr = buf_pointer = &buf[0];
-               hex = "0123456789ABCDEF";
+               hex = HEX_tab;
 
                /* check for leading '-', '+', ' ','#' or '0' flags  */
                for (;;)
@@ -492,11 +501,12 @@ NEXT_FLAG:
                flags.l_L_modifier = false;
                flags.h_modifier = false;
 
-               /* Optional 'l','L' r 'h' modifier? */
+               /* Optional 'l','L','z' or 'h' modifier? */
                switch (PGM_READ_CHAR(format))
                {
                        case 'l':
                        case 'L':
+                       case 'z':
                                flags.l_L_modifier = true;
                                format++;
                                break;
@@ -548,15 +558,34 @@ NEXT_FLAG:
                                ptr++;
                                break;
 
+                       /* Custom formatter for strings in program memory. */
+                       case 'S':
+#if CPU_HARVARD
+                               flags.progmem = true;
+#endif
+                               /* Fall trough */
+
                        case 's':
                                if ( !(buf_pointer = va_arg(ap, char *)) )
                                        buf_pointer = null_pointer;
                                if (precision < 0)
                                        precision = 10000;
-                               for (n=0; *buf_pointer++ && n < precision; n++)
-                                       ;
-                               ptr = --buf_pointer;
-                               buf_pointer -= n;
+
+                               /*
+                                * Move `ptr' to the last character of the
+                                * string that will be actually printed.
+                                */
+                               ptr = buf_pointer;
+#if CPU_HARVARD
+                               if (flags.progmem)
+                               {
+                                       for (n=0; pgm_read_char(ptr) && n < precision; n++)
+                                               ++ptr;
+                               }
+                               else
+#endif
+                               for (n=0; *ptr && n < precision; n++)
+                                       ++ptr;
                                break;
 
 #if CONFIG_PRINTF_OCTAL_FORMATTER
@@ -565,7 +594,7 @@ NEXT_FLAG:
                                        precision++;
 #endif
                        case 'x':
-                               hex = "0123456789abcdef";
+                               hex = hex_tab;
                        case 'u':
                        case 'p':
                        case 'X':
@@ -573,15 +602,15 @@ NEXT_FLAG:
 #if defined(__AVR__) || defined(__I196__) /* 16bit pointers */
                                        ulong = (unsigned long)(unsigned short)va_arg(ap, char *);
 #else /* 32bit pointers */
-                               ulong = (unsigned long)va_arg(ap, char *);
+                                       ulong = (unsigned long)va_arg(ap, char *);
 #endif /* 32bit pointers */
-                               else if (sizeof(short) == sizeof(int))
-                                       ulong = flags.l_L_modifier ?
-                                               va_arg(ap, unsigned long) : (unsigned long)va_arg(ap, unsigned int);
+                               else if (flags.l_L_modifier)
+                                       ulong = va_arg(ap, unsigned long);
+                               else if (flags.h_modifier)
+                                       ulong = (unsigned long)(unsigned short)va_arg(ap, unsigned int);
                                else
-                                       ulong = flags.h_modifier ?
-                                               (unsigned long)(unsigned short) va_arg(ap, int)
-                                               : (unsigned long)va_arg(ap, int);
+                                       ulong = va_arg(ap, unsigned int);
+
                                flags.div_factor =
 #if CONFIG_PRINTF_OCTAL_FORMATTER
                                        (format_flag == 'o') ? DIV_OCT :
@@ -592,32 +621,18 @@ NEXT_FLAG:
 
                        case 'd':
                        case 'i':
-                               if (sizeof(short) == sizeof(long))
-                               {
-                                       if ( (long)(ulong = va_arg(ap, unsigned long)) < 0)
-                                       {
-                                               flags.plus_space_flag = PSF_MINUS;
-                                               ulong = (unsigned long)(-((signed long)ulong));
-                                       }
-                               }
-                               else if (sizeof(short) == sizeof(int))
-                               {
-                                       if ( (long)(ulong = flags.l_L_modifier ?
-                                                               va_arg(ap,unsigned long) : (unsigned long)va_arg(ap,int)) < 0)
-                                       {
-                                               flags.plus_space_flag = PSF_MINUS;
-                                               ulong = (unsigned long)(-((signed long)ulong));
-                                       }
-                               }
+                               if (flags.l_L_modifier)
+                                       ulong = (unsigned long)(long)va_arg(ap, long);
                                else
+                                       ulong = (unsigned long)(long)va_arg(ap, int);
+
+                               /* Extract sign */
+                               if ((signed long)ulong < 0)
                                {
-                                       if ( (signed long)(ulong = (unsigned long) (flags.h_modifier ?
-                                                                       (short) va_arg(ap, int) : va_arg(ap,int))) < 0)
-                                       {
-                                               flags.plus_space_flag = PSF_MINUS;
-                                               ulong = (unsigned long)(-((signed long)ulong));
-                                       }
+                                       flags.plus_space_flag = PSF_MINUS;
+                                       ulong = (unsigned long)(-((signed long)ulong));
                                }
+
                                flags.div_factor = DIV_DEC;
 
                                /* Now convert to digits */
@@ -696,13 +711,13 @@ FLOATING_CONVERSION:
                                        precision = 6;
                                }
 
-                               if (sizeof(double) != sizeof(long double))
+                               if (sizeof(double) != sizeof(max_float_t))
                                {
                                        fvalue = flags.l_L_modifier ?
-                                               va_arg(ap,long double) : va_arg(ap,double);
+                                               va_arg(ap,max_float_t) : va_arg(ap,double);
                                }
                                else
-                                       fvalue = va_arg(ap,long double);
+                                       fvalue = va_arg(ap,max_float_t);
 
                                if (fvalue < 0)
                                {
@@ -731,7 +746,7 @@ FLOATING_CONVERSION:
                        default:
                                /* Undefined conversion! */
                                ptr = buf_pointer = bad_conversion;
-                               ptr += strlen(bad_conversion);
+                               ptr += sizeof(bad_conversion) - 1;
                                break;
 
                }
@@ -771,13 +786,28 @@ FLOATING_CONVERSION:
 #endif
                }
 
-               /* emit the string itself */
-               while (--precision >= 0)
+#if CPU_HARVARD
+               if (flags.progmem)
                {
-                       put_one_char(*buf_pointer++, secret_pointer);
+                       while (--precision >= 0)
+                       {
+                               put_one_char(pgm_read_char(buf_pointer++), secret_pointer);
 #if CONFIG_PRINTF_COUNT_CHARS
-                       nr_of_chars++;
+                               nr_of_chars++;
 #endif
+                       }
+               }
+               else
+#endif /* CPU_HARVARD */
+               {
+                       /* emit the string itself */
+                       while (--precision >= 0)
+                       {
+                               put_one_char(*buf_pointer++, secret_pointer);
+#if CONFIG_PRINTF_COUNT_CHARS
+                               nr_of_chars++;
+#endif
+                       }
                }
 
                /* emit trailing space characters */
@@ -794,7 +824,7 @@ FLOATING_CONVERSION:
 #else /* PRINTF_REDUCED starts here */
 
 #if CONFIG_PRINTF > PRINTF_NOMODIFIERS
-       char l_modifier, h_modifier;
+       bool l_modifier, h_modifier;
        unsigned long u_val, div_val;
 #else
        unsigned int u_val, div_val;
@@ -820,16 +850,16 @@ FLOATING_CONVERSION:
                /*=================================*/
                /* Optional 'l' or 'h' modifiers ? */
                /*=================================*/
-               l_modifier = h_modifier = 0;
+               l_modifier = h_modifier = false;
                switch (PGM_READ_CHAR(format))
                {
                        case 'l':
-                               l_modifier = 1;
+                               l_modifier = true;
                                format++;
                                break;
 
                        case 'h':
-                               h_modifier = 1;
+                               h_modifier = true;
                                format++;
                                break;
                }