1
0
mirror of https://github.com/adtools/clib2.git synced 2025-12-08 14:59:05 +00:00
Files
amiga-clib2/library/stdio_vfprintf.c
Olaf Barthel a7bac89279 c.lib 1.180 (23.10.2004)
- The printf() family now produces no output at all for %e, %f and %g if the
  floating point support code is disabled. Previously, a minimum field width
  specification could take effect, printing a series of 0 or blank space
  characters where no output should have been produced.


git-svn-id: file:///Users/olsen/Code/migration-svn-zu-git/logical-line-staging/clib2/trunk@14756 87f5fb63-7c3d-0410-a384-fd976d0f7a62
2004-10-23 16:38:18 +00:00

1518 lines
31 KiB
C

/*
* $Id: stdio_vfprintf.c,v 1.6 2004-10-23 16:38:18 obarthel Exp $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2004 by Olaf Barthel <olsen@sourcery.han.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of Olaf Barthel nor the names of contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*/
#ifndef _STDLIB_NULL_POINTER_CHECK_H
#include "stdlib_null_pointer_check.h"
#endif /* _STDLIB_NULL_POINTER_CHECK_H */
/****************************************************************************/
/*#define DEBUG*/
#ifndef _STDIO_HEADERS_H
#include "stdio_headers.h"
#endif /* _STDIO_HEADERS_H */
/****************************************************************************/
/*
* Uncomment this to activate '%lld' support and the like. Better still,
* define this is in the Makefile!
*/
/*#define USE_64_BIT_INTS*/
/****************************************************************************/
/* Data conversion flags for vfprintf() below. */
#define FORMATF_LeftJustified (1<<0) /* Output must be left justified */
#define FORMATF_ProduceSign (1<<1) /* Numbers always begin with a leading
sign character */
#define FORMATF_ProduceSpace (1<<2) /* Numbers always begin with a '-'
character or a blank space */
#define FORMATF_AlternateConversion (1<<3) /* Use alternative conversion format */
#define FORMATF_CapitalLetters (1<<4) /* Output must use upper case characters */
#define FORMATF_IsNegative (1<<5) /* Number is negative */
#define FORMATF_HexPrefix (1<<6) /* Prepend '0x' to the output */
#define FORMATF_ZeroPrefix (1<<7) /* Prepend '0' to the output */
/****************************************************************************/
#if defined(FLOATING_POINT_SUPPORT)
/****************************************************************************/
static int
get_num_leading_digits(__long_double_t v)
{
int num_digits;
if(v < 10.0)
{
num_digits = 1;
}
else
{
/* For some reason log10() can crash on GCC 68k... */
#if (!defined(__GNUC__) || defined(__PPC__))
{
num_digits = 1 + floor(log10(v));
}
#else
{
/* Perform the conversion one digit at a time... */
num_digits = 0;
while(floor(v) > 0.0)
{
num_digits++;
v /= 10.0;
}
}
#endif /* __GNUC__ && !__PPC__ */
}
return(num_digits);
}
/****************************************************************************/
#endif /* FLOATING_POINT_SUPPORT */
/****************************************************************************/
int
vfprintf(FILE * stream,const char * format, va_list arg)
{
enum parameter_size_t
{
parameter_size_long,
parameter_size_long_long,
parameter_size_short,
parameter_size_long_double,
parameter_size_default
};
struct iob * iob = (struct iob *)stream;
int format_flags;
char fill_character;
int minimum_field_width;
int precision;
enum parameter_size_t parameter_size;
char conversion_type;
char buffer[80];
int buffer_mode;
char *output_buffer;
int output_len;
char *prefix;
int result = EOF;
int len = 0;
int c;
#if defined(FLOATING_POINT_SUPPORT)
char trail_string[8];
int trail_string_len;
int num_trailing_zeroes;
#endif /* FLOATING_POINT_SUPPORT */
ENTER();
SHOWSTRING(format);
assert( stream != NULL && format != NULL && arg != NULL );
#if defined(CHECK_FOR_NULL_POINTERS)
{
if(stream == NULL || format == NULL)
{
SHOWMSG("invalid parameters");
errno = EFAULT;
goto out;
}
}
#endif /* CHECK_FOR_NULL_POINTERS */
/* If no buffering is specified but a buffer was allocated, switch to
line buffering. This is intended to help 'stderr' and others. */
buffer_mode = (iob->iob_Flags & IOBF_BUFFER_MODE);
if(buffer_mode == IOBF_BUFFER_MODE_NONE)
buffer_mode = IOBF_BUFFER_MODE_LINE;
assert( FLAG_IS_SET(iob->iob_Flags,IOBF_IN_USE) );
assert( iob->iob_BufferSize > 0 );
if(__fputc_check(stream) != OK)
goto out;
while((c = (*format++)) != '\0')
{
/* I this isn't a % charater, copy the input to the output. */
if(c != '%')
{
if(__putc(c,stream,buffer_mode) == EOF)
goto out;
len++;
continue;
}
format_flags = 0;
fill_character = ' ';
/* Collect the flags: left justification, sign, space,
* alternate format, fill character.
*/
while(TRUE)
{
c = (*format);
if(c == '-')
{
SHOWMSG("minus");
SET_FLAG(format_flags,FORMATF_LeftJustified);
format++;
}
else if (c == '+')
{
SHOWMSG("plus");
SET_FLAG(format_flags,FORMATF_ProduceSign);
format++;
}
else if (c == ' ')
{
SHOWMSG("space");
SET_FLAG(format_flags,FORMATF_ProduceSpace);
format++;
}
else if (c == '#')
{
SHOWMSG("alternate");
SET_FLAG(format_flags,FORMATF_AlternateConversion);
format++;
}
else if (c == '0')
{
SHOWMSG("leading zeroes");
fill_character = '0';
format++;
}
else
{
break;
}
}
if(c == '\0')
break;
/* Now for the field width. */
minimum_field_width = 0;
while(TRUE)
{
c = (*format);
if(c == '*')
{
SHOWMSG("use field width (stack)");
/* The field width is stored on the stack. */
assert(arg != NULL);
#if defined(CHECK_FOR_NULL_POINTERS)
{
if(arg == NULL)
{
errno = EFAULT;
goto out;
}
}
#endif /* CHECK_FOR_NULL_POINTERS */
minimum_field_width = va_arg(arg,int);
if(minimum_field_width < 0)
minimum_field_width = 0;
format++;
}
else if ('0' <= c && c <= '9')
{
int next_sum;
int sum = 0;
SHOWMSG("use field width (string)");
/* Process the field width. */
while(TRUE)
{
c = (*format);
if('0' <= c && c <= '9')
{
D(("digit = %lc",c));
next_sum = (10 * sum) + c - '0';
if(next_sum < sum) /* overflow? */
{
SHOWMSG("overflow");
break;
}
SHOWVALUE(sum);
sum = next_sum;
format++;
}
else
{
break;
}
}
minimum_field_width = sum;
SHOWVALUE(minimum_field_width);
}
else
{
break;
}
}
/* End of the format string? */
if(c == '\0')
break;
precision = -1;
/* Was a precision specified? */
if((*format) == '.')
{
SHOWMSG("precision required");
format++;
c = (*format);
if(c == '*')
{
SHOWMSG("use stack");
/* The precision is stored on the stack. */
assert(arg != NULL);
#if defined(CHECK_FOR_NULL_POINTERS)
{
if(arg == NULL)
{
errno = EFAULT;
goto out;
}
}
#endif /* CHECK_FOR_NULL_POINTERS */
precision = va_arg(arg,int);
if(precision < 0)
precision = 0;
format++;
}
else if ('0' <= c && c <= '9')
{
int next_sum;
int sum = 0;
SHOWMSG("use string");