[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[avr-libc-dev] Re: printf in avr-libc
From: |
Jörgen |
Subject: |
[avr-libc-dev] Re: printf in avr-libc |
Date: |
Thu, 12 Sep 2002 02:18:58 -0700 (PDT) |
Hi Guys,
Here's a version of printf that I have tried to
optimize for AVR+GCC. Float is not supported.
An extension - %z - takes strings from EEPROM. %s
takes ram string. PSTRs could easily be added.
All formatting should be supported.
Unfortunatly it is quite big (even with my
simplifications), but it is fairly complete and very
configurable.
Same flash code is used for sprintf_P and printf_P.
Same source code can be used for printf and printf_P.
I can contribute with doxygen documentation if you
want to include it in the library (if it is possible
according to the licenses).
One idea (not mine...) is to compile three versions of
the formatted_write function. formatted_write_small,
formatted_write_full and formatted_write_all. with
different capablities. At link you can set the weak
symbol _formatted_write to one of those three,
selecting how many features you need.
/Jörgen
--- Joerg Wunsch <address@hidden> wrote:
> As E. Weddington wrote:
>
> > > 1) Mix PSTR and memory variables in one printf,
> i.e.:
> > > kprintf("my pstr is %S and my ram str is
> %s\n", pstr, str);
> > >
> >
> > That would be a good extension to have (to mix
> different pointers
> > like that). Can we incorporate that into an
> (s)printf()?
>
> I'll keep it in mind.
>
> --
> J"org Wunsch Unix support engineer
> address@hidden
> http://www.interface-systems.de/~j/
>
>
> _______________________________________________
> AVR-libc-dev mailing list
> address@hidden
>
http://mail.freesoftware.fsf.org/mailman/listinfo/avr-libc-dev
__________________________________________________
Do you Yahoo!?
Yahoo! News - Today's headlines
http://news.yahoo.com
#ifndef _PRINTF_P_H_
#define _PRINTF_P_H_
#include <pgmspace.h>
#include <io.h>
///The printf functions, uses callback to output character
int _formatted_write(const char*fmt0,void put_one_char(char, void *),void
*secret_pointer, ...);
///for sprintf
void put_c_in_string (char c, void *ptr);
///sprintf function
#define sprintf(s,format, args...)
_formatted_write(PSTR(format),put_c_in_string,&s, ## args)
///External sendchar function, for example UART
extern void sendchar(char c);
void put_c_to_sendchar (char c, void *ptr);
#define printf(format, args...)
_formatted_write(PSTR(format),put_c_to_sendchar,0 , ## args)
//External dbg_sendchar, for example debug monitor or UART.
extern void dbg_sendchar(char data, void* not_used);
#define dbg_printf(format, args...)
_formatted_write(PSTR(format),dbg_sendchar,0, ## args)
#endif
/*
Copyright (C) 1993 Free Software Foundation
This file is part of the GNU IO Library. This library 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, or (at your option)
any later version.
This library 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 library; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
As a special exception, if you link this library with files
compiled with a GNU compiler to produce an executable, this does not 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 (c) 1990 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. [rescinded 22 July 1999]
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/******************************************************************************
This file is a patched version of printf called _printf_P
It is made to work with avr-gcc for Atmel AVR MCUs.
There are some differences from standard printf:
1. There is no floating point support (with fp the code is about 8K!)
2. Return type is void
3. Format string must be in program memory (by using macro printf this
is
done automaticaly)
4. %n is not implemented (just remove the comment around it if you need
it)
5. If LIGHTPRINTF is defined, the code is about 550 bytes smaller and
the
folowing specifiers are disabled :
space # * . - + p s o O
6. A function void uart_sendchar(char c) is used for output. The UART
must
be initialized before using printf.
Alexander Popov
address@hidden
small modifications to make it work with liblcd_dip122.a
replaced uart_sendchar with (*write_char)(char)
2001 Michael Schaenzler
*******************************************************************************/
/**
* @file
* formatted printf
*
* @author Jörgen Birkler (mailto:address@hidden)
*
* Even more updates and defines for AVR.
* Evaluated the .list files and did some optimisations.
* Using callback to output characters so code can be reused for
* sprintf, printf, printf_P, etc.
*
* \par Configuration
* Many options can be configured fo minimum RAM and FLASH usage.
* Some configurations will use strlen() and memchr().
* It will always use modulus (%) and division / from the std library, depending
* on configuration it will use either unsigned long int or unsigned int
* versions.
*
* \par Callback for char output
* The characters are output using a callback function supplied
* when calling the printf function. This will of course use more
* code but the advantage is that you can use the same function
* for outputing to Debug monitor, UART and LCD.
*
* \par Extensions for string in EEPROM
* You can enable type modifiers to read string from EEPROM.
* This is very useful as it can save you some of the precious
* FLASH memory. The type modifier for EEPROM strings is %z
* Example:
* {
* //FIXME:Insert code here
*
* }
*
*/
///Configuration
//@{
//Base size (all enabled except %n): 2986
///Support the %n format
#define FORMATTED_WRITE_SUPPORT_N (0)
///Support * for wdith and precision flags
#define FORMATTED_WRITE_SUPPORT_STAR (0) //2908 (-78)
///Support the # flag to output '0x' or '0' for hex and octal numbers
#define FORMATTED_WRITE_SUPPORT_ALT (0) //2868 (-128)
///Support of outputing '(NULL)' if string ptr is NULL
#define FORMATTED_WRITE_SUPPORT_NULL_STRINGS (0) //2940 (-46)
///Support flags, precision and width modifiers
#define FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION (1) //2188 (-798)
///Support of width/precision modifiers for strings
#define FORMATTED_WRITE_SUPPORT_PRECISION_FOR_STRINGS (0) //2896 (-90)
///Support both long, int and short parameters
#define FORMATTED_WRITE_SUPPORT_LONG_SHORT (0) //2734 (-250)
///Support for strings in EEPROM
#define FORMATTED_WRITE_SUPPORT_EEPROM_STRINGS (0)
//@}
//Check configuration
////////////////////////////
#ifdef FORMATTED_WRITE_SUPPORT_N
#ifdef FORMATTED_WRITE_SUPPORT_STAR
#ifdef FORMATTED_WRITE_SUPPORT_ALT
#ifdef FORMATTED_WRITE_SUPPORT_NULL_STRINGS
#ifdef FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION
#ifdef FORMATTED_WRITE_SUPPORT_PRECISION_FOR_STRINGS
#ifdef FORMATTED_WRITE_SUPPORT_LONG_SHORT
#ifdef FORMATTED_WRITE_SUPPORT_EEPROM_STRINGS
#define FORMATTED_WRITE_CONFIG_OK (1)
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#ifndef FORMATTED_WRITE_CONFIG_OK
#error Configuration not complete. Review configuration
#endif
#include <string.h>
#include <stdarg.h>
#ifndef _WIN32
#include "printf_P.h"
#endif //_WIN32
#define PRINT_CHAR(c) {put_one_char(c,appl_p);length++;}
#define PRINT(ptr,len) { \
unsigned int i; \
for(i=len;i > 0;i--) \
PRINT_CHAR(*ptr++); \
}
#define PRINT_EEPROM(ptr,len) { \
unsigned int i; \
for(i=len;i > 0;i--) \
PRINT_CHAR(eeprom_rb(ptr++)); \
}
#define PAD_SP(howmany) { \
unsigned int i; \
for(i=howmany;i > 0;i--) \
PRINT_CHAR(' '); \
}
#define PAD_0(howmany) { \
unsigned int i; \
for(i=howmany;i > 0;i--) \
PRINT_CHAR('0'); \
}
/// Macro for converting letters to digits
#define is_digit(c) ((c)>='0' && (c)<='9')
/** @page FORMATTED_WRITE_FlagsModifiers Flags and Modifiers
*
* %[flags] [width] [.precision] [{h | l | I64 | L}]type
*
* [flags] =
* - '–' Left align the result within the given field width. Default:Right
align.
* - '+' Prefix the output value with a sign (+ or –) if the output value
* is of a signed type. Default:Sign appears only for negative signed
values (–).
* - '0' If width is prefixed with 0, zeros are added until the minimum width
* is reached. If 0 and – appear, the 0 is ignored. If 0 is specified
* with an integer format (i, u, x, X, o, d) the 0 is ignored.
Default:No padding.)
* - ' ' Blank prefixes the output value with a blank if the output value is
signed and
* positive; the blank is ignored if both the blank and + flags appear.
Default:No blank appears.
* - '#' When used with the o, x, or X format, the # flag prefixes any nonzero
output
* value with 0, 0x, or 0X, respectively. Default:No blank appears.
* When used with the e, E, or f format, the # flag forces the output
value
* to contain a decimal point in all cases. Default:Decimal point
appears only if digits follow it.
* When used with the g or G format, the # flag forces the output value
* to contain a decimal point in all cases and prevents the truncation of
trailing zeros.
* Ignored when used with c, d, i, u, or s. Default: Decimal point
appears only
* if digits follow it. Trailing zeros are truncated.
*
* [width] = decimal number. Or '*' if to be read from argument list
*
* [.precision] = decimal number or '*' if to be read from argument list
*
* [{h | l | I64 | L}] = type specifier for the argument list variable
*
* type =
* - 'c' int or wint_t When used with printf functions, specifies a single-byte
character; when used with wprintf functions, specifies a wide character.
* - 'C' int or wint_t When used with printf functions, specifies a wide
character; when used with wprintf functions, specifies a single-byte character.
* - 'd' int Signed decimal integer.
* - 'i' int Signed decimal integer.
* - 'o' int Unsigned octal integer.
* - 'u' int Unsigned decimal integer.
* - 'x' int Unsigned hexadecimal integer, using "abcdef."
* - 'X' int Unsigned hexadecimal integer, using "ABCDEF."
* - 'e' double Signed value having the form [ – ]d.dddd e [sign]ddd where d is
a single decimal digit, dddd is one or more decimal digits, ddd is exactly
three decimal digits, and sign is + or –.
* - 'E' double Identical to the e format except that E rather than e
introduces the exponent.
* - 'f' double Signed value having the form [ – ]dddd.dddd, where dddd is one
or more decimal digits. The number of digits before the decimal point depends
on the magnitude of the number, and the number of digits after the decimal
point depends on the requested precision.
* - 'g' double Signed value printed in f or e format, whichever is more
compact for the given value and precision. The e format is used only when the
exponent of the value is less than –4 or greater than or equal to the precision
argument. Trailing zeros are truncated, and the decimal point appears only if
one or more digits follow it.
* - 'G' double Identical to the g format, except that E, rather than e,
introduces the exponent (where appropriate).
* - 'n' Pointer to integer Number of characters successfully written so far
to the stream or buffer; this value is stored in the integer whose address is
given as the argument.
* - 'p' Pointer to void Prints the address of the argument in hexadecimal
digits.
* - 's' String When used with printf functions, specifies a
single-byte–character string; when used with wprintf functions, specifies a
wide-character string. Characters are printed up to the first null character or
until the precision value is reached.
* - 'S' String When used with printf functions, specifies a wide-character
string; when used with wprintf functions, specifies a single-byte–character
string. Characters are printed up to the first null character or until the
precision value is reached.
*
*/
///Flags used during conversion.
//Setup value type and flags
/////////////////////////////////////
//#define LONGDBL 0x02 /* long double; unimplemented */
#if (FORMATTED_WRITE_SUPPORT_LONG_SHORT==1)
//Support for long and short types
typedef unsigned long value_t;
typedef signed long signed_value_t;
#define FLAG_LONGINT 0x01 // long integer
#define FLAG_SHORTINT 0x04 // short integer
#else //FORMATTED_WRITE_SUPPORT_LONG_SHORT
typedef unsigned int value_t;
typedef signed int signed_value_t;
#endif //FORMATTED_WRITE_SUPPORT_LONG_SHORT
#if (FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION==1)
#if (FORMATTED_WRITE_SUPPORT_ALT==1)
#define FLAG_ALT 0x08 // alternate form '0x'
for hex and '0' for octal
#endif //(FORMATTED_WRITE_SUPPORT_ALT==1)
#define FLAG_LADJUST 0x10 // left adjusted
#define FLAG_ZEROPAD 0x20 // zero (as opposed to blank)
pad
#endif //(FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION==1)
#define FLAG_HEXPREFIX 0x40 // add 0x or 0X prefix
#if (FORMATTED_WRITE_SUPPORT_EEPROM_STRINGS==1)
#define FLAG_EEPROM_STRING 0x80
#endif //(FORMATTED_WRITE_SUPPORT_EEPROM_STRINGS==1)
/**
* Size of decimal/hex/octal conversion buffer
* Octal conversion will require the most characters since it's the smallest
base
* To get the # characters solve:
* 8^chars >= 2^bits
* bits = sizeof(value_t) * 8
* 8^chars = (2^3)^chars = 2^(3*chars) >= 2^(bits) = 2^(sizeof(value_t)*8) =>
*3*chars >= sizeof(value_t)*8 => chars >= sizeof(value_t)*8 / 3
* Round up (sizeof(value_t)*8 + 2) / 3 >= sizeof(value_t)*8 / 3
*/
#define BUF_SIZE ((sizeof(value_t)*8 + 2) / 3)
#ifndef FORMATTED_WRITE_FORMAT_READ
#define FORMATTED_WRITE_FORMAT_READ(ptr) PRG_RDB(ptr)
#endif FORMATTED_WRITE_FORMAT_READ
#define to_digit(_ch) ((_ch)-'0')
#ifndef FORMATTED_WRITE_FORMAT_STRING_TYPE
#define FORMATTED_WRITE_FORMAT_STRING_TYPE PGM_P
#endif //FORMATTED_WRITE_FORMAT_STRING_TYPE
int
_formatted_write(
FORMATTED_WRITE_FORMAT_STRING_TYPE fmt0,
void put_one_char(char, void *),
void* appl_p, ...)
{
va_list ap;
const char *fmt = fmt0; // format string
char ch; // character from fmt
int length = 0; //Length of output characters
va_start(ap, appl_p);
// Scan the format for conversions (`%' character).
for (;;)
{
ch = FORMATTED_WRITE_FORMAT_READ(fmt++);
if (ch=='\0')
{
va_end(ap);
return length;
}
else if (ch!='%')
{
//Normal character
PRINT_CHAR(ch);
}
else
{
unsigned char flags = 0x00; // flags as above
char sign = '\0'; //
sign prefix (' ', '+', '-', or '\0')
#if (FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION==1)
signed char width = 0; // width from format
(%8d), or 0
signed char prec = -1; // precision from
format (%.3d), or -1
for (;;)
{
ch = FORMATTED_WRITE_FORMAT_READ(fmt++);
//Read flags
//////////////////////////////
if (ch=='-')
{
//Left align wihtin the width
flags |= FLAG_LADJUST;
}
else if (ch=='+')
{
sign = '+';
}
#if (FORMATTED_WRITE_SUPPORT_ALT==1)
else if (ch=='#')
{
flags |= FLAG_ALT;
}
#endif //#ifdef FORMATTED_WRITE_SUPPORT_ALT
else if (ch==' ')
{
sign = ' ';
/*
* ``If the space and + flags both
appear, the space
* flag will be ignored.''
* -- ANSI X3J11
*/
/*if (sign=='\0')
{
sign = ' ';
goto rflag;
}
else if (ch=='*'||ch=='-')
{
if (ch=='*')
// ``A negative field
width argument is taken as a
// - flag followed by a
positive field width.''
// -- ANSI X3J11
// They don't exclude
field widths read from args.
if ((width = va_arg(ap,
int)) >= 0)
goto rflag;
width = -width;
}
flags &= ~FLAG_ZEROPAD; // '-' disables
'0'
//goto rflag; */
}
else if (ch=='0')
{
//0 is taken as a flag, not as the
beginning of a field width.
//-- ANSI X3J11
if (!(flags & FLAG_LADJUST))
{
flags |= FLAG_ZEROPAD; /* '-'
disables '0' */
}
}
//Read width
////////////////////////////
#if (FORMATTED_WRITE_SUPPORT_STAR==1)
else if (ch == '*')
{
width = (unsigned char)va_arg(ap, int);
}
#endif //FORMATTED_WRITE_SUPPORT_STAR
else if (is_digit(ch))
{
signed char n = 0;
do
{
n *= 10;
n += to_digit(ch);
ch =
FORMATTED_WRITE_FORMAT_READ(fmt++);
} while (is_digit(ch));
fmt--;
width = n;
}
//Read precision
////////////////////////////
else if (ch=='.')
{
signed char n;
ch = FORMATTED_WRITE_FORMAT_READ(fmt++);
#if (FORMATTED_WRITE_SUPPORT_STAR==1)
if (ch == '*')
{
n = (signed char)va_arg(ap,
int);
}
else
#endif //FORMATTED_WRITE_SUPPORT_STAR
{
n = 0;
do
{
n = n*10 + to_digit(ch);
ch =
FORMATTED_WRITE_FORMAT_READ(fmt++);
} while (is_digit(ch));
fmt--;
}
prec = n;
}
#if (FORMATTED_WRITE_SUPPORT_TYPESPECIFIER==1)
else if (ch=='h')
{
flags |= FLAG_SHORTINT;
}
else if (ch=='l')
{
flags |= FLAG_LONGINT;
}
#endif //FORMATTED_WRITE_SUPPORT_TYPESPECIFIER
else
{
//End of flags
//////////////////////
#else //FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION
while (1)
{
ch = FORMATTED_WRITE_FORMAT_READ(fmt++);
{
#endif //FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION
char buf[BUF_SIZE]; //
space for %c, %[diouxX], %[eEfgG]
value_t value; /* integer arguments
%[diouxX] */
unsigned char size; // size
of converted field or string
const char* out_p;
#if (FORMATTED_WRITE_SUPPORT_LONG_SHORT==1)
//Check capital letters
if (!ch&~0x20 && ch!='X')
{
//Presume longint
flags |= FLAG_LONGINT;
}
#endif //(FORMATTED_WRITE_SUPPORT_LONG_SHORT==1)
//Small letters
ch|=0x20;
//Check zero terminated
if (ch == '\0')
{
return length;
}
else
//%n construct not supported
#if (FORMATTED_WRITE_SUPPORT_N==1)
if (ch=='n') {
if (flags & FLAG_LONGINT)
*va_arg(ap, long *) =
ret;
else if (flags & FLAG_SHORTINT)
*va_arg(ap, short *) =
ret;
else
*va_arg(ap, int *) =
ret;
continue; // no output
}
#endif //FORMATTED_WRITE_SUPPORT_N
//
if (ch == 'c')
{
buf[0] = (char)va_arg(ap, int);
size = 1;
sign = '\0';
out_p = buf;
}
else if (ch == '%')
{
buf[0] = '%';
size = 1;
sign = '\0';
out_p = buf;
}
else if (ch=='s')
{
// print a string from RAM
const char* str = va_arg(ap,
char *);
//No sign for strings
sign = '\0';
#if
(FORMATTED_WRITE_SUPPORT_NULL_STRINGS==1)
if (str == NULL)
{
unsigned char i=0;
buf[i++] = '(';
buf[i++] = 'N';
buf[i++] = 'U';
buf[i++] = 'L';
buf[i++] = 'L';
buf[i++] = ')';
size = i;
out_p = buf;
}
else
#endif
//FORMATTED_WRITE_SUPPORT_NULL_STRINGS
{
out_p = str;
#if
(FORMATTED_WRITE_SUPPORT_PRECISION_FOR_STRINGS==1 &&
FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION==1)
if (prec >= 0)
{
// can't use
strlen; can only look for the
// NUL in the
first 'prec' characters, and
// strlen()
will go further.
while (*src++
!= '\0' && size < prec)
{
size++;
}
/*
char *p =
(char*)memchr(str, 0, prec);
if (p != NULL) {
size =
(unsigned char)(p - str);
if
(size > prec)
size = prec;
}
else
{
size =
prec;
} */
}
else
#endif
//defined(FORMATTED_WRITE_SUPPORT_PRECISION_FOR_STRINGS) &&
defined(FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION)
{
size =
(unsigned char)strlen(str);
}
}
}
#if (FORMATTED_WRITE_SUPPORT_EEPROM_STRINGS==1)
else if (ch=='z')
{
// str is an address into EEPROM
const char* str = va_arg(ap,
char *);
//No sign for strings
sign = '\0';
size = 0;
out_p = str;
flags|=FLAG_EEPROM_STRING;
#if
(FORMATTED_WRITE_SUPPORT_PRECISION_FOR_STRINGS==1 &&
FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION==1)
if (prec >= 0)
{
// can't use strlen;
can only look for the
// NUL in the first
'prec' characters, and
// strlen() will go
further.
while
(eeprom_rb((unsigned int)str++) != '\0' && size < prec)
{
size++;
}
}
else
#endif
//defined(FORMATTED_WRITE_SUPPORT_PRECISION_FOR_STRINGS) &&
defined(FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION)
{
while
(eeprom_rb((unsigned int)str++) != '\0')
{
size++;
}
}
}
#endif //(FORMATTED_WRITE_SUPPORT_EEPROM_STRINGS==1)
else {
//presume one of %pdiux
#define OCT 8
#define DEC 10
#define HEX 16
unsigned char base;
// base for [diouxX] conversion
if (ch == 'p')
{
base=HEX;
value =
(value_t)va_arg(ap, void*);
sign = '$';
}
else if (ch=='d' || ch=='i')
{
signed_value_t val;
//Signed decimal integer
base=DEC;
#if
(FORMATTED_WRITE_SUPPORT_LONG_SHORT==1)
if (flags&FLAG_LONGINT)
{
val =
va_arg(ap, signed long);
}
else
{
int _d =
va_arg(ap, int);
val =
(flags&FLAG_SHORTINT) ? (signed long)(signed short)_d : (signed long)_d;
}
#else
//FORMATTED_WRITE_SUPPORT_LONG_SHORT
val = va_arg(ap, int);
#endif//FORMATTED_WRITE_SUPPORT_LONG_SHORT
if (val < 0)
{
value =
(value_t)-val;
sign = '-';
}
else {
value = val;
}
}
else if (ch=='x' || ch == 'o'
|| ch == 'u')
{
#if
(FORMATTED_WRITE_SUPPORT_LONG_SHORT==1)
if (flags&FLAG_LONGINT)
{
value =
va_arg(ap, unsigned long);
}
else
{
int _d =
va_arg(ap, int);
value =
(flags&FLAG_SHORTINT) ? (unsigned long)(unsigned short)_d : (unsigned long)_d;
}
#else
//FORMATTED_WRITE_SUPPORT_LONG_SHORT
value = va_arg(ap,
unsigned int);
#endif//FORMATTED_WRITE_SUPPORT_LONG_SHORT
if (ch=='x')
{
//Hex number
base=HEX;
#if
(FORMATTED_WRITE_SUPPORT_ALT==1)
//leading 0x/X
only if non-zero
if (flags &
FLAG_ALT && value != 0)
flags
|= FLAG_HEXPREFIX;
#endif
//FORMATTED_WRITE_SUPPORT_ALT
}
else if (ch=='o')
{
//Octal number
sign = '\0';
base=OCT;
}
else
{
//Unsigned
decimal integer
base=DEC;
}
}
else {
//Unrecognized format
specifier, use sign sepcifier to output character
base = 1;
value = 0;
sign = ch;
#if (FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION==1)
prec = -1;
width = 0;
#endif //FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION
}
//Start conversion
{
char* cp =
&buf[BUF_SIZE];
//The result of
converting a zero value with an
//explicit precision of
zero is no characters.
//-- ANSI X3J11
size = 0;
#if (FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION==1)
if (value > 0 || prec <
0)
#endif //FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION
{
unsigned char
notlastdigit;
do {
unsigned char _d = (unsigned char)(value % base);
notlastdigit=(unsigned char)(value>=base);
if
(_d<10) {
_d+='0';
}
else {
_d+='a'-10;
//if (ch=='X') _d&=~0x20;
}
*--cp=_d;
value
/= base;
} while
(notlastdigit);
#if
(FORMATTED_WRITE_SUPPORT_ALT==1)
// handle octal
leading 0
if (base==OCT
&& flags & FLAG_ALT && *cp != '0')
*--cp =
'0';
#endif
size =
(unsigned char)(&buf[BUF_SIZE] - cp);
}
out_p = cp;
}
}
/*
* All reasonable formats wind up here.
At this point,
* `cp' points to a string which (if
not flags&FLAG_LADJUST)
* should be padded out to `width'
places. If
* flags&FLAG_ZEROPAD, it should first
be prefixed by any
* sign or other prefix; otherwise, it
should be blank
* padded before the prefix is emitted.
After any
* left-hand padding and prefixing,
emit zeroes
* required by a decimal [diouxX]
precision, then print
* the string proper, then emit zeroes
required by any
* leftover floating precision;
finally, if FLAG_LADJUST,
* pad with blanks.
*/
{
signed char fieldsz = size;
// field size expanded by sign, dpad etc
#if (FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION==1)
signed char padding = prec -
size;
if (padding < 0) padding = 0;
fieldsz += padding;
#endif //FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION
if (sign != '\0') fieldsz++;
if (flags & FLAG_HEXPREFIX)
fieldsz += 2;
#if (FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION==1)
if (width < fieldsz) width =
fieldsz;
//right-adjusting blank padding
if ((flags &
(FLAG_LADJUST|FLAG_ZEROPAD)) == 0)
{
PAD_SP(width - fieldsz);
}
#endif //FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION
// prefix
if (sign) {
PRINT_CHAR(sign);
}
#if
(FORMATTED_WRITE_SUPPORT_ALT==1)
else if (flags &
FLAG_HEXPREFIX)
{
PRINT_CHAR('0');
PRINT_CHAR(ch);
}
#endif
//FORMATTED_WRITE_SUPPORT_ALT
#if (FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION==1)
// right-adjusting zero padding
if ((flags &
(FLAG_LADJUST|FLAG_ZEROPAD)) == FLAG_ZEROPAD)
{
PAD_0(width - fieldsz);
}
// leading zeroes from decimal
precision
PAD_0(padding);
#endif //FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION
// the string or number
while (size-- > 0)
{
unsigned char out;
#if (FORMATTED_WRITE_SUPPORT_EEPROM_STRINGS==1)
if
(flags&FLAG_EEPROM_STRING)
out =
eeprom_rb((unsigned int)out_p++);
else
#endif //(FORMATTED_WRITE_SUPPORT_EEPROM_STRINGS==1)
out = *out_p++;
PRINT_CHAR(out);
}
#if (FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION==1)
// left-adjusting padding
(always blank)
if (flags & FLAG_LADJUST)
PAD_SP(width - fieldsz);
#endif //FORMATTED_WRITE_SUPPORT_FLAGS_WIDTH_PRECISION
}
//Set ch to 0 to abort %
break; //break from flag while loop
}
} //while (ch != '\0');
} //if (ch != '%')
} //while (ch != '\0')
}
void put_c_in_string (char c, void *ptr) /* Low-level output */
{
*(*(char **) ptr)++ = c;
}
extern void sendchar(char ch);
void put_c_to_sendchar (char c, void *ptr) /* Low-level output */
{
ptr=ptr;
sendchar(c);
}
- Re: [avr-gcc-list] Re: [avr-libc-dev] I fixed dtostre(), (continued)
- [avr-libc-dev] Re: [avr-gcc-list] I fixed dtostre(), Jamie Morken, 2002/09/10
- Re: [avr-libc-dev] Re: [avr-gcc-list] I fixed dtostre(), Joerg Wunsch, 2002/09/10
- [avr-libc-dev] Re: printf in avr-libc, ken restivo, 2002/09/10
- Re: [avr-libc-dev] Re: printf in avr-libc, E. Weddington, 2002/09/11
- Re: [avr-libc-dev] Re: printf in avr-libc, Joerg Wunsch, 2002/09/11
- [avr-libc-dev] Re: printf in avr-libc,
Jörgen <=
- Re: [avr-libc-dev] Re: printf in avr-libc, Joerg Wunsch, 2002/09/12
- Re: [avr-libc-dev] Re: printf in avr-libc, Joerg Wunsch, 2002/09/12
- Re: [avr-libc-dev] Re: printf in avr-libc, Jörgen, 2002/09/12
- Re: [avr-libc-dev] Re: printf in avr-libc, E. Weddington, 2002/09/12
- [avr-libc-dev] Multithreaded strtok, Harald Kipp, 2002/09/13
- Re: [avr-libc-dev] Multithreaded strtok, Joerg Wunsch, 2002/09/13
- Re: [avr-libc-dev] Re: printf in avr-libc, Joerg Wunsch, 2002/09/13
- Re: [avr-libc-dev] Re: printf in avr-libc, daniel_laptop, 2002/09/13
- Re: [avr-libc-dev] Re: printf in avr-libc, Joerg Wunsch, 2002/09/13
- Re: [avr-libc-dev] Re: printf in avr-libc, daniel_laptop, 2002/09/13