703 lines
18 KiB
C
703 lines
18 KiB
C
/**
|
|
* @mainpage LEPHISTO
|
|
*
|
|
* Doxygen documentation for the Lephisto project. (c) SaraCraft.
|
|
*/
|
|
/**
|
|
* @file lephisto.c
|
|
*
|
|
* @brief Control the overall game flow: data loading/unloading and game loop.
|
|
*/
|
|
|
|
#include <SDL/SDL.h>
|
|
|
|
/* Global. */
|
|
#include <string.h>
|
|
#if defined(LINUX) && !defined(NODEBUG)
|
|
#include <signal.h>
|
|
#include <execinfo.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#endif /* defined(LINUX) && !defined(NODEBUG) */
|
|
|
|
/* Local. */
|
|
#include "lephisto.h"
|
|
#include "conf.h"
|
|
#include "log.h"
|
|
#include "physics.h"
|
|
#include "opengl.h"
|
|
#include "font.h"
|
|
#include "ship.h"
|
|
#include "pilot.h"
|
|
#include "player.h"
|
|
#include "input.h"
|
|
#include "joystick.h"
|
|
#include "space.h"
|
|
#include "rng.h"
|
|
#include "ai.h"
|
|
#include "outfit.h"
|
|
#include "pack.h"
|
|
#include "weapon.h"
|
|
#include "faction.h"
|
|
#include "xml.h"
|
|
#include "pause.h"
|
|
#include "toolkit.h"
|
|
#include "pilot.h"
|
|
#include "sound.h"
|
|
#include "music.h"
|
|
#include "spfx.h"
|
|
#include "economy.h"
|
|
#include "menu.h"
|
|
#include "mission.h"
|
|
#include "misn_lua.h"
|
|
#include "lfile.h"
|
|
#include "unidiff.h"
|
|
#include "nebulae.h"
|
|
|
|
|
|
#define XML_START_ID "Start" /**< XML document tag of module start file. */
|
|
#define START_DATA "../dat/start.xml" /**< Path to module start file. */
|
|
|
|
#define CONF_FILE "conf" /**< Configuration file by default. */
|
|
#define VERSION_FILE "VERSION" /**< Version file by default. */
|
|
#define VERSION_LEN 10 /**< Max length of the version file. */
|
|
#define FONT_SIZE 12 /**< Normal font size. */
|
|
#define FONT_SIZE_SMALL 10 /**< Small font size. */
|
|
|
|
#define LEPHISTO_INIT_DELAY 3000 /**< Minimum amount of time to wait with loading screen. */
|
|
|
|
static int quit = 0; /**< For primary loop. */
|
|
unsigned int time = 0; /**< USed to calculate FPS and movement, in pause.c */
|
|
static char version[VERSION_LEN];
|
|
|
|
/* Just some default crap. */
|
|
char* data = NULL; /**< Path to datafile. */
|
|
char dataname[DATA_NAME_LEN] = ""; /**< Name of data file. */
|
|
int nosound = 0; /**< Disable sound when loaded. */
|
|
int show_fps = 1; /**< Shows fps - default true. */
|
|
int max_fps = 0; /**< Default FPS limit, 0 is no limit. */
|
|
int indjoystick = -1; /**< Index of joystick to use, -1 is none. */
|
|
char* namjoystick = NULL; /**< Name of joystick to use, NULL is none. */
|
|
|
|
/* Prototypes. */
|
|
static void print_SDLversion(void);
|
|
static void load_screen(void);
|
|
static void load_all(void);
|
|
static void unload_all(void);
|
|
static void display_fps(const double dt);
|
|
static void window_caption(void);
|
|
static void data_name(void);
|
|
static void debug_sigInit(void);
|
|
/* Update. */
|
|
static void fps_control(void);
|
|
static void update_all(void);
|
|
static void update_routine(double dt);
|
|
static void render_all(void);
|
|
/* Misc. */
|
|
void main_loop(void); /* dialogue.c */
|
|
|
|
|
|
/**
|
|
* @fn int main(int argc, char** argv)
|
|
*
|
|
* @brief The entry point of Lephisto.
|
|
*
|
|
* @param[in] argc Number of arguments.
|
|
* @param[in] argv Array of argc arguments.
|
|
* @return EXIT_SUCCESS on success.
|
|
*/
|
|
#ifdef WIN32
|
|
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine,
|
|
int nCmdShow) {
|
|
int argc = 0;
|
|
char *argv[] = { NULL };
|
|
#else
|
|
int main(int argc, char** argv) {
|
|
#endif
|
|
|
|
char buf[PATH_MAX];
|
|
|
|
/* Print the version. */
|
|
snprintf(version, VERSION_LEN, "%d.%d.%d", VMAJOR, VMINOR, VREV);
|
|
LOG(" "APPNAME" v%s", version);
|
|
|
|
/* Initialize SDL for possible warnings. */
|
|
SDL_Init(0);
|
|
|
|
/* Set up debug signal handlers. */
|
|
debug_sigInit();
|
|
|
|
/* Create the home directory if needed. */
|
|
if(lfile_dirMakeExist("."))
|
|
WARN("Unable to create lephisto directory '%s'", lfile_basePath());
|
|
|
|
/* Input must be initialized for config to work. */
|
|
input_init();
|
|
|
|
/* Set the configuration. */
|
|
snprintf(buf, PATH_MAX, "%s"CONF_FILE, lfile_basePath());
|
|
conf_setDefaults(); /* Default config values. */
|
|
conf_loadConfig(buf); /* Have Lua parse config. */
|
|
conf_parseCLI(argc, argv); /* Parse CLI arguments. */
|
|
|
|
/* Load the data basics. */
|
|
data_name();
|
|
LOG(" %s", dataname);
|
|
DEBUG();
|
|
|
|
/* Display the SDL Version. */
|
|
print_SDLversion();
|
|
DEBUG();
|
|
|
|
/* Random numbers. */
|
|
rng_init();
|
|
|
|
/* OpenGL */
|
|
if(gl_init()) { /* Init video output. */
|
|
ERR("Initializing video output failed, exiting...");
|
|
SDL_Quit();
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
window_caption();
|
|
load_screen();
|
|
time = SDL_GetTicks();
|
|
|
|
/* OpenAL sound. */
|
|
if(nosound) {
|
|
LOG("Sound is disabled!");
|
|
sound_disabled = 1;
|
|
music_disabled = 1;
|
|
}
|
|
if(sound_init()) WARN("Problem setting up sound!");
|
|
music_choose("load");
|
|
|
|
/* Input. */
|
|
if((indjoystick >= 0) || (namjoystick != NULL)) {
|
|
if(joystick_init())
|
|
WARN("Error initializing joystick input");
|
|
if(namjoystick != NULL) {
|
|
/* Use a joystick name to find joystick. */
|
|
if(joystick_use(joystick_get(namjoystick))) {
|
|
WARN("Failure to open any joystick, falling back to default keybinds");
|
|
input_setDefault();
|
|
}
|
|
free(namjoystick);
|
|
}
|
|
else if(indjoystick >= 0)
|
|
/* Must be using an id instead. */
|
|
if(joystick_use(indjoystick)) {
|
|
WARN("Failure to open any joystick, falling back to default keybinds");
|
|
input_setDefault();
|
|
}
|
|
}
|
|
|
|
/* Misc. */
|
|
if(ai_init())
|
|
WARN("Error initializing AI");
|
|
|
|
/* Misc graphics init stuff. */
|
|
if(nebu_init() != 0) { /* Init the nebulae. */
|
|
/* An error happened. */
|
|
ERR("Unable to init the Nebulae subsystem!");
|
|
/* Weirdness will accur. */
|
|
}
|
|
gl_fontInit(NULL, NULL, FONT_SIZE); /* Init default font size. */
|
|
gl_fontInit(&gl_smallFont, NULL, FONT_SIZE_SMALL); /* Small font. */
|
|
gui_init(); /* Init the GUI crap. */
|
|
toolkit_init(); /* Init the toolkit. */
|
|
|
|
/* Data loading. */
|
|
load_all();
|
|
|
|
/* Start menu. */
|
|
menu_main();
|
|
|
|
/* Force a minimum delay with loading screen. */
|
|
if((SDL_GetTicks() - time) < LEPHISTO_INIT_DELAY)
|
|
SDL_Delay(LEPHISTO_INIT_DELAY - (SDL_GetTicks() - time));
|
|
time = SDL_GetTicks(); /* Init the time. */
|
|
|
|
/* Main loop. */
|
|
SDL_Event event;
|
|
/* flushes the event loop, since I notices that when the joystick is loaded, it */
|
|
/* creates button events that results in the player starting out accelerating. */
|
|
while(SDL_PollEvent(&event));
|
|
while(!quit) {
|
|
/* Event loop. */
|
|
while(SDL_PollEvent(&event)) {
|
|
if(event.type == SDL_QUIT) quit = 1; /* Handle quit. */
|
|
|
|
input_handle(&event); /* handles all the events the player keybinds. */
|
|
}
|
|
main_loop();
|
|
}
|
|
|
|
/* Clean up some stuff. */
|
|
player_cleanup(); /* Cleans up the player stuff. */
|
|
gui_free(); /* Free up the gui. */
|
|
weapon_exit(); /* Destroy all active weapons. */
|
|
space_exit(); /* Clean up the universe!!! */
|
|
pilots_free(); /* Free the pilots, they where locked up D: */
|
|
space_exit(); /* Cleans up the universe itself. */
|
|
|
|
/* Unload data. */
|
|
unload_all();
|
|
|
|
/* Cleanup opengl fonts. */
|
|
gl_freeFont(NULL);
|
|
gl_freeFont(&gl_smallFont);
|
|
|
|
/* Exit subsystems. */
|
|
toolkit_exit(); /* Kill the toolkit. */
|
|
ai_exit(); /* Stop the Lua AI magicness. */
|
|
joystick_exit(); /* Release joystick. */
|
|
input_exit(); /* Clean up keybindings. */
|
|
nebu_exit(); /* Destroys the nebulae. */
|
|
gl_exit(); /* Kills video output. */
|
|
sound_exit(); /* Kills the sound. */
|
|
SDL_Quit(); /* Quits SDL. */
|
|
|
|
/* All is good. */
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
/**
|
|
* @fn void load_scren(void)
|
|
*
|
|
* @brief Display a loading screen.
|
|
*/
|
|
void load_screen(void) {
|
|
int i;
|
|
glTexture* tex;
|
|
char file_path[PATH_MAX];
|
|
char** files;
|
|
uint32_t nfiles;
|
|
size_t len;
|
|
int nload;
|
|
|
|
/* Count the loading screens. */
|
|
files = pack_listfiles(data, &nfiles);
|
|
len = strlen("../gfx/loading");
|
|
nload = 0;
|
|
for(i = 0; i < (int)nfiles; i++) {
|
|
if(strncmp(files[i], "../gfx/loading", len)==0)
|
|
nload++;
|
|
free(files[i]);
|
|
}
|
|
|
|
/* Must have loading screens. */
|
|
if(nload == 0) {
|
|
WARN("No loading screens found!");
|
|
return;
|
|
}
|
|
|
|
/* Load the texture. */
|
|
snprintf(file_path, PATH_MAX, "../gfx/loading%03d.png", RNG(0, nload-1));
|
|
tex = gl_newImage(file_path);
|
|
|
|
/* Draw once, won't be redrawn. */
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
gl_blitScale(tex, 0., 0., SCREEN_W, SCREEN_H, NULL);
|
|
SDL_GL_SwapBuffers();
|
|
|
|
/* Free the textures. */
|
|
gl_freeTexture(tex);
|
|
}
|
|
|
|
/**
|
|
* @fn void load_all(void)
|
|
*
|
|
* @brief Load all the data, makes main() simpler.
|
|
*/
|
|
void load_all(void) {
|
|
/* Ordering of these is very important as they are interdependent. */
|
|
commodity_load();
|
|
factions_load(); /* Dep for fleet, space, missions. */
|
|
missions_load(); /* No dep. */
|
|
spfx_load();
|
|
outfit_load();
|
|
ships_load();
|
|
fleet_load();
|
|
space_load();
|
|
xmlCleanupParser(); /* Only needed to be run after all the loading is done. */
|
|
}
|
|
|
|
/**
|
|
* @fn void unload_all(void)
|
|
*
|
|
* @brief Unloads all data, simplifies main().
|
|
*/
|
|
void unload_all(void) {
|
|
/* Data unloading - order should not matter, but inverse load_all is good. */
|
|
fleet_free();
|
|
ships_free();
|
|
outfit_free();
|
|
spfx_free(); /* Remove the special effects. */
|
|
missions_free();
|
|
factions_free();
|
|
commodity_free();
|
|
var_cleanup(); /* Clean up mission variables. */
|
|
}
|
|
|
|
/**
|
|
* @fn void main_loop(void)
|
|
*
|
|
* @brief Split main loop from main() for secondary loop hack in toolkit.c.
|
|
*/
|
|
void main_loop(void) {
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
fps_control(); /* Everyone loves fps control.. */
|
|
|
|
sound_update(); /* Update sounds. */
|
|
if(toolkit) toolkit_update(); /* To simulate key repetition. */
|
|
if(!menu_isOpen(MENU_MAIN)) {
|
|
if(!paused) update_all(); /* Update game. */
|
|
render_all();
|
|
}
|
|
if(toolkit) toolkit_render();
|
|
|
|
gl_checkErr(); /* Check error every loop. */
|
|
|
|
SDL_GL_SwapBuffers();
|
|
}
|
|
|
|
static double fps_dt = 1.;
|
|
static double cur_dt = 0.;
|
|
/**
|
|
* @fn static void fps_control(void)
|
|
*
|
|
* @brief Controls the FPS.
|
|
*/
|
|
static void fps_control(void) {
|
|
unsigned int t;
|
|
double delay;
|
|
|
|
/* dt in ms/1000. */
|
|
t = SDL_GetTicks();
|
|
cur_dt = (double)(t-time)/1000.;
|
|
time = t;
|
|
|
|
if(paused) SDL_Delay(10); /* Drop paused FPS to be nice to the CPU. */
|
|
|
|
/* If the fps is limited.. */
|
|
if((max_fps != 0) && (cur_dt < 1./max_fps)) {
|
|
delay = 1./max_fps - cur_dt;
|
|
SDL_Delay((unsigned int)(delay*1000));
|
|
fps_dt += delay; /* Make sure it displays the propper FPS. */
|
|
}
|
|
}
|
|
|
|
static const double fps_min = 1./50.0;
|
|
/**
|
|
* @fn static void update_all(void)
|
|
*
|
|
* @brief Updates the game itself (player flying around etc).
|
|
*/
|
|
static void update_all(void) {
|
|
double tmpdt;
|
|
|
|
if(cur_dt > 0.25) { /* Slow timers down and rerun calculations */
|
|
pause_delay((unsigned int)cur_dt*1000.);
|
|
return;
|
|
}
|
|
/* We'll force a minimum of 50 FPS. */
|
|
else if(cur_dt > fps_min) {
|
|
tmpdt = cur_dt - fps_min;
|
|
pause_delay((unsigned int)(tmpdt*1000));
|
|
update_routine(fps_min);
|
|
|
|
/* Run as many cycles of dt=fps_min as needed. */
|
|
while(tmpdt > fps_min) {
|
|
pause_delay((unsigned int)(-fps_min*1000)); /* Increment counters */
|
|
update_routine(fps_min);
|
|
tmpdt -= fps_min;
|
|
}
|
|
/* Note we don't touch cur_dt so that fps_delay works well. */
|
|
update_routine(tmpdt); /* Leftovers. */
|
|
} else /* Standard, just update with the last dt. */
|
|
update_routine(cur_dt);
|
|
}
|
|
|
|
/**
|
|
* @fn static void update_routine(double dt)
|
|
*
|
|
* @brief Actually runs the update.
|
|
* @param[in] dt Current delta tick.
|
|
*/
|
|
static void update_routine(double dt) {
|
|
space_update(dt);
|
|
weapons_update(dt);
|
|
spfx_update(dt);
|
|
pilots_update(dt);
|
|
missions_update(dt);
|
|
}
|
|
|
|
/**
|
|
* @fn static void render_all(void)
|
|
*
|
|
* @brief Renders the game itself (player flying around etc).
|
|
*
|
|
* Blitting order. (layers)
|
|
*
|
|
* - BG
|
|
* -- Stars and planets.
|
|
* -- Background player stuff (planet targetting)
|
|
* -- Background particles.
|
|
* -- Back layer weapons.
|
|
* - N
|
|
* -- NPC ships.
|
|
* -- Front layer weapons.
|
|
* -- Normal layer particles (above ships).
|
|
* - FG
|
|
* -- Player.
|
|
* -- Foreground particles.
|
|
* -- Text and GUI.
|
|
*/
|
|
static void render_all(void) {
|
|
double dt;
|
|
|
|
dt = (paused) ? 0. : cur_dt;
|
|
/* Setup. */
|
|
spfx_start(dt);
|
|
/* BG. */
|
|
space_render(dt);
|
|
planets_render();
|
|
player_renderBG();
|
|
weapons_render(WEAPON_LAYER_BG, dt);
|
|
/* N. */
|
|
pilots_render();
|
|
weapons_render(WEAPON_LAYER_FG, dt);
|
|
spfx_render(SPFX_LAYER_BACK);
|
|
/* FG. */
|
|
player_render();
|
|
spfx_render(SPFX_LAYER_FRONT);
|
|
space_renderOverlay(dt);
|
|
player_renderGUI();
|
|
display_fps(dt); /* Exception. */
|
|
}
|
|
|
|
|
|
static double fps = 0.;
|
|
static double fps_cur = 0.;
|
|
/**
|
|
* @fn static void display_fps(const double dt)
|
|
*
|
|
* @brief Displays FPS on the screen.
|
|
*
|
|
* @param[in] dt Current delta tick.
|
|
*/
|
|
static void display_fps(const double dt) {
|
|
double x, y;
|
|
fps_dt += dt;
|
|
fps_cur += 1.;
|
|
if(fps_dt > 1.) {
|
|
/* Recalculate every second. */
|
|
fps = fps_cur / fps_dt;
|
|
fps_dt = fps_cur = 0.;
|
|
}
|
|
|
|
x = 10.;
|
|
y = (double)(gl_screen.h - 20);
|
|
if(show_fps)
|
|
gl_print(NULL, x, y, NULL, "%3.2f", fps);
|
|
}
|
|
|
|
/**
|
|
* @fn static void data_name(void)
|
|
*
|
|
* @brief Set the data module's name.
|
|
*/
|
|
static void data_name(void) {
|
|
uint32_t bufsize;
|
|
char* buf;
|
|
|
|
/* Check if data file is valid. */
|
|
if(pack_check(DATA)) {
|
|
ERR("Data file '%s' not found", data);
|
|
WARN("You should specify which data file to use with '-d'");
|
|
WARN("See -h or --help for more information");
|
|
SDL_Quit();
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/* Check the version. */
|
|
buf = pack_readfile(DATA, VERSION_FILE, &bufsize);
|
|
|
|
if(strncmp(buf, version, bufsize) != 0) {
|
|
WARN("Lephisto version and data module version differ!");
|
|
WARN("Lephisto is v%s, data is for v%s", version, buf);
|
|
}
|
|
|
|
free(buf);
|
|
|
|
/* Load the datafiles name. */
|
|
buf = pack_readfile(DATA, START_DATA, &bufsize);
|
|
|
|
xmlNodePtr node;
|
|
xmlDocPtr doc = xmlParseMemory(buf, bufsize);
|
|
|
|
node = doc->xmlChildrenNode;
|
|
if(!xml_isNode(node, XML_START_ID)) {
|
|
ERR("Maformed '"START_DATA"' file: missing root element '"XML_START_ID"'");
|
|
return;
|
|
}
|
|
|
|
node = node->xmlChildrenNode; /* First node. */
|
|
if(node == NULL) {
|
|
ERR("Malformed '"START_DATA"' file: does not contain elements");
|
|
return;
|
|
}
|
|
do {
|
|
if(xml_isNode(node, "name")) {
|
|
strncpy(dataname, xml_get(node), DATA_NAME_LEN);
|
|
dataname[DATA_NAME_LEN-1] = '\0';
|
|
}
|
|
} while(xml_nextNode(node));
|
|
|
|
xmlFreeDoc(doc);
|
|
free(buf);
|
|
}
|
|
|
|
/**
|
|
* @fn static void window_caption(void)
|
|
*
|
|
* @brief Set the window caption.
|
|
*/
|
|
static void window_caption(void) {
|
|
char tmp[DATA_NAME_LEN+10];
|
|
|
|
snprintf(tmp, DATA_NAME_LEN+10, APPNAME" - %s", dataname);
|
|
SDL_WM_SetCaption(tmp, NULL);
|
|
}
|
|
|
|
static char human_version[50]; /**< Stores human readable version string. */
|
|
|
|
/**
|
|
* @fn char* lephisto_version(void)
|
|
*
|
|
* @brief Return the version in a human readable string.
|
|
*
|
|
* @return The human readable version string.
|
|
*/
|
|
char* lephisto_version(void) {
|
|
if(human_version[0] == '\0')
|
|
snprintf(human_version, 50, " "APPNAME" v%s - %s", version, dataname);
|
|
|
|
return human_version;
|
|
}
|
|
|
|
/**
|
|
* @fn static void print print_SDLversion.
|
|
*
|
|
* @bief Print the SDL version to console.
|
|
*/
|
|
static void print_SDLversion(void) {
|
|
const SDL_version* linked;
|
|
SDL_version compiled;
|
|
SDL_VERSION(&compiled);
|
|
linked = SDL_Linked_Version();
|
|
|
|
DEBUG("SDL: %d.%d.%d [compiled: %d.%d.%d]",
|
|
linked->major, linked->minor, linked->patch,
|
|
compiled.major, compiled.minor, compiled.patch);
|
|
|
|
/* Check if major/minor version differ. */
|
|
if((linked->major*100 + linked->minor) > compiled.major*100 + compiled.minor)
|
|
WARN("SDL is newer than compiled version.");
|
|
if((linked->major*100 + linked->minor) < compiled.major*100 + compiled.minor)
|
|
WARN("SDL is older than compiled version.");
|
|
}
|
|
|
|
#if defined(LINUX) && !defined(NODEBUG)
|
|
/**
|
|
* @brief Get the string related to the signal code.
|
|
* @param sig Signal to which code belongs.
|
|
* @param sig_code Signal code to get string of.
|
|
* @return String of signal code.
|
|
*/
|
|
static const char* debug_sigCodeToStr(int sig, int sig_code) {
|
|
if(sig == SIGFPE)
|
|
switch(sig_code) {
|
|
case SI_USER: return "SIGFPE (raised by program)";
|
|
case FPE_INTDIV: return "SIGFPE (integer divide by zero)";
|
|
case FPE_INTOVF: return "SIGFPE (integer overflow)";
|
|
case FPE_FLTDIV: return "SIGFPE (floating-point divide by zero)";
|
|
case FPE_FLTOVF: return "SIGFPE (floating-point overflow)";
|
|
case FPE_FLTUND: return "SIGFPE (floating-point underflow)";
|
|
case FPE_FLTRES: return "SIGFPE (floating-point inexact result)";
|
|
case FPE_FLTINV: return "SIGFPE (floating-point invalid operation)";
|
|
case FPE_FLTSUB: return "SIGFPE (subscript out of range)";
|
|
default: return "SIGFPE";
|
|
}
|
|
else if(sig == SIGSEGV)
|
|
switch(sig_code) {
|
|
case SI_USER: return "SIGSEGV (raised by program)";
|
|
case SEGV_MAPERR: return "SIGEGV (address not mapped to object)";
|
|
case SEGV_ACCERR: return "SIGEGV (invalid permissions for mapped object)";
|
|
default: return "SIGSEGV";
|
|
}
|
|
else if(sig == SIGTRAP)
|
|
switch(sig_code) {
|
|
case SI_USER: return "SIGTRAP (raised by program)";
|
|
case TRAP_BRKPT: return "SIGTRAP (process breakpoint)";
|
|
case TRAP_TRACE: return "SIGTRAP (process trace trap)";
|
|
default: return "SIGTRAP";
|
|
}
|
|
/* No suitable code found. */
|
|
return strsignal(sig);
|
|
}
|
|
|
|
/**
|
|
* @brief Backtrace signal handler for linux.
|
|
* @param sig Signal.
|
|
* @param info Signal information.
|
|
* @param unused Unused.
|
|
*/
|
|
static void debug_sigHandler(int sig, siginfo_t* info, void* unused) {
|
|
(void) sig;
|
|
(void) unused;
|
|
int i, num;
|
|
void* buf[64];
|
|
char** symbols;
|
|
|
|
num = backtrace(buf, 64);
|
|
symbols = backtrace_symbols(buf, num);
|
|
|
|
DEBUG("LEPHISTO recieved %s!",
|
|
debug_sigCodeToStr(info->si_signo, info->si_code));
|
|
for(i = 0; i < num; i++)
|
|
DEBUG(" %s", symbols[i]);
|
|
DEBUG("Report this to project maintainer with the backtrace.");
|
|
|
|
exit(1);
|
|
}
|
|
#endif /* defined(LINUX) && !defined(DEBUG) */
|
|
|
|
/**
|
|
* @brief Set up the SignalHandler for Linux.
|
|
*/
|
|
static void debug_sigInit(void) {
|
|
#if defined(LINUX) && !defined(NODEBUG)
|
|
struct sigaction sa, so;
|
|
|
|
/* Set up handler. */
|
|
sa.sa_handler = NULL;
|
|
sa.sa_sigaction = debug_sigHandler;
|
|
sigemptyset(&sa.sa_mask);
|
|
sa.sa_flags = SA_SIGINFO;
|
|
|
|
/* Attach signals. */
|
|
sigaction(SIGSEGV, &sa, &so);
|
|
if(so.sa_handler == SIG_IGN)
|
|
DEBUG("Unable to set up SIGSEGV signal handler.");
|
|
sigaction(SIGFPE, &sa, &so);
|
|
if(so.sa_handler == SIG_IGN)
|
|
DEBUG("Unable to set up SIGFPE signal handler.");
|
|
sigaction(SIGTRAP, &sa, &so);
|
|
if(so.sa_handler == SIG_IGN)
|
|
DEBUG("Unable to get set up SIGTRAP signal handler.");
|
|
#endif /* #if defined(LINUX) && !defined(NODEBUG) */
|
|
}
|
|
|