mirror of
https://github.com/google/pebble.git
synced 2025-03-19 18:41:21 +00:00
756 lines
18 KiB
C
756 lines
18 KiB
C
|
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
|
||
|
* Copyright 2016 University of Szeged
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* Jerry printf implementation
|
||
|
*/
|
||
|
|
||
|
#include <assert.h>
|
||
|
#include <stdarg.h>
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "jerry-libc-defs.h"
|
||
|
|
||
|
/**
|
||
|
* printf's length type
|
||
|
*/
|
||
|
typedef enum
|
||
|
{
|
||
|
LIBC_PRINTF_ARG_LENGTH_TYPE_NONE, /**< (none) */
|
||
|
LIBC_PRINTF_ARG_LENGTH_TYPE_HH, /**< hh */
|
||
|
LIBC_PRINTF_ARG_LENGTH_TYPE_H, /**< h */
|
||
|
LIBC_PRINTF_ARG_LENGTH_TYPE_L, /**< l */
|
||
|
LIBC_PRINTF_ARG_LENGTH_TYPE_LL, /**< ll */
|
||
|
LIBC_PRINTF_ARG_LENGTH_TYPE_J, /**< j */
|
||
|
LIBC_PRINTF_ARG_LENGTH_TYPE_Z, /**< z */
|
||
|
LIBC_PRINTF_ARG_LENGTH_TYPE_T, /**< t */
|
||
|
LIBC_PRINTF_ARG_LENGTH_TYPE_HIGHL /**< L */
|
||
|
} libc_printf_arg_length_type_t;
|
||
|
|
||
|
/**
|
||
|
* printf's flags mask
|
||
|
*/
|
||
|
typedef uint8_t libc_printf_arg_flags_mask_t;
|
||
|
|
||
|
/**
|
||
|
* Left justification of field's contents
|
||
|
*/
|
||
|
#define LIBC_PRINTF_ARG_FLAG_LEFT_JUSTIFY (1 << 0)
|
||
|
|
||
|
/**
|
||
|
* Force print of number's sign
|
||
|
*/
|
||
|
#define LIBC_PRINTF_ARG_FLAG_PRINT_SIGN (1 << 1)
|
||
|
|
||
|
/**
|
||
|
* If no sign is printed, print space before value
|
||
|
*/
|
||
|
#define LIBC_PRINTF_ARG_FLAG_SPACE (1 << 2)
|
||
|
|
||
|
/**
|
||
|
* For o, x, X preceed value with 0, 0x or 0X for non-zero values.
|
||
|
*/
|
||
|
#define LIBC_PRINTF_ARG_FLAG_SHARP (1 << 3)
|
||
|
|
||
|
/**
|
||
|
* Left-pad field with zeroes instead of spaces
|
||
|
*/
|
||
|
#define LIBC_PRINTF_ARG_FLAG_ZERO_PADDING (1 << 4)
|
||
|
|
||
|
/**
|
||
|
* printf helper function that outputs a char
|
||
|
*/
|
||
|
static void
|
||
|
libc_printf_putchar (FILE *stream, /**< stream pointer */
|
||
|
char character) /**< character */
|
||
|
{
|
||
|
fwrite (&character, 1, sizeof (character), stream);
|
||
|
} /* libc_printf_putchar */
|
||
|
|
||
|
/**
|
||
|
* printf helper function that outputs justified string
|
||
|
*/
|
||
|
static void
|
||
|
libc_printf_justified_string_output (FILE *stream, /**< stream pointer */
|
||
|
const char *string_p, /**< string */
|
||
|
size_t width, /**< minimum field width */
|
||
|
bool is_left_justify, /**< justify to left (true) or right (false) */
|
||
|
bool is_zero_padding) /**< left-pad with zeroes (true) or spaces (false) */
|
||
|
{
|
||
|
const size_t str_length = strlen (string_p);
|
||
|
|
||
|
size_t outputted_length = 0;
|
||
|
|
||
|
if (!is_left_justify)
|
||
|
{
|
||
|
char padding_char = is_zero_padding ? '0' : ' ';
|
||
|
|
||
|
while (outputted_length + str_length < width)
|
||
|
{
|
||
|
libc_printf_putchar (stream, padding_char);
|
||
|
outputted_length++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fwrite (string_p, 1, str_length * sizeof (*string_p), stream);
|
||
|
outputted_length += str_length;
|
||
|
|
||
|
if (is_left_justify)
|
||
|
{
|
||
|
while (outputted_length < width)
|
||
|
{
|
||
|
libc_printf_putchar (stream, ' ');
|
||
|
outputted_length++;
|
||
|
}
|
||
|
}
|
||
|
} /* libc_printf_justified_string_output */
|
||
|
|
||
|
/**
|
||
|
* printf helper function that converts unsigned integer to string
|
||
|
*/
|
||
|
static char *
|
||
|
libc_printf_uint_to_string (uintmax_t value, /**< integer value */
|
||
|
char *buffer_p, /**< buffer for output string */
|
||
|
size_t buffer_size, /**< buffer size */
|
||
|
const char *alphabet, /**< alphabet used for digits */
|
||
|
uint32_t radix) /**< radix */
|
||
|
{
|
||
|
char *str_buffer_end = buffer_p + buffer_size;
|
||
|
char *str_p = str_buffer_end;
|
||
|
*--str_p = '\0';
|
||
|
|
||
|
assert (radix >= 2);
|
||
|
|
||
|
if ((radix & (radix - 1)) != 0)
|
||
|
{
|
||
|
/*
|
||
|
* Radix is not power of 2. Only 32-bit numbers are supported in this mode.
|
||
|
*/
|
||
|
assert ((value >> 32) == 0);
|
||
|
|
||
|
uint32_t value_lo = (uint32_t) value;
|
||
|
|
||
|
while (value_lo != 0)
|
||
|
{
|
||
|
assert (str_p != buffer_p);
|
||
|
|
||
|
*--str_p = alphabet[ value_lo % radix ];
|
||
|
value_lo /= radix;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
uint32_t shift = 0;
|
||
|
while (!(radix & (1u << shift)))
|
||
|
{
|
||
|
shift++;
|
||
|
|
||
|
assert (shift <= 32);
|
||
|
}
|
||
|
|
||
|
uint32_t value_lo = (uint32_t) value;
|
||
|
uint32_t value_hi = (uint32_t) (value >> 32);
|
||
|
|
||
|
while (value_lo != 0
|
||
|
|| value_hi != 0)
|
||
|
{
|
||
|
assert (str_p != buffer_p);
|
||
|
|
||
|
*--str_p = alphabet[ value_lo & (radix - 1) ];
|
||
|
value_lo >>= shift;
|
||
|
value_lo += (value_hi & (radix - 1)) << (32 - shift);
|
||
|
value_hi >>= shift;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (*str_p == '\0')
|
||
|
{
|
||
|
*--str_p = '0';
|
||
|
}
|
||
|
|
||
|
assert (str_p >= buffer_p && str_p < str_buffer_end);
|
||
|
|
||
|
return str_p;
|
||
|
} /* libc_printf_uint_to_string */
|
||
|
|
||
|
/**
|
||
|
* printf helper function that prints d and i arguments
|
||
|
*
|
||
|
* @return updated va_list
|
||
|
*/
|
||
|
static void
|
||
|
libc_printf_write_d_i (FILE *stream, /**< stream pointer */
|
||
|
va_list *args_list_p, /**< args' list */
|
||
|
libc_printf_arg_flags_mask_t flags, /**< field's flags */
|
||
|
libc_printf_arg_length_type_t length, /**< field's length type */
|
||
|
uint32_t width) /**< minimum field width to output */
|
||
|
{
|
||
|
assert ((flags & LIBC_PRINTF_ARG_FLAG_SHARP) == 0);
|
||
|
|
||
|
bool is_signed = true;
|
||
|
uintmax_t value = 0;
|
||
|
|
||
|
/* true - positive, false - negative */
|
||
|
bool sign = true;
|
||
|
const size_t bits_in_byte = 8;
|
||
|
const uintmax_t value_sign_mask = ((uintmax_t) 1) << (sizeof (value) * bits_in_byte - 1);
|
||
|
|
||
|
switch (length)
|
||
|
{
|
||
|
case LIBC_PRINTF_ARG_LENGTH_TYPE_NONE:
|
||
|
case LIBC_PRINTF_ARG_LENGTH_TYPE_HH: /* char is promoted to int */
|
||
|
case LIBC_PRINTF_ARG_LENGTH_TYPE_H: /* short int is promoted to int */
|
||
|
{
|
||
|
value = (uintmax_t) va_arg (*args_list_p, int);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case LIBC_PRINTF_ARG_LENGTH_TYPE_L:
|
||
|
{
|
||
|
value = (uintmax_t) va_arg (*args_list_p, long int);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case LIBC_PRINTF_ARG_LENGTH_TYPE_LL:
|
||
|
{
|
||
|
value = (uintmax_t) va_arg (*args_list_p, long long int);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case LIBC_PRINTF_ARG_LENGTH_TYPE_J:
|
||
|
{
|
||
|
value = (uintmax_t) va_arg (*args_list_p, intmax_t);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case LIBC_PRINTF_ARG_LENGTH_TYPE_Z:
|
||
|
{
|
||
|
is_signed = false;
|
||
|
value = (uintmax_t) va_arg (*args_list_p, size_t);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case LIBC_PRINTF_ARG_LENGTH_TYPE_T:
|
||
|
{
|
||
|
is_signed = false;
|
||
|
value = (uintmax_t) va_arg (*args_list_p, ptrdiff_t);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case LIBC_PRINTF_ARG_LENGTH_TYPE_HIGHL:
|
||
|
{
|
||
|
assert (!"unsupported length field L");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (is_signed)
|
||
|
{
|
||
|
sign = ((value & value_sign_mask) == 0);
|
||
|
|
||
|
if (!sign)
|
||
|
{
|
||
|
value = (uintmax_t) (-value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
char str_buffer[ 32 ];
|
||
|
char *string_p = libc_printf_uint_to_string (value,
|
||
|
str_buffer,
|
||
|
sizeof (str_buffer),
|
||
|
"0123456789",
|
||
|
10);
|
||
|
|
||
|
if (!sign
|
||
|
|| (flags & LIBC_PRINTF_ARG_FLAG_PRINT_SIGN))
|
||
|
{
|
||
|
assert (string_p > str_buffer);
|
||
|
*--string_p = (sign ? '+' : '-');
|
||
|
}
|
||
|
else if (flags & LIBC_PRINTF_ARG_FLAG_SPACE)
|
||
|
{
|
||
|
/* no sign and space flag, printing one space */
|
||
|
|
||
|
libc_printf_putchar (stream, ' ');
|
||
|
if (width > 0)
|
||
|
{
|
||
|
width--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
libc_printf_justified_string_output (stream,
|
||
|
string_p,
|
||
|
width,
|
||
|
flags & LIBC_PRINTF_ARG_FLAG_LEFT_JUSTIFY,
|
||
|
flags & LIBC_PRINTF_ARG_FLAG_ZERO_PADDING);
|
||
|
} /* libc_printf_write_d_i */
|
||
|
|
||
|
/**
|
||
|
* printf helper function that prints d and i arguments
|
||
|
*
|
||
|
* @return updated va_list
|
||
|
*/
|
||
|
static void
|
||
|
libc_printf_write_u_o_x_X (FILE *stream, /**< stream pointer */
|
||
|
char specifier, /**< specifier (u, o, x, X) */
|
||
|
va_list *args_list_p, /**< args' list */
|
||
|
libc_printf_arg_flags_mask_t flags, /**< field's flags */
|
||
|
libc_printf_arg_length_type_t length, /**< field's length type */
|
||
|
uint32_t width) /**< minimum field width to output */
|
||
|
{
|
||
|
uintmax_t value;
|
||
|
|
||
|
switch (length)
|
||
|
{
|
||
|
case LIBC_PRINTF_ARG_LENGTH_TYPE_NONE:
|
||
|
case LIBC_PRINTF_ARG_LENGTH_TYPE_HH: /* char is promoted to int */
|
||
|
case LIBC_PRINTF_ARG_LENGTH_TYPE_H: /* short int is promoted to int */
|
||
|
{
|
||
|
value = (uintmax_t) va_arg (*args_list_p, unsigned int);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case LIBC_PRINTF_ARG_LENGTH_TYPE_L:
|
||
|
{
|
||
|
value = (uintmax_t) va_arg (*args_list_p, unsigned long int);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case LIBC_PRINTF_ARG_LENGTH_TYPE_LL:
|
||
|
{
|
||
|
value = (uintmax_t) va_arg (*args_list_p, unsigned long long int);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case LIBC_PRINTF_ARG_LENGTH_TYPE_J:
|
||
|
{
|
||
|
value = (uintmax_t) va_arg (*args_list_p, uintmax_t);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case LIBC_PRINTF_ARG_LENGTH_TYPE_Z:
|
||
|
{
|
||
|
value = (uintmax_t) va_arg (*args_list_p, size_t);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case LIBC_PRINTF_ARG_LENGTH_TYPE_T:
|
||
|
{
|
||
|
value = (uintmax_t) va_arg (*args_list_p, ptrdiff_t);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case LIBC_PRINTF_ARG_LENGTH_TYPE_HIGHL:
|
||
|
{
|
||
|
assert (!"unsupported length field L");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
{
|
||
|
assert (!"unexpected length field");
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (flags & LIBC_PRINTF_ARG_FLAG_SHARP)
|
||
|
{
|
||
|
if (value != 0 && specifier != 'u')
|
||
|
{
|
||
|
libc_printf_putchar (stream, '0');
|
||
|
|
||
|
if (specifier == 'x')
|
||
|
{
|
||
|
libc_printf_putchar (stream, 'x');
|
||
|
}
|
||
|
else if (specifier == 'X')
|
||
|
{
|
||
|
libc_printf_putchar (stream, 'X');
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
assert (specifier == 'o');
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
uint32_t radix;
|
||
|
const char *alphabet;
|
||
|
|
||
|
switch (specifier)
|
||
|
{
|
||
|
case 'u':
|
||
|
{
|
||
|
alphabet = "0123456789";
|
||
|
radix = 10;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'o':
|
||
|
{
|
||
|
alphabet = "01234567";
|
||
|
radix = 8;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'x':
|
||
|
{
|
||
|
alphabet = "0123456789abcdef";
|
||
|
radix = 16;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'X':
|
||
|
{
|
||
|
alphabet = "0123456789ABCDEF";
|
||
|
radix = 16;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
{
|
||
|
assert (!"unexpected type field");
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
char str_buffer[ 32 ];
|
||
|
const char *string_p = libc_printf_uint_to_string (value,
|
||
|
str_buffer,
|
||
|
sizeof (str_buffer),
|
||
|
alphabet,
|
||
|
radix);
|
||
|
|
||
|
if (flags & LIBC_PRINTF_ARG_FLAG_PRINT_SIGN)
|
||
|
{
|
||
|
/* printing sign */
|
||
|
|
||
|
libc_printf_putchar (stream, '+');
|
||
|
if (width > 0)
|
||
|
{
|
||
|
width--;
|
||
|
}
|
||
|
}
|
||
|
else if (flags & LIBC_PRINTF_ARG_FLAG_SPACE)
|
||
|
{
|
||
|
/* no sign and space flag, printing one space */
|
||
|
|
||
|
libc_printf_putchar (stream, ' ');
|
||
|
if (width > 0)
|
||
|
{
|
||
|
width--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
libc_printf_justified_string_output (stream,
|
||
|
string_p,
|
||
|
width,
|
||
|
flags & LIBC_PRINTF_ARG_FLAG_LEFT_JUSTIFY,
|
||
|
flags & LIBC_PRINTF_ARG_FLAG_ZERO_PADDING);
|
||
|
} /* libc_printf_write_u_o_x_X */
|
||
|
|
||
|
/**
|
||
|
* vfprintf
|
||
|
*
|
||
|
* @return number of characters printed
|
||
|
*/
|
||
|
int
|
||
|
vfprintf (FILE *stream, /**< stream pointer */
|
||
|
const char *format, /**< format string */
|
||
|
va_list args) /**< arguments */
|
||
|
{
|
||
|
va_list args_copy;
|
||
|
|
||
|
va_copy (args_copy, args);
|
||
|
|
||
|
const char *format_iter_p = format;
|
||
|
|
||
|
while (*format_iter_p)
|
||
|
{
|
||
|
if (*format_iter_p != '%')
|
||
|
{
|
||
|
libc_printf_putchar (stream, *format_iter_p);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
libc_printf_arg_flags_mask_t flags = 0;
|
||
|
uint32_t width = 0;
|
||
|
libc_printf_arg_length_type_t length = LIBC_PRINTF_ARG_LENGTH_TYPE_NONE;
|
||
|
|
||
|
while (true)
|
||
|
{
|
||
|
format_iter_p++;
|
||
|
|
||
|
if (*format_iter_p == '-')
|
||
|
{
|
||
|
flags |= LIBC_PRINTF_ARG_FLAG_LEFT_JUSTIFY;
|
||
|
}
|
||
|
else if (*format_iter_p == '+')
|
||
|
{
|
||
|
flags |= LIBC_PRINTF_ARG_FLAG_PRINT_SIGN;
|
||
|
}
|
||
|
else if (*format_iter_p == ' ')
|
||
|
{
|
||
|
flags |= LIBC_PRINTF_ARG_FLAG_SPACE;
|
||
|
}
|
||
|
else if (*format_iter_p == '#')
|
||
|
{
|
||
|
flags |= LIBC_PRINTF_ARG_FLAG_SHARP;
|
||
|
}
|
||
|
else if (*format_iter_p == '0')
|
||
|
{
|
||
|
flags |= LIBC_PRINTF_ARG_FLAG_ZERO_PADDING;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (*format_iter_p == '*')
|
||
|
{
|
||
|
assert (!"unsupported width field *");
|
||
|
}
|
||
|
|
||
|
// If there is a number, recognize it as field width
|
||
|
while (*format_iter_p >= '0' && *format_iter_p <= '9')
|
||
|
{
|
||
|
width = width * 10u + (uint32_t) (*format_iter_p - '0');
|
||
|
|
||
|
format_iter_p++;
|
||
|
}
|
||
|
|
||
|
if (*format_iter_p == '.')
|
||
|
{
|
||
|
assert (!"unsupported precision field");
|
||
|
}
|
||
|
|
||
|
switch (*format_iter_p)
|
||
|
{
|
||
|
case 'h':
|
||
|
{
|
||
|
format_iter_p++;
|
||
|
if (*format_iter_p == 'h')
|
||
|
{
|
||
|
format_iter_p++;
|
||
|
|
||
|
length = LIBC_PRINTF_ARG_LENGTH_TYPE_HH;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
length = LIBC_PRINTF_ARG_LENGTH_TYPE_H;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'l':
|
||
|
{
|
||
|
format_iter_p++;
|
||
|
if (*format_iter_p == 'l')
|
||
|
{
|
||
|
format_iter_p++;
|
||
|
|
||
|
length = LIBC_PRINTF_ARG_LENGTH_TYPE_LL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
length = LIBC_PRINTF_ARG_LENGTH_TYPE_L;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'j':
|
||
|
{
|
||
|
format_iter_p++;
|
||
|
length = LIBC_PRINTF_ARG_LENGTH_TYPE_J;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'z':
|
||
|
{
|
||
|
format_iter_p++;
|
||
|
length = LIBC_PRINTF_ARG_LENGTH_TYPE_Z;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 't':
|
||
|
{
|
||
|
format_iter_p++;
|
||
|
length = LIBC_PRINTF_ARG_LENGTH_TYPE_T;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'L':
|
||
|
{
|
||
|
format_iter_p++;
|
||
|
length = LIBC_PRINTF_ARG_LENGTH_TYPE_HIGHL;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch (*format_iter_p)
|
||
|
{
|
||
|
case 'd':
|
||
|
case 'i':
|
||
|
{
|
||
|
libc_printf_write_d_i (stream, &args_copy, flags, length, width);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'u':
|
||
|
case 'o':
|
||
|
case 'x':
|
||
|
case 'X':
|
||
|
{
|
||
|
libc_printf_write_u_o_x_X (stream, *format_iter_p, &args_copy, flags, length, width);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'f':
|
||
|
case 'F':
|
||
|
case 'e':
|
||
|
case 'E':
|
||
|
case 'g':
|
||
|
case 'G':
|
||
|
case 'a':
|
||
|
case 'A':
|
||
|
{
|
||
|
assert (!"unsupported double type field");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'c':
|
||
|
{
|
||
|
if (length & LIBC_PRINTF_ARG_LENGTH_TYPE_L)
|
||
|
{
|
||
|
assert (!"unsupported length field L");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
char str[2] =
|
||
|
{
|
||
|
(char) va_arg (args_copy, int), /* char is promoted to int */
|
||
|
'\0'
|
||
|
};
|
||
|
|
||
|
libc_printf_justified_string_output (stream,
|
||
|
str,
|
||
|
width,
|
||
|
flags & LIBC_PRINTF_ARG_FLAG_LEFT_JUSTIFY,
|
||
|
flags & LIBC_PRINTF_ARG_FLAG_ZERO_PADDING);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 's':
|
||
|
{
|
||
|
if (length & LIBC_PRINTF_ARG_LENGTH_TYPE_L)
|
||
|
{
|
||
|
assert (!"unsupported length field L");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
char *str_p = va_arg (args_copy, char *);
|
||
|
|
||
|
libc_printf_justified_string_output (stream,
|
||
|
str_p,
|
||
|
width,
|
||
|
flags & LIBC_PRINTF_ARG_FLAG_LEFT_JUSTIFY,
|
||
|
flags & LIBC_PRINTF_ARG_FLAG_ZERO_PADDING);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'p':
|
||
|
{
|
||
|
va_list args_copy2;
|
||
|
va_copy (args_copy2, args_copy);
|
||
|
void *value = va_arg (args_copy2, void *);
|
||
|
va_end (args_copy2);
|
||
|
|
||
|
if (value == NULL)
|
||
|
{
|
||
|
printf ("(nil)");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
libc_printf_write_u_o_x_X (stream,
|
||
|
'x',
|
||
|
&args_copy,
|
||
|
flags | LIBC_PRINTF_ARG_FLAG_SHARP,
|
||
|
LIBC_PRINTF_ARG_LENGTH_TYPE_Z,
|
||
|
width);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'n':
|
||
|
{
|
||
|
assert (!"unsupported type field n");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
format_iter_p++;
|
||
|
}
|
||
|
|
||
|
va_end (args_copy);
|
||
|
|
||
|
return 0;
|
||
|
} /* vfprintf */
|
||
|
|
||
|
/**
|
||
|
* fprintf
|
||
|
*
|
||
|
* @return number of characters printed
|
||
|
*/
|
||
|
int
|
||
|
fprintf (FILE *stream, /**< stream pointer */
|
||
|
const char *format, /**< format string */
|
||
|
...) /**< parameters' values */
|
||
|
{
|
||
|
va_list args;
|
||
|
|
||
|
va_start (args, format);
|
||
|
|
||
|
int ret = vfprintf (stream, format, args);
|
||
|
|
||
|
va_end (args);
|
||
|
|
||
|
return ret;
|
||
|
} /* fprintf */
|
||
|
|
||
|
/**
|
||
|
* printf
|
||
|
*
|
||
|
* @return number of characters printed
|
||
|
*/
|
||
|
int
|
||
|
printf (const char *format, /**< format string */
|
||
|
...) /**< parameters' values */
|
||
|
{
|
||
|
va_list args;
|
||
|
|
||
|
va_start (args, format);
|
||
|
|
||
|
int ret = vfprintf (stdout, format, args);
|
||
|
|
||
|
va_end (args);
|
||
|
|
||
|
return ret;
|
||
|
} /* printf */
|
||
|
|