# HG changeset patch # User Medo # Date 1339493105 -7200 # Node ID 5143861c83bd9c9143a4e5564d5710378bf35b77 # Parent 8d04e85ca2041f034269cc6dbdea09e2cfc9317c Cleanup, refactoring and generally more development in the frontlib diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/frontlib.c --- a/project_files/frontlib/frontlib.c Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/frontlib.c Tue Jun 12 11:25:05 2012 +0200 @@ -1,21 +1,14 @@ #include "frontlib.h" #include "util/logging.h" -#include "model/map.h" -#include "ipc/mapconn.h" -#include "ipc/gameconn.h" - #include #include -#include -#include -#include -#include static int flib_initflags; int flib_init(int flags) { flib_initflags = flags; + flib_log_d("Initializing frontlib"); if(!(flib_initflags | FRONTLIB_SDL_ALREADY_INITIALIZED)) { if(SDL_Init(0)==-1) { flib_log_e("Error in SDL_Init: %s", SDL_GetError()); @@ -35,81 +28,9 @@ } void flib_quit() { + flib_log_d("Shutting down frontlib"); SDLNet_Quit(); if(!(flib_initflags | FRONTLIB_SDL_ALREADY_INITIALIZED)) { SDL_Quit(); } } - -static void onDisconnect(void *context, int reason) { - flib_log_i("Connection closed. Reason: %i", reason); - flib_gameconn **connptr = context; - flib_gameconn_destroy(*connptr); - *connptr = NULL; -} - -static void onGameRecorded(void *context, const uint8_t *record, int size, bool isSavegame) { - flib_log_i("Writing %s (%i bytes)...", isSavegame ? "savegame" : "demo", size); - FILE *file = fopen(isSavegame ? "testsave.42.hws" : "testdemo.42.hwd", "wb"); - fwrite(record, 1, size, file); - fclose(file); -} - -int main(int argc, char *argv[]) { - flib_init(0); - - flib_cfg_meta *metaconf = flib_cfg_meta_from_ini("basicsettings.ini", "gamemods.ini"); - assert(metaconf); - flib_gamesetup setup; - setup.gamescheme = flib_cfg_from_ini(metaconf, "scheme_shoppa.ini"); - setup.map = flib_map_create_maze("Jungle", MAZE_SIZE_MEDIUM_TUNNELS); - setup.seed = "apsfooasdgnds"; - setup.script = NULL; - setup.teamcount = 2; - setup.teams = calloc(2, sizeof(flib_team)); - setup.teams[0].color = 0xffff0000; - setup.teams[0].flag = "australia"; - setup.teams[0].fort = "Plane"; - setup.teams[0].grave = "Bone"; - setup.teams[0].hogsInGame = 2; - setup.teams[0].name = "Team Awesome"; - setup.teams[0].voicepack = "British"; - setup.teams[0].weaponset = flib_weaponset_create("Defaultweaps"); - setup.teams[0].hogs[0].difficulty = 2; - setup.teams[0].hogs[0].hat = "NoHat"; - setup.teams[0].hogs[0].initialHealth = 100; - setup.teams[0].hogs[0].name = "Harry 120"; - setup.teams[0].hogs[1].difficulty = 2; - setup.teams[0].hogs[1].hat = "chef"; - setup.teams[0].hogs[1].initialHealth = 100; - setup.teams[0].hogs[1].name = "Chefkoch"; - setup.teams[1].color = 0xff0000ff; - setup.teams[1].flag = "germany"; - setup.teams[1].fort = "Cake"; - setup.teams[1].grave = "Cherry"; - setup.teams[1].hogsInGame = 2; - setup.teams[1].name = "The Krauts"; - setup.teams[1].voicepack = "Pirate"; - setup.teams[1].weaponset = flib_weaponset_create("Defaultweaps"); - setup.teams[1].hogs[0].difficulty = 0; - setup.teams[1].hogs[0].hat = "quotecap"; - setup.teams[1].hogs[0].initialHealth = 100; - setup.teams[1].hogs[0].name = "Quote"; - setup.teams[1].hogs[1].difficulty = 0; - setup.teams[1].hogs[1].hat = "chef"; - setup.teams[1].hogs[1].initialHealth = 100; - setup.teams[1].hogs[1].name = "Chefkoch2"; - - flib_gameconn *gameconn = flib_gameconn_create("Medo42", metaconf, &setup, false); - assert(gameconn); - - flib_gameconn_onDisconnect(gameconn, &onDisconnect, &gameconn); - flib_gameconn_onGameRecorded(gameconn, &onGameRecorded, &gameconn); - - while(gameconn) { - flib_gameconn_tick(gameconn); - } - flib_log_i("Shutting down..."); - flib_quit(); - return 0; -} diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/ipc/demo.c --- a/project_files/frontlib/ipc/demo.c Mon Jun 11 00:06:22 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -#include "demo.h" -#include "../util/logging.h" - -#include -#include -#include - -static int demo_record(flib_vector demoBuffer, const void *data, size_t len) { - if(flib_vector_append(demoBuffer, data, len) < len) { - flib_log_e("Error recording demo: Out of memory."); - return -1; - } else { - return 0; - } -} - -int flib_demo_record_from_engine(flib_vector demoBuffer, const uint8_t *message, const char *playerName) { - if(!demoBuffer || !message || !playerName) { - flib_log_e("Call to flib_demo_record_from_engine with demoBuffer==null or message==null or playerName==null"); - return -1; - } - - if(strchr("?CEiQqHb", message[1])) { - return 0; // Those message types are not recorded in a demo. - } - - if(message[1] == 's') { - if(message[0] >= 3) { - // Chat messages are reformatted to make them look as if they were received, not sent. - // Get the actual chat message as C string - char chatMsg[256]; - memcpy(chatMsg, message+2, message[0]-3); - chatMsg[message[0]-3] = 0; - - // If the message starts with /me, it will be displayed differently. - char converted[257]; - bool memessage = message[0] >= 7 && !memcmp(message+2, "/me ", 4); - const char *template = memessage ? "s\x02* %s %s " : "s\x01%s: %s "; - int size = snprintf(converted+1, 256, template, playerName, chatMsg); - if(size>0) { - converted[0] = size>255 ? 255 : size; - return demo_record(demoBuffer, converted, converted[0]+1); - } else { - return 0; - } - } else { - return 0; // Malformed chat message is no reason to abort... - } - } else { - return demo_record(demoBuffer, message, message[0]+1); - } -} - -int flib_demo_record_to_engine(flib_vector demoBuffer, const uint8_t *message, size_t len) { - if(!demoBuffer || (len>0 && !message)) { - flib_log_e("Call to flib_demo_record_to_engine with demoBuffer==null or message==null"); - return -1; - } - return demo_record(demoBuffer, message, len); -} - -void flib_demo_replace_gamemode(flib_buffer buf, char gamemode) { - size_t msgStart = 0; - char *data = (char*)buf.data; - while(msgStart+2 < buf.size) { - if(!memcmp(data+msgStart, "\x02T", 2)) { - data[msgStart+2] = gamemode; - } - msgStart += (uint8_t)data[msgStart]+1; - } -} diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/ipc/demo.h --- a/project_files/frontlib/ipc/demo.h Mon Jun 11 00:06:22 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/** - * Demo recording functions. Only used by the ipc game code. - */ - -#ifndef DEMO_H_ -#define DEMO_H_ - -#include "../util/buffer.h" - -/** - * Record a message sent from the engine to the frontend. - * Returns 0 for OK, a negative value on error. - * Don't pass NULL. - */ -int flib_demo_record_from_engine(flib_vector demoBuffer, const uint8_t *message, const char *playerName); - -/** - * Record a message sent from the frontend to the engine. - * Returns 0 for OK, a negative value on error. - * Don't pass NULL. - */ -int flib_demo_record_to_engine(flib_vector demoBuffer, const uint8_t *message, size_t len); - -/** - * Replace game mode messages ("TL", "TD", "TS", "TN") in the recording to mirror - * the intended use. Pass 'S' for savegames, 'D' for demos. - */ -void flib_demo_replace_gamemode(flib_buffer buf, char gamemode); - -#endif /* DEMO_H_ */ diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/ipc/gameconn.c --- a/project_files/frontlib/ipc/gameconn.c Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/ipc/gameconn.c Tue Jun 12 11:25:05 2012 +0200 @@ -2,9 +2,11 @@ #include "ipcconn.h" #include "ipcprotocol.h" #include "../util/logging.h" +#include "../util/util.h" #include "../hwconsts.h" #include #include +#include typedef enum { AWAIT_CONNECTION, @@ -13,8 +15,10 @@ } gameconn_state; struct _flib_gameconn { - flib_ipcconn connection; - flib_vector configBuffer; + flib_ipcconn *connection; + flib_vector *configBuffer; + flib_vector *demoBuffer; + char *playerName; gameconn_state state; bool netgame; @@ -69,7 +73,7 @@ return false; } -static int fillConfigBuffer(flib_vector configBuffer, const char *playerName, flib_cfg_meta *metaconf, flib_gamesetup *setup, bool netgame) { +static int fillConfigBuffer(flib_vector *configBuffer, const char *playerName, flib_cfg_meta *metaconf, flib_gamesetup *setup, bool netgame) { bool error = false; bool perHogAmmo = false; bool sharedAmmo = false; @@ -89,7 +93,7 @@ } if(setup->teams) { for(int i=0; iteamcount; i++) { - error |= flib_ipc_append_addteam(configBuffer, &setup->teams[i], perHogAmmo, sharedAmmo); + error |= flib_ipc_append_addteam(configBuffer, setup->teams[i], perHogAmmo, sharedAmmo); } } error |= flib_ipc_append_message(configBuffer, "!"); @@ -98,11 +102,15 @@ static flib_gameconn *flib_gameconn_create_partial(bool record, const char *playerName, bool netGame) { flib_gameconn *result = NULL; - flib_gameconn *tempConn = calloc(1, sizeof(flib_gameconn)); + flib_gameconn *tempConn = flib_calloc(1, sizeof(flib_gameconn)); if(tempConn) { - tempConn->connection = flib_ipcconn_create(record, playerName); + tempConn->connection = flib_ipcconn_create(); tempConn->configBuffer = flib_vector_create(); - if(tempConn->connection && tempConn->configBuffer) { + tempConn->playerName = flib_strdupnull(playerName); + if(tempConn->connection && tempConn->configBuffer && tempConn->playerName) { + if(record) { + tempConn->demoBuffer = flib_vector_create(); + } tempConn->state = AWAIT_CONNECTION; tempConn->netgame = netGame; clearCallbacks(tempConn); @@ -164,8 +172,10 @@ clearCallbacks(conn); conn->destroyRequested = true; } else { - flib_ipcconn_destroy(&conn->connection); - flib_vector_destroy(&conn->configBuffer); + flib_ipcconn_destroy(conn->connection); + flib_vector_destroy(conn->configBuffer); + flib_vector_destroy(conn->demoBuffer); + free(conn->playerName); free(conn); } } @@ -180,6 +190,93 @@ } } +static void demo_append(flib_gameconn *conn, const void *data, size_t len) { + if(conn->demoBuffer) { + if(flib_vector_append(conn->demoBuffer, data, len) < len) { + flib_log_e("Error recording demo: Out of memory."); + flib_vector_destroy(conn->demoBuffer); + conn->demoBuffer = NULL; + } + } +} + +static int format_chatmessage(uint8_t buffer[257], const char *playerName, const char *message) { + size_t msglen = strlen(message); + + // If the message starts with /me, it will be displayed differently. + bool meMessage = msglen >= 4 && !memcmp(message, "/me ", 4); + const char *template = meMessage ? "s\x02* %s %s " : "s\x01%s: %s "; + int size = snprintf((char*)buffer+1, 256, template, playerName, meMessage ? message+4 : message); + if(size>0) { + buffer[0] = size>255 ? 255 : size; + return 0; + } else { + return -1; + } +} + +static void demo_append_chatmessage(flib_gameconn *conn, const char *message) { + // Chat messages are reformatted to make them look as if they were received, not sent. + uint8_t converted[257]; + if(!format_chatmessage(converted, conn->playerName, message)) { + demo_append(conn, converted, converted[0]+1); + } +} + +static void demo_replace_gamemode(flib_buffer buf, char gamemode) { + size_t msgStart = 0; + uint8_t *data = (uint8_t*)buf.data; + while(msgStart+2 < buf.size) { + if(!memcmp(data+msgStart, "\x02T", 2)) { + data[msgStart+2] = gamemode; + } + msgStart += (uint8_t)data[msgStart]+1; + } +} + +int flib_gameconn_send_enginemsg(flib_gameconn *conn, uint8_t *data, int len) { + int result = -1; + if(!conn || (!data && len>0)) { + flib_log_e("null parameter in flib_gameconn_send_enginemsg"); + } else if(!flib_ipcconn_send_raw(conn->connection, data, len)) { + demo_append(conn, data, len); + result = 0; + } + return result; +} + +int flib_gameconn_send_textmsg(flib_gameconn *conn, int msgtype, const char *msg) { + int result = -1; + if(!conn || !msg) { + flib_log_e("null parameter in flib_gameconn_send_textmsg"); + } else { + uint8_t converted[257]; + int size = snprintf((char*)converted+1, 256, "s%c%s", (char)msgtype, msg); + if(size>0) { + converted[0] = size>255 ? 255 : size; + if(!flib_ipcconn_send_raw(conn->connection, converted, converted[0]+1)) { + demo_append(conn, converted, converted[0]+1); + result = 0; + } + } + } + return result; +} + +int flib_gameconn_send_chatmsg(flib_gameconn *conn, const char *playername, const char *msg) { + int result = -1; + uint8_t converted[257]; + if(!conn || !playername || !msg) { + flib_log_e("null parameter in flib_gameconn_send_chatmsg"); + } else if(format_chatmessage(converted, playername, msg)) { + flib_log_e("Error formatting message in flib_gameconn_send_chatmsg"); + } else if(!flib_ipcconn_send_raw(conn->connection, converted, converted[0]+1)) { + demo_append(conn, converted, converted[0]+1); + result = 0; + } + return result; +} + void flib_gameconn_onConnect(flib_gameconn *conn, void (*callback)(void* context), void* context) { if(!conn) { flib_log_e("null parameter in flib_gameconn_onConnect"); @@ -246,6 +343,7 @@ conn->onDisconnectCb(conn->onDisconnectCtx, GAME_END_ERROR); return; } else { + demo_append(conn, configBuffer.data, configBuffer.size); conn->state = CONNECTED; conn->onConnectCb(conn->onConnectCtx); if(conn->destroyRequested) { @@ -272,30 +370,31 @@ continue; } switch(msgbuffer[1]) { - case '?': + case '?': // Ping // The pong is already part of the config message break; - case 'C': + case 'C': // Config query // And we already send the config message on connecting. break; - case 'E': + case 'E': // Error message if(len>=3) { msgbuffer[len-2] = 0; conn->onErrorMessageCb(conn->onErrorMessageCtx, (char*)msgbuffer+2); } break; - case 'i': + case 'i': // Statistics // TODO stats break; - case 'Q': - case 'H': - case 'q': + case 'Q': // Game interrupted + case 'H': // Game halted + case 'q': // game finished { int reason = msgbuffer[1]=='Q' ? GAME_END_INTERRUPTED : msgbuffer[1]=='H' ? GAME_END_HALTED : GAME_END_FINISHED; bool savegame = (reason != GAME_END_FINISHED) && !conn->netgame; - flib_constbuffer record = flib_ipcconn_getrecord(conn->connection, savegame); - if(record.size) { - conn->onGameRecordedCb(conn->onGameRecordedCtx, record.data, record.size, savegame); + if(conn->demoBuffer) { + flib_buffer demoBuffer = flib_vector_as_buffer(conn->demoBuffer); + demo_replace_gamemode(demoBuffer, savegame ? 'S' : 'D'); + conn->onGameRecordedCb(conn->onGameRecordedCtx, demoBuffer.data, demoBuffer.size, savegame); if(conn->destroyRequested) { return; } @@ -304,19 +403,23 @@ conn->onDisconnectCb(conn->onDisconnectCtx, reason); return; } - case 's': + case 's': // Chat message if(len>=3) { msgbuffer[len-2] = 0; + demo_append_chatmessage(conn, (char*)msgbuffer+2); + conn->onChatCb(conn->onChatCtx, (char*)msgbuffer+2, false); } break; - case 'b': + case 'b': // Teamchat message if(len>=3) { msgbuffer[len-2] = 0; conn->onChatCb(conn->onChatCtx, (char*)msgbuffer+2, true); } break; - default: + default: // Engine message + demo_append(conn, msgbuffer, len); + conn->onNetMessageCb(conn->onNetMessageCtx, msgbuffer, len); break; } diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/ipc/gameconn.h --- a/project_files/frontlib/ipc/gameconn.h Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/ipc/gameconn.h Tue Jun 12 11:25:05 2012 +0200 @@ -33,12 +33,9 @@ */ void flib_gameconn_tick(flib_gameconn *conn); -// TODO: Not needed yet, only for netgames -/* -flib_gameconn_send_enginemsg(flib_gameconn conn, uint8_t *data, int len); -flib_gameconn_send_textmsg(flib_gameconn conn, int msgtype, const char *msg); -flib_gameconn_send_chatmsg(flib_gameconn conn, const char *playername, const char *msg); -*/ +int flib_gameconn_send_enginemsg(flib_gameconn *conn, uint8_t *data, int len); +int flib_gameconn_send_textmsg(flib_gameconn *conn, int msgtype, const char *msg); +int flib_gameconn_send_chatmsg(flib_gameconn *conn, const char *playername, const char *msg); /** * handleConnect(void *context) diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/ipc/ipcconn.c --- a/project_files/frontlib/ipc/ipcconn.c Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/ipc/ipcconn.c Tue Jun 12 11:25:05 2012 +0200 @@ -1,6 +1,6 @@ #include "ipcconn.h" -#include "demo.h" #include "../util/logging.h" +#include "../util/util.h" #include "../socket.h" #include @@ -17,25 +17,21 @@ */ typedef struct _flib_ipcconn { uint8_t readBuffer[8192]; - char playerName[256]; - int readBufferSize; - flib_acceptor acceptor; + flib_acceptor *acceptor; uint16_t port; - flib_tcpsocket sock; - flib_vector demoBuffer; + flib_tcpsocket *sock; } _flib_ipcconn; -flib_ipcconn flib_ipcconn_create(bool recordDemo, const char *localPlayerName) { - flib_ipcconn result = malloc(sizeof(_flib_ipcconn)); - flib_acceptor acceptor = flib_acceptor_create(0); +flib_ipcconn *flib_ipcconn_create() { + flib_ipcconn *result = flib_malloc(sizeof(_flib_ipcconn)); + flib_acceptor *acceptor = flib_acceptor_create(0); if(!result || !acceptor) { - flib_log_e("Can't create ipcconn."); free(result); - flib_acceptor_close(&acceptor); + flib_acceptor_close(acceptor); return NULL; } @@ -44,44 +40,29 @@ result->readBufferSize = 0; result->port = flib_acceptor_listenport(acceptor); - if(localPlayerName) { - strncpy(result->playerName, localPlayerName, 255); - } else { - strncpy(result->playerName, "Player", 255); - } - - if(recordDemo) { - result->demoBuffer = flib_vector_create(); - } - flib_log_i("Started listening for IPC connections on port %u", (unsigned)result->port); return result; } -uint16_t flib_ipcconn_port(flib_ipcconn ipc) { +uint16_t flib_ipcconn_port(flib_ipcconn *ipc) { if(!ipc) { - flib_log_e("Call to flib_ipcconn_port with ipc==null"); + flib_log_e("null parameter in flib_ipcconn_port"); return 0; } return ipc->port; } -void flib_ipcconn_destroy(flib_ipcconn *ipcptr) { - if(!ipcptr) { - flib_log_e("Call to flib_ipcconn_destroy with ipcptr==null"); - } else if(*ipcptr) { - flib_ipcconn ipc = *ipcptr; - flib_acceptor_close(&ipc->acceptor); - flib_socket_close(&ipc->sock); - flib_vector_destroy(&ipc->demoBuffer); +void flib_ipcconn_destroy(flib_ipcconn *ipc) { + if(ipc) { + flib_acceptor_close(ipc->acceptor); + flib_socket_close(ipc->sock); free(ipc); - *ipcptr = NULL; } } -IpcConnState flib_ipcconn_state(flib_ipcconn ipc) { +IpcConnState flib_ipcconn_state(flib_ipcconn *ipc) { if(!ipc) { - flib_log_e("Call to flib_ipcconn_state with ipc==null"); + flib_log_e("null parameter in flib_ipcconn_state"); return IPC_NOT_CONNECTED; } else if(ipc->sock) { return IPC_CONNECTED; @@ -92,24 +73,25 @@ } } -static bool isMessageReady(flib_ipcconn ipc) { +static bool isMessageReady(flib_ipcconn *ipc) { return ipc->readBufferSize >= ipc->readBuffer[0]+1; } -static void receiveToBuffer(flib_ipcconn ipc) { +static void receiveToBuffer(flib_ipcconn *ipc) { if(ipc->sock) { int size = flib_socket_nbrecv(ipc->sock, ipc->readBuffer+ipc->readBufferSize, sizeof(ipc->readBuffer)-ipc->readBufferSize); if(size>=0) { ipc->readBufferSize += size; } else { - flib_socket_close(&ipc->sock); + flib_socket_close(ipc->sock); + ipc->sock = NULL; } } } -int flib_ipcconn_recv_message(flib_ipcconn ipc, void *data) { +int flib_ipcconn_recv_message(flib_ipcconn *ipc, void *data) { if(!ipc || !data) { - flib_log_e("Call to flib_ipcconn_recv_message with ipc==null or data==null"); + flib_log_e("null parameter in flib_ipcconn_recv_message"); return -1; } @@ -118,12 +100,6 @@ } if(isMessageReady(ipc)) { - if(ipc->demoBuffer) { - if(flib_demo_record_from_engine(ipc->demoBuffer, ipc->readBuffer, ipc->playerName) < 0) { - flib_log_w("Stopping demo recording due to an error."); - flib_vector_destroy(&ipc->demoBuffer); - } - } int msgsize = ipc->readBuffer[0]+1; memcpy(data, ipc->readBuffer, msgsize); memmove(ipc->readBuffer, ipc->readBuffer+msgsize, ipc->readBufferSize-msgsize); @@ -138,9 +114,9 @@ } } -int flib_ipcconn_recv_map(flib_ipcconn ipc, void *data) { +int flib_ipcconn_recv_map(flib_ipcconn *ipc, void *data) { if(!ipc || !data) { - flib_log_e("Call to flib_ipcconn_recv_map with ipc==null or data==null"); + flib_log_e("null parameter in flib_ipcconn_recv_map"); return -1; } @@ -156,7 +132,7 @@ } static void logSentMsg(const uint8_t *data, size_t len) { - if(flib_log_getLevel() > FLIB_LOGLEVEL_DEBUG) { + if(flib_log_isActive(FLIB_LOGLEVEL_DEBUG)) { size_t msgStart = 0; while(msgStart < len) { uint8_t msglen = data[msgStart]; @@ -171,9 +147,9 @@ } } -int flib_ipcconn_send_raw(flib_ipcconn ipc, const void *data, size_t len) { +int flib_ipcconn_send_raw(flib_ipcconn *ipc, const void *data, size_t len) { if(!ipc || (!data && len>0)) { - flib_log_e("Call to flib_ipcconn_send_raw with ipc==null or data==null"); + flib_log_e("null parameter in flib_ipcconn_send_raw"); return -1; } if(!ipc->sock) { @@ -183,23 +159,21 @@ if(flib_socket_send(ipc->sock, data, len) == len) { logSentMsg(data, len); - if(ipc->demoBuffer) { - if(flib_demo_record_to_engine(ipc->demoBuffer, data, len) < 0) { - flib_log_w("Stopping demo recording due to an error."); - flib_vector_destroy(&ipc->demoBuffer); - } - } return 0; } else { flib_log_w("Failed or incomplete ICP write: engine connection lost."); - flib_socket_close(&ipc->sock); + flib_socket_close(ipc->sock); + ipc->sock = NULL; return -1; } } -int flib_ipcconn_send_message(flib_ipcconn ipc, void *data, size_t len) { - if(!ipc || (!data && len>0) || len>255) { - flib_log_e("Call to flib_ipcconn_send_message with ipc==null or data==null or len>255"); +int flib_ipcconn_send_message(flib_ipcconn *ipc, void *data, size_t len) { + if(!ipc || (!data && len>0)) { + flib_log_e("null parameter in flib_ipcconn_send_message"); + return -1; + } else if(len>255) { + flib_log_e("Overlong message (%zu bytes) in flib_ipcconn_send_message", len); return -1; } @@ -209,29 +183,18 @@ return flib_ipcconn_send_raw(ipc, sendbuf, len+1); } -int flib_ipcconn_send_messagestr(flib_ipcconn ipc, char *data) { +int flib_ipcconn_send_messagestr(flib_ipcconn *ipc, char *data) { return flib_ipcconn_send_message(ipc, data, strlen(data)); } -void flib_ipcconn_accept(flib_ipcconn ipc) { +void flib_ipcconn_accept(flib_ipcconn *ipc) { if(!ipc) { - flib_log_e("Call to flib_ipcconn_accept with ipc==null"); + flib_log_e("null parameter in flib_ipcconn_accept"); } else if(!ipc->sock && ipc->acceptor) { ipc->sock = flib_socket_accept(ipc->acceptor, true); if(ipc->sock) { - flib_acceptor_close(&ipc->acceptor); + flib_acceptor_close(ipc->acceptor); + ipc->acceptor = NULL; } } } - -flib_constbuffer flib_ipcconn_getrecord(flib_ipcconn ipc, bool save) { - if(!ipc) { - flib_log_e("Call to flib_ipcconn_getrecord with ipc==null"); - } - if(!ipc || !ipc->demoBuffer) { - flib_constbuffer result = {NULL, 0}; - return result; - } - flib_demo_replace_gamemode(flib_vector_as_buffer(ipc->demoBuffer), save ? 'S' : 'D'); - return flib_vector_as_constbuffer(ipc->demoBuffer); -} diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/ipc/ipcconn.h --- a/project_files/frontlib/ipc/ipcconn.h Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/ipc/ipcconn.h Tue Jun 12 11:25:05 2012 +0200 @@ -15,11 +15,9 @@ typedef enum {IPC_NOT_CONNECTED, IPC_LISTENING, IPC_CONNECTED} IpcConnState; struct _flib_ipcconn; -typedef struct _flib_ipcconn *flib_ipcconn; +typedef struct _flib_ipcconn flib_ipcconn; /** - * TODO move demo recording up by one layer? - * * Start an engine connection by listening on a random port. The selected port can * be queried with flib_ipcconn_port and has to be passed to the engine. * @@ -32,19 +30,19 @@ * We stop accepting new connections once a connection has been established, so you * need to create a new ipcconn in order to start a new connection. */ -flib_ipcconn flib_ipcconn_create(bool recordDemo, const char *localPlayerName); +flib_ipcconn *flib_ipcconn_create(); -uint16_t flib_ipcconn_port(flib_ipcconn ipc); +uint16_t flib_ipcconn_port(flib_ipcconn *ipc); /** - * Free resources, close sockets, and set the pointer to NULL. + * Free resources and close sockets. */ -void flib_ipcconn_destroy(flib_ipcconn *ipcptr); +void flib_ipcconn_destroy(flib_ipcconn *ipc); /** * Determine the current connection state */ -IpcConnState flib_ipcconn_state(flib_ipcconn ipc); +IpcConnState flib_ipcconn_state(flib_ipcconn *ipc); /** * Receive a single message (up to 256 bytes) and copy it into the data buffer. @@ -58,7 +56,7 @@ * no further message is returned, to ensure you see all messages that were sent * before the connection closed. */ -int flib_ipcconn_recv_message(flib_ipcconn ipc, void *data); +int flib_ipcconn_recv_message(flib_ipcconn *ipc, void *data); /** * Try to receive 4097 bytes. This is the size of the reply the engine sends @@ -66,9 +64,9 @@ * twocolor image of the map (256x128), the last byte is the number of hogs that * fit on the map. */ -int flib_ipcconn_recv_map(flib_ipcconn ipc, void *data); +int flib_ipcconn_recv_map(flib_ipcconn *ipc, void *data); -int flib_ipcconn_send_raw(flib_ipcconn ipc, const void *data, size_t len); +int flib_ipcconn_send_raw(flib_ipcconn *ipc, const void *data, size_t len); /** * Write a single message (up to 255 bytes) to the engine. This call blocks until the @@ -77,32 +75,17 @@ * Calling this function in a state other than IPC_CONNECTED will fail immediately. * Returns a negative value on failure. */ -int flib_ipcconn_send_message(flib_ipcconn ipc, void *data, size_t len); +int flib_ipcconn_send_message(flib_ipcconn *ipc, void *data, size_t len); /** * Convenience function for sending a 0-delimited string. */ -int flib_ipcconn_send_messagestr(flib_ipcconn ipc, char *data); +int flib_ipcconn_send_messagestr(flib_ipcconn *ipc, char *data); /** * Call regularly to allow background work to proceed */ -void flib_ipcconn_accept(flib_ipcconn ipc); - -/** - * Get a record of the connection. This should be called after - * the connection is closed and all messages have been received. - * - * If demo recording was not enabled, or if the recording failed for some reason, - * the buffer will be empty. - * - * If save=true is passed, the result will be a savegame, otherwise it will be a - * demo. - * - * The buffer is only valid until flib_ipcconn_getsave is called again or the ipcconn - * is destroyed. - */ -flib_constbuffer flib_ipcconn_getrecord(flib_ipcconn ipc, bool save); +void flib_ipcconn_accept(flib_ipcconn *ipc); #endif /* IPCCONN_H_ */ diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/ipc/ipcprotocol.c --- a/project_files/frontlib/ipc/ipcprotocol.c Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/ipc/ipcprotocol.c Tue Jun 12 11:25:05 2012 +0200 @@ -7,7 +7,7 @@ #include #include -int flib_ipc_append_message(flib_vector vec, const char *fmt, ...) { +int flib_ipc_append_message(flib_vector *vec, const char *fmt, ...) { int result = -1; if(!vec || !fmt) { flib_log_e("null parameter in flib_ipc_appendmessage"); @@ -38,9 +38,9 @@ return result; } -int flib_ipc_append_mapconf(flib_vector vec, flib_map *map, bool mappreview) { +int flib_ipc_append_mapconf(flib_vector *vec, flib_map *map, bool mappreview) { int result = -1; - flib_vector tempvector = flib_vector_create(); + flib_vector *tempvector = flib_vector_create(); if(!vec || !map) { flib_log_e("null parameter in flib_ipc_append_mapconf"); } else if(tempvector) { @@ -83,11 +83,11 @@ } } } - flib_vector_destroy(&tempvector); + flib_vector_destroy(tempvector); return result; } -int flib_ipc_append_seed(flib_vector vec, const char *seed) { +int flib_ipc_append_seed(flib_vector *vec, const char *seed) { if(!vec || !seed) { flib_log_e("null parameter in flib_ipc_append_seed"); return -1; @@ -96,9 +96,9 @@ } } -int flib_ipc_append_gamescheme(flib_vector vec, flib_cfg *scheme, flib_cfg_meta *meta) { +int flib_ipc_append_gamescheme(flib_vector *vec, flib_cfg *scheme, flib_cfg_meta *meta) { int result = -1; - flib_vector tempvector = flib_vector_create(); + flib_vector *tempvector = flib_vector_create(); if(!vec || !scheme || !meta) { flib_log_e("null parameter in flib_ipc_append_gamescheme"); } else if(tempvector) { @@ -129,14 +129,14 @@ } } } - flib_vector_destroy(&tempvector); + flib_vector_destroy(tempvector); return result; } // FIXME shared ammo will break per-team ammo -int flib_ipc_append_addteam(flib_vector vec, flib_team *team, bool perHogAmmo, bool sharedAmmo) { +int flib_ipc_append_addteam(flib_vector *vec, flib_team *team, bool perHogAmmo, bool sharedAmmo) { int result = -1; - flib_vector tempvector = flib_vector_create(); + flib_vector *tempvector = flib_vector_create(); if(!vec || !team || !team->weaponset) { flib_log_e("invalid parameter in flib_ipc_append_addteam"); } else if(tempvector) { @@ -161,7 +161,9 @@ error |= flib_ipc_append_message(tempvector, "evoicepack %s", team->voicepack); error |= flib_ipc_append_message(tempvector, "eflag %s", team->flag); - // TODO bindings + for(int i=0; ibindingCount; i++) { + error |= flib_ipc_append_message(tempvector, "ebind %s %s", team->bindings[i].binding, team->bindings[i].action); + } for(int i=0; ihogsInGame; i++) { error |= flib_ipc_append_message(tempvector, "eaddhh %i %i %s", team->hogs[i].difficulty, team->hogs[i].initialHealth, team->hogs[i].name); @@ -176,6 +178,6 @@ } } } - flib_vector_destroy(&tempvector); + flib_vector_destroy(tempvector); return result; } diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/ipc/ipcprotocol.h --- a/project_files/frontlib/ipc/ipcprotocol.h Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/ipc/ipcprotocol.h Tue Jun 12 11:25:05 2012 +0200 @@ -15,7 +15,7 @@ * Returns nonzero if something goes wrong. In that case the buffer * contents are unaffected. */ -int flib_ipc_append_message(flib_vector vec, const char *fmt, ...); +int flib_ipc_append_message(flib_vector *vec, const char *fmt, ...); /** * Append IPC messages to the buffer that configure the engine for @@ -27,7 +27,7 @@ * Returns nonzero if something goes wrong. In that case the buffer * contents are unaffected. */ -int flib_ipc_append_mapconf(flib_vector vec, flib_map *map, bool mappreview); +int flib_ipc_append_mapconf(flib_vector *vec, flib_map *map, bool mappreview); /** * Append a seed message to the buffer. @@ -35,7 +35,7 @@ * Returns nonzero if something goes wrong. In that case the buffer * contents are unaffected. */ -int flib_ipc_append_seed(flib_vector vec, const char *seed); +int flib_ipc_append_seed(flib_vector *vec, const char *seed); /** * Append the game scheme to the buffer. @@ -43,8 +43,8 @@ * Returns nonzero if something goes wrong. In that case the buffer * contents are unaffected. */ -int flib_ipc_append_gamescheme(flib_vector vec, flib_cfg *seed, flib_cfg_meta *meta); +int flib_ipc_append_gamescheme(flib_vector *vec, flib_cfg *seed, flib_cfg_meta *meta); -int flib_ipc_append_addteam(flib_vector vec, flib_team *team, bool perHogAmmo, bool sharedAmmo); +int flib_ipc_append_addteam(flib_vector *vec, flib_team *team, bool perHogAmmo, bool sharedAmmo); #endif /* IPCPROTOCOL_H_ */ diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/ipc/mapconn.c --- a/project_files/frontlib/ipc/mapconn.c Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/ipc/mapconn.c Tue Jun 12 11:25:05 2012 +0200 @@ -4,6 +4,7 @@ #include "../util/logging.h" #include "../util/buffer.h" +#include "../util/util.h" #include @@ -15,8 +16,8 @@ struct _flib_mapconn { uint8_t mapBuffer[IPCCONN_MAPMSG_BYTES]; - flib_ipcconn connection; - flib_vector configBuffer; + flib_ipcconn *connection; + flib_vector *configBuffer; mapconn_state progress; @@ -38,9 +39,9 @@ conn->onFailureCb = &noop_handleFailure; } -static flib_vector createConfigBuffer(char *seed, flib_map *mapdesc) { - flib_vector result = NULL; - flib_vector tempbuffer = flib_vector_create(); +static flib_vector *createConfigBuffer(char *seed, flib_map *mapdesc) { + flib_vector *result = NULL; + flib_vector *tempbuffer = flib_vector_create(); if(tempbuffer) { bool error = false; error |= flib_ipc_append_seed(tempbuffer, seed); @@ -51,15 +52,15 @@ tempbuffer = NULL; } } - flib_vector_destroy(&tempbuffer); + flib_vector_destroy(tempbuffer); return result; } flib_mapconn *flib_mapconn_create(char *seed, flib_map *mapdesc) { flib_mapconn *result = NULL; - flib_mapconn *tempConn = calloc(1, sizeof(flib_mapconn)); + flib_mapconn *tempConn = flib_calloc(1, sizeof(flib_mapconn)); if(tempConn) { - tempConn->connection = flib_ipcconn_create(false, "Player"); + tempConn->connection = flib_ipcconn_create(); tempConn->configBuffer = createConfigBuffer(seed, mapdesc); if(tempConn->connection && tempConn->configBuffer) { tempConn->progress = AWAIT_CONNECTION; @@ -83,8 +84,8 @@ clearCallbacks(conn); conn->destroyRequested = true; } else { - flib_ipcconn_destroy(&conn->connection); - flib_vector_destroy(&conn->configBuffer); + flib_ipcconn_destroy(conn->connection); + flib_vector_destroy(conn->configBuffer); free(conn); } } diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/model/cfg.c --- a/project_files/frontlib/model/cfg.c Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/model/cfg.c Tue Jun 12 11:25:05 2012 +0200 @@ -8,7 +8,78 @@ #include -static void freeCfgMeta(flib_cfg_meta *cfg) { +static flib_cfg_meta *flib_cfg_meta_from_ini_handleError(flib_cfg_meta *result, dictionary *settingfile, dictionary *modfile) { + flib_cfg_meta_destroy(result); + iniparser_freedict(settingfile); + iniparser_freedict(modfile); + return NULL; +} + +flib_cfg_meta *flib_cfg_meta_from_ini(const char *settingpath, const char *modpath) { + if(!settingpath || !modpath) { + flib_log_e("null parameter in flib_cfg_meta_from_ini"); + return NULL; + } + flib_cfg_meta *result = flib_calloc(1, sizeof(flib_cfg_meta)); + dictionary *settingfile = iniparser_load(settingpath); + dictionary *modfile = iniparser_load(modpath); + + if(!result || !settingfile || !modfile) { + return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); + } + + result->settingCount = iniparser_getnsec(settingfile); + result->modCount = iniparser_getnsec(modfile); + result->settings = flib_calloc(result->settingCount, sizeof(flib_cfg_setting_meta)); + result->mods = flib_calloc(result->modCount, sizeof(flib_cfg_mod_meta)); + + if(!result->settings || !result->mods) { + return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); + } + + for(int i=0; isettingCount; i++) { + char *sectionName = iniparser_getsecname(settingfile, i); + if(!sectionName) { + return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); + } + + bool error = false; + result->settings[i].iniName = flib_strdupnull(sectionName); + result->settings[i].title = inihelper_getstringdup(settingfile, &error, sectionName, "title"); + result->settings[i].engineCommand = inihelper_getstringdup(settingfile, &error, sectionName, "command"); + result->settings[i].image = inihelper_getstringdup(settingfile, &error, sectionName, "image"); + result->settings[i].checkOverMax = inihelper_getbool(settingfile, &error, sectionName, "checkOverMax"); + result->settings[i].times1000 = inihelper_getbool(settingfile, &error, sectionName, "times1000"); + result->settings[i].min = inihelper_getint(settingfile, &error, sectionName, "min"); + result->settings[i].max = inihelper_getint(settingfile, &error, sectionName, "max"); + result->settings[i].def = inihelper_getint(settingfile, &error, sectionName, "default"); + if(error) { + flib_log_e("Missing or malformed ini parameter in file %s, section %s", settingpath, sectionName); + return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); + } + } + + for(int i=0; imodCount; i++) { + char *sectionName = iniparser_getsecname(modfile, i); + if(!sectionName) { + return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); + } + + bool error = false; + result->mods[i].iniName = flib_strdupnull(sectionName); + result->mods[i].bitmaskIndex = inihelper_getint(modfile, &error, sectionName, "bitmaskIndex"); + if(error) { + flib_log_e("Missing or malformed ini parameter in file %s, section %s", modpath, sectionName); + return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); + } + } + + iniparser_freedict(settingfile); + iniparser_freedict(modfile); + return result; +} + +void flib_cfg_meta_destroy(flib_cfg_meta *cfg) { if(cfg) { if(cfg->settings) { for(int i=0; isettingCount; i++) { @@ -29,90 +100,18 @@ } } -flib_cfg_meta *flib_cfg_meta_from_ini(const char *settingpath, const char *modpath) { - if(!settingpath || !modpath) { - return NULL; - } - flib_cfg_meta *result = calloc(1, sizeof(flib_cfg_meta)); - dictionary *settingfile = iniparser_load(settingpath); - dictionary *modfile = iniparser_load(modpath); - - if(!result || !settingfile || !modfile) { - goto handleError; - } - - result->settingCount = iniparser_getnsec(settingfile); - result->modCount = iniparser_getnsec(modfile); - result->settings = calloc(result->settingCount, sizeof(flib_cfg_setting_meta)); - result->mods = calloc(result->modCount, sizeof(flib_cfg_mod_meta)); - - if(!result->settings || !result->mods) { - goto handleError; - } - - for(int i=0; isettingCount; i++) { - char *sectionName = iniparser_getsecname(settingfile, i); - if(!sectionName) { - goto handleError; - } - - bool error = false; - result->settings[i].iniName = flib_strdupnull(sectionName); - result->settings[i].title = inihelper_getstringdup(settingfile, &error, sectionName, "title"); - result->settings[i].engineCommand = inihelper_getstringdup(settingfile, &error, sectionName, "command"); - result->settings[i].image = inihelper_getstringdup(settingfile, &error, sectionName, "image"); - result->settings[i].checkOverMax = inihelper_getbool(settingfile, &error, sectionName, "checkOverMax"); - result->settings[i].times1000 = inihelper_getbool(settingfile, &error, sectionName, "times1000"); - result->settings[i].min = inihelper_getint(settingfile, &error, sectionName, "min"); - result->settings[i].max = inihelper_getint(settingfile, &error, sectionName, "max"); - result->settings[i].def = inihelper_getint(settingfile, &error, sectionName, "default"); - if(error) { - flib_log_e("Missing or malformed ini parameter in file %s, section %s", settingpath, sectionName); - goto handleError; - } - } - - for(int i=0; imodCount; i++) { - char *sectionName = iniparser_getsecname(modfile, i); - if(!sectionName) { - goto handleError; - } - - bool error = false; - result->mods[i].iniName = flib_strdupnull(sectionName); - result->mods[i].bitmaskIndex = inihelper_getint(modfile, &error, sectionName, "bitmaskIndex"); - if(error) { - flib_log_e("Missing or malformed ini parameter in file %s, section %s", modpath, sectionName); - goto handleError; - } - } - - iniparser_freedict(settingfile); - iniparser_freedict(modfile); - return result; - - handleError: - freeCfgMeta(result); - iniparser_freedict(settingfile); - iniparser_freedict(modfile); - return NULL; -} - -void flib_cfg_meta_destroy(flib_cfg_meta *metainfo) { - freeCfgMeta(metainfo); -} - flib_cfg *flib_cfg_create(const flib_cfg_meta *meta, const char *schemeName) { - flib_cfg *result = calloc(1, sizeof(flib_cfg)); + flib_cfg *result = flib_calloc(1, sizeof(flib_cfg)); if(!meta || !result || !schemeName) { + flib_log_e("null parameter in flib_cfg_create"); return NULL; } result->modCount = meta->modCount; result->settingCount = meta->settingCount; result->schemeName = flib_strdupnull(schemeName); - result->mods = calloc(meta->modCount, sizeof(*result->mods)); - result->settings = calloc(meta->settingCount, sizeof(*result->settings)); + result->mods = flib_calloc(meta->modCount, sizeof(*result->mods)); + result->settings = flib_calloc(meta->settingCount, sizeof(*result->settings)); if(!result->mods || !result->settings || !result->schemeName) { flib_cfg_destroy(result); @@ -133,6 +132,7 @@ flib_cfg *flib_cfg_from_ini(const flib_cfg_meta *meta, const char *filename) { if(!meta || !filename) { + flib_log_e("null parameter in flib_cfg_from_ini"); return NULL; } dictionary *settingfile = iniparser_load(filename); @@ -170,8 +170,13 @@ int flib_cfg_to_ini(const flib_cfg_meta *meta, const char *filename, const flib_cfg *config) { int result = -1; - if(meta && filename && config && config->modCount==meta->modCount && config->settingCount==meta->settingCount) { - dictionary *dict = dictionary_new(0); + if(!meta || !filename || !config || config->modCount!=meta->modCount || config->settingCount!=meta->settingCount) { + flib_log_e("Invalid parameter in flib_cfg_to_ini"); + } else { + dictionary *dict = iniparser_load(filename); + if(!dict) { + dict = dictionary_new(0); + } if(dict) { bool error = false; // Add the sections diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/model/cfg.h --- a/project_files/frontlib/model/cfg.h Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/model/cfg.h Tue Jun 12 11:25:05 2012 +0200 @@ -44,11 +44,32 @@ bool *mods; } flib_cfg; +/** + * Read the meta-configuration from the relevant .ini files (e.g. which settings exist, + * what are their defaults etc.) + * + * Returns the meta-configuration or NULL. Destroy the meta-configuration with + * flib_cfg_meta_destroy. + */ flib_cfg_meta *flib_cfg_meta_from_ini(const char *settingpath, const char *modpath); void flib_cfg_meta_destroy(flib_cfg_meta *metainfo); +/** + * Create a new configuration with default settings. + * Returns NULL on error. + */ flib_cfg *flib_cfg_create(const flib_cfg_meta *meta, const char *schemeName); + +/** + * Load a configuration from the ini file. + * Returns NULL on error. + */ flib_cfg *flib_cfg_from_ini(const flib_cfg_meta *meta, const char *filename); + +/** + * Store the configuration to an ini file. + * Returns NULL on error. + */ int flib_cfg_to_ini(const flib_cfg_meta *meta, const char *filename, const flib_cfg *config); void flib_cfg_destroy(flib_cfg* cfg); diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/model/gamesetup.h --- a/project_files/frontlib/model/gamesetup.h Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/model/gamesetup.h Tue Jun 12 11:25:05 2012 +0200 @@ -18,7 +18,7 @@ char *script; // optional flib_cfg *gamescheme; // optional flib_map *map; // optional - flib_team *teams; // optional + flib_team **teams; // optional int teamcount; } flib_gamesetup; diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/model/map.c --- a/project_files/frontlib/model/map.c Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/model/map.c Tue Jun 12 11:25:05 2012 +0200 @@ -11,7 +11,7 @@ if(!theme) { flib_log_e("null parameter in flib_map_create_regular"); } else { - flib_map *newmap = calloc(1, sizeof(flib_map)); + flib_map *newmap = flib_calloc(1, sizeof(flib_map)); if(newmap) { newmap->mapgen = MAPGEN_REGULAR; newmap->templateFilter = templateFilter; @@ -31,7 +31,7 @@ if(!theme) { flib_log_e("null parameter in flib_map_create_maze"); } else { - flib_map *newmap = calloc(1, sizeof(flib_map)); + flib_map *newmap = flib_calloc(1, sizeof(flib_map)); if(newmap) { newmap->mapgen = MAPGEN_MAZE; newmap->mazeSize = mazeSize; @@ -51,7 +51,7 @@ if(!name) { flib_log_e("null parameter in flib_map_create_named"); } else { - flib_map *newmap = calloc(1, sizeof(flib_map)); + flib_map *newmap = flib_calloc(1, sizeof(flib_map)); if(newmap) { newmap->mapgen = MAPGEN_NAMED; newmap->name = flib_strdupnull(name); @@ -70,7 +70,7 @@ if(!theme || !drawData) { flib_log_e("null parameter in flib_map_create_named"); } else { - flib_map *newmap = calloc(1, sizeof(flib_map)); + flib_map *newmap = flib_calloc(1, sizeof(flib_map)); if(newmap) { newmap->mapgen = MAPGEN_DRAWN; newmap->drawData = flib_bufdupnull(drawData, drawDataSize); diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/model/team.c --- a/project_files/frontlib/model/team.c Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/model/team.c Tue Jun 12 11:25:05 2012 +0200 @@ -1,1 +1,109 @@ #include "team.h" + +#include "../util/inihelper.h" +#include "../util/util.h" +#include "../util/logging.h" + +static flib_team *from_ini_handleError(flib_team *result, dictionary *settingfile, char **bindingKeys) { + if(settingfile) { + iniparser_freedict(settingfile); + } + flib_team_destroy(result); + free(bindingKeys); + return NULL; +} + +flib_team *flib_team_from_ini(const char *filename) { + flib_team *result = flib_calloc(1, sizeof(flib_team)); + dictionary *settingfile = NULL; + char **bindingKeys = NULL; + + if(!filename) { + flib_log_e("null parameter in flib_team_from_ini"); + return from_ini_handleError(result, settingfile, bindingKeys); + } + + if(!result) { + return from_ini_handleError(result, settingfile, bindingKeys); + } + + settingfile = iniparser_load(filename); + if(!settingfile) { + flib_log_e("Error loading team file %s", filename); + return from_ini_handleError(result, settingfile, bindingKeys); + } + + bool error = false; + result->name = inihelper_getstringdup(settingfile, &error, "team", "name"); + result->grave = inihelper_getstringdup(settingfile, &error, "team", "grave"); + result->fort = inihelper_getstringdup(settingfile, &error, "team", "fort"); + result->voicepack = inihelper_getstringdup(settingfile, &error, "team", "voicepack"); + result->flag = inihelper_getstringdup(settingfile, &error, "team", "flag"); + result->rounds = inihelper_getint(settingfile, &error, "team", "rounds"); + result->wins = inihelper_getint(settingfile, &error, "team", "wins"); + result->campaignProgress = inihelper_getint(settingfile, &error, "team", "campaignprogress"); + int difficulty = inihelper_getint(settingfile, &error, "team", "difficulty"); + + char sectionName[10]; + strcpy(sectionName, "hedgehog0"); + for(int i=0; ihogs[i].name = inihelper_getstringdup(settingfile, &error, sectionName, "name"); + result->hogs[i].hat = inihelper_getstringdup(settingfile, &error, sectionName, "hat"); + result->hogs[i].rounds = inihelper_getint(settingfile, &error, sectionName, "rounds"); + result->hogs[i].kills = inihelper_getint(settingfile, &error, sectionName, "kills"); + result->hogs[i].deaths = inihelper_getint(settingfile, &error, sectionName, "deaths"); + result->hogs[i].suicides = inihelper_getint(settingfile, &error, sectionName, "suicides"); + result->hogs[i].difficulty = difficulty; + result->hogs[i].initialHealth = TEAM_DEFAULT_HEALTH; + } + + result->bindingCount = iniparser_getsecnkeys(settingfile, "binds"); + result->bindings = flib_calloc(result->bindingCount, sizeof(flib_binding)); + bindingKeys = iniparser_getseckeys(settingfile, "binds"); + if(!result->bindings || !bindingKeys) { + return from_ini_handleError(result, settingfile, bindingKeys); + } + + for(int i=0; ibindingCount; i++) { + result->bindings[i].binding = flib_strdupnull(iniparser_getstring(settingfile, bindingKeys[i], NULL)); + // The key names all start with "binds:", so we skip that. + result->bindings[i].action = inihelper_urldecode(bindingKeys[i]+strlen("binds:")); + if(!result->bindings[i].action || !result->bindings[i].binding) { + error = true; + } + } + + if(error) { + flib_log_e("Error reading team file %s", filename); + return from_ini_handleError(result, settingfile, bindingKeys); + } + + iniparser_freedict(settingfile); + free(bindingKeys); + return result; +} + +void flib_team_destroy(flib_team *team) { + if(team) { + for(int i=0; ihogs[i].name); + free(team->hogs[i].hat); + } + free(team->name); + free(team->grave); + free(team->fort); + free(team->voicepack); + free(team->flag); + if(team->bindings) { + for(int i=0; ibindingCount; i++) { + free(team->bindings[i].action); + free(team->bindings[i].binding); + } + } + free(team->bindings); + free(team->hash); + flib_weaponset_destroy(team->weaponset); + free(team); + } +} diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/model/team.h --- a/project_files/frontlib/model/team.h Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/model/team.h Tue Jun 12 11:25:05 2012 +0200 @@ -12,6 +12,13 @@ #define TEAM_DEFAULT_DIFFICULTY 0 #define TEAM_DEFAULT_HEALTH 100 +// TODO default bindings? + +typedef struct { + char *action; + char *binding; +} flib_binding; + typedef struct { char *name; char *hat; @@ -19,12 +26,13 @@ // Statistics. They are irrelevant for the engine or server, // but provided for ini reading/writing by the frontend. int rounds; + int kills; int deaths; - int kills; int suicides; - // These settings are sometimes used on a per-team basis. int difficulty; + + // Transient setting used in game setup int initialHealth; } flib_hog; @@ -36,16 +44,43 @@ char *voicepack; char *flag; - // TODO binds + flib_binding *bindings; + int bindingCount; + + // Statistics. They are irrelevant for the engine or server, + // but provided for ini reading/writing by the frontend. + int rounds; + int wins; + int campaignProgress; // Transient settings used in game setup uint32_t color; int hogsInGame; bool remoteDriven; - char *hash; + char *hash; // TODO calculate - // This setting is sometimes used on a per-game basis. flib_weaponset *weaponset; } flib_team; +/** + * Returns a new team, or NULL on error. name must not be NULL. + * + * The new team is pre-filled with default settings (see hwconsts.h) + */ +flib_team *flib_team_create(const char *name); + +/** + * Loads a team, returns NULL on error. + */ +flib_team *flib_team_from_ini(const char *filename); + +/** + * Write the team to an ini file. Attempts to retain extra ini settings + * that were already present. Note that not all fields of a team struct + * are stored in the ini, some are only used intermittently to store + * information about a team in the context of a game. + */ +int flib_team_to_ini(const char *filename, const flib_team *team); +void flib_team_destroy(flib_team *team); + #endif /* TEAM_H_ */ diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/model/weapon.c --- a/project_files/frontlib/model/weapon.c Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/model/weapon.c Tue Jun 12 11:25:05 2012 +0200 @@ -38,7 +38,7 @@ if(!name || !loadoutStr || !crateProbStr || !crateAmmoStr || !delayStr) { flib_log_e("null parameter in flib_weaponset_create_str"); } else { - flib_weaponset *newSet = calloc(1, sizeof(flib_weaponset)); + flib_weaponset *newSet = flib_calloc(1, sizeof(flib_weaponset)); char *nameCopy = flib_strdupnull(name); if(newSet && nameCopy) { newSet->name = nameCopy; @@ -101,7 +101,10 @@ if(!filename || !set) { flib_log_e("null parameter in flib_weaponset_to_ini"); } else { - dictionary *dict = dictionary_new(0); + dictionary *dict = iniparser_load(filename); + if(!dict) { + dict = dictionary_new(0); + } if(dict) { bool error = false; // Add the sections diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/model/weapon.h --- a/project_files/frontlib/model/weapon.h Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/model/weapon.h Tue Jun 12 11:25:05 2012 +0200 @@ -7,7 +7,7 @@ * These values are all in the range 0..9 * * For loadout, 9 means inifinite ammo. - * For the other setting, 9 might actually be invalid, it's not possible to set more than 8 in the QtFrontend. (TODO) + * For the other setting, 9 is invalid. */ typedef struct { char loadout[WEAPONS_COUNT+1]; @@ -25,7 +25,16 @@ * settings (see hwconsts.h) */ flib_weaponset *flib_weaponset_create(const char *name); + +/** + * Loads a weapon set, returns NULL on error. + */ flib_weaponset *flib_weaponset_from_ini(const char *filename); + +/** + * Write the weapon set to an ini file. Attempts to + * retain extra ini settings that were already present. + */ int flib_weaponset_to_ini(const char *filename, const flib_weaponset *set); void flib_weaponset_destroy(flib_weaponset *set); diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/socket.c --- a/project_files/frontlib/socket.c Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/socket.c Tue Jun 12 11:25:05 2012 +0200 @@ -1,5 +1,6 @@ #include "socket.h" #include "util/logging.h" +#include "util/util.h" #include #include #include @@ -23,10 +24,9 @@ return get_peer_ip(sock) == (uint32_t)((127UL<<24)+1); // 127.0.0.1 } -static flib_tcpsocket flib_socket_create(TCPsocket sdlsock) { - flib_tcpsocket result = malloc(sizeof(_flib_tcpsocket)); +static flib_tcpsocket *flib_socket_create(TCPsocket sdlsock) { + flib_tcpsocket *result = flib_calloc(1, sizeof(_flib_tcpsocket)); if(!result) { - flib_log_e("Can't allocate socket: Out of memory!"); return NULL; } result->sock = sdlsock; @@ -43,10 +43,9 @@ return result; } -flib_acceptor flib_acceptor_create(uint16_t port) { - flib_acceptor result = malloc(sizeof(_flib_acceptor)); +flib_acceptor *flib_acceptor_create(uint16_t port) { + flib_acceptor *result = flib_calloc(1, sizeof(_flib_acceptor)); if(!result) { - flib_log_e("Can't allocate acceptor: Out of memory!"); return NULL; } @@ -86,7 +85,7 @@ } } -uint16_t flib_acceptor_listenport(flib_acceptor acceptor) { +uint16_t flib_acceptor_listenport(flib_acceptor *acceptor) { if(!acceptor) { flib_log_e("Call to flib_acceptor_listenport with acceptor==null"); return 0; @@ -94,22 +93,19 @@ return acceptor->port; } -void flib_acceptor_close(flib_acceptor *acceptorptr) { - if(!acceptorptr) { - flib_log_e("Call to flib_acceptor_close with acceptorptr==null"); - } else if(*acceptorptr) { - SDLNet_TCP_Close((*acceptorptr)->sock); - free(*acceptorptr); - *acceptorptr = NULL; +void flib_acceptor_close(flib_acceptor *acceptor) { + if(acceptor) { + SDLNet_TCP_Close(acceptor->sock); + free(acceptor); } } -flib_tcpsocket flib_socket_accept(flib_acceptor acceptor, bool localOnly) { +flib_tcpsocket *flib_socket_accept(flib_acceptor *acceptor, bool localOnly) { if(!acceptor) { flib_log_e("Call to flib_socket_accept with acceptor==null"); return NULL; } - flib_tcpsocket result = NULL; + flib_tcpsocket *result = NULL; TCPsocket sock = NULL; while(!result && (sock = SDLNet_TCP_Accept(acceptor->sock))) { if(localOnly && !connection_is_local(sock)) { @@ -125,20 +121,16 @@ return result; } -void flib_socket_close(flib_tcpsocket *sockptr) { - if(!sockptr) { - flib_log_e("Call to flib_socket_close with sockptr==null"); - } else if(*sockptr) { - flib_tcpsocket sock = *sockptr; +void flib_socket_close(flib_tcpsocket *sock) { + if(sock) { SDLNet_DelSocket(sock->sockset, (SDLNet_GenericSocket)sock->sock); SDLNet_TCP_Close(sock->sock); SDLNet_FreeSocketSet(sock->sockset); free(sock); - *sockptr = NULL; } } -int flib_socket_nbrecv(flib_tcpsocket sock, void *data, int maxlen) { +int flib_socket_nbrecv(flib_tcpsocket *sock, void *data, int maxlen) { if(!sock || (maxlen>0 && !data)) { flib_log_e("Call to flib_socket_nbrecv with sock==null or data==null"); return -1; @@ -155,7 +147,7 @@ } } -int flib_socket_send(flib_tcpsocket sock, const void *data, int len) { +int flib_socket_send(flib_tcpsocket *sock, const void *data, int len) { if(!sock || (len>0 && !data)) { flib_log_e("Call to flib_socket_send with sock==null or data==null"); return -1; diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/socket.h --- a/project_files/frontlib/socket.h Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/socket.h Tue Jun 12 11:25:05 2012 +0200 @@ -16,10 +16,10 @@ #include struct _flib_tcpsocket; -typedef struct _flib_tcpsocket *flib_tcpsocket; +typedef struct _flib_tcpsocket flib_tcpsocket; struct _flib_acceptor; -typedef struct _flib_acceptor *flib_acceptor; +typedef struct _flib_acceptor flib_acceptor; /** * Create a new acceptor which will listen for incoming TCP connections @@ -28,28 +28,28 @@ * * Can return NULL on error. */ -flib_acceptor flib_acceptor_create(uint16_t port); +flib_acceptor *flib_acceptor_create(uint16_t port); /** * Return the port on which the acceptor is listening. */ -uint16_t flib_acceptor_listenport(flib_acceptor acceptor); +uint16_t flib_acceptor_listenport(flib_acceptor *acceptor); /** - * Close the acceptor, free its memory and set it to NULL. + * Close the acceptor and free its memory. * If the acceptor is already NULL, nothing happens. */ -void flib_acceptor_close(flib_acceptor *acceptorptr); +void flib_acceptor_close(flib_acceptor *acceptor); /** * Try to accept a connection from an acceptor (listening socket). * if localOnly is true, this will only accept connections which came from 127.0.0.1 * Returns NULL if nothing can be accepted. */ -flib_tcpsocket flib_socket_accept(flib_acceptor acceptor, bool localOnly); +flib_tcpsocket *flib_socket_accept(flib_acceptor *acceptor, bool localOnly); /** - * Close the socket, free its memory and set it to NULL. + * Close the socket and free its memory. * If the socket is already NULL, nothing happens. */ void flib_socket_close(flib_tcpsocket *socket); @@ -60,8 +60,8 @@ * Returns the ammount of data received, 0 if there was nothing to receive, * or a negative number if the connection was closed or an error occurred. */ -int flib_socket_nbrecv(flib_tcpsocket sock, void *data, int maxlen); +int flib_socket_nbrecv(flib_tcpsocket *sock, void *data, int maxlen); -int flib_socket_send(flib_tcpsocket sock, const void *data, int len); +int flib_socket_send(flib_tcpsocket *sock, const void *data, int len); #endif /* SOCKET_H_ */ diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/test.c Tue Jun 12 11:25:05 2012 +0200 @@ -0,0 +1,178 @@ +#include "frontlib.h" +#include "util/logging.h" +#include "model/map.h" +#include "ipc/mapconn.h" +#include "ipc/gameconn.h" + +#include +#include +#include + +// Callback function that will be called when the map is rendered +static void handleMapSuccess(void *context, const uint8_t *bitmap, int numHedgehogs) { + printf("Drawing map for %i brave little hogs...", numHedgehogs); + + // Draw the map as ASCII art + for(int y=0; y>3] & (1<<(7-(pixelnum&7))); + printf(pixel ? "#" : " "); + } + printf("\n"); + } + + // Destroy the connection object (this will end the "tick" loop below) + flib_mapconn **connptr = context; + flib_mapconn_destroy(*connptr); + *connptr = NULL; +} + +static void onDisconnect(void *context, int reason) { + flib_log_i("Connection closed. Reason: %i", reason); + flib_gameconn **connptr = context; + flib_gameconn_destroy(*connptr); + *connptr = NULL; +} + +static void onGameRecorded(void *context, const uint8_t *record, int size, bool isSavegame) { + flib_log_i("Writing %s (%i bytes)...", isSavegame ? "savegame" : "demo", size); + FILE *file = fopen(isSavegame ? "testsave.42.hws" : "testdemo.42.hwd", "wb"); + fwrite(record, 1, size, file); + fclose(file); +} + +// Callback function that will be called on error +static void handleMapFailure(void *context, const char *errormessage) { + flib_log_e("Map rendering failed: %s", errormessage); + + // Destroy the connection object (this will end the "tick" loop below) + flib_mapconn **connptr = context; + flib_mapconn_destroy(*connptr); + *connptr = NULL; +} + +static void startEngineMap(int port) { + char commandbuffer[255]; + const char *enginePath = "C:\\Programmieren\\Hedgewars\\bin"; + const char *configPath = "C:\\Programmieren\\Hedgewars\\share\\hedgewars"; + snprintf(commandbuffer, 255, "start %s\\hwengine.exe %s %i landpreview", enginePath, configPath, port); + system(commandbuffer); +} + +static void startEngineGame(int port) { + char commandbuffer[255]; + const char *enginePath = "C:\\Programmieren\\Hedgewars\\bin"; + const char *configPath = "C:\\Programmieren\\Hedgewars\\share\\hedgewars"; + const char *dataPath = "C:\\Programmieren\\Hedgewars\\share\\hedgewars\\Data"; + snprintf(commandbuffer, 255, "start %s\\hwengine.exe %s 1024 768 32 %i 0 0 0 10 10 %s 0 0 TWVkbzQy 0 0 en.txt", enginePath, configPath, port, dataPath); + flib_log_d("Starting engine with CMD: %s", commandbuffer); + system(commandbuffer); +} + +void testMapPreview() { + // Create a map description and check that there was no error + flib_map *map = flib_map_create_maze("Jungle", MAZE_SIZE_SMALL_TUNNELS); + assert(map); + + // Create a new connection to the engine and check that there was no error + flib_mapconn *mapConnection = flib_mapconn_create("This is the seed value", map); + assert(mapConnection); + + // We don't need the map description anymore + flib_map_destroy(map); + map = NULL; + + // Register the callback functions + flib_mapconn_onFailure(mapConnection, &handleMapFailure, &mapConnection); + flib_mapconn_onSuccess(mapConnection, &handleMapSuccess, &mapConnection); + + // Start the engine process and tell it which port the frontlib is listening on + startEngineMap(flib_mapconn_getport(mapConnection)); + + // Usually, flib_mapconn_tick will be called in an event loop that runs several + // times per second. It handles I/O operations and progress, and calls + // callbacks when something interesting happens. + while(mapConnection) { + flib_mapconn_tick(mapConnection); + } +} + +void testGame() { + flib_cfg_meta *metaconf = flib_cfg_meta_from_ini("basicsettings.ini", "gamemods.ini"); + assert(metaconf); + flib_gamesetup setup; + setup.gamescheme = flib_cfg_from_ini(metaconf, "scheme_shoppa.ini"); + setup.map = flib_map_create_maze("Jungle", MAZE_SIZE_MEDIUM_TUNNELS); + setup.seed = "apsfooasdgnds"; + setup.script = NULL; + setup.teamcount = 2; + setup.teams = calloc(2, sizeof(flib_team*)); + setup.teams[0] = calloc(1, sizeof(flib_team)); + setup.teams[0]->color = 0xffff0000; + setup.teams[0]->flag = "australia"; + setup.teams[0]->fort = "Plane"; + setup.teams[0]->grave = "Bone"; + setup.teams[0]->hogsInGame = 2; + setup.teams[0]->name = "Team Awesome"; + setup.teams[0]->voicepack = "British"; + setup.teams[0]->weaponset = flib_weaponset_create("Defaultweaps"); + setup.teams[0]->hogs[0].difficulty = 2; + setup.teams[0]->hogs[0].hat = "NoHat"; + setup.teams[0]->hogs[0].initialHealth = 100; + setup.teams[0]->hogs[0].name = "Harry 120"; + setup.teams[0]->hogs[1].difficulty = 2; + setup.teams[0]->hogs[1].hat = "chef"; + setup.teams[0]->hogs[1].initialHealth = 100; + setup.teams[0]->hogs[1].name = "Chefkoch"; + setup.teams[1] = flib_team_from_ini("Cave Dwellers.hwt"); + setup.teams[1]->color = 0xff0000ff; + setup.teams[1]->hogsInGame = 8; + setup.teams[1]->weaponset = flib_weaponset_create("Defaultweaps"); + + flib_gameconn *gameconn = flib_gameconn_create("Medo42", metaconf, &setup, false); + assert(gameconn); + + flib_gameconn_onDisconnect(gameconn, &onDisconnect, &gameconn); + flib_gameconn_onGameRecorded(gameconn, &onGameRecorded, &gameconn); + + startEngineGame(flib_gameconn_getport(gameconn)); + + while(gameconn) { + flib_gameconn_tick(gameconn); + } +} + +void testDemo() { + FILE *demofile = fopen("testdemo.42.hwd", "rb"); + assert(demofile); + flib_vector *vec = flib_vector_create(); + uint8_t demobuf[512]; + int len; + while((len=fread(demobuf, 1, 512, demofile))>0) { + flib_vector_append(vec, demobuf, len); + } + fclose(demofile); + flib_constbuffer constbuf = flib_vector_as_constbuffer(vec); + flib_gameconn *gameconn = flib_gameconn_create_playdemo(constbuf.data, constbuf.size); + flib_vector_destroy(vec); + assert(gameconn); + flib_gameconn_onDisconnect(gameconn, &onDisconnect, &gameconn); + flib_gameconn_onGameRecorded(gameconn, &onGameRecorded, &gameconn); + startEngineGame(flib_gameconn_getport(gameconn)); + + while(gameconn) { + flib_gameconn_tick(gameconn); + } +} + +int main(int argc, char *argv[]) { + flib_init(0); + flib_log_setLevel(FLIB_LOGLEVEL_ALL); + + //testMapPreview(); + testDemo(); + + flib_quit(); + return 0; +} diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/util/buffer.c --- a/project_files/frontlib/util/buffer.c Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/util/buffer.c Tue Jun 12 11:25:05 2012 +0200 @@ -1,40 +1,43 @@ #include "buffer.h" #include "logging.h" +#include "util.h" #include #include #include +#define MIN_VECTOR_CAPACITY 16 + typedef struct _flib_vector { void *data; size_t size; size_t capacity; } _flib_vector; -flib_vector flib_vector_create() { - flib_vector result = malloc(sizeof(_flib_vector)); - if(result == NULL) { - return NULL; +flib_vector *flib_vector_create() { + flib_vector *result = NULL; + flib_vector *tmpVector = flib_calloc(1, sizeof(_flib_vector)); + if(tmpVector) { + tmpVector->data = flib_malloc(MIN_VECTOR_CAPACITY); + if(tmpVector->data) { + tmpVector->size = 0; + tmpVector->capacity = MIN_VECTOR_CAPACITY; + result = tmpVector; + tmpVector = NULL; + } } - result->data = malloc(16); - if(result->data == NULL) { - free(result); - return NULL; - } - result->size = 0; - result->capacity = 16; + flib_vector_destroy(tmpVector); return result; } void flib_vector_destroy(flib_vector *vec) { - if(vec && *vec) { - free((*vec)->data); - free(*vec); - *vec = NULL; + if(vec) { + free(vec->data); + free(vec); } } -static void try_realloc(flib_vector vec, size_t newCapacity) { +static void try_realloc(flib_vector *vec, size_t newCapacity) { void *newData = realloc(vec->data, newCapacity); if(newData) { vec->data = newData; @@ -42,11 +45,16 @@ } } -static size_t getFreeCapacity(flib_vector vec) { +static size_t getFreeCapacity(flib_vector *vec) { return vec->capacity - vec->size; } -int flib_vector_append(flib_vector vec, const void *data, size_t len) { +int flib_vector_append(flib_vector *vec, const void *data, size_t len) { + if(!vec) { + flib_log_e("null parameter in flib_vector_append"); + return 0; + } + if(getFreeCapacity(vec) < len) { // Resize exponentially for constant amortized time, // But at least by as much as we need of course, @@ -63,7 +71,7 @@ } // Check if we were able to resize. - // If not, try to allocate at least what we need... + // If not, try to allocate at least what we need. if(getFreeCapacity(vec) < len) { try_realloc(vec, vec->capacity+minExtraCapacity); @@ -74,17 +82,47 @@ } } - memmove(vec->data + vec->size, data, len); + memmove(((uint8_t*)vec->data) + vec->size, data, len); vec->size += len; return len; } -flib_buffer flib_vector_as_buffer(flib_vector vec) { - flib_buffer result = {vec->data, vec->size}; - return result; +flib_buffer flib_vector_as_buffer(flib_vector *vec) { + if(!vec) { + flib_log_e("null parameter in flib_vector_as_buffer"); + flib_buffer result = {NULL, 0}; + return result; + } else { + flib_buffer result = {vec->data, vec->size}; + return result; + } } -flib_constbuffer flib_vector_as_constbuffer(flib_vector vec) { - flib_constbuffer result = {vec->data, vec->size}; - return result; +flib_constbuffer flib_vector_as_constbuffer(flib_vector *vec) { + if(!vec) { + flib_log_e("null parameter in flib_vector_as_constbuffer"); + flib_constbuffer result = {NULL, 0}; + return result; + } else { + flib_constbuffer result = {vec->data, vec->size}; + return result; + } } + +void *flib_vector_data(flib_vector *vec) { + if(!vec) { + flib_log_e("null parameter in flib_vector_data"); + return NULL; + } else { + return vec->data; + } +} + +size_t flib_vector_size(flib_vector *vec) { + if(!vec) { + flib_log_e("null parameter in flib_vector_size"); + return 0; + } else { + return vec->size; + } +} diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/util/buffer.h --- a/project_files/frontlib/util/buffer.h Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/util/buffer.h Tue Jun 12 11:25:05 2012 +0200 @@ -24,35 +24,50 @@ } flib_constbuffer; /** - * Simple variable-capacity data structure (opaque type). + * Simple variable-capacity data structure that can be efficiently appended to. */ struct _flib_vector; -typedef struct _flib_vector *flib_vector; +typedef struct _flib_vector flib_vector; /** * Create a new vector. Needs to be destroyed again later with flib_vector_destroy. * May return NULL if memory runs out. */ -flib_vector flib_vector_create(); +flib_vector *flib_vector_create(); /** - * Free the memory of this vector and set it to NULL. + * Free the memory of this vector */ void flib_vector_destroy(flib_vector *vec); /** * Append the provided data to the end of the vector, enlarging it as required. * Returns the ammount of data appended, which is either len (success) or 0 (out of memory). - * The vector remains unchanged if an out of memory situation occurs. + * The vector remains unchanged if appending fails. */ -int flib_vector_append(flib_vector vec, const void *data, size_t len); +int flib_vector_append(flib_vector *vec, const void *data, size_t len); + +/** + * Return a pointer to the current data buffer of the vector. This pointer can + * become invalid if the vector size or capacity is changed. + */ +void *flib_vector_data(flib_vector *vec); /** - * Return a buffer or constbuffer pointing to the current contents of the vector. + * Return the current size of the vector. + */ +size_t flib_vector_size(flib_vector *vec); + +/** + * Return a buffer pointing to the current contents of the vector. * These will become invalid if the vector size or capacity is changed. */ -flib_buffer flib_vector_as_buffer(flib_vector vec); -flib_constbuffer flib_vector_as_constbuffer(flib_vector vec); +flib_buffer flib_vector_as_buffer(flib_vector *vec); +/** + * Return a constbuffer pointing to the current contents of the vector. + * These will become invalid if the vector size or capacity is changed. + */ +flib_constbuffer flib_vector_as_constbuffer(flib_vector *vec); #endif diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/util/inihelper.c --- a/project_files/frontlib/util/inihelper.c Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/util/inihelper.c Tue Jun 12 11:25:05 2012 +0200 @@ -22,7 +22,7 @@ return NULL; } - char *outbuf = malloc(insize*3+1); + char *outbuf = flib_malloc(insize*3+1); if(!outbuf) { return NULL; } @@ -41,11 +41,12 @@ } } outbuf[outpos] = 0; - return outbuf; + char *shrunk = realloc(outbuf, outpos+1); + return shrunk ? shrunk : outbuf; } char *inihelper_urldecode(const char *inbuf) { - char *outbuf = malloc(strlen(inbuf)+1); + char *outbuf = flib_malloc(strlen(inbuf)+1); if(!outbuf) { return NULL; } @@ -61,11 +62,13 @@ } } outbuf[outpos] = 0; - return outbuf; + char *shrunk = realloc(outbuf, outpos+1); + return shrunk ? shrunk : outbuf; } char *inihelper_createDictKey(const char *sectionName, const char *keyName) { if(!sectionName || !keyName) { + flib_log_e("null parameter in inihelper_createDictKey"); return NULL; } return flib_asprintf("%s:%s", sectionName, keyName); @@ -73,6 +76,7 @@ char *inihelper_getstring(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) { if(!inifile || !sectionName || !keyName) { + flib_log_e("null parameter in inihelper_getstring"); *error = true; return NULL; } @@ -84,7 +88,7 @@ char *result = iniparser_getstring(inifile, extendedkey, NULL); free(extendedkey); if(!result) { - flib_log_i("Missing ini setting: %s/%s", sectionName, keyName); + flib_log_d("Missing ini setting: %s/%s", sectionName, keyName); *error = true; } return result; @@ -102,10 +106,12 @@ errno = 0; long val = strtol(value, NULL, 10); if(errno!=0) { + flib_log_w("Cannot parse ini setting %s/%s = \"%s\" as integer.", sectionName, keyName, value); *error = true; return 0; } if(valINT_MAX) { + flib_log_w("ini setting %s/%s = \"%s\" is too large or too small.", sectionName, keyName, value); *error = true; return 0; } @@ -121,6 +127,7 @@ bool trueval = strchr("1tTyY", value[0]); bool falseval = strchr("0fFnN", value[0]); if(!trueval && !falseval) { + flib_log_w("ini setting %s/%s = \"%s\" is not a recognized truth value.", sectionName, keyName, value); *error = true; return false; } else { @@ -132,13 +139,13 @@ int inihelper_setstr(dictionary *dict, const char *sectionName, const char *keyName, const char *value) { int result = -1; if(!dict || !sectionName || !keyName || !value) { - flib_log_e("inihelper_setstr called with bad parameters"); + flib_log_e("null parameter in inihelper_setstr"); } else { char *extendedkey = inihelper_createDictKey(sectionName, keyName); if(extendedkey) { result = iniparser_set(dict, extendedkey, value); - free(extendedkey); } + free(extendedkey); } return result; } @@ -146,7 +153,7 @@ int inihelper_setint(dictionary *dict, const char *sectionName, const char *keyName, int value) { int result = -1; if(!dict || !sectionName || !keyName) { - flib_log_e("inihelper_setint called with bad parameters"); + flib_log_e("null parameter in inihelper_setint"); } else { char *strvalue = flib_asprintf("%i", value); if(strvalue) { @@ -160,7 +167,7 @@ int inihelper_setbool(dictionary *dict, const char *sectionName, const char *keyName, bool value) { int result = -1; if(!dict || !sectionName || !keyName) { - flib_log_e("inihelper_setint called with bad parameters"); + flib_log_e("null parameter in inihelper_setbool"); } else { result = inihelper_setstr(dict, sectionName, keyName, value ? "true" : "false"); } diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/util/inihelper.h --- a/project_files/frontlib/util/inihelper.h Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/util/inihelper.h Tue Jun 12 11:25:05 2012 +0200 @@ -1,6 +1,9 @@ /** - * Some helper functions for working with the iniparser functions - in particular, - * for interoperability with the ini format used by the QtSettings class. + * Convenience interface for ini reading/writing. + * + * We currently use iniparser in the background, but using its interface directly is a bit verbose. + * This module is supposed to 1. make ini reading and writing a bit more convenient, and 2. hide + * the iniparser dependency so it can at need be easily replaced. */ #ifndef INIHELPER_H_ @@ -10,6 +13,9 @@ #include +struct _flib_ini; +typedef struct _flib_inihelper flib_ini; + /** * Returned buffer must be free()d */ @@ -48,7 +54,20 @@ */ bool inihelper_getbool(dictionary *inifile, bool *error, const char *sectionName, const char *keyName); +/** + * Returns a nonzero value on error. + */ int inihelper_setstr(dictionary *dict, const char *sectionName, const char *keyName, const char *value); + +/** + * Returns a nonzero value on error. + */ int inihelper_setint(dictionary *dict, const char *sectionName, const char *keyName, int value); + +/** + * Set an ini setting to "true" or "false". + * Returns a nonzero value on error. + */ int inihelper_setbool(dictionary *dict, const char *sectionName, const char *keyName, bool value); + #endif /* INIHELPER_H_ */ diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/util/logging.c --- a/project_files/frontlib/util/logging.c Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/util/logging.c Tue Jun 12 11:25:05 2012 +0200 @@ -85,3 +85,7 @@ void flib_log_setFile(FILE *file) { flib_logfile = file; } + +bool flib_log_isActive(int level) { + return level >= flib_log_getLevel(); +} diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/util/logging.h --- a/project_files/frontlib/util/logging.h Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/util/logging.h Tue Jun 12 11:25:05 2012 +0200 @@ -1,8 +1,9 @@ #ifndef LOGGING_H_ #define LOGGING_H_ -#include +#include #include +#include #define FLIB_LOGLEVEL_ALL -100 #define FLIB_LOGLEVEL_DEBUG -1 @@ -11,6 +12,9 @@ #define FLIB_LOGLEVEL_ERROR 2 #define FLIB_LOGLEVEL_NONE 100 +/** + * Returns a pointer to a static buffer, don't free or store. + */ char* flib_format_ip(uint32_t numip); void flib_log_e(const char *fmt, ...); @@ -21,5 +25,6 @@ int flib_log_getLevel(); void flib_log_setLevel(int level); void flib_log_setFile(FILE *logfile); +bool flib_log_isActive(int level); #endif /* LOGGING_H_ */ diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/util/util.c --- a/project_files/frontlib/util/util.c Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/util/util.c Tue Jun 12 11:25:05 2012 +0200 @@ -1,4 +1,5 @@ #include "util.h" +#include "logging.h" #include #include @@ -16,16 +17,20 @@ char *flib_vasprintf(const char *fmt, va_list args) { char *result = NULL; - int requiredSize = vsnprintf(NULL, 0, fmt, args)+1; // Figure out how much memory we need, - if(requiredSize>=0) { - char *tmpbuf = malloc(requiredSize); // allocate it - if(tmpbuf) { - if(vsnprintf(tmpbuf, requiredSize, fmt, args)>=0) { // and then do the actual formatting. + if(!fmt) { + flib_log_e("null parameter in flib_vasprintf"); + } else { + int requiredSize = vsnprintf(NULL, 0, fmt, args)+1; // Figure out how much memory we need, + if(requiredSize<0) { + flib_log_e("Error formatting string with template \"%s\" in flib_vasprintf", fmt); + } else { + char *tmpbuf = flib_malloc(requiredSize); // allocate it + if(tmpbuf && vsnprintf(tmpbuf, requiredSize, fmt, args)>=0) { // and then do the actual formatting. result = tmpbuf; tmpbuf = NULL; } + free(tmpbuf); } - free(tmpbuf); } return result; } @@ -41,9 +46,25 @@ if(!buf || size==0) { return NULL; } - void *result = malloc(size); + void *result = flib_malloc(size); if(result) { memcpy(result, buf, size); } return result; } + +void *flib_malloc(size_t size) { + void *result = malloc(size); + if(!result) { + flib_log_e("Out of memory trying to malloc %zu bytes.", size); + } + return result; +} + +void *flib_calloc(size_t count, size_t elementsize) { + void *result = calloc(count, elementsize); + if(!result) { + flib_log_e("Out of memory trying to calloc %zu objects of %zu bytes each.", count, elementsize); + } + return result; +} diff -r 8d04e85ca204 -r 5143861c83bd project_files/frontlib/util/util.h --- a/project_files/frontlib/util/util.h Mon Jun 11 00:06:22 2012 +0200 +++ b/project_files/frontlib/util/util.h Tue Jun 12 11:25:05 2012 +0200 @@ -13,7 +13,7 @@ char *flib_asprintf(const char *fmt, ...); /** - * Exactly as flib_asprintf, but accepts va_args. + * Exactly as flib_asprintf, but accepts a va_list. */ char *flib_vasprintf(const char *fmt, va_list args); @@ -33,4 +33,16 @@ */ void *flib_bufdupnull(const void *buf, size_t size); +/** + * Simple malloc wrapper that automatically logs an error if no memory + * is available. Otherwise behaves exactly like malloc. + */ +void *flib_malloc(size_t size); + +/** + * Simple calloc wrapper that automatically logs an error if no memory + * is available. Otherwise behaves exactly like calloc. + */ +void *flib_calloc(size_t count, size_t elementsize); + #endif