diff --git a/Makefile b/Makefile index f64263b..9b439c1 100644 --- a/Makefile +++ b/Makefile @@ -9,14 +9,14 @@ CYGWIN = $(findstring CYGWIN, $(UNAME)) MINGW = $(findstring MINGW32, $(UNAME)) CC ?= clang -CFLAGS += -Wall -Wextra -I. -fno-strict-aliasing -fsigned-char +CFLAGS += -Wall -Wextra -Werror -I. -fno-strict-aliasing -fsigned-char ifneq ($(shell git describe --always 2>/dev/null),) CFLAGS += -DGMQCC_GITINFO="\"$(shell git describe --always)\"" endif #turn on tons of warnings if clang is present # but also turn off the STUPID ONES ifeq ($(CC), clang) - CFLAGS += \ + CFLAGS += \ -Weverything \ -Wno-padded \ -Wno-format-nonliteral \ @@ -41,7 +41,8 @@ ifeq ($(track), no) CFLAGS += -DNOTRACK endif -OBJ_D = util.o code.o ast.o ir.o conout.o ftepp.o opts.o fs.o utf8.o correct.o pak.o +OBJ_D = util.o code.o ast.o ir.o conout.o ftepp.o opts.o fs.o utf8.o correct.o +OBJ_P = util.o fs.o conout.o opts.o pak.o OBJ_T = test.o util.o conout.o fs.o OBJ_C = main.o lexer.o parser.o fs.o OBJ_X = exec-standalone.o util.o conout.o fs.o @@ -56,6 +57,7 @@ ifneq ("$(CYGWIN)", "") QCVM = qcvm.exe GMQCC = gmqcc.exe TESTSUITE = testsuite.exe + PAK = pak.exe else ifneq ("$(MINGW)", "") #nullify the common variables that @@ -67,6 +69,7 @@ ifneq ("$(MINGW)", "") QCVM = qcvm.exe GMQCC = gmqcc.exe TESTSUITE = testsuite.exe + PAK = pak.exe else #arm support for linux .. we need to allow unaligned accesses #to memory otherwise we just segfault everywhere @@ -77,6 +80,7 @@ else QCVM = qcvm GMQCC = gmqcc TESTSUITE = testsuite + PAK = pak endif endif @@ -148,7 +152,10 @@ $(GMQCC): $(OBJ_C) $(OBJ_D) $(TESTSUITE): $(OBJ_T) $(CC) -o $@ $^ $(CFLAGS) -all: $(GMQCC) $(QCVM) $(TESTSUITE) +$(PAK): $(OBJ_P) + $(CC) -o $@ $^ $(CFLAGS) + +all: $(GMQCC) $(QCVM) $(TESTSUITE) $(PAK) check: all @ ./$(TESTSUITE) diff --git a/pak.c b/pak.c index 29e028c..1f905fe 100644 --- a/pak.c +++ b/pak.c @@ -28,7 +28,7 @@ * The PAK format uses a FOURCC concept for storing the magic ident within * the header as a uint32_t. */ -#define PAK_FOURCC ((uint32_t)(('P' << 24) | ('A' << 16) | ('C' << 8) | 'K')) +#define PAK_FOURCC ((uint32_t)(('P' | ('A' << 8) | ('C' << 16) | ('K' << 24)))) typedef struct { uint32_t magic; /* "PACK" */ @@ -441,3 +441,140 @@ bool pak_close(pak_file_t *pak) { return true; } + +/* + * Fancy GCC-like LONG parsing allows things like --opt=param with + * assignment operator. This is used for redirecting stdout/stderr + * console to specific files of your choice. + */ +static bool parsecmd(const char *optname, int *argc_, char ***argv_, char **out, int ds, bool split) { + int argc = *argc_; + char **argv = *argv_; + + size_t len = strlen(optname); + + if (strncmp(argv[0]+ds, optname, len)) + return false; + + /* it's --optname, check how the parameter is supplied */ + if (argv[0][ds+len] == '=') { + *out = argv[0]+ds+len+1; + return true; + } + + if (!split || argc < ds) /* no parameter was provided, or only single-arg form accepted */ + return false; + + /* using --opt param */ + *out = argv[1]; + --*argc_; + ++*argv_; + return true; +} + +int main(int argc, char **argv) { + bool extract = true; + char *redirout = (char*)stdout; + char *redirerr = (char*)stderr; + char *directory = NULL; + char *file = NULL; + char **files = NULL; + pak_file_t *pak = NULL; + size_t iter = 0; + + con_init(); + + /* + * Command line option parsing commences now We only need to support + * a few things in the test suite. + */ + while (argc > 1) { + ++argv; + --argc; + + if (argv[0][0] == '-') { + if (parsecmd("redirout", &argc, &argv, &redirout, 1, false)) + continue; + if (parsecmd("redirerr", &argc, &argv, &redirerr, 1, false)) + continue; + if (parsecmd("directory", &argc, &argv, &directory, 1, false)) + continue; + if (parsecmd("file", &argc, &argv, &file, 1, false)) + continue; + + con_change(redirout, redirerr); + + switch (argv[0][1]) { + case 'e': extract = true; continue; + case 'c': extract = false; continue; + } + + if (!strcmp(argv[0]+1, "debug")) { + OPTS_OPTION_BOOL(OPTION_DEBUG) = true; + continue; + } + if (!strcmp(argv[0]+1, "memchk")) { + OPTS_OPTION_BOOL(OPTION_MEMCHK) = true; + continue; + } + if (!strcmp(argv[0]+1, "nocolor")) { + con_color(0); + continue; + } + } + + vec_push(files, argv[0]); + } + con_change(redirout, redirerr); + + + if (!file) { + con_err("-file must be specified for output/input PAK file\n"); + return EXIT_FAILURE; + } + + if (extract) { + if (!(pak = pak_open(file, "r"))) { + con_err("failed to open PAK file %s\n", file); + return EXIT_FAILURE; + } + + if (!pak_extract_all(pak, (directory) ? directory : "./")) { + con_err("failed to extract PAK %s (files may be missing)\n", file); + pak_close(pak); + return EXIT_FAILURE; + } + + /* not possible */ + if (!pak_close(pak)) + abort(); + + util_meminfo(); + return EXIT_SUCCESS; + } + + if (!(pak = pak_open(file, "w"))) { + con_err("failed to open PAK %s for writing\n", file); + return EXIT_FAILURE; + } + + if (directory && !fs_dir_change(directory)) { + con_err("failed to change directory %s\n", directory); + pak_close(pak); + return EXIT_FAILURE; + } + + for (iter = 0; iter < vec_size(files); iter++) { + if (!(pak_insert_one(pak, files[iter]))) { + con_err("failed inserting %s for PAK %s\n", files[iter], file); + pak_close(pak); + return EXIT_FAILURE; + } + } + + /* not possible */ + if (!pak_close(pak)) + abort(); + + return EXIT_SUCCESS; +}