std: remove the printf implementation

This commit is contained in:
Lephe 2021-06-07 18:53:05 +02:00
parent faf5dc711a
commit 991b616a10
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
17 changed files with 17 additions and 1516 deletions

View File

@ -51,8 +51,6 @@ set(SOURCES_COMMON
src/kmalloc/arena_gint.c
src/kmalloc/arena_osheap.c
src/kmalloc/kmalloc.c
src/kprint/kprint.c
src/kprint/kformat_fp.c
src/mmu/mmu.c
src/render/dhline.c
src/render/dimage.c
@ -67,7 +65,6 @@ set(SOURCES_COMMON
src/spu/spu.c
src/std/aprint.c
src/std/malloc.c
src/std/print.c
src/tmu/inth-etmu.s
src/tmu/inth-tmu.s
src/tmu/sleep.c
@ -80,7 +77,6 @@ set(SOURCES_COMMON
src/usb/usb.c
src/3rdparty/tinymt32/rand.c
src/3rdparty/tinymt32/tinymt32.c
src/3rdparty/grisu2b_59_56/grisu2b_59_56.c
)
set(SOURCES_FX
src/gray/engine.c
@ -132,10 +128,6 @@ include_directories(
"${FXSDK_COMPILER_INSTALL}/include/openlibm")
add_compile_options(-Wall -Wextra -std=c11 -Os -fstrict-volatile-bitfields -mtas)
# Silence extended warnings on Grisu2b code
set_source_files_properties(src/3rdparty/grisu2b_59_56/grisu2b_59_56.c PROPERTIES
COMPILE_OPTIONS "-Wno-all;-Wno-extra")
if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G)
add_compile_definitions(FX9860G)
add_library(gint-fx STATIC ${SOURCES_COMMON} ${SOURCES_FX} ${ASSETS_FX})

View File

@ -18,10 +18,6 @@ Currently, this includes:
* A stripped-down version of the [TinyMT random number generator](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/TINYMT/index.html)
([GitHub repository](https://github.com/MersenneTwister-Lab/TinyMT)) by
Mutsuo Saito and Makoto Matsumoto. See `src/3rdparty/tinymt32/LICENSE.txt`.
* A stripped-down version of the [Grisu2b floating-point representation
algorithm](https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf)
with α=-59 and γ=-56, by Florian Loitsch. See `src/3rdparty/grisu2b_59_56/README`
for details, and [the original code here](https://drive.google.com/open?id=0BwvYOx00EwKmejFIMjRORTFLcTA).
## Programming interface

View File

@ -1,155 +0,0 @@
//---
// gint:kprint - gint's printf(3)-like formatted printer
//---
#ifndef GINT_KPRINT
#define GINT_KPRINT
#include <gint/defs/types.h>
#include <gint/defs/attributes.h>
#include <stdarg.h>
//---
// Formatted printing
//---
/* kvsprint(): Formatted print to string
This function is similar to vsnprintf(3), except that variadic arguments are
passed as a pointer to va_list. For standard functions like vsnprintf(3),
see <stdio.h>. */
size_t kvsprint(char *output, size_t len, char const *format, va_list *args);
/* kprint_enable_fp(): Enable and load floating-point formats
Loads floating-point formats %e, %E, %f, %F, %g and %G. By default these
formats are not enabled because the formatting code takes a large amount of
space. Calling this function pulls the floating-point formatter from the
gint library at link time. */
void kprint_enable_fp(void);
//---
// Printer extensions
//---
/* Arguments passed to formatters */
#define KFORMAT_ARGS \
GUNUSED int spec, /* Specifier letter */ \
GUNUSED kprint_options_t *opt, /* Other options in format */ \
va_list *args /* Vararg list to read from */
/* kprint_options_t: Standard format options */
typedef struct {
/* Minimal length of formatted string (padding can be added) */
uint16_t length;
/* How much significant characters of data, meaning varies */
int16_t precision;
/* Size specifier for integers (%o, %x, %i, %d, %u), may be one of:
(0) char (8-bit)
(1) short (16-bit)
(2) int (32-bit)
(3) long (32-bit)
(4) long long (64-bit) */
uint8_t size;
/* (#) Alternative form: base prefixes, decimal point */
uint alternative :1;
/* ( ) Add a blank sign before nonnegative numbers */
uint blank_sign :1;
/* (+) Always add a sign before a number (overrides ' ') */
uint force_sign :1;
/* Alignment options: each option overrides all others before itself
NUL By default, align right
(0) Left-pad numerical values with zeros
(-) Align left by adding space on the right, dropping zeros */
uint8_t alignment;
} GPACKED(2) kprint_options_t;
/* kprint_formatter_t: Type of format function */
typedef void (*kprint_formatter_t)(KFORMAT_ARGS);
/* kprint_register(): Register a formatter
The formatter designated by the specified lowercase letter (eg 'q') is
registered. It will handle formats for both the lowercase and uppercase
formats (eg "%q" and "%Q").
Default formatters can be overridden (although not advised), but formatters
for "h" and "l" and "z" cannot be set because these letters are used as size
specifiers (eg in "%hd" or "%zu").
A formatter can be removed or disabled by registering NULL.
@spec Specifier to use, should be a lowercase letter
@kformat Format function */
void kprint_register(int spec, kprint_formatter_t kformat);
/* kprint_out(): Output a single character to the kprint buffer */
void kprint_out(int byte);
/* kprint_outn(): Output the same character <n> times */
void kprint_outn(int byte, int n);
/* kprint_outstr(): Output a string to the kprint buffer */
void kprint_outstr(char const *str, int n);
//---
// Helper functions for formatters
//---
/* kprint_geometry_t: General geometry for a format
This helper defines the structure of a format as follows:
sign v |< zeros >| |< content >|
_ _ _ _ _ _ _ _ _ + 0 x 0 0 0 0 0 0 8 a c 7 . 3 c _ _ _ _ _ _ _ _ _ _
|< left_spaces >| ^^^ prefix |< right_spaces >|
The sign character is absent if sign=0, the prefix is specified by length
and is also absent if prefix=0. */
typedef struct
{
uint16_t left_spaces; /* Spaces before content */
uint8_t sign; /* Sign character (NUL, ' ', '+' or '-') */
uint8_t prefix; /* Base prefix ('0', '0x', etc) length */
uint16_t zeros; /* For integer displays, number of zeros */
uint16_t content; /* Content length in bytes */
uint16_t right_spaces; /* Spaces after content */
/* Style of display:
KPRINT_GENERIC Sign ignored, 0-padding ignored
KPRINT_INTEGER .precision causes 0-padding
KPRINT_NUMERIC No effect */
enum { KPRINT_GENERIC = 0, KPRINT_INTEGER, KPRINT_NUMERIC } style;
} GPACKED(2) kprint_geometry_t;
/* kformat_geometry(): Calculate the geometry of a format
The caller provides as input:
* opt, as passed by the main kprint() routine
* g->prefix, the length of the desired prefix (if unused, 0)
* g->content, the natural content length for the provided data
* g->sign, the sign of the input ("+" or "-"); for KPRINT_GENERIC, 0
* g->style, which affects the meaning of options
This function outputs:
* g->sign, which will be changed to " " or NUL (0) depending on options
* All fields of g that are not part of the input
The algorithm for laying out the format is as follows.
1. For numerical and integer formats, turn a "+" sign into " " if
opt->blank_sign is set, "+" if opt->force_sign is set, NUL otherwise.
2. Compute the total amount of padding needed to reach opt->length.
3. In integer style, if a precision is specified and more than content
length plus sign and prefix, turn some padding into zeros.
4. If numerical and integer styles, if opt->alignment == '0' turn all the
padding into zeros.
5. Turn remaining padding into spaces at the left (if opt->alignment == NUL)
or right (if opt->alignment == '-').
@opt Options provided by the main kprint() routine
@g Format geometry (input/output) */
void kformat_geometry(kprint_options_t *opt, kprint_geometry_t *g);
#endif /* GINT_KPRINT */

View File

@ -1,49 +1,2 @@
//---
// gint:std:stdio - a few <stdio.h> functions provided by gint
//---
#ifndef GINT_STD_STDIO
#define GINT_STD_STDIO
#include <stddef.h>
#include <stdarg.h>
/* Formatted printing functions
These functions implement most of printf(3)'s features, including:
* Signed and unsigned integer formats (%d, %i, %o, %u, %x, %X)
* Character, string and pointer formats (%c, %s, %p)
* Format options (0, #, -, (space), length, precision)
* Parameter length (hh, h, l, ll, z)
* Limiting the size of the output and still returning the whole length
* If kprint_enable_fp() from <gint/kprint.h> is called: floating-point
formats (%e, %E, %f, %F, %g, %G) (disabled by default to save space)
They do not support:
* Hexadecimal floating-point (%a, %A)
* The strerror() shorthand, since there is no errno (%m)
* Some size modifiers: long double (L), intmax_t (j), ptrdiff_t (t), and the
nonstandard synonyms q (ll) and Z (z)
* Dynamic length field (*)
* Thousands separators (') and locale-aware digits (I)
* Nonstandard synonyms %C (%lc) and %S (%ls)
A new fixed-point format %j has been added; it behaves like %d but includes
a decimal point. The number of decimal places is specified by the precision
field. For instance %.3j with 12345 prints "123.45". This can be used for
decimal fixed-point values. */
/* Print to string from var args */
int sprintf(char *str, char const *format, ...);
/* Print to string from va_list */
int vsprintf(char *str, char const *format, va_list args);
/* Print to string with limited size from var args */
int snprintf(char *str, size_t n, char const *format, ...);
/* Print to string with limited size from va_list */
int vsnprintf(char *str, size_t n, char const *format, va_list args);
/* Print to auto-allocated string */
int asprintf(char **strp, char const *format, ...);
/* Print to auto-allocated string from va_list */
int vasprintf(char **strp, char const *format, va_list args);
#endif /* GINT_STD_STDIO */
/* Now provided by fxlibc. */
#include <stdio.h>

View File

@ -1,22 +0,0 @@
Copyright (c) 2009 Florian Loitsch
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,14 +0,0 @@
Grisu is an algorithm by Florian Loitsch to print the decimal representation of
floating-point numbers.
The original code from which this folder is extracted can be found at
<https://drive.google.com/open?id=0BwvYOx00EwKmejFIMjRORTFLcTA>.
Only a minimal variation, the Grisu2 rounding algorithm with α=-59 and γ=-56,
is present here. The code has been adapted to fit the limited runtime as well
as the use of OpenLibm.
See the original paper at <https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf>
and Florian Loitsch's home page at <https://florian.loitsch.com/publications>.
The files are licensed under the permissive conditions of the attached LICENSE.

View File

@ -1,58 +0,0 @@
/*
Copyright (c) 2009 Florian Loitsch
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <stdint.h>
typedef struct diy_fp_t {
uint64_t f;
int e;
} diy_fp_t;
static diy_fp_t minus(diy_fp_t x, diy_fp_t y) {
diy_fp_t r = {.f = x.f - y.f, .e = x.e};
return r;
}
/*
static diy_fp_t minus(diy_fp_t x, diy_fp_t y) {
assert(x.e == y.e);
assert(x.f >= y.f);
diy_fp_t r = {.f = x.f - y.f, .e = x.e};
return r;
}
*/
static diy_fp_t multiply(diy_fp_t x, diy_fp_t y) {
uint64_t a,b,c,d,ac,bc,ad,bd,tmp,h;
diy_fp_t r; uint64_t M32 = 0xFFFFFFFF;
a = x.f >> 32; b = x.f & M32;
c = y.f >> 32; d = y.f & M32;
ac = a*c; bc = b*c; ad = a*d; bd = b*d;
tmp = (bd>>32) + (ad&M32) + (bc&M32);
tmp += 1U << 31; /// mult_round
r.f = ac+(ad>>32)+(bc>>32)+(tmp >>32);
r.e = x.e + y.e + 64;
return r;
}

View File

@ -1,110 +0,0 @@
/*
Copyright (c) 2009 Florian Loitsch
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include "diy_fp.h"
#include "powers.h"
#include <stdbool.h>
typedef union {
double d;
uint64_t n;
} converter_t;
static uint64_t double_to_uint64(double d) { converter_t tmp; tmp.d = d; return tmp.n; }
static double uint64_to_double(uint64_t d64) { converter_t tmp; tmp.n = d64; return tmp.d; }
#define DP_SIGNIFICAND_SIZE 52
#define DP_EXPONENT_BIAS (0x3FF + DP_SIGNIFICAND_SIZE)
#define DP_MIN_EXPONENT (-DP_EXPONENT_BIAS)
#define DP_EXPONENT_MASK 0x7FF0000000000000
#define DP_SIGNIFICAND_MASK 0x000FFFFFFFFFFFFF
#define DP_HIDDEN_BIT 0x0010000000000000
static diy_fp_t normalize_diy_fp(diy_fp_t in) {
diy_fp_t res = in;
/* Normalize now */
/* the original number could have been a denormal. */
while (! (res.f & DP_HIDDEN_BIT))
{
res.f <<= 1;
res.e--;
}
/* do the final shifts in one go. Don't forget the hidden bit (the '-1') */
res.f <<= (DIY_SIGNIFICAND_SIZE - DP_SIGNIFICAND_SIZE - 1);
res.e = res.e - (DIY_SIGNIFICAND_SIZE - DP_SIGNIFICAND_SIZE - 1);
return res;
}
static diy_fp_t double2diy_fp(double d) {
uint64_t d64 = double_to_uint64(d);
int biased_e = (d64 & DP_EXPONENT_MASK) >> DP_SIGNIFICAND_SIZE;
uint64_t significand = (d64 & DP_SIGNIFICAND_MASK);
diy_fp_t res;
if (biased_e != 0)
{
res.f = significand + DP_HIDDEN_BIT;
res.e = biased_e - DP_EXPONENT_BIAS;
} else {
res.f = significand;
res.e = DP_MIN_EXPONENT + 1;
}
return res;
}
static diy_fp_t normalize_boundary(diy_fp_t in) {
diy_fp_t res = in;
/* Normalize now */
/* the original number could have been a denormal. */
while (! (res.f & (DP_HIDDEN_BIT << 1)))
{
res.f <<= 1;
res.e--;
}
/* do the final shifts in one go. Don't forget the hidden bit (the '-1') */
res.f <<= (DIY_SIGNIFICAND_SIZE - DP_SIGNIFICAND_SIZE - 2);
res.e = res.e - (DIY_SIGNIFICAND_SIZE - DP_SIGNIFICAND_SIZE - 2);
return res;
}
static void normalized_boundaries(double d, diy_fp_t* out_m_minus, diy_fp_t* out_m_plus) {
diy_fp_t v = double2diy_fp(d);
diy_fp_t pl, mi;
bool significand_is_zero = v.f == DP_HIDDEN_BIT;
pl.f = (v.f << 1) + 1; pl.e = v.e - 1;
pl = normalize_boundary(pl);
if (significand_is_zero)
{
mi.f = (v.f << 2) - 1;
mi.e = v.e - 2;
} else {
mi.f = (v.f << 1) - 1;
mi.e = v.e - 1;
}
mi.f <<= mi.e - pl.e;
mi.e = pl.e;
*out_m_plus = pl;
*out_m_minus = mi;
}

View File

@ -1,27 +0,0 @@
/*
Copyright (c) 2009 Florian Loitsch
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
void grisu2(double v, char* buffer, int* length, int* K);

View File

@ -1,95 +0,0 @@
/*
Copyright (c) 2009 Florian Loitsch
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#include "diy_fp.h"
#include "k_comp.h"
#include "double.h"
#include "powers.h"
#include <stdbool.h>
#include "grisu2.h"
#include <stdint.h>
#define TEN9 1000000000
void grisu_round(char* buffer, int len,
uint64_t delta, uint64_t rest,
uint64_t ten_kappa, uint64_t wp_w) {
while (rest < wp_w &&
delta - rest >= ten_kappa &&
(rest + ten_kappa < wp_w || /// closer
wp_w - rest > rest+ten_kappa - wp_w))
{
buffer[len-1]--; rest += ten_kappa;
}
}
void digit_gen(diy_fp_t W, diy_fp_t Mp, diy_fp_t delta,
char* buffer, int* len, int* K) {
uint32_t div; int d,kappa; diy_fp_t one, wp_w;
wp_w = minus(Mp, W);
one.f = ((uint64_t) 1) << -Mp.e; one.e = Mp.e;
uint32_t p1 = Mp.f >> -one.e; /// Mp_cut
uint64_t p2 = Mp.f & (one.f - 1);
*len = 0; kappa = 10; div = TEN9;
while (kappa > 0) {
d = p1 / div;
if (d || *len) buffer[(*len)++] = '0' + d; /// Mp_inv1
p1 %= div; kappa--;
uint64_t tmp = (((uint64_t)p1)<<-one.e)+p2;
if (tmp <= delta.f) { /// Mp_delta
*K += kappa;
grisu_round(buffer, *len, delta.f, tmp, ((uint64_t)div) << -one.e, wp_w.f);
return;
}
div /= 10;
}
uint64_t unit = 1;
while (1) {
p2 *= 10; delta.f *= 10; unit *= 10;
d = p2 >> -one.e;
if (d || *len) buffer[(*len)++] = '0' + d;
p2 &= one.f - 1; kappa--;
if (p2 < delta.f) {
*K += kappa;
grisu_round(buffer, *len, delta.f, p2, one.f, wp_w.f*unit);
return;
}
}
}
void grisu2(double v, char* buffer, int* length, int* K) {
diy_fp_t w_m, w_p;
int q = 64, alpha = -59, gamma = -56; int pos;
normalized_boundaries(v, &w_m, &w_p);
diy_fp_t w = normalize_diy_fp(double2diy_fp(v));
int mk = k_comp(w_p.e + q, alpha, gamma);
diy_fp_t c_mk = cached_power(mk);
diy_fp_t W = multiply(w, c_mk);
diy_fp_t Wp = multiply(w_p, c_mk);
diy_fp_t Wm = multiply(w_m, c_mk);
Wm.f++; Wp.f--;
diy_fp_t delta = minus(Wp, Wm);
*K = -mk;
digit_gen(W, Wp, delta, buffer, length, K);
}

View File

@ -1,32 +0,0 @@
/*
Copyright (c) 2009 Florian Loitsch
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <openlibm.h>
#define D_1_LOG2_10 0.30102999566398114 // 1 / lg(10)
static int k_comp(int e, int alpha, int gamma) {
return ceil((alpha-e+63) * D_1_LOG2_10);
}

View File

@ -1,27 +0,0 @@
/*
Copyright (c) 2009 Florian Loitsch
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include "diy_fp.h"
#include "powers_ten_round64.h"

File diff suppressed because one or more lines are too long

View File

@ -1,282 +0,0 @@
//---
// gint:kprint:kformat-fp: Floating-point formatted printing
//
// This object file provides floating-point formatters. It can be linked in by
// calling kprint_enable_fp() and will automatically register floating-point
// formatters that use the Grisu2b algorithm.
//---
#include <gint/defs/types.h>
#include <gint/defs/util.h>
#include <gint/kprint.h>
#include "../3rdparty/grisu2b_59_56/grisu2.h"
//---
// String generation for doubles
//---
/* The grisu2() function does not have a size limit so we generate into a
buffer large enough to hold the result. */
static char digit_buffer[50];
/* Round a number at the specified place (which can be out of bounds). An extra
byte before the buffer should be secured to leave room for a new digit in
case a carry reaches there. Returns the new start-of-buffer.
@buffer Buffer with generated digits, updated if needed
@length Number of digits generated in the buffer, updated if needed
@e Location of decimal dot relative to integer in buffer
@place Decimal to place to round to */
static void round_str(char **buffer_ptr, int *length, int e, int place)
{
char *buffer = *buffer_ptr;
/* Interpret place as relative to buffer indices */
place += *length + e - 1;
/* Specified place is out-of-bounds */
if(place < 0 || place >= *length - 1) return;
/* Next digit is 0..4 so rounding has no effect */
if(buffer[place + 1] < '5') return;
/* Propagate carries if needed */
while(place >= -1)
{
buffer[place]++;
if(buffer[place] <= '9') break;
buffer[place] = '0';
place--;
}
/* Add one digit if needed */
if(place >= 0) return;
(*buffer_ptr)--;
(*length)++;
}
/* Remove zeros at the end of the digits, reducing [length] accordingly. */
static int remove_zeros(char *buffer, int length, int unremovable)
{
int removed = 0;
while(length > unremovable && buffer[length - 1] == '0')
{
buffer[length - 1] = 0;
length--;
removed++;
}
return removed;
}
/* Handles infinities and NaNs. */
static int special_notation(double v, int upper)
{
if(__builtin_isinf(v) && v < 0)
{
kprint_outstr(upper ? "-INF" : "-inf", 4);
return 1;
}
if(__builtin_isinf(v))
{
kprint_outstr(upper ? "INF" : "inf", 3);
return 1;
}
if(__builtin_isnan(v))
{
kprint_outstr(upper ? "NAN" : "nan", 3);
return 1;
}
return 0;
}
/* Prints decimal explicitly for %f and %g. */
static void direct_notation(kprint_options_t *opt, kprint_geometry_t g,
char *digits, int length, int e)
{
/* Number of characters for decimal part, including dot */
int dec_chars = opt->precision + (opt->precision > 0);
/* See case discussion below */
g.content = (length + e >= 0) ? length + e + dec_chars : 1 + dec_chars;
kformat_geometry(opt, &g);
kprint_outn(' ', g.left_spaces);
if(g.sign) kprint_out(g.sign);
kprint_outn('0', g.zeros);
int pre = opt->precision;
if(e >= 0) /* xxxxxx00[.00] */
{
/* Decimal dot is after digits; rounding never occurs */
kprint_outstr(digits, length);
kprint_outn('0', e);
if(pre > 0)
{
kprint_out('.');
kprint_outn('0', pre);
}
}
else if(length + e > 0) /* xxxy(.xx), xx.xy(xx), xx.xxxx[00] */
{
/* Decimal dot is within the digits; we might have rounded */
kprint_outstr(digits, length + e);
if(pre > 0)
{
kprint_out('.');
kprint_outstr(digits + length + e, min(-e, pre));
kprint_outn('0', pre + e);
}
}
else if(length + e <= 0) /* 0.00(00xxxx), 0.00xy(xx), 0.00xxxx00 */
{
/* Decimal dot is before the digits; we might have rounded */
kprint_out('0');
if(pre > 0)
{
kprint_out('.');
kprint_outn('0', min(-e - length, pre));
kprint_outstr(digits, min(length, pre + length + e));
kprint_outn('0', pre + e);
}
}
kprint_outn(' ', g.right_spaces);
}
/* Prints exponent notation for %e and %g. */
static void exponent_notation(kprint_options_t *opt, kprint_geometry_t g,
char *digits, int length, int e, int uppercase)
{
int true_e = e + length - 1;
/* Number of characters for decimal part and for exponent */
int dec_chars = opt->precision + (opt->precision > 0);
int exp_chars = 4 + (true_e >= 100 || true_e <= -100);
g.content = 1 + dec_chars + exp_chars;
kformat_geometry(opt, &g);
kprint_outn(' ', g.left_spaces);
if(g.sign) kprint_out(g.sign);
kprint_outn('0', g.zeros);
/* Digits */
kprint_out(digits[0]);
if(opt->precision > 0)
{
kprint_out('.');
kprint_outstr(digits + 1, min(length - 1, opt->precision));
kprint_outn('0', opt->precision - (length - 1));
}
/* Exponent */
kprint_out(uppercase ? 'E' : 'e');
kprint_out(true_e >= 0 ? '+' : '-');
if(true_e < 0) true_e = -true_e;
if(true_e >= 100)
{
kprint_out(true_e / 100 + '0');
true_e %= 100;
}
kprint_out(true_e / 10 + '0');
kprint_out(true_e % 10 + '0');
kprint_outn(' ', g.right_spaces);
}
//---
// Formatters for kprint
//---
static void kformat_fp(KFORMAT_ARGS)
{
double v = va_arg(*args, double);
digit_buffer[0] = '0';
char *digits = digit_buffer + 1;
int length = 0, e = 0;
int is_e = (spec | 0x20) == 'e';
int is_f = (spec | 0x20) == 'f';
int is_g = (spec | 0x20) == 'g';
/* In %e and %f, default to 6 decimals. In %g, default to 6 significant
digits, and force to at least 1 */
if(opt->precision < 0) opt->precision = 6;
if(opt->precision == 0 && is_g) opt->precision = 1;
if(special_notation(v, (spec & 0x20) == 0)) return;
/* fabs(v) = int(digits) * 10^e */
if(v == 0.0) digits[length++] = '0';
else grisu2(v, digits, &length, &e);
digits[length] = 0;
/* In %f and %e, .precision is the number of decimal places; in %g, it
is the number of significant digits. Determine the number of decimal
places for the rounding (which is one more than the final number if
a carry creates a new significant digit on the left) */
int round_place = opt->precision;
if(is_e) round_place -= (length + e - 1);
if(is_g) round_place -= (length + e);
/* Round off to the specified number of decimal places. digits and
length may extend one place left because of carries */
round_str(&digits, &length, e, round_place);
kprint_geometry_t g = {
.sign = (v < 0) ? '-' : '+',
.prefix = 0,
.style = KPRINT_NUMERIC,
};
if(is_f) return direct_notation(opt, g, digits, length, e);
if(is_e) return exponent_notation(opt, g, digits, length, e,spec=='E');
int true_e = length + e - 1;
int extreme = (true_e < -4) || (true_e >= opt->precision);
/* %g is left. Remove decimal zeros at the end of the digit string,
starting from the last-shown digit. Keep all figits before the
point, the amount of which depends on the mode */
int removed = remove_zeros(digits, min(length, opt->precision),
extreme ? 1 : true_e + 1);
opt->precision -= removed;
if(extreme)
{
/* Don't print more significant digits than we have digits
(elimination of trailing zeros) */
opt->precision = min(opt->precision, length);
/* There is one leading digit and this many decimal places */
opt->precision--;
return exponent_notation(opt, g, digits, length, e, spec=='G');
}
else
{
/* Number of digits before the point */
int leading_digits = true_e + 1;
/* Eliminate trailing zeros after the point */
opt->precision = min(opt->precision, length);
/* Remove leading digits from decimal place count */
opt->precision -= leading_digits;
return direct_notation(opt, g, digits, length, e);
}
}
/* kprint_enable_fp(): Enable and load floating-point formats */
void kprint_enable_fp(void)
{
kprint_register('e', kformat_fp);
kprint_register('f', kformat_fp);
kprint_register('g', kformat_fp);
}

View File

@ -1,539 +0,0 @@
//---
// gint:kprint - gint's printf(3)-like formatted printer
//
// Things to change when creating new formats:
// -> List of prototypes at the end of the definition section
// -> Formatted table just below the list of prototypes
// -> List of non-numerical specifiers in kformat_geometry()
//---
#include <gint/std/stdio.h>
#include <gint/std/string.h>
#include <gint/kprint.h>
#include <gint/defs/attributes.h>
#include <gint/defs/types.h>
#include <gint/defs/util.h>
#include <stdarg.h>
//---
// kprint() definitions
//---
#define KPRINT_BUFSIZE 64
/* Current position in the output buffer */
static char *kprint_ptr = NULL;
/* Limit of the output buffer */
static char *kprint_limit = NULL;
/* Total number of characters written for this call to kprint() */
static size_t kprint_count = 0;
/* Address of the current output buffer */
static char *kprint_buffer = NULL;
/* Internal buffer, used in many cases */
static char kprint_internal[KPRINT_BUFSIZE];
/* Output kind for this execution of kprint() */
static enum {
/* Output is user-provided string, then internal buffer for the rest */
KPrintOutputString = 0,
/* Output is a device, file descriptor, whatever */
// KprintOutputDevice = 1,
} kprint_type;
/* Default formatters */
static void kformat_char (KFORMAT_ARGS);
static void kformat_int (KFORMAT_ARGS);
static void kformat_uint (KFORMAT_ARGS);
static void kformat_ptr (KFORMAT_ARGS);
static void kformat_str (KFORMAT_ARGS);
static void kformat_fixed(KFORMAT_ARGS);
/* Formatter functions for a..z */
kprint_formatter_t kprint_formatters[26] = {
/* Standard formats plus the 'j' for fixed-point integers in base 10 */
NULL, NULL, kformat_char, kformat_int,
NULL, NULL, NULL, NULL,
kformat_int, kformat_fixed, NULL, NULL,
NULL, NULL, kformat_uint, kformat_ptr,
NULL, NULL, kformat_str, NULL,
kformat_uint, NULL, NULL, kformat_uint,
NULL, NULL,
};
/* kprint_register(): Register a formatter */
void kprint_register(int spec, kprint_formatter_t kformat)
{
/* Non-letters */
if(spec < 'a' || spec > 'z') return;
/* Size-specifying letters */
if(spec == 'h' || spec == 'l' || spec == 'L' || spec == 'z') return;
kprint_formatters[spec - 'a'] = kformat;
}
//---
// Output functions
//---
/* kprint_flush(): Flush the buffer when it's full */
static void kprint_flush(void)
{
/* Update the number of flushed characters */
kprint_count += kprint_ptr - kprint_buffer;
if(kprint_type != KPrintOutputString) return;
/* Make sure to write a NUL at the end of the string, even if
it means overriding one of the generated characters */
if(kprint_buffer != kprint_internal)
{
char *nul = min(kprint_ptr, kprint_limit - 1);
*nul = 0x00;
}
/* Switch to the internal buffer now that the output string has
been filled */
kprint_buffer = kprint_internal;
kprint_limit = kprint_internal + KPRINT_BUFSIZE;
kprint_ptr = kprint_buffer;
}
/* kprint_out(): Output a single character to the kprint buffer */
GINLINE void kprint_out(int byte)
{
if(kprint_ptr >= kprint_limit) kprint_flush();
*kprint_ptr++ = byte;
}
/* kprint_outn(): Output the same character <n> times */
GINLINE void kprint_outn(int byte, int n)
{
while(n-- > 0) kprint_out(byte);
}
/* kprint_outstr(): Output a string to the kprint buffer */
GINLINE void kprint_outstr(char const *str, int n)
{
for(int i = 0; i < n; i++) kprint_out(str[i]);
}
//---
// Parsing helpers
//---
/* kprint_opt(): Parse option strings */
kprint_options_t kprint_opt(char const **options_ptr)
{
/* No options enabled by default, set the size to int */
kprint_options_t opt = { .size = 2, .precision = -1 };
/* This function acts as a deterministic finite automaton */
enum {
basic, /* Reading option characters */
length, /* Reading length digits */
precision, /* Reading precision digits */
} state = basic;
char const *options = *options_ptr;
for(int c; (c = *options); options++)
{
int c_low = c | 0x20;
if(c_low >= 'a' && c_low <= 'z' && c != 'h' && c != 'l' &&
c != 'L') break;
if(c == '.')
{
state = precision;
opt.precision = 0;
continue;
}
else if(state == length && c >= '0' && c <= '9')
{
opt.length = opt.length * 10 + (c - '0');
continue;
}
else if(state == precision && c >= '0' && c <= '9')
{
opt.precision = opt.precision * 10 + (c - '0');
continue;
}
/* Remain in basic state mode */
state = basic;
if(c == '#') opt.alternative = 1;
if(c == ' ') opt.blank_sign = 1;
if(c == '+') opt.force_sign = 1;
/* Alignment options, including priority */
if((c == '-' || c == '0') && opt.alignment != '0')
{
opt.alignment = c;
}
/* Data size */
if(c == 'h') opt.size--;
if(c == 'l') opt.size++;
if(c == 'z') opt.size = 3;
if(c == 'L') {}
if(c >= '1' && c <= '9') state = length, options--;
}
*options_ptr = options;
return opt;
}
//---
// Base formatted printer
//---
/* kprint(): The kernel's formatted printer */
void kprint(char const *format, va_list *args)
{
int c, spec;
kprint_options_t opt;
while((c = *format++))
{
if(c != '%')
{
kprint_out(c);
continue;
}
if(!(c = *format)) break;
/* '%' character */
if(c == '%')
{
kprint_out('%');
format++;
continue;
}
opt = kprint_opt(&format);
spec = *format++;
int id = (spec | 0x20) - 'a';
if(id >= 0 && id < 26 && kprint_formatters[id])
kprint_formatters[id](spec, &opt, args);
}
kprint_flush();
}
/* kvsprint(): Formatted print to string */
size_t kvsprint(char *output, size_t length, char const *format, va_list *args)
{
kprint_buffer = output;
kprint_limit = output + length;
kprint_count = 0;
kprint_ptr = kprint_buffer;
kprint_type = KPrintOutputString;
kprint(format, args);
return kprint_count;
}
//---
// Formatter helpers
//---
/* kformat_geometry(): Calculate the geometry of a format */
void kformat_geometry(kprint_options_t *opt, kprint_geometry_t *g)
{
int integral = (g->style == KPRINT_INTEGER);
int numerical = (g->style == KPRINT_NUMERIC) || integral;
ssize_t padding;
/* Sign character (no discussion required for negative values) */
if(numerical && g->sign == '+')
{
g->sign = 0;
if(opt->blank_sign) g->sign = ' ';
if(opt->force_sign) g->sign = '+';
}
g->zeros = 0;
padding = opt->length - (g->sign != 0) - g->prefix
- max(g->content, opt->precision);
if(padding < 0) padding = 0;
/* In integral modes, precision forces zeros */
if(integral && opt->precision >= 0)
{
if(opt->alignment == '0') opt->alignment = 0;
ssize_t zeros = opt->precision - g->content;
if(zeros > 0) g->zeros = zeros;
}
if(opt->alignment == '0')
{
/* Zeros are only allowed in numerical modes */
if(numerical) g->zeros = padding;
else g->left_spaces = padding;
}
else if(opt->alignment == '-')
{
g->right_spaces = padding;
}
else
{
g->left_spaces = padding;
}
}
/* digits_10(): Generate digits in base 10
Fills up the provided digit string from least significant to most
significant digit, not adding zeros except if argument is zero. Returns the
number of digits. No NUL terminator is added. */
static int digits_10(char *str, uint64_t n)
{
int digits = 0;
while(n || !digits)
{
/* TODO: Use qdiv() in kprint's digits_10() */
str[digits++] = (n % 10) + '0';
n /= 10;
}
return digits;
}
/* digits_16(): Generate digits in base 16 */
static int digits_16(char *str, int uppercase, uint64_t n)
{
char *hex = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
int digits = 0;
while(n || !digits)
{
str[digits++] = hex[n & 0xf];
n >>= 4;
}
return digits;
}
/* digits_8(): Generate digits in base 8 */
static int digits_8(char *str, uint64_t n)
{
int digits = 0;
while(n || !digits)
{
str[digits++] = (n & 0x7) + '0';
n >>= 3;
}
return digits;
}
//---
// Loading helpers
//---
static int64_t load_i(int size, va_list *args)
{
/* All smaller types are promoted to int with sign extension, so we
don't need to care about them. */
if(size == 3) return va_arg(*args, long);
if(size == 4) return va_arg(*args, long long);
return va_arg(*args, int);
}
static uint64_t load_u(int size, va_list *args)
{
/* Again, no need to care about small types */
if(size == 3) return va_arg(*args, unsigned long);
if(size == 4) return va_arg(*args, unsigned long long);
return va_arg(*args, unsigned int);
}
//---
// Individual formatters
//---
/* kformat_char(): Character formatter (%c)
(-) Move spaces to the right
{len} Specifies numbers of (whitespace-padded) characters to print */
static void kformat_char(KFORMAT_ARGS)
{
int c = va_arg(*args, int);
kprint_geometry_t g = {
.prefix = 0, .sign = 0, .content = 1,
};
kformat_geometry(opt, &g);
kprint_outn(' ', g.left_spaces);
kprint_out(c);
kprint_outn(' ', g.right_spaces);
}
/* kformat_str(): String formatter (%s)
(-) Move spaces to the right
{len} Minimal numbers of characters to output
{pre} Maximal numbers of bytes to read from argument */
static void kformat_str(KFORMAT_ARGS)
{
char const *s = va_arg(*args, char const *);
/* Compute content length, which is the smallest of two sizes: the
length set as precision and the actual length of the string */
size_t len = 0;
uint32_t precision = opt->precision ? opt->precision : (-1);
while(s[len] && len < precision) len++;
kprint_geometry_t g = {
.prefix = 0, .sign = 0, .content = len,
};
kformat_geometry(opt, &g);
kprint_outn(' ', g.left_spaces);
for(size_t i = 0; i < len; i++) kprint_out(s[i]);
kprint_outn(' ', g.right_spaces);
}
/* kformat_int(): Integer formatter (%d, %i)
(0) Pad with zeros, rather than spaces, on the left
(-) Move spaces to the right (overrides '0', extends {pre})
( ) Force a blank sign before nonnegative numbers
(+) Force a sign before every number (overrides ' ')
{len} Minimal number of characters to print
{pre} Forces a minimal number of digits, creating 0s (overrides '0') */
static void kformat_int(KFORMAT_ARGS)
{
int64_t n = load_i(opt->size, args);
/* Compute the sign and the absolute value */
kprint_geometry_t g = {
.sign = (n < 0) ? '-' : '+',
.prefix = 0,
.style = KPRINT_INTEGER,
};
if(n < 0) n = -n;
/* Get the digit string */
char digits[32];
int pure, total;
pure = digits_10(digits, n);
if(opt->precision == 0 && !n) pure = 0;
total = max(pure, opt->precision);
g.content = total;
kformat_geometry(opt, &g);
/* Print the result */
kprint_outn(' ', g.left_spaces);
if(g.sign) kprint_out(g.sign);
kprint_outn('0', g.zeros);
kprint_outn('0', total - pure);
for(int i = pure - 1; i >= 0; i--) kprint_out(digits[i]);
kprint_outn(' ', g.right_spaces);
}
/* kformat_uint(): Unsigned integer formatter in various bases (%u, %o, %x)
(#) Enable base prefixes ("0" in octal, "0x" in hexadecimal)
(0) Pad with zeros, rather than spaces, on the left
(-) Move spaces to the right (overrides '0', extends {pre})
{len} Minimal number of characters to print
{pre} Forces a minimal number of digits, creating 0s (overrides '0') */
static void kformat_uint(KFORMAT_ARGS)
{
uint64_t n = load_u(opt->size, args);
char digits[48];
int pure = 0, total;
int specl = spec | 0x20;
if(specl == 'u') pure = digits_10(digits, n);
if(specl == 'o') pure = digits_8(digits, n);
if(specl == 'x') pure = digits_16(digits, spec == 'X', n);
if(opt->precision == 0 && !n) pure = 0;
total = max(pure, opt->precision);
/* Prefix length */
size_t prefix = 0;
if(opt->alternative) prefix = (specl != 'u') + (specl == 'x');
kprint_geometry_t g = {
.sign = 0, .prefix = prefix, .content = total,
.style = KPRINT_INTEGER,
};
kformat_geometry(opt, &g);
/* Output */
kprint_outn(' ', g.left_spaces);
if(opt->alternative)
{
if(specl != 'u') kprint_out('0');
if(specl == 'x') kprint_out(spec);
}
kprint_outn('0', g.zeros);
kprint_outn('0', total - pure);
for(int i = pure - 1; i >= 0; i--) kprint_out(digits[i]);
kprint_outn(' ', g.right_spaces);
}
/* kformat_ptr(): Pointer formatter */
static void kformat_ptr(KFORMAT_ARGS)
{
void *p = va_arg(*args, void *);
char digits[] = "00000000";
digits_16(digits, 0, (uint32_t)p);
kprint_out('0');
kprint_out('x');
for(int i = 7; i >= 0; i--) kprint_out(digits[i]);
}
/* kformat_fixed(): Fixed-point decimal formatter
(0) Pad with zeros, rather than spaces, on the left
(-) Move spaces to the right (overrides '0')
( ) Force a blank sign before nonnegative numbers
(+) Force a sign before every number (overrides ' ')
{len} Minimal number of characters to print
{pre} Number of digits after the decimal dot */
static void kformat_fixed(KFORMAT_ARGS)
{
int64_t n = load_i(opt->size, args);
/* Compute the sign and the absolute value */
kprint_geometry_t g = {
.sign = (n < 0) ? '-' : '+',
.prefix = 0,
.style = KPRINT_NUMERIC,
};
if(n < 0) n = -n;
/* Get the digit string */
char digits[32];
g.content = digits_10(digits, n) + 1;
kformat_geometry(opt, &g);
/* Print the result */
kprint_outn(' ', g.left_spaces);
if(g.sign) kprint_out(g.sign);
kprint_outn('0', g.zeros);
for(int i = g.content - 2; i >= 0; i--)
{
if(i == opt->precision - 1) kprint_out('.');
kprint_out(digits[i]);
}
kprint_outn(' ', g.right_spaces);
}

View File

@ -2,22 +2,9 @@
// gint:src:aprint - Allocating extensions to formatted printing
//---
#include <gint/std/stdio.h>
#include <stdio.h>
#include <gint/std/stdlib.h>
#include <gint/kprint.h>
#include <stdarg.h>
/* asprintf() */
GWEAK int asprintf(char **strp, char const *format, ...)
{
va_list args;
va_start(args, format);
int count = vasprintf(strp, format, args);
va_end(args);
return count;
}
#include <gint/defs/attributes.h>
/* vasprintf() */
GWEAK int vasprintf(char **strp, char const *format, va_list args1)
@ -36,3 +23,16 @@ GWEAK int vasprintf(char **strp, char const *format, va_list args1)
*strp = str;
return count;
}
/* asprintf() */
GWEAK int asprintf(char **strp, char const *format, ...)
{
va_list args;
va_start(args, format);
int count = vasprintf(strp, format, args);
va_end(args);
return count;
}

View File

@ -1,43 +0,0 @@
//---
// gint:src:print - Standard formatted printing functions
//---
#include <gint/std/stdio.h>
#include <gint/kprint.h>
#include <stdarg.h>
/* sprintf() */
GWEAK int sprintf(char *str, char const *format, ...)
{
va_list args;
va_start(args, format);
int count = kvsprint(str, 65536, format, &args);
va_end(args);
return count;
}
/* vsprintf() */
GWEAK int vsprintf(char *str, char const *format, va_list args)
{
return kvsprint(str, 65536, format, &args);
}
/* snprintf() */
GWEAK int snprintf(char *str, size_t n, char const *format, ...)
{
va_list args;
va_start(args, format);
int count = kvsprint(str, n, format, &args);
va_end(args);
return count;
}
/* vsprintf() */
GWEAK int vsnprintf(char *str, size_t n, char const *format, va_list args)
{
return kvsprint(str, n, format, &args);
}