forked from KolibriOS/kolibrios
Added git source kolibri-libc and
Configured autobuild git-svn-id: svn://kolibrios.org@8687 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void clearerr(FILE *stream) {
|
||||
stream->error = 0;
|
||||
stream->eof = 0;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int fclose(FILE *stream) {
|
||||
free(stream);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int feof(FILE *stream) {
|
||||
return stream->eof;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int ferror(FILE *stream) {
|
||||
return stream->error;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int fflush(FILE *stream) {
|
||||
return 0;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int fgetpos(FILE *restrict stream, fpos_t *restrict pos) {
|
||||
*pos = stream->position;
|
||||
return 0;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int fsetpos(FILE *stream, const fpos_t *pos) {
|
||||
stream->position = *pos;
|
||||
stream->eof = 0;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#include <stdio.h>
|
||||
|
||||
long int ftell(FILE *stream) {
|
||||
return stream->position;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <stdio.h>
|
||||
#include "conio.h"
|
||||
|
||||
int getchar(void) {
|
||||
int c = __con_getch();
|
||||
if (c == 0) {
|
||||
c = EOF;
|
||||
}
|
||||
return 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;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void perror(const char *s) {
|
||||
debug_printf("%s: It's some error, maybe...\n", s);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/ksys.h>
|
||||
|
||||
int remove(const char *name) {
|
||||
return _ksys_file_delete(name);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void rewind(FILE *stream) {
|
||||
stream->position = 0;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void setbuf(FILE *restrict stream, char *restrict buf) {
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int setvbuf(FILE *restrict stream, char *restrict buf, int mode, size_t size) {
|
||||
return 0;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#include <stdio.h>
|
||||
|
||||
FILE *tmpfile(void) {
|
||||
char name[FILENAME_MAX + 1];
|
||||
|
||||
if (!tmpnam(name)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fopen(name, "wb+");
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
Reference in New Issue
Block a user