-/*!
+/**
* \file
* <!--
- * Copyright 2003, 2004 Develer S.r.l. (http://www.develer.com/)
- * This file is part of DevLib - See devlib/README for information.
+ * This file is part of BeRTOS.
+ *
+ * Bertos is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction. Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License. This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ *
+ * Copyright 2003, 2004, 2005 Develer S.r.l. (http://www.develer.com/)
+ *
* -->
*
* \version $Id$
* width and precision arguments.
*/
-/*#*
- *#* $Log$
- *#* Revision 1.8 2004/08/25 14:12:09 rasky
- *#* Aggiornato il comment block dei log RCS
- *#*
- *#* 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.6 2004/07/30 14:34:10 rasky
- *#* Vari fix per documentazione e commenti
- *#* Aggiunte PP_CATn e STATIC_ASSERT
- *#*
- *#* Revision 1.5 2004/07/29 22:57:09 bernie
- *#* Switch to new-style config handling.
- *#*
- *#* Revision 1.4 2004/07/21 00:20:20 bernie
- *#* Allow completely disabling printf()-like formatter.
- *#*
- *#* Revision 1.3 2004/07/18 22:00:15 bernie
- *#* Reorganize configuration parameters to match DevLib's convention.
- *#*
- *#* Revision 1.2 2004/06/03 11:27:09 bernie
- *#* Add dual-license information.
- *#*
- *#* Revision 1.1 2004/05/23 15:43:16 bernie
- *#* Import mware modules.
- *#*
- *#*/
#include "formatwr.h"
-#include <compiler.h> /* progmem macros */
-#include <config.h> /* CONFIG_ macros */
-#include <drv/kdebug.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
- /*! Enable arcane %n formatter */
+ /** Disable the arcane %n formatter. */
#define CONFIG_PRINTF_N_FORMATTER 0
#endif
#ifndef CONFIG_PRINTF_OCTAL_FORMATTER
- /*! Enable %o formatter */
+ /** Disable the %o formatter. */
#define CONFIG_PRINTF_OCTAL_FORMATTER 0
#endif
-// True if we must keep a count of the number of characters we print
+/* True if we must keep a count of the number of characters we print. */
#define CONFIG_PRINTF_COUNT_CHARS (CONFIG_PRINTF_RETURN_COUNT || CONFIG_PRINTF_N_FORMATTER)
#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? */
-/*#define FRMWRI_BUFSIZE 134*/
- #error 134 is too much, the code must be fixed to have a lower precision limit
+ /* 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
/*
* Conservative estimate. Should be (probably) 12 (which is the size necessary
- * to represent (2^32-1) in octal plus the sign bit
+ * to represent (2^32-1) in octal plus the sign bit.
*/
#define FRMWRI_BUFSIZE 16
#endif
+/* Probably useful for fancy microcontrollers such as the PIC, nobody knows. */
#ifndef MEM_ATTRIBUTE
#define MEM_ATTRIBUTE
#endif
#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,
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))
#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".
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;
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 (;;)
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;
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
precision++;
#endif
case 'x':
- hex = "0123456789abcdef";
+ hex = hex_tab;
case 'u':
case 'p':
case 'X':
#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);
- flags.div_factor =
+ ulong = va_arg(ap, unsigned int);
+
+ flags.div_factor =
#if CONFIG_PRINTF_OCTAL_FORMATTER
- (format_flag == 'o') ? DIV_OCT :
+ (format_flag == 'o') ? DIV_OCT :
#endif
(format_flag == 'u') ? DIV_DEC : DIV_HEX;
flags.plus_space_flag = PSF_NONE;
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 */
{
precision = 6;
}
- if (sizeof(double) != sizeof(long double))
+
+ if (sizeof(double) != sizeof(max_float_t))
{
- if ( (fvalue = flags.l_L_modifier ?
- va_arg(ap,long double) : va_arg(ap,double)) < 0)
- {
- flags.plus_space_flag = PSF_MINUS;
- fvalue = -fvalue;
- }
+ fvalue = flags.l_L_modifier ?
+ va_arg(ap,max_float_t) : va_arg(ap,double);
}
- else if ( (fvalue = va_arg(ap,long double)) < 0)
+ else
+ fvalue = va_arg(ap,max_float_t);
+
+ if (fvalue < 0)
{
flags.plus_space_flag = PSF_MINUS;
fvalue = -fvalue;
}
break;
-#else /* CONFIG_PRINTF <= PRINTF_NOFLOAT */
- case 'g':
- case 'G':
- case 'f':
- case 'e':
- case 'E':
- ptr = buf_pointer = bad_conversion;
- while (*ptr)
- ptr++;
- break;
#endif /* CONFIG_PRINTF <= PRINTF_NOFLOAT */
case '\0': /* Really bad place to find NUL in */
default:
/* Undefined conversion! */
ptr = buf_pointer = bad_conversion;
- ptr += 3;
+ ptr += sizeof(bad_conversion) - 1;
break;
}
#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 */
#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;
/*=================================*/
/* 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;
}