Utility functions:
src/util.h
Code:
#ifndef LAUNCHER_UTIL_H
#define LAUNCHER_UTIL_H
#define MAGIC_LENGTH(magic) (sizeof(magic) / sizeof(char))
void * l_calloc(size_t, size_t);
char * str_alloc(size_t);
int dir_exists(const char*);
int file_exists(const char*);
#endif
src/util.c
Code:
#ifndef __LAUNCHER_UTIL_C
#define __LAUNCHER_UTIL_C
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "util.h"
void * l_calloc(size_t len, size_t elem)
{
void* buf = calloc(len, elem);
if( buf == NULL )
{
exit(-1);
}
return buf;
}
char * str_alloc(size_t len)
{
return (char*) l_calloc(len, sizeof(char));
}
int dir_exists(const char* dir)
{
struct stat st;
if (stat(dir, &st) == 0)
{
return S_ISDIR(st.st_mode) ? 1 : 0;
}
return -1;
}
int file_exists(const char* dir)
{
struct stat st;
if (stat(dir, &st) == 0)
{
return S_ISREG(st.st_mode) ? 1 : 0;
}
return -1;
}
#endif
Functions to do with mods: (including the actual launching bit)
src/mod.h
Code:
#ifndef LAUNCHER_MOD_H
#define LAUNCHER_MOD_H
#define M2TW_EXE "medieval2.exe"
#define KGDM_EXE "kingdoms.exe"
#define MOD_FLAG "--features.mod="
typedef struct {
char * cfg;
char * dir;
} Mod;
Mod* allocate_mod(unsigned int, unsigned int);
Mod* create_mod(char*, char*);
void free_mod(Mod*);
void launch_mod(Mod*);
const char* exe_for_mod(Mod*);
#endif
src/mod.c
Code:
#ifndef LAUNCHER_MOD_C
#define LAUNCHER_MOD_C
#ifdef _WIN32
#include <process.h>
#else
#include <libgen.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include "mod.h"
#include "util.h"
#define EXE_CMP(cfg, cmp, ret) if(strncasecmp((cfg), (cmp), MAGIC_LENGTH(cmp) -1) == 0) { return (ret); }
Mod* allocate_mod(unsigned int cfg_length, unsigned int dir_length)
{
Mod* mod = (Mod*) l_calloc(1, sizeof(Mod));
char *c = str_alloc(cfg_length + sizeof(char)),
*m = str_alloc(dir_length + sizeof(char));
mod->cfg = c;
mod->dir = m;
return mod;
}
Mod* create_mod(char *cfg, char* dir)
{
Mod* mod = (Mod*) l_calloc(1, sizeof(Mod));
mod->cfg = cfg;
mod->dir = dir;
return mod;
}
void free_mod(Mod* m)
{
free(m->cfg);
free(m->dir);
free(m);
}
void launch_mod(Mod* m)
{
const char* exe=exe_for_mod(m);
if(exe == NULL)
{
exe = KGDM_EXE;
fprintf(stderr, "Fallback to: %s\n", exe);
}
char * cfg_a = m->cfg, * dir_a = m->dir;
free(m);
if(execl(exe, exe, cfg_a, dir_a, NULL) == -1)
{
fputs("Unable to launch the mod\n", stderr);
free(cfg_a);
free(dir_a);
}
}
const char* exe_for_mod(Mod* mod)
{
#ifdef _WIN32
char abs_path[_MAX_PATH] = {0};
if(_fullpath(abs_path, mod->cfg + sizeof(char), _MAX_PATH) == NULL)
{
fprintf(stderr, "Unable to resolve basename for: %s\n", mod->cfg + sizeof(char));
return NULL;
}
char c[_MAX_FNAME] = {0};
_splitpath(abs_path, NULL, NULL, c, NULL);
#else
char * c = basename(mod->cfg + sizeof(char));
#endif
EXE_CMP(c, "kingdoms", KGDM_EXE);
EXE_CMP(c, "kgdm", KGDM_EXE);
EXE_CMP(c, "medieval", M2TW_EXE);
EXE_CMP(c, "m2", M2TW_EXE);
fprintf(stderr, "No program name prefix in: %s\n", c);
return NULL;
}
#endif
The actual program:
src/main.c
Code:
#ifndef __LAUNCHER_MAIN_C
#define __LAUNCHER_MAIN_C
#include <stdio.h>
#include <string.h>
#include "mod.h"
#include "util.h"
#define CLI_SYNTAX_ERROR(cond, msg) if (cond) { msg; return -2; }
#define CLI_VALUE_ERROR(cond, mod, msg) if (cond) { msg; free_mod(mod); return -3; }
int main (int argc, char** argv)
{
CLI_SYNTAX_ERROR(argc == 1, fputs("Missing CFG argument\n", stderr));
CLI_SYNTAX_ERROR((*argv[1]) != '@', fprintf(stderr, "Bad CFG argument: %s\n", argv[1]));
unsigned int k=1, cfg_len, count = 1, sz = MAGIC_LENGTH(MOD_FLAG) - 1, dir_len = 0;
for(cfg_len = strlen(argv[k]) /*-1*/, ++k; k <argc && strncmp(argv[k], MOD_FLAG, sz) != 0; ++k, ++count)
{
cfg_len += strlen(argv[k]) + 1;
}
CLI_SYNTAX_ERROR(k == argc, fputs("Missing --features.mod argument.\n", stderr));
CLI_SYNTAX_ERROR(cfg_len == 1 /*0*/, fputs("Empty CFG argument.\n", stderr));
dir_len = strlen(argv[k]) /*- sz*/;
CLI_SYNTAX_ERROR(dir_len == sz /*0*/, fputs("Empty --features.mod argument.\n", stderr));
char* last=strrchr(argv[k], '/');
#ifdef _WIN32
if(last == NULL || (*(last + 1)) != '\0')
{
last = strrchr(argv[k], '\\');
}
#endif
if(last != NULL && (*(last + 1)) == '\0')
{
dir_len --;
}
Mod *mod= allocate_mod(cfg_len, dir_len);
mod->dir = strncpy(mod->dir, argv[k] /*+ sz * sizeof(char)*/, dir_len);
char* d=mod->dir + sz * sizeof(char);
CLI_VALUE_ERROR(dir_exists(d) != 1, mod, fprintf(stderr, "Mod directory does not exist: %s\n", d));
mod->cfg = strcpy(mod->cfg, argv[1] /*+ sizeof(char)*/);
for(k = 2; k <= count; ++k)
{
strcat(strcat(mod->cfg, " "), argv[k]);
}
char* c=mod->cfg + sizeof(char);
CLI_VALUE_ERROR(file_exists(c) != 1, mod, fprintf(stderr, "Mod CFG does not exist: %s\n", c));
launch_mod(mod);
return -4;
}
#endif