view patchmap.c @ 1822:892d5277f1ff

Remove note about the search pattern parser being not very tolerant, it's somewhat better now.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 30 Oct 2017 12:55:21 +0200
parents 72adabd8e746
children 79dd960610cb
line wrap: on
line source

/*
 * patchmap - Patch a map with given diff file
 * Programmed by Matti 'ccr' Hämäläinen (Ggr Pupunen)
 * (C) Copyright 2008-2015 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);
}


BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
{
    switch (optN)
    {
    case 0:
        argShowHelp();
        exit(0);
        break;

    case 1:
        th_verbosityLevel++;
        break;

    case 2:
        th_verbosityLevel = -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)
        mapFilename = currArg;
    else
    if (!patchFilename)
        patchFilename = currArg;
    else
    {
        THERR("Too many input map files specified!\n");
        return FALSE;
    }

    return TRUE;
}


int main(int argc, char *argv[])
{
    MapBlock *map, *patch;
    FILE *outFile;

    // Initialize
    th_init("patchmap", "Patch a mapfile with a diff", "0.1", NULL, NULL);
    th_verbosityLevel = 1;

    // Parse arguments
    if (!th_args_process(argc, argv, optList, optListN,
        argHandleOpt, argHandleFile, OPTH_BAILOUT))
        exit(1);

    if (mapFilename == NULL || patchFilename == NULL)
    {
        THERR("Nothing to do. (try --help)\n");
        exit(0);
    }

    // Read map and patch file
    if ((map = mapBlockParseFile(mapFilename, FALSE)) == NULL)
        exit(2);

    if ((patch = mapBlockParseFile(patchFilename, TRUE)) == NULL)
        exit(3);

    // 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);
        exit(4);
    }

    // Generate
    for (int y = 0; y < map->height; y++)
    {
        unsigned char
            *d = map->data + (map->scansize * y),
            *s = patch->data + (patch->scansize * y);

        for (int x = 0; x < map->width; x++)
        {
            const int i = (*s & 63);
            unsigned char c;

            if (*s == 0xfd)
                c = ' ';
            else
            if (i < nmapPieces)
                c = mapPieces[i].symbol;
            else
            {
                THERR("[%d,%d] invalid symbol index %d (%d) in patch\n",
                    x+1, y+1, *s, i);
                exit(5);
            }

            if (*s < 64)
            {
                if (optCheck && *s != *d)
                {
                    THERR("[%d,%d] mismatch %d != %d\n",
                    x+1, y+1, *s, *d);
                }
            }
            else
                *d = c;

            s++;
            d++;
        }
    }

    // Open output file
    if (destFilename == NULL)
        outFile = stdout;
    else
    if ((outFile = fopen(destFilename, "wb")) == NULL)
    {
        THERR("Error opening output file '%s'!\n",
            destFilename);
        exit(1);
    }

    mapBlockPrint(outFile, map);

    fclose(outFile);

    return 0;
}