mirror of
https://github.com/adtools/clib2.git
synced 2025-12-08 14:59:05 +00:00
git-svn-id: file:///Users/olsen/Code/migration-svn-zu-git/logical-line-staging/clib2/trunk@15142 87f5fb63-7c3d-0410-a384-fd976d0f7a62
1703 lines
36 KiB
C
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);
|
|