mirror of
https://github.com/solemnwarning/ipxwrapper
synced 2024-12-30 16:45:37 +01:00
Replace snprintf() implementation used within DLLs.
It appears that some of the mswsock.dll functions get called on Windows 98 in a context where calling any of the printf functions provided by the CRT causes subtle memory corruption which doesn't manifest until the process exits, triggering a page fault in KERNEL32.DLL and making the system unusable. 1990s Windows makes me miss the sophistication of 1970s UNIX.
This commit is contained in:
parent
379f3d6eb6
commit
26f6511dee
22
Makefile
22
Makefile
@ -86,7 +86,7 @@ dist: all
|
||||
|
||||
IPXWRAPPER_OBJS := src/ipxwrapper.o src/winsock.o src/ipxwrapper_stubs.o src/log.o src/common.o \
|
||||
src/interface.o src/interface2.o src/router.o src/ipxwrapper.def src/addrcache.o src/config.o src/addr.o \
|
||||
src/firewall.o src/ethernet.o src/funcprof.o src/coalesce.o inih/ini.o
|
||||
src/firewall.o src/ethernet.o src/funcprof.o src/coalesce.o src/snprintf.o inih/ini.o
|
||||
|
||||
ipxwrapper.dll: $(IPXWRAPPER_OBJS)
|
||||
echo 'const char *version_string = "$(VERSION)", *compile_time = "'`date`'";' | $(CC) -c -x c -o version.o -
|
||||
@ -99,7 +99,7 @@ src/ipxwrapper_stubs.s: src/ipxwrapper_stubs.txt
|
||||
# WSOCK32.DLL
|
||||
#
|
||||
|
||||
wsock32.dll: src/stubdll.o src/wsock32_stubs.o src/log.o src/common.o src/config.o src/addr.o src/funcprof.o inih/ini.o src/wsock32.def
|
||||
wsock32.dll: src/stubdll.o src/wsock32_stubs.o src/log.o src/common.o src/config.o src/addr.o src/funcprof.o src/snprintf.o inih/ini.o src/wsock32.def
|
||||
$(CC) $(CFLAGS) -Wl,--enable-stdcall-fixup -static-libgcc -shared -o $@ $^
|
||||
|
||||
src/wsock32_stubs.s: src/wsock32_stubs.txt
|
||||
@ -109,7 +109,7 @@ src/wsock32_stubs.s: src/wsock32_stubs.txt
|
||||
# MSWSOCK.DLL
|
||||
#
|
||||
|
||||
mswsock.dll: src/stubdll.o src/mswsock_stubs.o src/log.o src/common.o src/config.o src/addr.o src/funcprof.o inih/ini.o src/mswsock.def
|
||||
mswsock.dll: src/stubdll.o src/mswsock_stubs.o src/log.o src/common.o src/config.o src/addr.o src/funcprof.o src/snprintf.o inih/ini.o src/mswsock.def
|
||||
$(CC) $(CFLAGS) -Wl,--enable-stdcall-fixup -static-libgcc -shared -o $@ $^
|
||||
|
||||
src/mswsock_stubs.s: src/mswsock_stubs.txt
|
||||
@ -119,7 +119,7 @@ src/mswsock_stubs.s: src/mswsock_stubs.txt
|
||||
# DPWSOCKX.DLL
|
||||
#
|
||||
|
||||
dpwsockx.dll: src/directplay.o src/log.o src/dpwsockx_stubs.o src/common.o src/config.o src/addr.o src/funcprof.o inih/ini.o src/dpwsockx.def
|
||||
dpwsockx.dll: src/directplay.o src/log.o src/dpwsockx_stubs.o src/common.o src/config.o src/addr.o src/funcprof.o src/snprintf.o inih/ini.o src/dpwsockx.def
|
||||
$(CC) $(CFLAGS) -Wl,--enable-stdcall-fixup -static-libgcc -shared -o $@ $^ -lwsock32
|
||||
|
||||
src/dpwsockx_stubs.s: src/dpwsockx_stubs.txt
|
||||
@ -130,7 +130,7 @@ src/dpwsockx_stubs.s: src/dpwsockx_stubs.txt
|
||||
#
|
||||
|
||||
IPXCONFIG_OBJS := src/ipxconfig.o icons/ipxconfig.o src/addr.o src/interface2.o src/common.o \
|
||||
src/config.o src/ipxconfig_stubs.o src/funcprof.o inih/ini.o
|
||||
src/config.o src/ipxconfig_stubs.o src/funcprof.o src/snprintf.o inih/ini.o
|
||||
|
||||
ipxconfig.exe: $(IPXCONFIG_OBJS)
|
||||
$(CXX) $(CXXFLAGS) -Wl,--enable-stdcall-fixup -static-libgcc -static-libstdc++ -mwindows -o $@ $^ -liphlpapi -lcomctl32 -lws2_32
|
||||
@ -167,21 +167,21 @@ test-prep: $(TESTS) $(TOOLS) $(TOOL_DLLS)
|
||||
|
||||
.PHONY: tools test-prep
|
||||
|
||||
tests/addr.exe: tests/addr.o tests/tap/basic.o src/addr.o
|
||||
tests/addrcache.exe: tests/addrcache.o tests/tap/basic.o src/addrcache.o src/addr.o
|
||||
tests/ethernet.exe: tests/ethernet.o tests/tap/basic.o src/ethernet.o src/addr.o
|
||||
tests/addr.exe: tests/addr.o tests/tap/basic.o src/addr.o src/snprintf.o
|
||||
tests/addrcache.exe: tests/addrcache.o tests/tap/basic.o src/addrcache.o src/addr.o src/common.o src/snprintf.o
|
||||
tests/ethernet.exe: tests/ethernet.o tests/tap/basic.o src/ethernet.o src/addr.o src/snprintf.o
|
||||
|
||||
tests/%.exe: tests/%.o
|
||||
tests/%.exe: tests/%.o src/snprintf.o
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lwsock32
|
||||
|
||||
tests/%.o: tests/%.c
|
||||
$(CC) $(CFLAGS) $(DEPFLAGS) -I./ -c -o $@ $<
|
||||
$(DEPPOST)
|
||||
|
||||
tools/fionread.exe: tests/fionread.o tests/tap/basic.o src/addr.o
|
||||
tools/fionread.exe: tests/fionread.o tests/tap/basic.o src/addr.o src/snprintf.o
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lwsock32
|
||||
|
||||
tools/%.exe: tools/%.o src/addr.o
|
||||
tools/%.exe: tools/%.o src/addr.o src/snprintf.o
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lwsock32 -lole32 -lrpcrt4
|
||||
|
||||
tools/%.o: tools/%.c
|
||||
|
74
include/snprintf.h
Normal file
74
include/snprintf.h
Normal file
@ -0,0 +1,74 @@
|
||||
// Copyright (C) 2019 Miroslaw Toton, mirtoto@gmail.com
|
||||
#ifndef SNPRINTF_H_
|
||||
#define SNPRINTF_H_
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/** @see snprintf() */
|
||||
int mirtoto_vsnprintf(char *string, size_t length, const char *format, va_list args) __attribute__((format(printf, 3, 0)));
|
||||
|
||||
/**
|
||||
* Implementation of snprintf() function which create @p string of maximum
|
||||
* @p length - 1 according of instruction provided by @p format.
|
||||
*
|
||||
* # Supportted types
|
||||
*
|
||||
* Type | Description
|
||||
* -------- | ----------------------------------------
|
||||
* d / i | signed decimal integer
|
||||
* u | unsigned decimal integer
|
||||
* o | unsigned octal integer
|
||||
* x | unsigned hexadecimal integer
|
||||
* f / F | decimal floating point
|
||||
* e / E | scientific (exponential) floating point
|
||||
* g / G | scientific or decimal floating point
|
||||
* c | character
|
||||
* s | string
|
||||
* p | pointer
|
||||
* % | percent character
|
||||
*
|
||||
* # Supported lengths
|
||||
*
|
||||
* Length | Description
|
||||
* -------- | ----------------------------------------
|
||||
* hh | signed / unsigned char
|
||||
* h | signed / unsigned short
|
||||
* l | signed / unsigned long
|
||||
* ll | signed / unsigned long long
|
||||
*
|
||||
* # Supported flags
|
||||
*
|
||||
* Flag | Description
|
||||
* -------- | ----------------------------------------
|
||||
* - | justify left
|
||||
* + | justify right or put a plus if number
|
||||
* # | prefix 0x, 0X for hex and 0 for octal
|
||||
* * | width and/or precision is specified as an int argument
|
||||
* 0 | for number padding with zeros instead of spaces
|
||||
* (space) | leave a blank for number with no sign
|
||||
*
|
||||
* @param string Output buffer.
|
||||
* @param length Size of output buffer @p string.
|
||||
* @param format Format of input parameters.
|
||||
* @param ... Input parameters according of @p format.
|
||||
*
|
||||
* @retval >=0 Amount of characters put in @p string.
|
||||
* @retval -1 Output buffer size is too small.
|
||||
*/
|
||||
int mirtoto_snprintf(char *string, size_t length, const char *format, ...) __attribute__((format(printf, 3, 4)));
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif // SNPRINTF_H_
|
11
src/addr.c
11
src/addr.c
@ -1,5 +1,5 @@
|
||||
/* ipxwrapper - Address manipulation functions
|
||||
* Copyright (C) 2012-2014 Daniel Collins <solemnwarning@solemnwarning.net>
|
||||
* Copyright (C) 2012-2024 Daniel Collins <solemnwarning@solemnwarning.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
@ -22,6 +22,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <snprintf.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "addr.h"
|
||||
@ -70,8 +71,9 @@ char *addr32_string(char *buf, addr32_t addr)
|
||||
unsigned char c[6];
|
||||
addr32_out(c, addr);
|
||||
|
||||
sprintf(
|
||||
mirtoto_snprintf(
|
||||
buf,
|
||||
ADDR32_STRING_SIZE,
|
||||
|
||||
"%02X:%02X:%02X:%02X",
|
||||
|
||||
@ -112,8 +114,9 @@ char *addr48_string(char *buf, addr48_t addr)
|
||||
unsigned char c[6];
|
||||
addr48_out(c, addr);
|
||||
|
||||
sprintf(
|
||||
mirtoto_snprintf(
|
||||
buf,
|
||||
ADDR48_STRING_SIZE,
|
||||
|
||||
"%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
|
||||
@ -149,7 +152,7 @@ void ipx_to_string(char *buf, addr32_t net, addr48_t node, uint16_t sock)
|
||||
addr48_string(buf + 12, node);
|
||||
buf[29] = '/';
|
||||
|
||||
sprintf(buf + 30, "%hu", ntohs(sock));
|
||||
mirtoto_snprintf(buf + 30, IPX_SADDR_SIZE - 30, "%hu", ntohs(sock));
|
||||
}
|
||||
|
||||
/* Generate a (probably) unique locally-administered MAC address. */
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <snprintf.h>
|
||||
|
||||
#include "ipxwrapper.h"
|
||||
#include "common.h"
|
||||
@ -84,10 +85,10 @@ void log_printf(enum ipx_log_level level, const char *fmt, ...) {
|
||||
char msg[1024], tstr[64];
|
||||
|
||||
va_start(argv, fmt);
|
||||
vsnprintf(msg, 1024, fmt, argv);
|
||||
mirtoto_vsnprintf(msg, 1024, fmt, argv);
|
||||
va_end(argv);
|
||||
|
||||
snprintf(tstr, 64, "[%u.%02u, thread %u] ", (unsigned int)(called/1000), (unsigned int)((called % 1000) / 10), (unsigned int)GetCurrentThreadId());
|
||||
mirtoto_snprintf(tstr, 64, "[%u.%02u, thread %u] ", (unsigned int)(called/1000), (unsigned int)((called % 1000) / 10), (unsigned int)GetCurrentThreadId());
|
||||
|
||||
OVERLAPPED off;
|
||||
off.Offset = 0;
|
||||
|
981
src/snprintf.c
Normal file
981
src/snprintf.c
Normal file
@ -0,0 +1,981 @@
|
||||
// Copyright (C) 2019 Miroslaw Toton, mirtoto@gmail.com
|
||||
|
||||
/**
|
||||
* Unix snprintf() implementation.
|
||||
* @version 2.3
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Revision History:
|
||||
*
|
||||
* @version 2.3
|
||||
* @author Miroslaw Toton (mirtoto), mirtoto@gmail.com
|
||||
* - support NULL as output buffer to calculate size of output string
|
||||
* - fix 0 precision for 0 value integers
|
||||
*
|
||||
* @version 2.2
|
||||
* @author Miroslaw Toton (mirtoto), mirtoto@gmail.com
|
||||
* - fix precision for integers
|
||||
* - remove global buffers and unnecessary copying & lookin through srings
|
||||
* - cleanup code and add Doxygen style comments
|
||||
*
|
||||
* @version 2.1
|
||||
* @author Miroslaw Toton (mirtoto), mirtoto@gmail.com
|
||||
* - fix problem with very big and very low "long long" values
|
||||
* - change exponent width from 3 to 2
|
||||
* - fix zero value for floating
|
||||
* - support for "p" (%p)
|
||||
*
|
||||
* @version 2.0
|
||||
* @author Miroslaw Toton (mirtoto), mirtoto@gmail.com
|
||||
* - move all defines & macros from header to codefile
|
||||
* - support for "long long" (%llu, %lld, %llo, %llx)
|
||||
* - fix for interpreting precision in some situations
|
||||
* - fix unsigned (%u) for negative input
|
||||
* - fix h & hh length of input number specifier
|
||||
* - fix Clang linter warnings
|
||||
*
|
||||
* @version 1.1
|
||||
* @author Alain Magloire, alainm@rcsm.ee.mcgill.ca
|
||||
* - added changes from Miles Bader
|
||||
* - corrected a bug with %f
|
||||
* - added support for %#g
|
||||
* - added more comments :-)
|
||||
*
|
||||
* @version 1.0
|
||||
* @author Alain Magloire, alainm@rcsm.ee.mcgill.ca
|
||||
* - supporting must ANSI syntaxic_sugars (see below)
|
||||
*
|
||||
* @version 0.0
|
||||
* @author Alain Magloire, alainm@rcsm.ee.mcgill.ca
|
||||
* - suppot %s %c %d
|
||||
*
|
||||
* For the floating point format the challenge was finding a way to
|
||||
* manipulate the Real numbers without having to resort to mathematical
|
||||
* function (it would require to link with -lm) and not going down
|
||||
* to the bit pattern (not portable).
|
||||
*
|
||||
* So a number, a real is:
|
||||
*
|
||||
* real = integral + fraction
|
||||
*
|
||||
* integral = ... + a(2)*10^2 + a(1)*10^1 + a(0)*10^0
|
||||
* fraction = b(1)*10^-1 + b(2)*10^-2 + ...
|
||||
*
|
||||
* where:
|
||||
* 0 <= a(i) => 9
|
||||
* 0 <= b(i) => 9
|
||||
*
|
||||
* from then it was simple math
|
||||
*
|
||||
* THANKS (for the patches and ideas):
|
||||
* - Miles Bader
|
||||
* - Cyrille Rustom
|
||||
* - Jacek Slabocewiz
|
||||
* - Mike Parker (mouse)
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "snprintf.h"
|
||||
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wextra-semi-stmt"
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* This struct holds temporary data during processing @p format
|
||||
* of vsnprintf()/snprintf() functions.
|
||||
*/
|
||||
struct DATA {
|
||||
size_t counter; /**< counter of length of string in DATA::ps */
|
||||
size_t ps_size; /**< size of DATA::ps - 1 */
|
||||
char *ps; /**< pointer to output string */
|
||||
const char *pf; /**< pointer to input format string */
|
||||
|
||||
/** Value of DATA::width - undefined width of field. */
|
||||
#define WIDTH_UNSET -1
|
||||
|
||||
int width; /**< width of field */
|
||||
|
||||
/** Value of DATA::precision - undefined precision of field. */
|
||||
#define PRECISION_UNSET -1
|
||||
|
||||
int precision;
|
||||
|
||||
/** Value of DATA::align - undefined align of field. */
|
||||
#define ALIGN_UNSET 0
|
||||
/** Value of DATA::align - align right of field. */
|
||||
#define ALIGN_RIGHT 1
|
||||
/** Value of DATA::align - align left of field. */
|
||||
#define ALIGN_LEFT 2
|
||||
|
||||
unsigned int align:2; /**< align of field */
|
||||
unsigned int is_square:1; /**< is field with hash flag? */
|
||||
unsigned int is_space:1; /**< is field with space flag? */
|
||||
unsigned int is_dot:1; /**< is field with dot flag? */
|
||||
unsigned int is_star_w:1; /**< is field with width defined? */
|
||||
unsigned int is_star_p:1; /**< is field with precision defined? */
|
||||
|
||||
/** Value of DATA::a_long - "int" type of input argument. */
|
||||
#define INT_LEN_DEFAULT 0
|
||||
/** Value of DATA::a_long - "long" type of input argument. */
|
||||
#define INT_LEN_LONG 1
|
||||
/** Value of DATA::a_long - "long long" of input type argument. */
|
||||
#define INT_LEN_LONG_LONG 2
|
||||
/** Value of DATA::a_long - "short" type of input argument. */
|
||||
#define INT_LEN_SHORT 3
|
||||
/** Value of DATA::a_long - "char" type of input argument. */
|
||||
#define INT_LEN_CHAR 4
|
||||
|
||||
unsigned int a_long:3; /**< type of input */
|
||||
|
||||
unsigned int rfu:6; /**< RFU */
|
||||
|
||||
char pad; /**< padding character */
|
||||
|
||||
char slop[5]; /**< RFU */
|
||||
};
|
||||
|
||||
/** Round off to the precision. */
|
||||
#define ROUND_TO_PRECISION(d, p) \
|
||||
((d < 0.) ? d - pow_10(-(p)->precision) * 0.5 : d + pow_10(-(p)->precision) * 0.5)
|
||||
|
||||
/** Put a @p c character to output buffer if there is enough space. */
|
||||
#define PUT_CHAR(c, p) \
|
||||
if ((p)->counter < (p)->ps_size) { \
|
||||
if ((p)->ps != NULL) { \
|
||||
*(p)->ps++ = (c); \
|
||||
} \
|
||||
(p)->counter++; \
|
||||
}
|
||||
|
||||
/** Put optionally '+' character to to output buffer if there is enough space. */
|
||||
#define PUT_PLUS(d, p) \
|
||||
if ((d) > 0 && (p)->align == ALIGN_RIGHT) { \
|
||||
PUT_CHAR('+', p); \
|
||||
}
|
||||
|
||||
/** Put optionally ' ' character to to output buffer if there is enough space. */
|
||||
#define PUT_SPACE(d, p) \
|
||||
if ((p)->is_space && (d) > 0) { \
|
||||
PUT_CHAR(' ', p); \
|
||||
}
|
||||
|
||||
/** Padding right optionally. */
|
||||
#define PAD_RIGHT(p) \
|
||||
if ((p)->width > 0 && (p)->align != ALIGN_LEFT) { \
|
||||
for (; (p)->width > 0; (p)->width--) { \
|
||||
PUT_CHAR((p)->pad, p); \
|
||||
} \
|
||||
}
|
||||
|
||||
/** Padding left optionally. */
|
||||
#define PAD_LEFT(p) \
|
||||
if ((p)->width > 0 && (p)->align == ALIGN_LEFT) { \
|
||||
for (; (p)->width > 0; (p)->width--) { \
|
||||
PUT_CHAR((p)->pad, p); \
|
||||
} \
|
||||
}
|
||||
|
||||
/** Get width and precision arguments if available. */
|
||||
#define WIDTH_AND_PRECISION_ARGS(p) \
|
||||
if ((p)->is_star_w) { \
|
||||
(p)->width = va_arg(args, int); \
|
||||
} \
|
||||
if ((p)->is_star_p) { \
|
||||
(p)->precision = va_arg(args, int); \
|
||||
}
|
||||
|
||||
/** Get integer argument of given type and convert it to long long. */
|
||||
#define INTEGER_ARG(p, type, ll) \
|
||||
WIDTH_AND_PRECISION_ARGS(p); \
|
||||
if ((p)->a_long == INT_LEN_LONG_LONG) { \
|
||||
ll = (long long)va_arg(args, type long long); \
|
||||
} else if ((p)->a_long == INT_LEN_LONG) { \
|
||||
ll = (long long)va_arg(args, type long); \
|
||||
} else { \
|
||||
type int a = va_arg(args, type int); \
|
||||
if ((p)->a_long == INT_LEN_SHORT) { \
|
||||
ll = (type short)a; \
|
||||
} else if ((p)->a_long == INT_LEN_CHAR) { \
|
||||
ll = (type char)a; \
|
||||
} else { \
|
||||
ll = a; \
|
||||
} \
|
||||
}
|
||||
|
||||
/** Get double argument. */
|
||||
#define DOUBLE_ARG(p, d) \
|
||||
WIDTH_AND_PRECISION_ARGS(p); \
|
||||
if ((p)->precision == PRECISION_UNSET) { \
|
||||
(p)->precision = 6; \
|
||||
} \
|
||||
d = va_arg(args, double);
|
||||
|
||||
/**
|
||||
* Convert maximum @p n characters of @p a string to integer.
|
||||
*
|
||||
* Function stop conversion and return result in any of the following cases:
|
||||
* - encounter end of string ('\0') character,
|
||||
* - encounter non digit character,
|
||||
* - reach @p n characters.
|
||||
*
|
||||
* @return Integer (as type 'int') representation of @p a.
|
||||
*
|
||||
static int antoi(const char *a, size_t n) {
|
||||
size_t i = 0;
|
||||
int res = 0;
|
||||
|
||||
for (; a[i] != '\0' && i < n && isdigit(a[i]); i++) {
|
||||
res = res * 10 + (a[i] - '0');
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Convert @p a string to @p res integer.
|
||||
*
|
||||
* Function stop conversion and return result in any of the following cases:
|
||||
* - encounter end of string ('\0') character,
|
||||
* - encounter non digit character.
|
||||
*
|
||||
* @param a Not NULL input string.
|
||||
* @param res Not NULL pointer to output integer.
|
||||
*
|
||||
* @return Number of parsed character form @p a.
|
||||
*/
|
||||
static int strtoi(const char *a, int *res) {
|
||||
int i = 0;
|
||||
|
||||
*res = 0;
|
||||
|
||||
for (; a[i] != '\0' && isdigit(a[i]); i++) {
|
||||
*res = *res * 10 + (a[i] - '0');
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert @p number to string representation of given @p base.
|
||||
*
|
||||
* @param number Input number to conversion.
|
||||
* @param is_signed Interpret @p number as 'unsigned' (0) / 'signed' (1).
|
||||
* @param precision Input @p number precision.
|
||||
* @param base Output base (8, 10, 16).
|
||||
* @param output Buffer for output string.
|
||||
* @param output_size Size of @p optput buffer (at least 3 characters).
|
||||
*/
|
||||
static void inttoa(long long number, int is_signed, int precision, int base,
|
||||
char *output, size_t output_size) {
|
||||
size_t i = 0, j;
|
||||
|
||||
output_size--; /* for '\0' character */
|
||||
|
||||
if (number != 0) {
|
||||
unsigned long long n;
|
||||
|
||||
if (is_signed && number < 0) {
|
||||
n = (unsigned long long)-number;
|
||||
output_size--; /* for '-' character */
|
||||
} else {
|
||||
n = (unsigned long long)number;
|
||||
}
|
||||
|
||||
while (n != 0 && i < output_size) {
|
||||
int r = (int)(n % (unsigned long long)(base));
|
||||
output[i++] = (char)r + (r < 10 ? '0' : 'a' - 10);
|
||||
n /= (unsigned long long)(base);
|
||||
}
|
||||
|
||||
if (precision > 0) { /* precision defined ? */
|
||||
for (; i < (size_t)precision && i < output_size; i++) {
|
||||
output[i] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
/* put the sign ? */
|
||||
if (is_signed && number < 0) {
|
||||
output[i++] = '-';
|
||||
}
|
||||
|
||||
output[i] = '\0';
|
||||
|
||||
/* reverse every thing */
|
||||
for (i--, j = 0; j < i; j++, i--) {
|
||||
char tmp = output[i];
|
||||
output[i] = output[j];
|
||||
output[j] = tmp;
|
||||
}
|
||||
} else {
|
||||
precision = precision < 0 ? 1 : precision;
|
||||
for (i = 0; i < (size_t)precision && i < output_size; i++) {
|
||||
output[i] = '0';
|
||||
}
|
||||
output[i] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/** Find the nth power of 10. */
|
||||
static double pow_10(int n) {
|
||||
int i = 1;
|
||||
double p = 1., m;
|
||||
|
||||
if (n < 0) {
|
||||
n = -n;
|
||||
m = .1;
|
||||
} else {
|
||||
m = 10.;
|
||||
}
|
||||
|
||||
for (; i <= n; i++) {
|
||||
p *= m;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function find the integral part of the log in base 10.
|
||||
*
|
||||
* @note This not a real log10().
|
||||
* I just need and approximation (integerpart) of x in:
|
||||
* 10^x ~= r
|
||||
*
|
||||
* log_10(200) = 2;
|
||||
* log_10(250) = 2;
|
||||
*/
|
||||
static int log_10(double r) {
|
||||
int i = 0;
|
||||
double result = 1.;
|
||||
|
||||
if (r == 0.) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (r < 0.) {
|
||||
r = -r;
|
||||
}
|
||||
|
||||
if (r < 1.) {
|
||||
for (; result >= r; i++) {
|
||||
result *= .1;
|
||||
}
|
||||
|
||||
i = -i;
|
||||
} else {
|
||||
for (; result <= r; i++) {
|
||||
result *= 10.;
|
||||
}
|
||||
|
||||
--i;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function return the fraction part of a @p real and set in @p ip the integral
|
||||
* part. In many ways it resemble the modf() found on most Un*x.
|
||||
*/
|
||||
static double integral(double real, double *ip) {
|
||||
int log;
|
||||
double real_integral = 0.;
|
||||
|
||||
/* equal to zero ? */
|
||||
if (real == 0.) {
|
||||
*ip = 0.;
|
||||
return 0.;
|
||||
}
|
||||
|
||||
/* negative number ? */
|
||||
if (real < 0.) {
|
||||
real = -real;
|
||||
}
|
||||
|
||||
/* a fraction ? */
|
||||
if (real < 1.) {
|
||||
*ip = 0.;
|
||||
return real;
|
||||
}
|
||||
|
||||
/* the real work :-) */
|
||||
for (log = log_10(real); log >= 0; log--) {
|
||||
double i = 0., p = pow_10(log);
|
||||
double s = (real - real_integral) / p;
|
||||
for (; i + 1. <= s; i++) {}
|
||||
real_integral += i * p;
|
||||
}
|
||||
|
||||
*ip = real_integral;
|
||||
return (real - real_integral);
|
||||
}
|
||||
|
||||
/** Maximum size of the buffer for the integral part. */
|
||||
#define MAX_INTEGRAL_SIZE (99 + 1)
|
||||
/** Maximum size of the buffer for the fraction part. */
|
||||
#define MAX_FRACTION_SIZE (29 + 1)
|
||||
/** Precision. */
|
||||
#define PRECISION (1.e-6)
|
||||
|
||||
/**
|
||||
* Return an ASCII representation of the integral and fraction
|
||||
* part of the @p number.
|
||||
*/
|
||||
static void floattoa(double number, int precision,
|
||||
char *output_integral, size_t output_integral_size,
|
||||
char *output_fraction, size_t output_fraction_size) {
|
||||
|
||||
size_t i, j;
|
||||
int is_negative = 0;
|
||||
double ip, fp; /* integer and fraction part */
|
||||
double fraction;
|
||||
|
||||
/* taking care of the obvious case: 0.0 */
|
||||
if (number == 0.) {
|
||||
output_integral[0] = output_fraction[0] = '0';
|
||||
output_integral[1] = output_fraction[1] = '\0';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* for negative numbers */
|
||||
if (number < 0.) {
|
||||
number = -number;
|
||||
is_negative = 1;
|
||||
output_integral_size--; /* sign consume one digit */
|
||||
}
|
||||
|
||||
fraction = integral(number, &ip);
|
||||
number = ip;
|
||||
/* do the integral part */
|
||||
if (ip == 0.) {
|
||||
output_integral[0] = '0';
|
||||
i = 1;
|
||||
} else {
|
||||
for (i = 0; i < output_integral_size - 1 && number != 0.; ++i) {
|
||||
number /= 10;
|
||||
/* force to round */
|
||||
output_integral[i] = (char)((integral(number, &ip) + PRECISION) * 10) + '0';
|
||||
if (!isdigit(output_integral[i])) { /* bail out overflow !! */
|
||||
break;
|
||||
}
|
||||
number = ip;
|
||||
}
|
||||
}
|
||||
|
||||
/* Oh No !! out of bound, ho well fill it up ! */
|
||||
if (number != 0.) {
|
||||
for (i = 0; i < output_integral_size - 1; ++i) {
|
||||
output_integral[i] = '9';
|
||||
}
|
||||
}
|
||||
|
||||
/* put the sign ? */
|
||||
if (is_negative) {
|
||||
output_integral[i++] = '-';
|
||||
}
|
||||
|
||||
output_integral[i] = '\0';
|
||||
|
||||
/* reverse every thing */
|
||||
for (i--, j = 0; j < i; j++, i--) {
|
||||
char tmp = output_integral[i];
|
||||
output_integral[i] = output_integral[j];
|
||||
output_integral[j] = tmp;
|
||||
}
|
||||
|
||||
/* the fractional part */
|
||||
for (i = 0, fp = fraction; precision > 0 && i < output_fraction_size - 1; i++, precision--) {
|
||||
output_fraction[i] = (char)(int)((fp + PRECISION) * 10. + '0');
|
||||
if (!isdigit(output_fraction[i])) { /* underflow ? */
|
||||
break;
|
||||
}
|
||||
|
||||
fp = (fp * 10.0) - (double)(long)((fp + PRECISION) * 10.);
|
||||
}
|
||||
output_fraction[i] = '\0';
|
||||
}
|
||||
|
||||
/** Format @p ll number as ASCII decimal string according to @p p flags. */
|
||||
static void decimal(struct DATA *p, long long ll) {
|
||||
char number[MAX_INTEGRAL_SIZE], *pnumber = number;
|
||||
inttoa(ll, *p->pf == 'i' || *p->pf == 'd', p->precision, 10,
|
||||
number, sizeof(number));
|
||||
|
||||
p->width -= strlen(number);
|
||||
PAD_RIGHT(p);
|
||||
|
||||
PUT_PLUS(ll, p);
|
||||
PUT_SPACE(ll, p);
|
||||
|
||||
for (; *pnumber != '\0'; pnumber++) {
|
||||
PUT_CHAR(*pnumber, p);
|
||||
}
|
||||
|
||||
PAD_LEFT(p);
|
||||
}
|
||||
|
||||
/** Format @p ll number as ASCII octal string according to @p p flags. */
|
||||
static void octal(struct DATA *p, long long ll) {
|
||||
char number[MAX_INTEGRAL_SIZE], *pnumber = number;
|
||||
inttoa(ll, 0, p->precision, 8, number, sizeof(number));
|
||||
|
||||
p->width -= strlen(number);
|
||||
PAD_RIGHT(p);
|
||||
|
||||
if (p->is_square && *number != '\0') { /* prefix '0' for octal */
|
||||
PUT_CHAR('0', p);
|
||||
}
|
||||
|
||||
for (; *pnumber != '\0'; pnumber++) {
|
||||
PUT_CHAR(*pnumber, p);
|
||||
}
|
||||
|
||||
PAD_LEFT(p);
|
||||
}
|
||||
|
||||
/** Format @p ll number as ASCII hexadecimal string according to @p p flags. */
|
||||
static void hex(struct DATA *p, long long ll) {
|
||||
char number[MAX_INTEGRAL_SIZE], *pnumber = number;
|
||||
inttoa(ll, 0, p->precision, 16, number, sizeof(number));
|
||||
|
||||
p->width -= strlen(number);
|
||||
PAD_RIGHT(p);
|
||||
|
||||
if (p->is_square && *number != '\0') { /* prefix '0x' for hex */
|
||||
PUT_CHAR('0', p);
|
||||
PUT_CHAR(*p->pf == 'p' ? 'x' : *p->pf, p);
|
||||
}
|
||||
|
||||
for (; *pnumber != '\0'; pnumber++) {
|
||||
PUT_CHAR((*p->pf == 'X' ? (char)toupper(*pnumber) : *pnumber), p);
|
||||
}
|
||||
|
||||
PAD_LEFT(p);
|
||||
}
|
||||
|
||||
/** Format @p str string according to @p p flags. */
|
||||
static void strings(struct DATA *p, char *s) {
|
||||
int len = (int)strlen(s);
|
||||
if (p->precision != PRECISION_UNSET && len > p->precision) { /* the smallest number */
|
||||
len = p->precision;
|
||||
}
|
||||
|
||||
p->width -= len;
|
||||
|
||||
PAD_RIGHT(p);
|
||||
|
||||
for (; len-- > 0; s++) {
|
||||
PUT_CHAR(*s, p);
|
||||
}
|
||||
|
||||
PAD_LEFT(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format @p d floating point number as ASCII decimal floating point
|
||||
* according to @p p flags.
|
||||
*/
|
||||
static void floating(struct DATA *p, double d) {
|
||||
char integral[MAX_INTEGRAL_SIZE], *pintegral = integral;
|
||||
char fraction[MAX_FRACTION_SIZE], *pfraction = fraction;
|
||||
|
||||
d = ROUND_TO_PRECISION(d, p);
|
||||
floattoa(d, p->precision,
|
||||
integral, sizeof(integral), fraction, sizeof(fraction));
|
||||
|
||||
/* calculate the padding. 1 for the dot */
|
||||
if (d > 0. && p->align == ALIGN_RIGHT) {
|
||||
p->width -= 1;
|
||||
}
|
||||
p->width -= p->is_space + (int)strlen(integral) + p->precision + 1;
|
||||
if (p->precision == 0) {
|
||||
p->width += 1;
|
||||
}
|
||||
|
||||
PAD_RIGHT(p);
|
||||
PUT_PLUS(d, p);
|
||||
PUT_SPACE(d, p);
|
||||
|
||||
for (; *pintegral != '\0'; pintegral++) {
|
||||
PUT_CHAR(*pintegral, p);
|
||||
}
|
||||
|
||||
if (p->precision != 0 || p->is_square) { /* put the '.' */
|
||||
PUT_CHAR('.', p);
|
||||
}
|
||||
|
||||
if (*p->pf == 'g' || *p->pf == 'G') { /* smash the trailing zeros */
|
||||
size_t i;
|
||||
for (i = strlen(fraction); i > 0 && fraction[i - 1] == '0'; i--) {
|
||||
fraction[i - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
for (; *pfraction != '\0'; pfraction++) {
|
||||
PUT_CHAR(*pfraction, p);
|
||||
}
|
||||
|
||||
PAD_LEFT(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format @p d floating point number as ASCII scientific (exponential)
|
||||
* floating point according to @p p flags.
|
||||
*/
|
||||
static void exponent(struct DATA *p, double d) {
|
||||
char integral[MAX_INTEGRAL_SIZE], *pintegral = integral;
|
||||
char fraction[MAX_FRACTION_SIZE], *pfraction = fraction;
|
||||
int log = log_10(d);
|
||||
d /= pow_10(log); /* get the Mantissa */
|
||||
d = ROUND_TO_PRECISION(d, p);
|
||||
|
||||
floattoa(d, p->precision,
|
||||
integral, sizeof(integral), fraction, sizeof(fraction));
|
||||
/* 1 for unit, 1 for the '.', 1 for 'e|E',
|
||||
* 1 for '+|-', 2 for 'exp' */
|
||||
/* calculate how much padding need */
|
||||
if (d > 0. && p->align == ALIGN_RIGHT) {
|
||||
p->width -= 1;
|
||||
}
|
||||
p->width -= p->is_space + p->precision + 7;
|
||||
|
||||
PAD_RIGHT(p);
|
||||
PUT_PLUS(d, p);
|
||||
PUT_SPACE(d, p);
|
||||
|
||||
for (; *pintegral != '\0'; pintegral++) {
|
||||
PUT_CHAR(*pintegral, p);
|
||||
}
|
||||
|
||||
if (p->precision != 0 || p->is_square) { /* the '.' */
|
||||
PUT_CHAR('.', p);
|
||||
}
|
||||
|
||||
if (*p->pf == 'g' || *p->pf == 'G') { /* smash the trailing zeros */
|
||||
size_t i;
|
||||
for (i = strlen(fraction); i > 0 && fraction[i - 1] == '0'; i--) {
|
||||
fraction[i - 1] = '\0';
|
||||
}
|
||||
}
|
||||
for (; *pfraction != '\0'; pfraction++) {
|
||||
PUT_CHAR(*pfraction, p);
|
||||
}
|
||||
|
||||
if (*p->pf == 'g' || *p->pf == 'e') { /* the exponent put the 'e|E' */
|
||||
PUT_CHAR('e', p);
|
||||
} else {
|
||||
PUT_CHAR('E', p);
|
||||
}
|
||||
|
||||
if (log >= 0) { /* the sign of the exp */
|
||||
PUT_CHAR('+', p);
|
||||
}
|
||||
|
||||
inttoa(log, 1, 2, 10, integral, sizeof(integral));
|
||||
for (pintegral = integral; *pintegral != '\0'; pintegral++) { /* exponent */
|
||||
PUT_CHAR(*pintegral, p);
|
||||
}
|
||||
|
||||
PAD_LEFT(p);
|
||||
}
|
||||
|
||||
/** Initialize and parse the conversion specifiers. */
|
||||
static void conv_flags(struct DATA *p) {
|
||||
p->width = WIDTH_UNSET;
|
||||
p->precision = PRECISION_UNSET;
|
||||
p->is_star_w = p->is_star_p = 0;
|
||||
p->is_square = p->is_space = 0;
|
||||
p->a_long = INT_LEN_DEFAULT;
|
||||
p->align = ALIGN_UNSET;
|
||||
p->pad = ' ';
|
||||
p->is_dot = 0;
|
||||
|
||||
for (; p != NULL && p->pf != NULL; p->pf++) {
|
||||
switch (*p->pf) {
|
||||
case ' ':
|
||||
p->is_space = 1;
|
||||
break;
|
||||
|
||||
case '#':
|
||||
p->is_square = 1;
|
||||
break;
|
||||
|
||||
case '*':
|
||||
if (p->width == WIDTH_UNSET) {
|
||||
p->width = 1;
|
||||
p->is_star_w = 1;
|
||||
} else {
|
||||
p->precision = 1;
|
||||
p->is_star_p = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case '+':
|
||||
p->align = ALIGN_RIGHT;
|
||||
break;
|
||||
|
||||
case '-':
|
||||
p->align = ALIGN_LEFT;
|
||||
break;
|
||||
|
||||
case '.':
|
||||
if (p->width == WIDTH_UNSET) {
|
||||
p->width = 0;
|
||||
}
|
||||
p->is_dot = 1;
|
||||
break;
|
||||
|
||||
case '0':
|
||||
p->pad = '0';
|
||||
if (p->is_dot) {
|
||||
p->precision = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9': /* get all the digits */
|
||||
p->pf += strtoi(p->pf,
|
||||
p->width == WIDTH_UNSET ? &p->width : &p->precision) - 1;
|
||||
break;
|
||||
|
||||
case '%':
|
||||
return;
|
||||
|
||||
default:
|
||||
p->pf--; /* went to far go back */
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int mirtoto_vsnprintf(char *string, size_t length, const char *format, va_list args) {
|
||||
struct DATA data;
|
||||
|
||||
/* calculate only size of output string */
|
||||
if (string == NULL) {
|
||||
length = __SIZE_MAX__;
|
||||
/* sanity check, the string must be > 1 */
|
||||
} else if (length < 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
data.ps_size = length - 1; /* leave room for '\0' */
|
||||
data.ps = string;
|
||||
data.pf = format;
|
||||
data.counter = 0;
|
||||
|
||||
for (; *data.pf != '\0' && (data.counter < data.ps_size); data.pf++) {
|
||||
if (*data.pf == '%') { /* we got a magic % cookie */
|
||||
int is_continue = 1;
|
||||
conv_flags(&data); /* initialise format flags */
|
||||
while (*data.pf != '\0' && is_continue) {
|
||||
switch (*(++data.pf)) {
|
||||
case '\0': /* a NULL here ? ? bail out */
|
||||
PUT_CHAR('%', &data);
|
||||
if (data.ps != NULL) {
|
||||
*data.ps = '\0';
|
||||
}
|
||||
return (int)data.counter;
|
||||
|
||||
case 'f':
|
||||
case 'F': { /* decimal floating point */
|
||||
double d;
|
||||
DOUBLE_ARG(&data, d);
|
||||
floating(&data, d);
|
||||
is_continue = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'e':
|
||||
case 'E': { /* scientific (exponential) floating point */
|
||||
double d;
|
||||
DOUBLE_ARG(&data, d);
|
||||
exponent(&data, d);
|
||||
is_continue = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'g':
|
||||
case 'G': { /* scientific or decimal floating point */
|
||||
int log;
|
||||
double d;
|
||||
DOUBLE_ARG(&data, d);
|
||||
log = log_10(d);
|
||||
/* use decimal floating point (%f / %F) if exponent is in the range
|
||||
[-4,precision] exclusively else use scientific floating
|
||||
point (%e / %E) */
|
||||
if (-4 < log && log < data.precision) {
|
||||
floating(&data, d);
|
||||
} else {
|
||||
exponent(&data, d);
|
||||
}
|
||||
is_continue = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'u': { /* unsigned decimal integer */
|
||||
long long ll;
|
||||
INTEGER_ARG(&data, unsigned, ll);
|
||||
decimal(&data, ll);
|
||||
is_continue = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'i':
|
||||
case 'd': { /* signed decimal integer */
|
||||
long long ll;
|
||||
INTEGER_ARG(&data, signed, ll);
|
||||
decimal(&data, ll);
|
||||
is_continue = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'o': { /* octal (always unsigned) */
|
||||
long long ll;
|
||||
INTEGER_ARG(&data, unsigned, ll);
|
||||
octal(&data, ll);
|
||||
is_continue = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'x':
|
||||
case 'X': { /* hexadecimal (always unsigned) */
|
||||
long long ll;
|
||||
INTEGER_ARG(&data, unsigned, ll);
|
||||
hex(&data, ll);
|
||||
is_continue = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'c': { /* single character */
|
||||
int i = va_arg(args, int);
|
||||
PUT_CHAR((char)i, &data);
|
||||
is_continue = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 's': /* string of characters */
|
||||
WIDTH_AND_PRECISION_ARGS(&data);
|
||||
strings(&data, va_arg(args, char *));
|
||||
is_continue = 0;
|
||||
break;
|
||||
|
||||
case 'p': { /* pointer */
|
||||
void *v = va_arg(args, void *);
|
||||
data.is_square = 1;
|
||||
if (v == NULL) {
|
||||
strings(&data, "(nil)");
|
||||
} else {
|
||||
hex(&data, (long long)v);
|
||||
}
|
||||
is_continue = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'n': /* what's the count ? */
|
||||
*(va_arg(args, int *)) = (int)data.counter;
|
||||
is_continue = 0;
|
||||
break;
|
||||
|
||||
case 'l': /* long or long long */
|
||||
if (data.a_long == INT_LEN_LONG) {
|
||||
data.a_long = INT_LEN_LONG_LONG;
|
||||
} else {
|
||||
data.a_long = INT_LEN_LONG;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'h': /* short or char */
|
||||
if (data.a_long == INT_LEN_SHORT) {
|
||||
data.a_long = INT_LEN_CHAR;
|
||||
} else {
|
||||
data.a_long = INT_LEN_SHORT;
|
||||
}
|
||||
break;
|
||||
|
||||
case '%': /* nothing just % */
|
||||
PUT_CHAR('%', &data);
|
||||
is_continue = 0;
|
||||
break;
|
||||
|
||||
case '#':
|
||||
case ' ':
|
||||
case '+':
|
||||
case '*':
|
||||
case '-':
|
||||
case '.':
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
conv_flags(&data);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* is this an error ? maybe bail out */
|
||||
PUT_CHAR('%', &data);
|
||||
is_continue = 0;
|
||||
break;
|
||||
} /* end switch */
|
||||
} /* end of while */
|
||||
} else { /* not % */
|
||||
PUT_CHAR(*data.pf, &data); /* add the char the string */
|
||||
}
|
||||
}
|
||||
|
||||
if (data.ps != NULL) {
|
||||
*data.ps = '\0'; /* the end ye ! */
|
||||
}
|
||||
|
||||
return (int)data.counter;
|
||||
}
|
||||
|
||||
int mirtoto_snprintf(char *string, size_t length, const char *format, ...) {
|
||||
int rval;
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
rval = mirtoto_vsnprintf(string, length, format, args);
|
||||
va_end(args);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
@ -23,6 +23,7 @@
|
||||
#include <mswsock.h>
|
||||
#include <nspapi.h>
|
||||
#include <wsnwlink.h>
|
||||
#include <snprintf.h>
|
||||
|
||||
#include "ipxwrapper.h"
|
||||
#include "coalesce.h"
|
||||
@ -494,7 +495,7 @@ int WSAAPI closesocket(SOCKET sockfd)
|
||||
static HANDLE _open_socket_mutex(uint16_t socket, bool exclusive)
|
||||
{
|
||||
char mutex_name[256];
|
||||
snprintf(mutex_name, sizeof(mutex_name), "ipxwrapper_socket_%hu", socket);
|
||||
mirtoto_snprintf(mutex_name, sizeof(mutex_name), "ipxwrapper_socket_%hu", socket);
|
||||
|
||||
HANDLE mutex = CreateMutex(NULL, FALSE, mutex_name);
|
||||
if(!mutex)
|
||||
@ -1243,7 +1244,8 @@ int WSAAPI setsockopt(SOCKET fd, int level, int optname, const char FAR *optval,
|
||||
strcat(opt_s, " ");
|
||||
}
|
||||
|
||||
sprintf(opt_s + i * 3, "%02X", (unsigned int)(unsigned char)optval[i]);
|
||||
int p = i * 3;
|
||||
mirtoto_snprintf(opt_s + p, sizeof(opt_s) - p, "%02X", (unsigned int)(unsigned char)optval[i]);
|
||||
}
|
||||
|
||||
if(optval)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* IPXWrapper test suite
|
||||
* Copyright (C) 2017-2023 Daniel Collins <solemnwarning@solemnwarning.net>
|
||||
* Copyright (C) 2017-2024 Daniel Collins <solemnwarning@solemnwarning.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
@ -33,7 +33,7 @@ static time_t mock_time(void)
|
||||
return now;
|
||||
}
|
||||
|
||||
/* Need to implement log_printf() and w32_error() for addrcache.c */
|
||||
/* Need to implement log_printf() for addrcache.c */
|
||||
|
||||
void log_printf(enum ipx_log_level level, const char *fmt, ...)
|
||||
{
|
||||
@ -46,14 +46,6 @@ void log_printf(enum ipx_log_level level, const char *fmt, ...)
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
const char *w32_error(DWORD errnum) {
|
||||
static char buf[1024] = {'\0'};
|
||||
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errnum, 0, buf, 1023, NULL);
|
||||
buf[strcspn(buf, "\r\n")] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
extern time_t (*addrcache_time)(void);
|
||||
|
Loading…
x
Reference in New Issue
Block a user