#include <cstdarg>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <unistd.h>
extern "C"
{
#include "config.h"
#include "integer.h"
#include "tradstdc.h"
#include "global.h"
#include "wintype.h"
}
extern "C"
{
int nhmain(int argc, char* argv[]);
using ShimCallback = void (*)(const char*, void*, const char*, ...);
void shim_graphics_set_callback(ShimCallback callback);
}
namespace
{
std::map<int, std::vector<anything>> menus;
bool map_was_drawn = false;
void set_int_return(void* return_ptr, int value)
{
if(return_ptr != nullptr)
{
*static_cast<int*>(return_ptr) = value;
}
}
void set_string_return(void* return_ptr, const char* value)
{
if(return_ptr == nullptr)
{
return;
}
auto** destination = static_cast<char**>(return_ptr);
*destination = const_cast<char*>(value);
}
void probe_callback(const char* name, void* return_ptr, const char* fmt, ...)
{
if(name == nullptr)
{
return;
}
va_list arguments;
va_start(arguments, fmt);
if(std::strcmp(name, "shim_raw_print") == 0
|| std::strcmp(name, "shim_raw_print_bold") == 0)
{
const char* message = va_arg(arguments, const char*);
std::fprintf(stderr, "NetHack: %s\n",
message == nullptr ? "(null)" : message);
}
else if(std::strcmp(name, "shim_start_menu") == 0)
{
int window = va_arg(arguments, int);
(void) va_arg(arguments, unsigned long);
menus[window].clear();
}
else if(std::strcmp(name, "shim_add_menu") == 0)
{
int window = va_arg(arguments, int);
(void) va_arg(arguments, const void*);
const auto* identifier = va_arg(arguments, const anything*);
(void) va_arg(arguments, int);
(void) va_arg(arguments, int);
(void) va_arg(arguments, int);
(void) va_arg(arguments, int);
(void) va_arg(arguments, const char*);
(void) va_arg(arguments, unsigned int);
if(identifier != nullptr)
{
menus[window].push_back(*identifier);
}
}
else if(std::strcmp(name, "shim_select_menu") == 0)
{
int window = va_arg(arguments, int);
int how = va_arg(arguments, int);
auto** menu_list = va_arg(arguments, menu_item**);
const auto found = menus.find(window);
if(how != 0 && menu_list != nullptr && found != menus.end()
&& !found->second.empty())
{
auto* selected = static_cast<menu_item*>(
std::malloc(sizeof(menu_item)));
if(selected != nullptr)
{
selected[0].item = found->second.front();
selected[0].count = -1;
selected[0].itemflags = 0;
*menu_list = selected;
va_end(arguments);
set_int_return(return_ptr, 1);
return;
}
}
va_end(arguments);
set_int_return(return_ptr, 0);
return;
}
else if(std::strcmp(name, "shim_print_glyph") == 0)
{
map_was_drawn = true;
}
else if(map_was_drawn
&& (std::strcmp(name, "shim_nhgetch") == 0
|| std::strcmp(name, "shim_nh_poskey") == 0))
{
std::fprintf(stderr, "NetHack library startup reached the first key.\n");
std::_Exit(0);
}
va_end(arguments);
if(name == nullptr || return_ptr == nullptr)
{
return;
}
if(std::strcmp(name, "shim_nhgetch") == 0
|| std::strcmp(name, "shim_nh_poskey") == 0
|| std::strcmp(name, "shim_message_menu") == 0)
{
*static_cast<int*>(return_ptr) = 27;
}
else if(std::strcmp(name, "shim_yn_function") == 0)
{
*static_cast<char*>(return_ptr) = 27;
}
else if(std::strcmp(name, "shim_get_ext_cmd") == 0)
{
*static_cast<int*>(return_ptr) = -1;
}
else if(std::strcmp(name, "shim_select_menu") == 0)
{
*static_cast<int*>(return_ptr) = 0;
}
else if(std::strcmp(name, "shim_get_color_string") == 0)
{
set_string_return(return_ptr, "");
}
}
} // namespace
int main(int argc, char* argv[])
{
#ifdef NETHACK_PROBE_RUNTIME_DIR
if(chdir(NETHACK_PROBE_RUNTIME_DIR) != 0)
{
std::perror("chdir");
return 1;
}
#endif
shim_graphics_set_callback(probe_callback);
if(argc == 1)
{
char program[] = "nethack_engine_probe";
char name_option[] = "-u";
char name[] = "Agent";
char* probe_argv[] = {program, name_option, name, nullptr};
return nhmain(3, probe_argv);
}
return nhmain(argc, argv);
}