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;
}