/programs/develop/libraries/kolibri-libc/source/stdio/clearerr.c |
---|
0,0 → 1,6 |
#include <stdio.h> |
void clearerr(FILE *stream) { |
stream->error = 0; |
stream->eof = 0; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/conio.c |
---|
0,0 → 1,68 |
#include <sys/ksys.h> |
#include "conio.h" |
static char* __con_caption = "Console application"; |
static char* __con_dllname = "/sys/lib/console.obj"; |
int __con_is_load = 0; |
void stdcall (*__con_init_hidden)(int wnd_width, int wnd_height,int scr_width, int scr_height, const char* title); |
void stdcall (*__con_write_asciiz)(const char* str); |
void stdcall (*__con_write_string)(const char* str, unsigned length); |
int stdcall (*__con_getch)(void); |
short stdcall (*__con_getch2)(void); |
int stdcall (*__con_kbhit)(void); |
char* stdcall (*__con_gets)(char* str, int n); |
char* stdcall (*__con_gets2)(__con_gets2_callback callback, char* str, int n); |
void stdcall (*__con_exit)(int status); |
void stdcall (*__con_set_title)(const char* title); |
static void __con_panic(char* func_name) |
{ |
_ksys_debug_puts("libc.obj: "); |
_ksys_debug_puts(func_name); |
_ksys_debug_puts(" = NULL\n"); |
_ksys_exit(); |
} |
static void __con_lib_link(ksys_coff_etable_t *exp) |
{ |
__con_init_hidden = _ksys_get_coff_func(exp, "con_init", __con_panic); |
__con_write_asciiz = _ksys_get_coff_func(exp, "con_write_asciiz", __con_panic); |
__con_write_string = _ksys_get_coff_func(exp, "con_write_string", __con_panic); |
__con_getch = _ksys_get_coff_func(exp, "con_getch", __con_panic); |
__con_getch2 = _ksys_get_coff_func(exp, "con_getch2", __con_panic); |
__con_kbhit = _ksys_get_coff_func(exp, "con_kbhit", __con_panic); |
__con_gets = _ksys_get_coff_func(exp, "con_gets", __con_panic); |
__con_gets2 = _ksys_get_coff_func(exp, "con_gets2", __con_panic); |
__con_exit = _ksys_get_coff_func(exp, "con_exit", __con_panic); |
__con_set_title = _ksys_get_coff_func(exp, "con_set_title", __con_panic); |
} |
int __con_init(void) |
{ |
return __con_init_opt(-1, -1, -1, -1, __con_caption); |
} |
void con_set_title(const char* title){ |
__con_init(); |
__con_set_title(title); |
} |
int __con_init_opt(int wnd_width, int wnd_height,int scr_width, int scr_height, const char* title) |
{ |
if(!__con_is_load){ |
ksys_coff_etable_t *__con_lib; |
__con_lib = _ksys_load_coff(__con_dllname); |
if(__con_lib==NULL){ |
_ksys_debug_puts("Error! Can't load console.obj lib\n"); |
return 1; |
} |
__con_lib_link(__con_lib); |
__con_init_hidden(wnd_width, wnd_height, scr_width, scr_height, title); |
__con_is_load= 1; |
return 0; |
} |
return 1; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/conio.h |
---|
0,0 → 1,76 |
/* |
This is adapded thunk for console.obj sys library |
Only for internal use in stdio.h |
Adapted for tcc by Siemargl, 2016 |
*/ |
#ifndef _CONIO_H_ |
#define _CONIO_H_ |
#define cdecl __attribute__ ((cdecl)) |
#define stdcall __attribute__ ((stdcall)) |
void stdcall (*__con_write_asciiz)(const char* str); |
/* Display ASCIIZ-string to the console at the current position, shifting |
the current position. */ |
void stdcall (*__con_write_string)(const char* str, unsigned length); |
/* Similar to __con_write_asciiz, but length of the string must be given as a |
separate parameter */ |
int stdcall (*__con_getch)(void); |
/* Get one character from the keyboard. |
For normal characters function returns ASCII-code. For extended |
characters (eg, Fx, and arrows), first function call returns 0 |
and second call returns the extended code (similar to the DOS-function |
input). Starting from version 7, after closing the console window, |
this function returns 0. */ |
short stdcall (*__con_getch2)(void); |
/* Reads a character from the keyboard. Low byte contains the ASCII-code |
(0 for extended characters), high byte - advanced code (like in BIOS |
input functions). Starting from version 7, after closing the console |
window, this function returns 0. */ |
int stdcall (*__con_kbhit)(void); |
/* Returns 1 if a key was pressed, 0 otherwise. To read pressed keys use |
__con_getch and __con_getch2. Starting from version 6, after closing |
the console window, this function returns 1. */ |
char* stdcall (*__con_gets)(char* str, int n); |
/* Reads a string from the keyboard. Reading is interrupted when got |
"new line" character, or after reading the (n-1) characters (depending on |
what comes first). In the first case the newline is also recorded in the |
str. The acquired line is complemented by a null character. |
Starting from version 6, the function returns a pointer to the entered |
line if reading was successful, and NULL if the console window was closed. */ |
typedef int (stdcall * __con_gets2_callback)(int keycode, char** pstr, int* pn, |
int* ppos); |
char* stdcall (*__con_gets2)(__con_gets2_callback callback, char* str, int n); |
/* Con_gets completely analogous, except that when the user |
press unrecognized key, it calls the specified callback-procedure |
(which may, for example, handle up / down for history and tab to enter |
autocompletion). You should pass to the procedure: key code and three pointers |
- to the string, to the maximum length and to the current position. |
function may change the contents of string and may change the string |
itself (for example, to reallocate memory for increase the limit), |
maximum length, and position of the line - pointers are passed for it. |
Return value: 0 = line wasn't changed 1 = line changed, you should |
remove old string and display new, 2 = line changed, it is necessary |
to display it; 3 = immediately exit the function. |
Starting from version 6, the function returns a pointer to the entered |
line with the successful reading, and NULL if the console window was closed. */ |
int __con_is_load; |
unsigned *__con_dll_ver; |
int __con_init(void); |
int __con_init_opt(int wnd_width, int wnd_height, int scr_width, int scr_height, const char* title); |
void stdcall (*__con_exit)(int status); |
#endif |
/programs/develop/libraries/kolibri-libc/source/stdio/debug_printf.c |
---|
0,0 → 1,15 |
/* Copyright (C) 2021 Logaev Maxim (turbocat2001), GPLv2 */ |
#include <stdio.h> |
#include <stdarg.h> |
#include <limits.h> |
void debug_printf(const char *format,...) |
{ |
va_list ap; |
static char log_board[STDIO_MAX_MEM]; |
va_start (ap, format); |
vsnprintf(log_board, STDIO_MAX_MEM, format, ap); |
va_end(ap); |
_ksys_debug_puts(log_board); |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/fclose.c |
---|
0,0 → 1,7 |
#include <stdio.h> |
#include <stdlib.h> |
int fclose(FILE *stream) { |
free(stream); |
return 0; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/feof.c |
---|
0,0 → 1,5 |
#include <stdio.h> |
int feof(FILE *stream) { |
return stream->eof; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/ferror.c |
---|
0,0 → 1,5 |
#include <stdio.h> |
int ferror(FILE *stream) { |
return stream->error; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/fflush.c |
---|
0,0 → 1,5 |
#include <stdio.h> |
int fflush(FILE *stream) { |
return 0; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/fgetc.c |
---|
0,0 → 1,38 |
#include <stdio.h> |
#include <errno.h> |
#include <sys/ksys.h> |
int fgetc(FILE* stream) |
{ |
unsigned bytes_read; |
char c; |
unsigned status = _ksys_file_read_file(stream->name, stream->position, 1, &c, &bytes_read); |
if (status != KSYS_FS_ERR_SUCCESS) { |
switch (status) { |
case KSYS_FS_ERR_EOF: |
stream->eof = 1; |
break; |
case KSYS_FS_ERR_1: |
case KSYS_FS_ERR_2: |
case KSYS_FS_ERR_3: |
case KSYS_FS_ERR_4: |
case KSYS_FS_ERR_5: |
case KSYS_FS_ERR_7: |
case KSYS_FS_ERR_8: |
case KSYS_FS_ERR_9: |
case KSYS_FS_ERR_10: |
case KSYS_FS_ERR_11: |
default: |
// Just some IO error, who knows what exactly happened |
errno = EIO; |
stream->error = errno; |
break; |
} |
return EOF; |
} |
stream->position++; |
return c; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/fgetpos.c |
---|
0,0 → 1,6 |
#include <stdio.h> |
int fgetpos(FILE *restrict stream, fpos_t *restrict pos) { |
*pos = stream->position; |
return 0; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/fgets.c |
---|
0,0 → 1,24 |
#include <stdio.h> |
#include "conio.h" |
#include <errno.h> |
char *fgets(char *str, int n, FILE *stream) |
{ |
int i=0, sym_code; |
if(!stream || !str){ |
errno = EINVAL; |
return NULL; |
} |
while (i<n-1){ |
sym_code = fgetc(stream); |
if(sym_code =='\n' || sym_code == EOF){ break; } |
str[i]=(char)sym_code; |
i++; |
} |
if(i<1){ return NULL; } |
return str; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/fopen.c |
---|
0,0 → 1,7 |
#include <stdio.h> |
#include <stdlib.h> |
FILE *fopen(const char *restrict _name, const char *restrict _mode) { |
FILE *out = malloc(sizeof(FILE)); |
return freopen(_name, _mode, out); |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/format_print.c |
---|
0,0 → 1,817 |
/////////////////////////////////////////////////////////////////////////////// |
// \author (c) Marco Paland (info@paland.com) |
// 2014-2019, PALANDesign Hannover, Germany |
// |
// \license The MIT License (MIT) |
// |
// 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. |
// |
// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on |
// embedded systems with a very limited resources. These routines are thread |
// safe and reentrant! |
// Use this instead of the bloated standard/newlib printf cause these use |
// malloc for printf (and may not be thread safe). |
// |
/////////////////////////////////////////////////////////////////////////////// |
#include <stdbool.h> |
#include <stdint.h> |
#include <stdio.h> |
#include "format_print.h" |
#include <math.h> |
// 'ntoa' conversion buffer size, this must be big enough to hold one converted |
// numeric number including padded zeros (dynamically created on stack) |
// default: 32 byte |
#ifndef PRINTF_NTOA_BUFFER_SIZE |
#define PRINTF_NTOA_BUFFER_SIZE 32U |
#endif |
// 'ftoa' conversion buffer size, this must be big enough to hold one converted |
// float number including padded zeros (dynamically created on stack) |
// default: 32 byte |
#ifndef PRINTF_FTOA_BUFFER_SIZE |
#define PRINTF_FTOA_BUFFER_SIZE 32U |
#endif |
// support for the floating point type (%f) |
// default: activated |
#ifndef PRINTF_DISABLE_SUPPORT_FLOAT |
#define PRINTF_SUPPORT_FLOAT |
#endif |
// support for exponential floating point notation (%e/%g) |
// default: activated |
#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL |
#define PRINTF_SUPPORT_EXPONENTIAL |
#endif |
// define the default floating point precision |
// default: 6 digits |
#ifndef PRINTF_DEFAULT_FLOAT_PRECISION |
#define PRINTF_DEFAULT_FLOAT_PRECISION 6U |
#endif |
// define the largest float suitable to print with %f |
// default: 1e9 |
#ifndef PRINTF_MAX_FLOAT |
#define PRINTF_MAX_FLOAT 1e9 |
#endif |
// support for the long long types (%llu or %p) |
// default: activated |
#ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG |
#define PRINTF_SUPPORT_LONG_LONG |
#endif |
// support for the ptrdiff_t type (%t) |
// ptrdiff_t is normally defined in <stddef.h> as long or long long type |
// default: activated |
#ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T |
#define PRINTF_SUPPORT_PTRDIFF_T |
#endif |
/////////////////////////////////////////////////////////////////////////////// |
// internal flag definitions |
#define FLAGS_ZEROPAD (1U << 0U) |
#define FLAGS_LEFT (1U << 1U) |
#define FLAGS_PLUS (1U << 2U) |
#define FLAGS_SPACE (1U << 3U) |
#define FLAGS_HASH (1U << 4U) |
#define FLAGS_UPPERCASE (1U << 5U) |
#define FLAGS_CHAR (1U << 6U) |
#define FLAGS_SHORT (1U << 7U) |
#define FLAGS_LONG (1U << 8U) |
#define FLAGS_LONG_LONG (1U << 9U) |
#define FLAGS_PRECISION (1U << 10U) |
#define FLAGS_ADAPT_EXP (1U << 11U) |
// import float.h for DBL_MAX |
#if defined(PRINTF_SUPPORT_FLOAT) |
#include <float.h> |
#endif |
// internal buffer output |
void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen) |
{ |
if (idx < maxlen) { |
((char*)buffer)[idx] = character; |
} |
} |
// internal null output |
void _out_null(char character, void* buffer, size_t idx, size_t maxlen) |
{ |
(void)character; (void)buffer; (void)idx; (void)maxlen; |
} |
// internal secure strlen |
// \return The length of the string (excluding the terminating 0) limited by 'maxsize' |
static inline unsigned int _strnlen_s(const char* str, size_t maxsize) |
{ |
const char* s; |
for (s = str; *s && maxsize--; ++s); |
return (unsigned int)(s - str); |
} |
// internal test if char is a digit (0-9) |
// \return true if char is a digit |
static inline bool _is_digit(char ch) |
{ |
return (ch >= '0') && (ch <= '9'); |
} |
// internal ASCII string to unsigned int conversion |
static unsigned int _atoi(const char** str) |
{ |
unsigned int i = 0U; |
while (_is_digit(**str)) { |
i = i * 10U + (unsigned int)(*((*str)++) - '0'); |
} |
return i; |
} |
// output the specified string in reverse, taking care of any zero-padding |
static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags) |
{ |
const size_t start_idx = idx; |
// pad spaces up to given width |
if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { |
for (size_t i = len; i < width; i++) { |
out(' ', buffer, idx++, maxlen); |
} |
} |
// reverse string |
while (len) { |
out(buf[--len], buffer, idx++, maxlen); |
} |
// append pad spaces up to given width |
if (flags & FLAGS_LEFT) { |
while (idx - start_idx < width) { |
out(' ', buffer, idx++, maxlen); |
} |
} |
return idx; |
} |
// internal itoa format |
static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags) |
{ |
// pad leading zeros |
if (!(flags & FLAGS_LEFT)) { |
if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { |
width--; |
} |
while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) { |
buf[len++] = '0'; |
} |
while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) { |
buf[len++] = '0'; |
} |
} |
// handle hash |
if (flags & FLAGS_HASH) { |
if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) { |
len--; |
if (len && (base == 16U)) { |
len--; |
} |
} |
if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { |
buf[len++] = 'x'; |
} |
else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { |
buf[len++] = 'X'; |
} |
else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) { |
buf[len++] = 'b'; |
} |
if (len < PRINTF_NTOA_BUFFER_SIZE) { |
buf[len++] = '0'; |
} |
} |
if (len < PRINTF_NTOA_BUFFER_SIZE) { |
if (negative) { |
buf[len++] = '-'; |
} |
else if (flags & FLAGS_PLUS) { |
buf[len++] = '+'; // ignore the space if the '+' exists |
} |
else if (flags & FLAGS_SPACE) { |
buf[len++] = ' '; |
} |
} |
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); |
} |
// internal itoa for 'long' type |
static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags) |
{ |
char buf[PRINTF_NTOA_BUFFER_SIZE]; |
size_t len = 0U; |
// no hash for 0 values |
if (!value) { |
flags &= ~FLAGS_HASH; |
} |
// write if precision != 0 and value is != 0 |
if (!(flags & FLAGS_PRECISION) || value) { |
do { |
const char digit = (char)(value % base); |
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; |
value /= base; |
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); |
} |
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); |
} |
// internal itoa for 'long long' type |
#if defined(PRINTF_SUPPORT_LONG_LONG) |
static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags) |
{ |
char buf[PRINTF_NTOA_BUFFER_SIZE]; |
size_t len = 0U; |
// no hash for 0 values |
if (!value) { |
flags &= ~FLAGS_HASH; |
} |
// write if precision != 0 and value is != 0 |
if (!(flags & FLAGS_PRECISION) || value) { |
do { |
const char digit = (char)(value % base); |
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; |
value /= base; |
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); |
} |
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); |
} |
#endif // PRINTF_SUPPORT_LONG_LONG |
#if defined(PRINTF_SUPPORT_FLOAT) |
#if defined(PRINTF_SUPPORT_EXPONENTIAL) |
// forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT |
static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags); |
#endif |
// internal ftoa for fixed decimal floating point |
static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) |
{ |
char buf[PRINTF_FTOA_BUFFER_SIZE]; |
size_t len = 0U; |
double diff = 0.0; |
// powers of 10 |
static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; |
// test for special values |
if (value != value) |
return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags); |
if (value < -DBL_MAX) |
return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags); |
if (value > DBL_MAX) |
return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags); |
// test for very large values |
// standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad |
if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) { |
#if defined(PRINTF_SUPPORT_EXPONENTIAL) |
return _etoa(out, buffer, idx, maxlen, value, prec, width, flags); |
#else |
return 0U; |
#endif |
} |
// test for negative |
bool negative = false; |
if (value < 0) { |
negative = true; |
value = 0 - value; |
} |
// set default precision, if not set explicitly |
if (!(flags & FLAGS_PRECISION)) { |
prec = PRINTF_DEFAULT_FLOAT_PRECISION; |
} |
// limit precision to 9, cause a prec >= 10 can lead to overflow errors |
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) { |
buf[len++] = '0'; |
prec--; |
} |
int whole = (int)value; |
double tmp = (value - whole) * pow10[prec]; |
unsigned long frac = (unsigned long)tmp; |
diff = tmp - frac; |
if (diff > 0.5) { |
++frac; |
// handle rollover, e.g. case 0.99 with prec 1 is 1.0 |
if (frac >= pow10[prec]) { |
frac = 0; |
++whole; |
} |
} |
else if (diff < 0.5) { |
} |
else if ((frac == 0U) || (frac & 1U)) { |
// if halfway, round up if odd OR if last digit is 0 |
++frac; |
} |
if (prec == 0U) { |
diff = value - (double)whole; |
if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) { |
// exactly 0.5 and ODD, then round up |
// 1.5 -> 2, but 2.5 -> 2 |
++whole; |
} |
} |
else { |
unsigned int count = prec; |
// now do fractional part, as an unsigned number |
while (len < PRINTF_FTOA_BUFFER_SIZE) { |
--count; |
buf[len++] = (char)(48U + (frac % 10U)); |
if (!(frac /= 10U)) { |
break; |
} |
} |
// add extra 0s |
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) { |
buf[len++] = '0'; |
} |
if (len < PRINTF_FTOA_BUFFER_SIZE) { |
// add decimal |
buf[len++] = '.'; |
} |
} |
// do whole part, number is reversed |
while (len < PRINTF_FTOA_BUFFER_SIZE) { |
buf[len++] = (char)(48 + (whole % 10)); |
if (!(whole /= 10)) { |
break; |
} |
} |
// pad leading zeros |
if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) { |
if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { |
width--; |
} |
while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { |
buf[len++] = '0'; |
} |
} |
if (len < PRINTF_FTOA_BUFFER_SIZE) { |
if (negative) { |
buf[len++] = '-'; |
} |
else if (flags & FLAGS_PLUS) { |
buf[len++] = '+'; // ignore the space if the '+' exists |
} |
else if (flags & FLAGS_SPACE) { |
buf[len++] = ' '; |
} |
} |
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); |
} |
#if defined(PRINTF_SUPPORT_EXPONENTIAL) |
// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse <m.jasperse@gmail.com> |
static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) |
{ |
// check for NaN and special values |
if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) { |
return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags); |
} |
// determine the sign |
const bool negative = value < 0; |
if (negative) { |
value = -value; |
} |
// default precision |
if (!(flags & FLAGS_PRECISION)) { |
prec = PRINTF_DEFAULT_FLOAT_PRECISION; |
} |
// determine the decimal exponent |
// based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c) |
union { |
uint64_t U; |
double F; |
} conv; |
conv.F = value; |
int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2 |
conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2) |
// now approximate log10 from the log2 integer part and an expansion of ln around 1.5 |
int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168); |
// now we want to compute 10^expval but we want to be sure it won't overflow |
exp2 = (int)(expval * 3.321928094887362 + 0.5); |
const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; |
const double z2 = z * z; |
conv.U = (uint64_t)(exp2 + 1023) << 52U; |
// compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex |
conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); |
// correct for rounding errors |
if (value < conv.F) { |
expval--; |
conv.F /= 10; |
} |
// the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters |
unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U; |
// in "%g" mode, "prec" is the number of *significant figures* not decimals |
if (flags & FLAGS_ADAPT_EXP) { |
// do we want to fall-back to "%f" mode? |
if ((value >= 1e-4) && (value < 1e6)) { |
if ((int)prec > expval) { |
prec = (unsigned)((int)prec - expval - 1); |
} |
else { |
prec = 0; |
} |
flags |= FLAGS_PRECISION; // make sure _ftoa respects precision |
// no characters in exponent |
minwidth = 0U; |
expval = 0; |
} |
else { |
// we use one sigfig for the whole part |
if ((prec > 0) && (flags & FLAGS_PRECISION)) { |
--prec; |
} |
} |
} |
// will everything fit? |
unsigned int fwidth = width; |
if (width > minwidth) { |
// we didn't fall-back so subtract the characters required for the exponent |
fwidth -= minwidth; |
} else { |
// not enough characters, so go back to default sizing |
fwidth = 0U; |
} |
if ((flags & FLAGS_LEFT) && minwidth) { |
// if we're padding on the right, DON'T pad the floating part |
fwidth = 0U; |
} |
// rescale the float value |
if (expval) { |
value /= conv.F; |
} |
// output the floating part |
const size_t start_idx = idx; |
idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP); |
// output the exponent part |
if (minwidth) { |
// output the exponential symbol |
out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen); |
// output the exponent value |
idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth-1, FLAGS_ZEROPAD | FLAGS_PLUS); |
// might need to right-pad spaces |
if (flags & FLAGS_LEFT) { |
while (idx - start_idx < width) out(' ', buffer, idx++, maxlen); |
} |
} |
return idx; |
} |
#endif // PRINTF_SUPPORT_EXPONENTIAL |
#endif // PRINTF_SUPPORT_FLOAT |
// internal vsnprintf |
int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va) |
{ |
unsigned int flags, width, precision, n; |
size_t idx = 0U; |
if (!buffer) { |
// use null output function |
out = _out_null; |
} |
while (*format) |
{ |
// format specifier? %[flags][width][.precision][length] |
if (*format != '%') { |
// no |
out(*format, buffer, idx++, maxlen); |
format++; |
continue; |
} |
else { |
// yes, evaluate it |
format++; |
} |
// evaluate flags |
flags = 0U; |
do { |
switch (*format) { |
case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break; |
case '-': flags |= FLAGS_LEFT; format++; n = 1U; break; |
case '+': flags |= FLAGS_PLUS; format++; n = 1U; break; |
case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break; |
case '#': flags |= FLAGS_HASH; format++; n = 1U; break; |
default : n = 0U; break; |
} |
} while (n); |
// evaluate width field |
width = 0U; |
if (_is_digit(*format)) { |
width = _atoi(&format); |
} |
else if (*format == '*') { |
const int w = va_arg(va, int); |
if (w < 0) { |
flags |= FLAGS_LEFT; // reverse padding |
width = (unsigned int)-w; |
} |
else { |
width = (unsigned int)w; |
} |
format++; |
} |
// evaluate precision field |
precision = 0U; |
if (*format == '.') { |
flags |= FLAGS_PRECISION; |
format++; |
if (_is_digit(*format)) { |
precision = _atoi(&format); |
} |
else if (*format == '*') { |
const int prec = (int)va_arg(va, int); |
precision = prec > 0 ? (unsigned int)prec : 0U; |
format++; |
} |
} |
// evaluate length field |
switch (*format) { |
case 'l' : |
flags |= FLAGS_LONG; |
format++; |
if (*format == 'l') { |
flags |= FLAGS_LONG_LONG; |
format++; |
} |
break; |
case 'h' : |
flags |= FLAGS_SHORT; |
format++; |
if (*format == 'h') { |
flags |= FLAGS_CHAR; |
format++; |
} |
break; |
#if defined(PRINTF_SUPPORT_PTRDIFF_T) |
case 't' : |
flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); |
format++; |
break; |
#endif |
case 'j' : |
flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); |
format++; |
break; |
case 'z' : |
flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); |
format++; |
break; |
default : |
break; |
} |
// evaluate specifier |
switch (*format) { |
case 'd' : |
case 'i' : |
case 'u' : |
case 'x' : |
case 'X' : |
case 'o' : |
case 'b' : { |
// set the base |
unsigned int base; |
if (*format == 'x' || *format == 'X') { |
base = 16U; |
} |
else if (*format == 'o') { |
base = 8U; |
} |
else if (*format == 'b') { |
base = 2U; |
} |
else { |
base = 10U; |
flags &= ~FLAGS_HASH; // no hash for dec format |
} |
// uppercase |
if (*format == 'X') { |
flags |= FLAGS_UPPERCASE; |
} |
// no plus or space flag for u, x, X, o, b |
if ((*format != 'i') && (*format != 'd')) { |
flags &= ~(FLAGS_PLUS | FLAGS_SPACE); |
} |
// ignore '0' flag when precision is given |
if (flags & FLAGS_PRECISION) { |
flags &= ~FLAGS_ZEROPAD; |
} |
// convert the integer |
if ((*format == 'i') || (*format == 'd')) { |
// signed |
if (flags & FLAGS_LONG_LONG) { |
#if defined(PRINTF_SUPPORT_LONG_LONG) |
const long long value = va_arg(va, long long); |
idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); |
#endif |
} |
else if (flags & FLAGS_LONG) { |
const long value = va_arg(va, long); |
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); |
} |
else { |
const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int); |
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); |
} |
} |
else { |
// unsigned |
if (flags & FLAGS_LONG_LONG) { |
#if defined(PRINTF_SUPPORT_LONG_LONG) |
idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags); |
#endif |
} |
else if (flags & FLAGS_LONG) { |
idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags); |
} |
else { |
const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int); |
idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags); |
} |
} |
format++; |
break; |
} |
#if defined(PRINTF_SUPPORT_FLOAT) |
case 'f' : |
case 'F' : |
if (*format == 'F') flags |= FLAGS_UPPERCASE; |
idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); |
format++; |
break; |
#if defined(PRINTF_SUPPORT_EXPONENTIAL) |
case 'e': |
case 'E': |
case 'g': |
case 'G': |
if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP; |
if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE; |
idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); |
format++; |
break; |
#endif // PRINTF_SUPPORT_EXPONENTIAL |
#endif // PRINTF_SUPPORT_FLOAT |
case 'c' : { |
unsigned int l = 1U; |
// pre padding |
if (!(flags & FLAGS_LEFT)) { |
while (l++ < width) { |
out(' ', buffer, idx++, maxlen); |
} |
} |
// char output |
out((char)va_arg(va, int), buffer, idx++, maxlen); |
// post padding |
if (flags & FLAGS_LEFT) { |
while (l++ < width) { |
out(' ', buffer, idx++, maxlen); |
} |
} |
format++; |
break; |
} |
case 's' : { |
const char* p = va_arg(va, char*); |
unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1); |
// pre padding |
if (flags & FLAGS_PRECISION) { |
l = (l < precision ? l : precision); |
} |
if (!(flags & FLAGS_LEFT)) { |
while (l++ < width) { |
out(' ', buffer, idx++, maxlen); |
} |
} |
// string output |
while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) { |
out(*(p++), buffer, idx++, maxlen); |
} |
// post padding |
if (flags & FLAGS_LEFT) { |
while (l++ < width) { |
out(' ', buffer, idx++, maxlen); |
} |
} |
format++; |
break; |
} |
case 'p' : { |
width = sizeof(void*) * 2U; |
flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE; |
#if defined(PRINTF_SUPPORT_LONG_LONG) |
const bool is_ll = sizeof(uintptr_t) == sizeof(long long); |
if (is_ll) { |
idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags); |
} |
else { |
#endif |
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags); |
#if defined(PRINTF_SUPPORT_LONG_LONG) |
} |
#endif |
format++; |
break; |
} |
case '%' : |
out('%', buffer, idx++, maxlen); |
format++; |
break; |
default : |
out(*format, buffer, idx++, maxlen); |
format++; |
break; |
} |
} |
// termination |
out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); |
// return written chars without terminating \0 |
return (int)idx; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/format_print.h |
---|
0,0 → 1,14 |
#include <stddef.h> |
#include <stdarg.h> |
#pragma pack(push,1) |
typedef struct { |
void (*fct)(char character, void* arg); |
void* arg; |
} out_fct_wrap_type; |
#pragma pack(pop) |
typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen); |
void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen); |
void _out_null(char character, void* buffer, size_t idx, size_t maxlen); |
int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va); |
/programs/develop/libraries/kolibri-libc/source/stdio/format_scan.c |
---|
0,0 → 1,403 |
/* |
function for format read from any source |
Siemargl formats as http://www.cplusplus.com/reference/cstdio/scanf/, no wchar though |
http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap05.html is used too |
todo: |
[characters], [^characters] |
-%n nothing scanned, filled only if good result |
-%d, i, u, o, x, p read similar - detect base by prefix 0 or 0x |
-%a |
-can overflow unsigned as signed |
-radix point always '.', no LOCALEs |
*/ |
#include <stdio.h> |
#include <ctype.h> |
#include <math.h> |
#include <stdarg.h> |
#include "format_scan.h" |
static int __try_parse_real(long double *real, int ch, const void *src, void *save, virtual_getc vgetc, virtual_ungetc vungetc) |
// returns 1 if OK, -1 == EOF, -2 parse broken |
{ |
int sign = 1, have_digits = 0; |
long long div; |
if (ch == '+') |
{ |
ch = vgetc(save, src); |
if (ch == EOF) return EOF; |
} else |
if (ch == '-') |
{ |
sign = -1; |
ch = vgetc(save, src); |
if (ch == EOF) return EOF; |
}; |
*real = 0.0; |
for (;;) // mantissa before point |
{ |
// test ch is valid |
if (isdigit(ch)) |
{ |
*real = *real * 10 + ch - '0'; |
have_digits++; |
ch = vgetc(save, src); |
if (ch == EOF || isspace(ch)) break; // ok, just finish num |
} else |
if (ch == '.' || ch == 'E' || ch == 'e') |
{ |
break; // ok |
} |
else |
{ |
vungetc(save, ch, src); |
break; |
} |
} |
if (ch != '.' && ch != 'E' && ch != 'e') // ok, just integer part |
{ |
*real *= sign; |
if (have_digits) |
return 1; |
else |
return -2; |
} |
if(ch == '.') |
{ |
ch = vgetc(save, src); |
div = 10; // use as divisor |
for (;;) // mantissa after point |
{ |
// test ch is valid |
if (isdigit(ch)) |
{ |
*real += (double)(ch - '0') / div; |
div *= 10; |
have_digits++; |
ch = vgetc(save, src); |
if (ch == EOF || isspace(ch)) break; // ok, just finish num |
} else |
if (ch == 'E' || ch == 'e') |
{ |
break; // ok |
} |
else |
{ |
vungetc(save, ch, src); |
break; |
} |
} |
if (ch != 'E' && ch != 'e') // ok, real as XX.YY |
{ |
*real *= sign; |
if (have_digits) |
return 1; |
else |
return -2; |
} |
} |
ch = vgetc(save, src); |
*real *= sign; |
// exponent |
sign = 1; |
if (ch == '+') |
{ |
ch = vgetc(save, src); |
if (ch == EOF) return EOF; |
} else |
if (ch == '-') |
{ |
sign = -1; |
ch = vgetc(save, src); |
if (ch == EOF) return EOF; |
}; |
div = 0; |
for (;;) |
{ |
// test ch is valid |
if (isdigit(ch)) |
{ |
div = div * 10 + ch - '0'; |
ch = vgetc(save, src); |
if (ch == EOF || isspace(ch)) break; // ok, just finish num |
} |
else |
{ |
vungetc(save, ch, src); |
break; |
} |
} |
div *= sign; |
*real *= pow(10,div); |
return 1; |
} |
static int __try_parse_int(long long *digit, int ch, const void *src, void *save, virtual_getc vgetc, virtual_ungetc vungetc) |
{ |
int sign = 1, base = 10, have_digits = 0; |
if (ch == '+') |
{ |
ch = vgetc(save, src); |
if (ch == EOF) return EOF; |
} else |
if (ch == '-') |
{ |
sign = -1; |
ch = vgetc(save, src); |
if (ch == EOF) return EOF; |
}; |
if (ch == '0') // octal or hex, read next |
{ |
base = 8; |
ch = vgetc(save, src); |
if (ch == EOF || isspace(ch)) |
have_digits++; |
else |
if (ch == 'x' || ch == 'X') |
{ |
base = 16; |
ch = vgetc(save, src); |
if (ch == EOF) return EOF; |
} |
} |
*digit = 0; |
for (;;) |
{ |
// test ch is valid |
if ((isdigit(ch) && base == 10) || |
(isdigit(ch) && base == 8 && ch < '8') || |
(isxdigit(ch) && base == 16)) |
{ |
if (base == 16) |
{ |
if (ch <= '9') ch-= '0'; |
else |
if (ch <= 'F') ch = 10 + ch - 'A'; |
else |
ch = 10 + ch - 'a'; |
} |
else |
ch -= '0'; |
*digit = *digit * base + ch; |
have_digits++; |
ch = vgetc(save, src); |
if (ch == EOF || isspace(ch)) break; // ok, just finish num |
} |
else if (ch == EOF || isspace(ch)) |
break; |
else |
{ |
vungetc(save, ch, src); |
break; |
} |
} |
*digit *= sign; |
if (have_digits) |
return 1; |
else |
return -2; |
} |
int _format_scan(const void *src, const char *fmt, va_list argp, virtual_getc vgetc, virtual_ungetc vungetc) |
{ |
int i; |
int length; |
int fmt1, fmt2; // width, precision |
size_t pos, posc; |
const char *fmtc; // first point to %, fmtc points to specifier |
int ch; |
int format_flag; |
int flag_long; // 2 = long double or long long int or wchar |
int *point_to_n = NULL, nread = 0; |
int flags; // parsed flags |
int save = 0; |
char *arg_str; |
int *arg_int; |
long *arg_long; |
long long *arg_longlong; |
float *arg_float; |
double *arg_double; |
long double *arg_longdouble; |
long long digit; |
long double real; |
pos = 0; |
while(*fmt) |
{ |
while (*fmt && isspace(*fmt)) fmt++; // skip paces in format str |
if (*fmt != '%') // usual char |
{ |
ch = vgetc(&save, src); |
if (ch != *fmt++) // char not match format |
{ |
vungetc(&save, ch, src); |
break; |
} |
pos++; |
continue; |
} |
if (*(fmt + 1) == '%') // %% |
{ |
ch = vgetc(&save, src); |
if (ch != '%') // char not match format |
{ |
vungetc(&save, ch, src); |
break; |
} |
pos++; |
fmt += 2; |
continue; |
} |
//checking to containg format in the string |
fmtc = fmt; |
posc = pos; |
flags = 0; |
format_flag = 0; |
flag_long = 0; // 2 = long double or long long int or wchar |
while(*fmtc != '\0' && !format_flag) // searching end of format |
{ |
fmtc++; posc++; |
switch( *fmtc ) |
{ |
case 'a': |
format_flag = 1; |
flags |= flag_unsigned; |
break; |
case 'c': case 'd': case 'i': case 'e': case 'f': case 'g': case 's': case 'n': |
format_flag = 1; |
break; |
case 'l': |
flag_long = flag_long ? 2 : 1; // ll.eq.L |
break; |
case 'L': |
flag_long = 2; |
break; |
case 'o': case 'u': case 'x': case 'p': |
format_flag = 1; |
flags |= flag_unsigned; |
break; |
case '*': case '.': // just skip |
break; |
default: |
if(isdigit(*fmtc)) break; |
goto exit_me; // non format char found - user error |
} |
} |
if (format_flag == 0) |
{ |
goto exit_me; // format char not found - user error |
} |
fmt1 = 0; |
fmt2 = 0; |
if (posc - pos > 1) // try to read width, precision |
{ |
fmt++; |
for(i = pos + 1; i < posc; i++) |
{ |
switch(*fmt) |
{ |
case '0': |
if(fmt1 == 0 && (flags & flag_point) == 0) flags |= flag_lead_zeros; |
case '1': case '2': case '3': case '4': |
case '5': case '6': case '7': case '8': case '9': |
if ((flags & flag_point) == 0) |
fmt1 = fmt1 * 10 + (*fmt -'0'); |
else |
fmt2 = fmt2 * 10 + (*fmt -'0'); |
break; |
case '*': // ignoring |
break; |
case '.': |
flags |= flag_point; |
break; |
case 'l': case 'L': // valid chars - skip |
break; |
default: // must be error |
goto exit_me; // format char not found - user error |
} |
fmt++; |
} |
} |
// do real work - format arguments values |
// skip input spaces |
do { |
ch = vgetc(&save, src); |
if (ch == EOF) goto exit_me; |
} while (isspace(ch)); |
switch(*fmtc) |
{ |
case 'n': |
point_to_n = va_arg(argp, int*); |
vungetc(&save, ch, src); |
break; |
case 'c': // read width chars, ever spaces |
arg_str = va_arg(argp, char*); |
if (fmt1 == 0) length = 1; |
else length = fmt1; |
for (i = 0; i < length;) |
{ |
*arg_str++ = ch; i++; |
ch = vgetc(&save, src); |
if (ch == EOF) break; |
} |
if (i < length) goto exit_me; // not enough chars |
break; |
case 's': |
arg_str = va_arg(argp, char*); |
if (fmt1 == 0) length = STDIO_MAX_MEM; // max string scan 4096 |
else length = fmt1; |
for (i = 0; i < length; i++) |
{ |
*arg_str++ = ch; |
ch = vgetc(&save, src); |
if (ch == EOF || isspace(ch)) break; // ok, just finish string |
} |
*arg_str++ = '\0'; |
break; |
case 'd': case 'i': case 'u': |
case 'o': case 'p': case 'x': |
i = __try_parse_int(&digit, ch, src, &save, vgetc, vungetc); |
if (i < 0) goto exit_me; |
if (flag_long == 0) { arg_int = va_arg(argp, int*); *arg_int = (int)digit; } else |
if (flag_long == 1) { arg_long = va_arg(argp, long*); *arg_long = (long)digit; } else |
if (flag_long == 2) { arg_longlong = va_arg(argp, long long*); *arg_longlong = digit; } |
break; |
case 'a': case 'A': case 'f': case 'F': |
case 'e': case 'E': |
case 'g': case 'G': |
i = __try_parse_real(&real, ch, src, &save, vgetc, vungetc); |
if (i < 0) goto exit_me; |
if (flag_long == 0) { arg_float = va_arg(argp, float*); *arg_float = (float)real; } else |
if (flag_long == 1) { arg_double = va_arg(argp, double*); *arg_double = (double)real; } else |
if (flag_long == 2) { arg_longdouble = va_arg(argp, long double*); *arg_longdouble = real; } |
break; |
} |
fmt = fmtc + 1; |
nread++; |
} |
exit_me: |
if (point_to_n) *point_to_n = nread; |
return nread; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/format_scan.h |
---|
0,0 → 1,20 |
#include <stdio.h> |
typedef int (*virtual_getc)(void *sp, const void *obj); |
typedef void (*virtual_ungetc)(void *sp, int c, const void *obj); |
enum flags_t |
{ |
flag_unsigned = 0x02, |
flag_register = 0x04, |
flag_plus = 0x08, |
flag_left_just = 0x10, |
flag_lead_zeros = 0x20, |
flag_space_plus = 0x40, |
flag_hash_sign = 0x80, |
flag_point = 0x100 |
}; |
char *__scanf_buffer; |
extern int _format_scan(const void *src, const char *fmt, va_list argp, virtual_getc vgetc, virtual_ungetc vungetc); |
/programs/develop/libraries/kolibri-libc/source/stdio/fprintf.c |
---|
0,0 → 1,14 |
#include "sys/ksys.h" |
#include <stdio.h> |
#include <stdarg.h> |
int fprintf(FILE *restrict f, const char *restrict fmt, ...) |
{ |
int ret; |
va_list ap; |
va_start(ap, fmt); |
ret = vfprintf(f, fmt, ap); |
va_end(ap); |
return ret; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/fputc.c |
---|
0,0 → 1,12 |
#include <stdio.h> |
#include <errno.h> |
#include <sys/ksys.h> |
int fputc(int c, FILE *stream) |
{ |
if(fwrite(&c, sizeof(int), 1, stream)==1){ |
return c; |
}else{ |
return EOF; |
} |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/fputs.c |
---|
0,0 → 1,6 |
#include <stdio.h> |
#include <string.h> |
int fputs(const char *str, FILE *stream){ |
return fwrite(str, sizeof(char), strlen(str), stream); |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/fread.c |
---|
0,0 → 1,20 |
#include <stdio.h> |
size_t fread(void *restrict ptr, size_t size, size_t nmemb, FILE *restrict stream) { |
unsigned bytes_read = 0; |
unsigned bytes_count = size * nmemb; |
for (size_t i = 0; i < bytes_count; i++) { |
char c = fgetc(stream); |
if (c == EOF) { |
break; |
} |
*(char*)(ptr+i) = c; |
bytes_read++; |
} |
return bytes_read / size; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/freopen.c |
---|
0,0 → 1,42 |
#include "sys/ksys.h" |
#include <errno.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
FILE *freopen(const char *restrict _name, const char *restrict _mode, FILE *restrict out) { |
static ksys_bdfe_t info; |
info.size=0; |
if (!out) { |
errno = ENOMEM; |
return NULL; |
} |
_ksys_file_get_info(_name, &info); |
out->name = strdup(_name); |
out->position = 0; |
out->error = 0; |
out->eof = 0; |
out->kind = 0; |
out->orientation = 0; |
out->mode = 0; |
out->start_size = info.size; |
if (strchr(_mode, 'b')) { out->mode |= _STDIO_F_B; } |
if (strchr(_mode, 'x')) { out->mode |= _STDIO_F_X; } |
if (strchr(_mode, 'a')) { out->mode |= _STDIO_F_A; } |
if (strchr(_mode, 'r')) { out->mode |= _STDIO_F_R; } |
if (strchr(_mode, 'w')) { out->mode |= _STDIO_F_W; } |
if (strchr(_mode, '+')) { out->mode |= _STDIO_F_R | _STDIO_F_W; } |
if (out->mode & _STDIO_F_A) { |
out->position = info.size; |
out->append_offset = info.size; |
} else if(out->mode & _STDIO_F_W){ |
if(_ksys_file_create(_name)){ |
return NULL; |
} |
} |
return out; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/fscanf.c |
---|
0,0 → 1,13 |
#include <stdio.h> |
int fscanf(FILE* stream, const char* format, ...) |
{ |
va_list arg; |
int n; |
va_start(arg, format); |
n = vfscanf(stream, format, arg); |
va_end(arg); |
return n; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/fseek.c |
---|
0,0 → 1,17 |
#include <stdio.h> |
#include <sys/ksys.h> |
int fseek(FILE *stream, long int offset, int whence) { |
if (whence == SEEK_SET) { |
stream->position = offset; |
} else if (whence == SEEK_CUR) { |
stream->position += offset; |
} else if (whence == SEEK_END) { |
ksys_bdfe_t info; |
if (_ksys_file_get_info(stream->name, &info)) { |
return -1; |
} |
stream->position = info.size + offset; |
} |
stream->eof = 0; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/fsetpos.c |
---|
0,0 → 1,7 |
#include <stdio.h> |
int fsetpos(FILE *stream, const fpos_t *pos) { |
stream->position = *pos; |
stream->eof = 0; |
return 0; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/ftell.c |
---|
0,0 → 1,5 |
#include <stdio.h> |
long int ftell(FILE *stream) { |
return stream->position; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/fwrite.c |
---|
0,0 → 1,40 |
#include <stdio.h> |
#include "conio.h" |
#include <sys/ksys.h> |
#include <errno.h> |
size_t fwrite(const void *restrict ptr, size_t size, size_t nmemb, FILE *restrict stream) { |
unsigned bytes_written = 0; |
unsigned bytes_count = size * nmemb; |
if(!stream){ |
errno = EINVAL; |
return 0; |
} |
if(stream==stdout){ |
__con_init(); |
__con_write_string((char*)ptr, bytes_count); |
return nmemb; |
} |
else if(stream==stderr){ |
for (size_t i = 0; i < bytes_count; i++) { |
char c = *(char*)(ptr+i); |
_ksys_debug_putc(c); |
} |
} |
else{ |
if(stream->mode != _STDIO_F_R){ |
unsigned status = _ksys_file_write_file(stream->name, stream->position, bytes_count, ptr, &bytes_written); |
if (status != KSYS_FS_ERR_SUCCESS) { |
errno = EIO; |
stream->error = errno; |
return 0; |
}else { |
stream->position+=bytes_written; |
} |
} |
} |
return bytes_written; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/getchar.c |
---|
0,0 → 1,10 |
#include <stdio.h> |
#include "conio.h" |
int getchar(void) { |
int c = __con_getch(); |
if (c == 0) { |
c = EOF; |
} |
return c; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/gets.c |
---|
0,0 → 1,16 |
#include <stdio.h> |
#include <string.h> |
#include "conio.h" |
#include <errno.h> |
#include <limits.h> |
char *gets(char* str) |
{ |
__con_init(); |
if(__con_gets(str, STDIO_MAX_MEM)==NULL){ |
errno = EIO; |
return NULL; |
} |
str[strlen(str)-1]='\0'; |
return str; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/perror.c |
---|
0,0 → 1,5 |
#include <stdio.h> |
void perror(const char *s) { |
debug_printf("%s: It's some error, maybe...\n", s); |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/printf.c |
---|
0,0 → 1,14 |
/* Copyright (C) 2021 Logaev Maxim (turbocat2001), GPLv2 */ |
#include <stdarg.h> |
#include <stdio.h> |
#include <stdlib.h> |
//#include "format_print.h" |
int printf(const char *format, ...) |
{ |
va_list arg; |
va_start(arg, format); |
return vprintf(format, arg); |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/puts.c |
---|
0,0 → 1,14 |
/* Copyright (C) 2021 Logaev Maxim (turbocat2001), GPLv2 */ |
#include <stdio.h> |
#include <string.h> |
#include "conio.h" |
#include "sys/ksys.h" |
int puts(const char *str) |
{ |
__con_init(); |
__con_write_asciiz(str); |
__con_write_asciiz("\n"); |
return strlen(str); |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/remove.c |
---|
0,0 → 1,6 |
#include <stdio.h> |
#include <sys/ksys.h> |
int remove(const char *name) { |
return _ksys_file_delete(name); |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/rename.c |
---|
0,0 → 1,6 |
#include <stdio.h> |
#include <sys/ksys.h> |
int rename(const char *name, const char *new_name) { |
return _ksys_file_rename(name, new_name); |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/rewind.c |
---|
0,0 → 1,5 |
#include <stdio.h> |
void rewind(FILE *stream) { |
stream->position = 0; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/scanf.c |
---|
0,0 → 1,21 |
//#include "format_scan.h" |
#include <stdlib.h> |
#include <errno.h> |
int scanf ( const char * format, ...) |
{ |
va_list arg; |
int n; |
va_start(arg, format); |
if(__scanf_buffer == NULL) __scanf_buffer = malloc(STDIO_MAX_MEM); |
if(__scanf_buffer == NULL) errno = ENOMEM; return ENOMEM; |
*__scanf_buffer = 0; |
n = vscanf(format, arg); |
va_end(arg); |
return n; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/setbuf.c |
---|
0,0 → 1,5 |
#include <stdio.h> |
void setbuf(FILE *restrict stream, char *restrict buf) { |
return; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/setvbuf.c |
---|
0,0 → 1,5 |
#include <stdio.h> |
int setvbuf(FILE *restrict stream, char *restrict buf, int mode, size_t size) { |
return 0; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/snprintf.c |
---|
0,0 → 1,13 |
/* Copyright (C) 2021 Logaev Maxim (turbocat2001), GPLv2 */ |
//#include "format_print.h" |
#include <stdio.h> |
int snprintf(char* buffer, size_t count, const char* format, ...) |
{ |
va_list va; |
va_start(va, format); |
const int ret = _vsnprintf(_out_buffer, buffer, count, format, va); |
va_end(va); |
return ret; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/sprintf.c |
---|
0,0 → 1,13 |
/* Copyright (C) 2021 Logaev Maxim (turbocat2001), GPLv2 */ |
//#include "format_print.h" |
#include <stdio.h> |
int sprintf(char* buffer, const char* format, ...) |
{ |
va_list va; |
va_start(va, format); |
const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va); |
va_end(va); |
return ret; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/sscanf.c |
---|
0,0 → 1,12 |
#include <stdio.h> |
int sscanf(const char * s, const char * format, ...) |
{ |
va_list arg; |
int n; |
va_start(arg, format); |
n = vsscanf(s, format, arg); |
va_end(arg); |
return n; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/tmpfile.c |
---|
0,0 → 1,11 |
#include <stdio.h> |
FILE *tmpfile(void) { |
char name[FILENAME_MAX + 1]; |
if (!tmpnam(name)) { |
return NULL; |
} |
return fopen(name, "wb+"); |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/tmpnam.c |
---|
0,0 → 1,16 |
#include <stdio.h> |
#include <sys/ksys.h> |
#include <string.h> |
static char buf[FILENAME_MAX + 1]; |
static int static_index = 0; |
char *tmpnam(char *name) { |
ksys_proc_table_t table; |
_ksys_process_info(&table, -1); |
char *out = name ? name : buf; |
// PID is also unique for each thread |
sprintf(out, "/tmp0/1/%x_%x.tmp", table.pid, static_index++); |
return out; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/vfprintf.c |
---|
0,0 → 1,32 |
#include <stdio.h> |
#include <errno.h> |
#include <stdlib.h> |
#include <limits.h> |
int vfprintf(FILE * file, const char *format, va_list arg) |
{ |
static char *buf=NULL; |
int printed=0, rc = 0; |
if(!file){ |
errno = EBADF; |
return errno; |
} |
if(!format){ |
errno = EINVAL; |
return errno; |
} |
buf = malloc(STDIO_MAX_MEM); |
if(!buf){ |
errno = ENOMEM; |
return errno; |
} |
printed = vsnprintf(buf, STDIO_MAX_MEM, format,arg); |
rc = fwrite(buf, sizeof(char), printed, file); |
free(buf); |
return rc; |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/vfscanf.c |
---|
0,0 → 1,55 |
#include <stdio.h> |
#include <stdarg.h> |
#include <stdlib.h> |
//#include "format_scan.h" |
#include <errno.h> |
// non standard realization - support for virtually change ONLY ONE char |
static int __ungetc_emu(int c, FILE* stream) |
{ |
unsigned res; |
if(stream){ |
errno = EINVAL; |
return EOF; |
} |
if ((stream->mode & 3) != _STDIO_F_R && (stream->mode & _STDIO_F_A) == 0){ |
errno = EACCES; |
return EOF; |
} |
ksys_bdfe_t *file_info = malloc(sizeof(ksys_bdfe_t)); |
if(file_info==NULL){ |
errno = ENOMEM; |
return EOF; |
} |
if(!_ksys_file_get_info(stream->name, file_info)){ |
errno = ENFILE; |
return EOF; |
} |
if (stream->position > file_info->size || stream->position == 0 || c == EOF || stream->__ungetc_emu_buff != EOF){ |
errno = EOF; |
return EOF; |
} |
stream->__ungetc_emu_buff = c; |
stream->position --; |
return c; |
} |
static int __virtual_getc_file(void *sp, const void *obj) |
{ |
FILE *f = (FILE *)obj; |
int ch = fgetc(f); |
return ch; |
} |
static void __virtual_ungetc_file(void *sp, int c, const void *obj) |
{ |
FILE *f = (FILE *)obj; |
if (f) __ungetc_emu(c, f); |
} |
int vfscanf(FILE * stream, const char * format, va_list arg) |
{ |
return _format_scan(stream, format, arg, &__virtual_getc_file, &__virtual_ungetc_file); |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/vprintf.c |
---|
0,0 → 1,26 |
/* Copyright (C) 2021 Logaev Maxim (turbocat2001), GPLv2 */ |
#include <stdarg.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include "conio.h" |
#include <sys/ksys.h> |
#include <errno.h> |
#include <limits.h> |
//#include "format_print.h" |
int vprintf ( const char * format, va_list arg ) |
{ |
int len = 0; |
char *s = malloc(STDIO_MAX_MEM); |
if(!s){ |
errno = ENOMEM; |
return errno; |
} |
__con_init(); |
len = vsnprintf(s, STDIO_MAX_MEM, format, arg); |
__con_write_string(s, len); |
free(s); |
return(len); |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/vscanf.c |
---|
0,0 → 1,49 |
#include <string.h> |
char *__scanf_buffer=NULL; |
typedef int (*virtual_getc)(void *sp, const void *obj); |
typedef void (*virtual_ungetc)(void *sp, int c, const void *obj); |
char *__scanf_buffer; |
extern int _format_scan(const void *src, const char *fmt, va_list argp, virtual_getc vgetc, virtual_ungetc vungetc); |
static int __virtual_getc_con(void *sp, const void *obj) |
// get next chat from string obj, save point is ptr to string char ptr |
{ |
int ch; |
const char**spc= (const char**)sp; |
if (!spc) return EOF; // error |
if (!*spc) *spc = __scanf_buffer; // first call, init savepoint |
while (!**spc) // need to read more |
{ |
if(!gets(__scanf_buffer)) return EOF; |
*spc = __scanf_buffer; |
strcat(__scanf_buffer,"\n"); // imitate delimiter |
} |
if (**spc == 26 || **spc == 3) // ^C ^Z end of scan, clear buffer |
{ |
*spc = __scanf_buffer; |
*__scanf_buffer = 0; |
return EOF; // ^C ^Z |
} |
ch = **spc; (*spc)++ ; |
return ch; |
} |
static void __virtual_ungetc_con(void *sp, int c, const void *obj) |
// if can, one step back savepoint in s |
{ |
const char**spc= (const char**)sp; |
if (spc && *spc > __scanf_buffer) (*spc)--; |
//printf("Ungetc '%c'[%d];", c, c); |
} |
int vscanf(const char * format, va_list arg) |
{ |
return _format_scan(NULL, format, arg, &__virtual_getc_con, &__virtual_ungetc_con); |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/vsnprintf.c |
---|
0,0 → 1,6 |
//#include "format_print.h" |
int vsnprintf(char* buffer, size_t count, const char* format, va_list va) |
{ |
return _vsnprintf(_out_buffer, buffer, count, format, va); |
} |
/programs/develop/libraries/kolibri-libc/source/stdio/vsscanf.c |
---|
0,0 → 1,32 |
//#include "format_scan.h" |
static int __virtual_getc_str(void *sp, const void *obj) |
// get next chat from string obj, save point is ptr to string char ptr |
{ |
int ch; |
const char *s = (const char *)obj; |
const char**spc= (const char**)sp; |
if (!s || !spc) return EOF; // error |
if (!*spc) *spc = s; // first call, init savepoint |
if (!**spc) return EOF; // EOS |
ch = **spc; (*spc)++ ; |
return ch; |
} |
void __virtual_ungetc_str(void *sp, int c, const void *obj) |
// if can, one step back savepoint in s |
{ |
const char *s = (const char *)obj; |
const char**spc= (const char**)sp; |
if (s && spc && *spc > s) (*spc)--; |
} |
int vsscanf(const char * s, const char * format, va_list arg) |
{ |
return _format_scan(s, format, arg, &__virtual_getc_str, &__virtual_ungetc_str); |
}; |