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 502d1aaab7 - Removed some more compiler warnings.
git-svn-id: file:///Users/olsen/Code/migration-svn-zu-git/logical-line-staging/clib2/trunk@15142 87f5fb63-7c3d-0410-a384-fd976d0f7a62
2006-09-22 09:02:51 +00:00

1703 lines
36 KiB
C

/*
* $Id: stdio_vfprintf.c,v 1.22 2006-09-22 09:02:51 obarthel Exp $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2006 by Olaf Barthel <olsen (at) 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 */
/****************************************************************************/
#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)
/****************************************************************************/
#define max(a,b) ((a) > (b) ? (a) : (b))
/****************************************************************************/
STATIC int
get_num_leading_digits(__long_double_t v,int radix)
{
int num_digits;
SHOWVALUE(radix);
if(v < radix)
{
num_digits = 1;
}
else
{
/* For some reason log() can crash on GCC 68k... */
#if (!defined(__GNUC__) || defined(__PPC__))
{
num_digits = 1 + floor(log(v) / log((double)radix));
}
#else
{
/* Perform the conversion one digit at a time... */
num_digits = 0;
while(floor(v) > 0.0)
{
num_digits++;
v /= radix;
}
}
#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_byte,
parameter_size_long,
parameter_size_short,
parameter_size_size_t,
parameter_size_ptrdiff_t,
parameter_size_long_long,
parameter_size_long_double,
parameter_size_intmax_t,
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;
char prefix_buffer[8];
int result = EOF;
int len = 0;
int c;
#if defined(FLOATING_POINT_SUPPORT)
char * internal_buffer = NULL;
size_t internal_buffer_size = 0;
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(__check_abort_enabled)
__check_abort();
flockfile(stream);
#if defined(CHECK_FOR_NULL_POINTERS)
{
if(stream == NULL || format == NULL)
{
SHOWMSG("invalid parameters");
__set_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) < 0)
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);