view diffmap.c @ 945:81184d58133c aprilli2011

Sync.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 14 May 2010 11:18:20 +0000
parents 304a50a9d51f
children 82469eecbae7
line wrap: on
line source

/*
 * diffmap - Compute 'diff' between two maps
 * Programmed by Matti 'ccr' Hämäläinen (Ggr Pupunen)
 * (C) Copyright 2006-2008 Tecnic Software productions (TNSP)
 */
#include "maputils.h"
#include "th_util.h"
#include "th_args.h"
#include "th_string.h"
#include <string.h>

#define DEF_FILTER "C?%"

char    *srcFilename1 = NULL,
        *srcFilename2 = NULL,
        *destFilename = NULL;
BOOL    optUseOldFormat = FALSE,
        optAlwaysDiff = FALSE;
char    *optFilter1 = "",
        *optFilter2 = DEF_FILTER;


/* Arguments
 */
optarg_t 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 (" DEF_FILTER ") for mapfile #2", OPT_ARGREQ },
    { 7, 'a', "always",     "Always output diff file even when no changes", OPT_NONE },
};

const int optListN = (sizeof(optList) / sizeof(optarg_t));


void argShowHelp(void)
{
    th_args_help(stderr, optList, optListN, th_prog_name,
    "[options] <mapfile #1> <mapfile #2>");
}


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

    return TRUE;
}


mapblock_t * diffBlocks(mapblock_t *map1, mapblock_t *map2, BOOL useOld, char *filter1, char *filter2, size_t *count)
{
    int x, y;
    mapblock_t *res;
    unsigned char *p1, *p2, *pd;
    
    if (map1->w != map2->w || map1->h != map2->h) {
        THERR("Mapblock size mismatch (%d, %d) vs (%d, %d)\n",
            map1->w, map1->h,
            map2->w, map2->h);
        return NULL;
    }
    
    if ((res = allocBlock(map1->w, map1->h)) == NULL) {
        THERR("Could not allocate mapblock (%d, %d)\n",
            map1->w, map1->h);
        return NULL;
    }
    
    p1 = map1->d;
    p2 = map2->d;
    pd = (unsigned char *) res->d;
    *count = 0;
    for (y = 0; y < map1->h; y++)
    for (x = 0; x < map1->w; x++) {
        int c;
        
        if (*p1 != *p2 && !strchr(filter1, *p1) && !strchr(filter2, *p2)) {
            c = mcGet(*p2, useOld, FALSE);
            if (c < 0)
                *pd = 0xfd;
            else
                *pd = c | 64;
            THMSG(2, "[%d,%d]: %d -> %d\n", x+1, y+1, *p1, *p2);
            (*count)++;
        } else {
            c = mcGet(*p1, useOld, FALSE);
            if (c < 0)
                *pd = 0xfd;
            else
                *pd = c;
        }
        
        p1++; p2++; pd++;
    }
    
    return res;
}


int main(int argc, char *argv[])
{
    mapblock_t *map1, *map2, *res;
    FILE *outFile;
    size_t count;
    
    /* Initialize */
    th_init("diffmap", "Create a diff between two ASCII mapfiles", "0.5", NULL, NULL);
    th_verbosityLevel = 1;

    /* Parse arguments */
    if (!th_args_process(argc, argv, optList, optListN,
        argHandleOpt, argHandleFile, TRUE))
        exit(1);
    
    if (srcFilename1 == NULL || srcFilename2 == NULL) {
        THERR("Nothing to do. (try --help)\n");
        exit(0);
    }
    
    /* Read mapfiles */
    if ((map1 = parseFile(srcFilename1, FALSE)) == NULL)
        exit(2);

    if ((map2 = parseFile(srcFilename2, FALSE)) == NULL)
        exit(2);
    
    /* Compute and output data */
    count = 0;
    if ((res = diffBlocks(map1, map2, optUseOldFormat, optFilter1, optFilter2, &count)) == NULL) {
        THERR("Could not create diff between inputs!\n");
        exit(3);
    }
    THMSG(1, "%ld differences.\n", count);
    
    /* Open output file */
    if (optAlwaysDiff || count > 0) {
        THMSG(2, "Outputting map %d x %d...\n", res->w, res->h);

        if (destFilename == NULL)
            outFile = stdout;
        else if ((outFile = fopen(destFilename, "wb")) == NULL) {
            THERR("Error opening output file '%s'!\n",
            destFilename);
            exit(1);
        }
    
        fprintf(outFile, DIFF_MAGIC "%d\n", DIFF_VERSION);
        printBlockRaw(outFile, res);
    
        fclose(outFile);
    } else {
        THMSG(2, "Not outputting diff because of no changes found.\n");
    }
    
    exit(count);
    return count;
}