WIN32 build
This commit is contained in:
parent
00b4214ea0
commit
08bc5f890a
14 changed files with 184 additions and 8 deletions
|
@ -34,6 +34,30 @@ add_executable(
|
||||||
utils.cpp
|
utils.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_executable(
|
||||||
|
kek-win32
|
||||||
|
bus.cpp
|
||||||
|
console.cpp
|
||||||
|
console_posix.cpp
|
||||||
|
cpu.cpp
|
||||||
|
debugger.cpp
|
||||||
|
disk_backend.cpp
|
||||||
|
disk_backend_file.cpp
|
||||||
|
disk_backend_nbd.cpp
|
||||||
|
error.cpp
|
||||||
|
kw11-l.cpp
|
||||||
|
loaders.cpp
|
||||||
|
log.cpp
|
||||||
|
main.cpp
|
||||||
|
memory.cpp
|
||||||
|
rk05.cpp
|
||||||
|
rl02.cpp
|
||||||
|
tm-11.cpp
|
||||||
|
tty.cpp
|
||||||
|
utils.cpp
|
||||||
|
windows/win32.cpp
|
||||||
|
)
|
||||||
|
|
||||||
include(CheckIPOSupported)
|
include(CheckIPOSupported)
|
||||||
check_ipo_supported(RESULT supported)
|
check_ipo_supported(RESULT supported)
|
||||||
|
|
||||||
|
@ -45,6 +69,9 @@ set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||||
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||||
find_package(Threads)
|
find_package(Threads)
|
||||||
target_link_libraries(kek Threads::Threads)
|
target_link_libraries(kek Threads::Threads)
|
||||||
|
target_link_libraries(kek-win32 Threads::Threads)
|
||||||
|
|
||||||
|
target_link_libraries(kek-win32 ws2_32)
|
||||||
|
|
||||||
include(FindPkgConfig)
|
include(FindPkgConfig)
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,10 @@
|
||||||
|
|
||||||
#include "bus.h"
|
#include "bus.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#include "windows/win32.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
constexpr const int t_width { 80 };
|
constexpr const int t_width { 80 };
|
||||||
constexpr const int t_height { 25 };
|
constexpr const int t_height { 25 };
|
||||||
|
|
|
@ -1,9 +1,15 @@
|
||||||
// (C) 2018-2023 by Folkert van Heusden
|
// (C) 2018-2023 by Folkert van Heusden
|
||||||
// Released under MIT license
|
// Released under MIT license
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#include <conio.h>
|
||||||
|
|
||||||
|
#include <winsock2.h>
|
||||||
|
#else
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <termios.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "console_posix.h"
|
#include "console_posix.h"
|
||||||
|
@ -13,6 +19,7 @@
|
||||||
console_posix::console_posix(std::atomic_uint32_t *const stop_event, bus *const b) :
|
console_posix::console_posix(std::atomic_uint32_t *const stop_event, bus *const b) :
|
||||||
console(stop_event, b)
|
console(stop_event, b)
|
||||||
{
|
{
|
||||||
|
#if !defined(_WIN32)
|
||||||
if (tcgetattr(STDIN_FILENO, &org_tty_opts) == -1)
|
if (tcgetattr(STDIN_FILENO, &org_tty_opts) == -1)
|
||||||
error_exit(true, "console_posix: tcgetattr failed");
|
error_exit(true, "console_posix: tcgetattr failed");
|
||||||
|
|
||||||
|
@ -21,22 +28,36 @@ console_posix::console_posix(std::atomic_uint32_t *const stop_event, bus *const
|
||||||
|
|
||||||
if (tcsetattr(STDIN_FILENO, TCSANOW, &tty_opts_raw) == -1)
|
if (tcsetattr(STDIN_FILENO, TCSANOW, &tty_opts_raw) == -1)
|
||||||
error_exit(true, "console_posix: tcsetattr failed");
|
error_exit(true, "console_posix: tcsetattr failed");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
console_posix::~console_posix()
|
console_posix::~console_posix()
|
||||||
{
|
{
|
||||||
stop_thread();
|
stop_thread();
|
||||||
|
|
||||||
|
#if !defined(_WIN32)
|
||||||
if (tcsetattr(STDIN_FILENO, TCSANOW, &org_tty_opts) == -1)
|
if (tcsetattr(STDIN_FILENO, TCSANOW, &org_tty_opts) == -1)
|
||||||
error_exit(true, "~console_posix: tcsetattr failed");
|
error_exit(true, "~console_posix: tcsetattr failed");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int console_posix::wait_for_char_ll(const short timeout)
|
int console_posix::wait_for_char_ll(const short timeout)
|
||||||
{
|
{
|
||||||
|
#if defined(_WIN32)
|
||||||
|
fd_set rfds;
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_SET(STDIN_FILENO, &rfds);
|
||||||
|
|
||||||
|
timeval to { timeout / 1000000, timeout % 1000000 };
|
||||||
|
|
||||||
|
if (select(STDIN_FILENO + 1, &rfds, nullptr, nullptr, &to) == 1 && FD_ISSET(STDIN_FILENO, &rfds))
|
||||||
|
return _getch();
|
||||||
|
#else
|
||||||
struct pollfd fds[] = { { STDIN_FILENO, POLLIN, timeout } };
|
struct pollfd fds[] = { { STDIN_FILENO, POLLIN, timeout } };
|
||||||
|
|
||||||
if (poll(fds, 1, timeout) == 1 && fds[0].revents)
|
if (poll(fds, 1, timeout) == 1 && fds[0].revents)
|
||||||
return getchar();
|
return getchar();
|
||||||
|
#endif
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
// (C) 2018-2023 by Folkert van Heusden
|
// (C) 2018-2023 by Folkert van Heusden
|
||||||
// Released under MIT license
|
// Released under MIT license
|
||||||
|
|
||||||
|
#if !defined(_WIN32)
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
|
|
||||||
|
@ -9,7 +11,9 @@
|
||||||
class console_posix : public console
|
class console_posix : public console
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
#if !defined(_WIN32)
|
||||||
struct termios org_tty_opts { 0 };
|
struct termios org_tty_opts { 0 };
|
||||||
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int wait_for_char_ll(const short timeout) override;
|
int wait_for_char_ll(const short timeout) override;
|
||||||
|
|
|
@ -36,12 +36,26 @@ bool disk_backend_file::read(const off_t offset, const size_t n, uint8_t *const
|
||||||
{
|
{
|
||||||
DOLOG(debug, false, "disk_backend_file::read: read %zu bytes from offset %zu", n, offset);
|
DOLOG(debug, false, "disk_backend_file::read: read %zu bytes from offset %zu", n, offset);
|
||||||
|
|
||||||
|
#if defined(_WIN32) // hope for the best
|
||||||
|
if (lseek(fd, offset, SEEK_SET) == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return ::read(fd, target, n) == ssize_t(n);
|
||||||
|
#else
|
||||||
return pread(fd, target, n, offset) == ssize_t(n);
|
return pread(fd, target, n, offset) == ssize_t(n);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool disk_backend_file::write(const off_t offset, const size_t n, const uint8_t *const from)
|
bool disk_backend_file::write(const off_t offset, const size_t n, const uint8_t *const from)
|
||||||
{
|
{
|
||||||
DOLOG(debug, false, "disk_backend_file::write: write %zu bytes to offset %zu", n, offset);
|
DOLOG(debug, false, "disk_backend_file::write: write %zu bytes to offset %zu", n, offset);
|
||||||
|
|
||||||
|
#if defined(_WIN32) // hope for the best
|
||||||
|
if (lseek(fd, offset, SEEK_SET) == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return ::write(fd, from, n) == ssize_t(n);
|
||||||
|
#else
|
||||||
return pwrite(fd, from, n, offset) == ssize_t(n);
|
return pwrite(fd, from, n, offset) == ssize_t(n);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,18 +4,31 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "disk_backend_nbd.h"
|
#include "disk_backend_nbd.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#ifdef ESP32
|
#if defined(ESP32)
|
||||||
#include <lwip/netdb.h>
|
#include <lwip/netdb.h>
|
||||||
#include <lwip/sockets.h>
|
#include <lwip/sockets.h>
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
// from https://stackoverflow.com/questions/12765743/implicit-declaration-of-function-getaddrinfo-on-mingw
|
||||||
|
#define _NTDDI_VERSION_FROM_WIN32_WINNT2(ver) ver##0000
|
||||||
|
#define _NTDDI_VERSION_FROM_WIN32_WINNT(ver) _NTDDI_VERSION_FROM_WIN32_WINNT2(ver)
|
||||||
|
|
||||||
|
#ifndef _WIN32_WINNT
|
||||||
|
# define _WIN32_WINNT 0x501
|
||||||
|
#endif
|
||||||
|
#ifndef NTDDI_VERSION
|
||||||
|
# define NTDDI_VERSION _NTDDI_VERSION_FROM_WIN32_WINNT(_WIN32_WINNT)
|
||||||
|
#endif
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#include <winsock2.h>
|
||||||
#else
|
#else
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
10
error.cpp
10
error.cpp
|
@ -8,9 +8,9 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <regex.h>
|
|
||||||
#if defined(ESP32)
|
#if defined(ESP32)
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#elif defined(_WIN32)
|
||||||
#else
|
#else
|
||||||
#include <ncursesw/ncurses.h>
|
#include <ncursesw/ncurses.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,18 +21,20 @@
|
||||||
{
|
{
|
||||||
int e = errno;
|
int e = errno;
|
||||||
|
|
||||||
|
#if !defined(_WIN32)
|
||||||
|
(void)endwin();
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(ESP32)
|
#if defined(ESP32)
|
||||||
Serial.println(format);
|
Serial.println(format);
|
||||||
#else
|
#else
|
||||||
(void)endwin();
|
|
||||||
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
(void)vfprintf(stderr, format, ap);
|
(void)vfprintf(stderr, format, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
if (sys_err == TRUE)
|
if (sys_err == true)
|
||||||
fprintf(stderr, "error: %s (%d)\n", strerror(e), e);
|
fprintf(stderr, "error: %s (%d)\n", strerror(e), e);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
8
log.cpp
8
log.cpp
|
@ -7,10 +7,12 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "windows/win32.h"
|
||||||
|
|
||||||
|
|
||||||
static const char *logfile = strdup("/tmp/myip.log");
|
static const char *logfile = strdup("/tmp/myip.log");
|
||||||
|
@ -65,11 +67,13 @@ void dolog(const log_level_t ll, const char *fmt, ...)
|
||||||
if (!lfh)
|
if (!lfh)
|
||||||
error_exit(true, "Cannot access log-file %s", logfile);
|
error_exit(true, "Cannot access log-file %s", logfile);
|
||||||
|
|
||||||
|
#if !defined(_WIN32)
|
||||||
if (lf_uid != -1 && fchown(fileno(lfh), lf_uid, lf_gid) == -1)
|
if (lf_uid != -1 && fchown(fileno(lfh), lf_uid, lf_gid) == -1)
|
||||||
error_exit(true, "Cannot change logfile (%s) ownership", logfile);
|
error_exit(true, "Cannot change logfile (%s) ownership", logfile);
|
||||||
|
|
||||||
if (fcntl(fileno(lfh), F_SETFD, FD_CLOEXEC) == -1)
|
if (fcntl(fileno(lfh), F_SETFD, FD_CLOEXEC) == -1)
|
||||||
error_exit(true, "fcntl(FD_CLOEXEC) failed");
|
error_exit(true, "fcntl(FD_CLOEXEC) failed");
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,8 +81,12 @@ void dolog(const log_level_t ll, const char *fmt, ...)
|
||||||
time_t t_now = now / 1000000;
|
time_t t_now = now / 1000000;
|
||||||
|
|
||||||
tm tm { 0 };
|
tm tm { 0 };
|
||||||
|
#if defined(_WIN32)
|
||||||
|
tm = *localtime(&t_now);
|
||||||
|
#else
|
||||||
if (!localtime_r(&t_now, &tm))
|
if (!localtime_r(&t_now, &tm))
|
||||||
error_exit(true, "localtime_r failed");
|
error_exit(true, "localtime_r failed");
|
||||||
|
#endif
|
||||||
|
|
||||||
char *ts_str = nullptr;
|
char *ts_str = nullptr;
|
||||||
|
|
||||||
|
|
13
main.cpp
13
main.cpp
|
@ -9,7 +9,9 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#if !defined(_WIN32)
|
||||||
#include "console_ncurses.h"
|
#include "console_ncurses.h"
|
||||||
|
#endif
|
||||||
#include "console_posix.h"
|
#include "console_posix.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "debugger.h"
|
#include "debugger.h"
|
||||||
|
@ -21,7 +23,9 @@
|
||||||
#include "loaders.h"
|
#include "loaders.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
#if !defined(_WIN32)
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
|
#endif
|
||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
@ -32,6 +36,7 @@ std::atomic_bool *running { nullptr };
|
||||||
|
|
||||||
std::atomic_bool sigw_event { false };
|
std::atomic_bool sigw_event { false };
|
||||||
|
|
||||||
|
#if !defined(_WIN32)
|
||||||
void sw_handler(int s)
|
void sw_handler(int s)
|
||||||
{
|
{
|
||||||
if (s == SIGWINCH)
|
if (s == SIGWINCH)
|
||||||
|
@ -42,6 +47,7 @@ void sw_handler(int s)
|
||||||
event = EVENT_TERMINATE;
|
event = EVENT_TERMINATE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void help()
|
void help()
|
||||||
{
|
{
|
||||||
|
@ -227,9 +233,12 @@ int main(int argc, char *argv[])
|
||||||
if (sa_set)
|
if (sa_set)
|
||||||
c->setRegister(7, start_addr);
|
c->setRegister(7, start_addr);
|
||||||
|
|
||||||
|
#if !defined(_WIN32)
|
||||||
if (withUI)
|
if (withUI)
|
||||||
cnsl = new console_ncurses(&event, b);
|
cnsl = new console_ncurses(&event, b);
|
||||||
else {
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
DOLOG(info, true, "This PDP-11 emulator is called \"kek\" (reason for that is forgotten) and was written by Folkert van Heusden.");
|
DOLOG(info, true, "This PDP-11 emulator is called \"kek\" (reason for that is forgotten) and was written by Folkert van Heusden.");
|
||||||
|
|
||||||
DOLOG(info, true, "Built on: " __DATE__ " " __TIME__);
|
DOLOG(info, true, "Built on: " __DATE__ " " __TIME__);
|
||||||
|
@ -262,6 +271,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
DOLOG(info, true, "Start running at %06o", c->getRegister(7));
|
DOLOG(info, true, "Start running at %06o", c->getRegister(7));
|
||||||
|
|
||||||
|
#if !defined(_WIN32)
|
||||||
struct sigaction sa { };
|
struct sigaction sa { };
|
||||||
sa.sa_handler = sw_handler;
|
sa.sa_handler = sw_handler;
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
|
@ -272,6 +282,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
sigaction(SIGTERM, &sa, nullptr);
|
sigaction(SIGTERM, &sa, nullptr);
|
||||||
sigaction(SIGINT , &sa, nullptr);
|
sigaction(SIGINT , &sa, nullptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (test.empty() == false)
|
if (test.empty() == false)
|
||||||
load_p11_x11(b, test);
|
load_p11_x11(b, test);
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#include "windows/win32.h"
|
||||||
|
|
||||||
|
|
||||||
void setBit(uint16_t & v, const int bit, const bool vb)
|
void setBit(uint16_t & v, const int bit, const bool vb)
|
||||||
{
|
{
|
||||||
const uint16_t mask = 1 << bit;
|
const uint16_t mask = 1 << bit;
|
||||||
|
|
3
windows/README.txt
Normal file
3
windows/README.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
cmake -DCMAKE_TOOLCHAIN_FILE=mingw64.cmake ..
|
||||||
|
|
||||||
|
make kek-win32
|
14
windows/mingw64.cmake
Normal file
14
windows/mingw64.cmake
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# cmake -DCMAKE_TOOLCHAIN_FILE=mingw64.cmake ..
|
||||||
|
|
||||||
|
set(CMAKE_SYSTEM_NAME Windows)
|
||||||
|
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
|
||||||
|
|
||||||
|
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc-posix)
|
||||||
|
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++-posix)
|
||||||
|
set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
|
||||||
|
|
||||||
|
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX} /usr/lib/gcc/${TOOLCHAIN_PREFIX}/7.3-posix)
|
||||||
|
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
48
windows/win32.cpp
Normal file
48
windows/win32.cpp
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#if defined(_WIN32)
|
||||||
|
// from https://stackoverflow.com/questions/40159892/using-asprintf-on-windows
|
||||||
|
|
||||||
|
#include <stdio.h> /* needed for vsnprintf */
|
||||||
|
#include <stdlib.h> /* needed for malloc, free */
|
||||||
|
#include <stdarg.h> /* needed for va_* */
|
||||||
|
|
||||||
|
int vscprintf(const char *format, va_list ap)
|
||||||
|
{
|
||||||
|
va_list ap_copy;
|
||||||
|
va_copy(ap_copy, ap);
|
||||||
|
int retval = vsnprintf(NULL, 0, format, ap_copy);
|
||||||
|
va_end(ap_copy);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* asprintf, vasprintf:
|
||||||
|
* MSVC does not implement these, thus we implement them here
|
||||||
|
* GNU-C-compatible compilers implement these with the same names, thus we
|
||||||
|
* don't have to do anything
|
||||||
|
*/
|
||||||
|
int vasprintf(char **strp, const char *format, va_list ap)
|
||||||
|
{
|
||||||
|
int len = vscprintf(format, ap);
|
||||||
|
if (len == -1)
|
||||||
|
return -1;
|
||||||
|
char *str = (char*)malloc((size_t) len + 1);
|
||||||
|
if (!str)
|
||||||
|
return -1;
|
||||||
|
int retval = vsnprintf(str, len + 1, format, ap);
|
||||||
|
if (retval == -1) {
|
||||||
|
free(str);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*strp = str;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int asprintf(char **strp, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, format);
|
||||||
|
int retval = vasprintf(strp, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
#endif
|
4
windows/win32.h
Normal file
4
windows/win32.h
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
int vasprintf(char **strp, const char *format, va_list ap);
|
||||||
|
int asprintf(char **strp, const char *format, ...);
|
Loading…
Add table
Reference in a new issue