Mercurial > hg > batmud > maputils
view src/patchmap.c @ 2470:d0aad04c3e61
th-libs now uses stdbool.h if possible, so we need to rename all
BOOL/TRUE/FALSE to bool/true/false.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Wed, 07 Dec 2022 13:23:46 +0200 |
parents | eba783bef2ee |
children | 76b67c40fbf5 |
line wrap: on
line source
/* * Patch a map with given diff file * Programmed by Matti 'ccr' Hämäläinen <ccr@tnsp.org> * (C) Copyright 2008-2022 Tecnic Software productions (TNSP) */ #include "libmaputils.h" #include "th_util.h" #include "th_args.h" #include "th_string.h" char *mapFilename = NULL, *patchFilename = NULL, *destFilename = NULL; bool optCheck = false; /* Arguments */ static const th_optarg optList[] = { { 0, '?', "help", "Show this help", OPT_NONE }, { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, { 2, 'q', "quiet", "Be quiet", OPT_NONE }, { 3, 'c', "check", "Check non-patched blocks", OPT_NONE }, { 4, 'o', "output", "Output filename", OPT_ARGREQ }, }; static const int optListN = sizeof(optList) / sizeof(optList[0]); void argShowHelp(void) { th_print_banner(stdout, th_prog_name, "[options] <mapfile> <patchfile>"); th_args_help(stdout, optList, optListN, 0, 80 - 2); } bool argHandleOpt(const int optN, char *optArg, char *currArg) { switch (optN) { case 0: argShowHelp(); exit(0); break; case 1: th_verbosity++; break; case 2: th_verbosity = -1; break; case 3: optCheck = true; THMSG(2, "Checking non-patched blocks for match.\n"); break; case 4: destFilename = optArg; THMSG(2, "Output file set to '%s'.\n", destFilename); break; default: THERR("Unknown option '%s'.\n", currArg); return false; } return true; } bool argHandleFile(char *currArg) { if (mapFilename == NULL) mapFilename = currArg; else if (patchFilename == NULL) patchFilename = currArg; else { THERR("Too many input map files specified!\n"); return false; } return true; } int main(int argc, char *argv[]) { MapBlock *map = NULL, *patch = NULL; FILE *outFile = NULL; int res = 0; // Initialize th_init("patchmap", "Patch a mapfile with a diff", "0.1", NULL, NULL); th_verbosity = 1; // Parse arguments if (!th_args_process(argc, argv, optList, optListN, argHandleOpt, argHandleFile, OPTH_BAILOUT)) { res = 1; goto exit; } if (mapFilename == NULL || patchFilename == NULL) { THERR("Nothing to do. (try --help)\n"); res = 1; goto exit; } // Read map and patch file if ((map = mapBlockParseFile(mapFilename, false)) == NULL || (patch = mapBlockParseFile(patchFilename, true)) == NULL) { res = 2; goto exit; } // Check map and diff sizes if (optCheck && (map->width != patch->width || map->height != patch->height)) { THERR("Map and patch dimensions do not match (%d x %d [map] <-> %d x %d [patch])\n", map->width, map->height, patch->width, patch->height); res = 2; goto exit; } // Generate for (int yc = 0; yc < map->height; yc++) { unsigned char *dp = map->data + (map->scansize * yc), *sp = patch->data + (patch->scansize * yc); for (int xc = 0; xc < map->width; xc++, sp++, dp++) { const int i = (*sp & 63); unsigned char ch; if (*sp == 0xfd) ch = ' '; else if (i < nmapPieces) ch = mapPieces[i].symbol; else { THERR("[%d,%d] invalid symbol index %d (%d) in patch\n", xc+1, yc+1, *sp, i); res = 7; goto exit; } if (*sp < 64) { if (optCheck && *sp != *dp) { THERR("[%d,%d] mismatch %d != %d\n", xc+1, yc+1, *sp, *dp); } } else *dp = ch; } } // Open output file if (destFilename == NULL) outFile = stdout; else if ((outFile = fopen(destFilename, "wb")) == NULL) { THERR("Error opening output file '%s'!\n", destFilename); res = 6; goto exit; } mapBlockPrint(outFile, map); exit: if (outFile != NULL) fclose(outFile); mapBlockFree(map); mapBlockFree(patch); return res; }