Mercurial > hg > batmud > maputils
view src/diffmap.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
/* * Compute 'diff' between two maps * Programmed by Matti 'ccr' Hämäläinen <ccr@tnsp.org> * (C) Copyright 2006-2022 Tecnic Software productions (TNSP) */ #include "libmaputils.h" #include "th_util.h" #include "th_args.h" #include "th_string.h" #define SET_DEF_FILTER "C?%" /* Variables */ char *srcFilename1 = NULL, *srcFilename2 = NULL, *destFilename = NULL; bool optUseOldFormat = false, optAlwaysDiff = false; char *optFilter1 = "", *optFilter2 = SET_DEF_FILTER; /* 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, 'O', "old-format", "Input using old symbols/colors", OPT_NONE }, { 4, 'o', "output", "Output filename", OPT_ARGREQ }, { 5, 'F', NULL, "Filter chars (none) for mapfile #1", OPT_ARGREQ }, { 6, 'f', NULL, "Filter chars (" SET_DEF_FILTER ") for mapfile #2", OPT_ARGREQ }, { 7, 'a', "always", "Always output diff file even when no changes", OPT_NONE }, }; static const int optListN = sizeof(optList) / sizeof(optList[0]); void argShowHelp(void) { th_print_banner(stdout, th_prog_name, "[options] <mapfile #1> <mapfile #2>"); 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: optUseOldFormat = true; THMSG(2, "Input is using old map symbols/colors.\n"); break; case 4: destFilename = optArg; THMSG(2, "Output file set to '%s'.\n", optArg); break; case 5: optFilter1 = optArg; THMSG(2, "Filter characters for mapfile #1 set to'%s'.\n", optArg); break; case 6: optFilter2 = optArg; THMSG(2, "Filter characters for mapfile #2 set to'%s'.\n", optArg); break; case 7: optAlwaysDiff = true; THMSG(2, "Outputting diff file even with no changes.\n"); break; default: THERR("Unknown option '%s'.\n", currArg); return false; } return true; } bool argHandleFile(char *currArg) { if (srcFilename1 == NULL) srcFilename1 = currArg; else if (srcFilename2 == NULL) srcFilename2 = currArg; else { THERR("Too many input map files specified!\n"); return false; } return true; } MapBlock * diffBlocks(const MapBlock *map1, const MapBlock *map2, const bool useOld, const char *filter1, const char *filter2, size_t *count) { MapBlock *res; size_t nfilter1 = strlen(filter1), nfilter2 = strlen(filter2); if (map1->width != map2->width || map1->height != map2->height) { THERR("Mapblock size mismatch (%d, %d) vs (%d, %d)\n", map1->width, map1->height, map2->width, map2->height); return NULL; } if ((res = mapBlockAlloc(map1->width, map1->height)) == NULL) { THERR("Could not allocate mapblock (%d, %d)\n", map1->width, map1->height); return NULL; } *count = 0; for (int y = 0; y < map1->height; y++) { unsigned char *p1 = map1->data + (map1->scansize * y), *p2 = map2->data + (map2->scansize * y), *pd = res->data + (res->scansize * y); for (int x = 0; x < map1->width; x++) { int c; if (*p1 != *p2 && !muStrChr((unsigned char *) filter1, nfilter1, *p1) && !muStrChr((unsigned char *) filter2, nfilter2, *p2)) { c = muGetMapPieceIndex(*p2, useOld, false); *pd = (c < 0) ? 0xfd : (c | 64); THMSG(2, "[%d,%d]: %d -> %d\n", x+1, y+1, *p1, *p2); (*count)++; } else { c = muGetMapPieceIndex(*p1, useOld, false); *pd = (c < 0) ? 0xfd : c; } p1++; p2++; pd++; } } return res; } int main(int argc, char *argv[]) { MapBlock *srcMap1 = NULL, *srcMap2 = NULL, *resMap = NULL; FILE *outFile = NULL; size_t count; int res = 0; // Initialize th_init("diffmap", "Create a diff between two ASCII mapfiles", "0.5", NULL, NULL); th_verbosity = 1; // Parse arguments if (!th_args_process(argc, argv, optList, optListN, argHandleOpt, argHandleFile, true)) { res = 1; goto exit; } if (srcFilename1 == NULL || srcFilename2 == NULL) { THERR("Nothing to do. (try --help)\n"); res = 1; goto exit; } // Read mapfiles if ((srcMap1 = mapBlockParseFile(srcFilename1, false)) == NULL || (srcMap2 = mapBlockParseFile(srcFilename2, false)) == NULL) { res = 2; goto exit; } // Compute and output data count = 0; if ((resMap = diffBlocks(srcMap1, srcMap2, optUseOldFormat, optFilter1, optFilter2, &count)) == NULL) { THERR("Could not create diff between inputs!\n"); res = 3; goto exit; } THMSG(1, "%" PRIu_SIZE_T " differences.\n", count); // Open output file res = count > 0 ? 0 : 4; if (optAlwaysDiff || count > 0) { THMSG(2, "Outputting map diff %d x %d...\n", resMap->width, resMap->height); if (destFilename == NULL) outFile = stdout; else if ((outFile = fopen(destFilename, "wb")) == NULL) { THERR("Error opening output file '%s'!\n", destFilename); res = 6; goto exit; } fprintf(outFile, DIFF_MAGIC "%d\n", DIFF_VERSION); mapBlockPrintRaw(outFile, resMap); } else { THMSG(2, "Not outputting diff as no changes were found.\n"); goto exit; } exit: if (outFile != NULL) fclose(outFile); mapBlockFree(srcMap1); mapBlockFree(srcMap2); mapBlockFree(resMap); return res; }