Mercurial > hg > batmud > maputils
view mapstats.c @ 945:81184d58133c aprilli2011
Sync.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 14 May 2010 11:18:20 +0000 |
parents | 0de9199f67d8 |
children | 667ce752bfe3 |
line wrap: on
line source
/* * Calculate terrain type (and other) statistics from ASCII map * Programmed by Matti 'ccr' Hämäläinen (Ggr Pupunen) * (C) Copyright 2007 Tecnic Software productions (TNSP) */ #include "maputils.h" #include "th_args.h" #include "th_string.h" #include <string.h> typedef int (*compareFunc)(const void *, const void *); enum { SORT_NONE, SORT_NAME, SORT_SYMBOL, SORT_AMOUNT }; char *srcFilename = NULL, *destFilename = NULL; BOOL optUseOldFormat = FALSE, optInputIsDiff = FALSE, optSortBy = SORT_NONE, optCityFormat = FALSE; typedef struct { ulint_t n; int piece; } statpiece_t; /* 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, 'd', "input-diff", "Input is a diff", OPT_NONE }, { 4, 'O', "old-format", "Input using old symbols/colors", OPT_NONE }, { 5, 'o', "output", "Output filename", OPT_ARGREQ }, { 6, 's', "sort", "Sort (by name,symbol,amount)", OPT_ARGREQ }, { 7, 'c', "city-format","Input is a city map", OPT_NONE }, }; const int optListN = (sizeof(optList) / sizeof(optarg_t)); void argShowHelp(void) { th_args_help(stderr, optList, optListN, th_prog_name, "[options] <input mapfile>"); } 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: optInputIsDiff = TRUE; THMSG(2, "Input is a 'diff', handling it as such.\n"); break; case 4: optUseOldFormat = TRUE; THMSG(2, "Input is using old map symbols/colors.\n"); break; case 5: destFilename = optArg; THMSG(2, "Output file set to '%s'.\n", destFilename); break; case 6: if (!strncmp(optArg, "n", 1)) optSortBy = SORT_NAME; else if (!strncmp(optArg, "s", 1)) optSortBy = SORT_SYMBOL; else if (!strncmp(optArg, "a", 1)) optSortBy = SORT_AMOUNT; else { THERR("Unknown sorting method name '%s'!\n", optArg); exit(1); } THMSG(2, "Sorting via method %d\n", optSortBy); break; case 7: optCityFormat = TRUE; THMSG(2, "Input is handled as a city map\n"); break; default: THERR("Unknown option '%s'.\n", currArg); return FALSE; } return TRUE; } BOOL argHandleFile(char *currArg) { if (!srcFilename) srcFilename = currArg; else { THERR("Too many input map files specified!\n"); return FALSE; } return TRUE; } int compareByName(const void *p1, const void *p2) { statpiece_t *vp1 = (statpiece_t *) p1, *vp2 = (statpiece_t *) p2; const mappiece_t *mp1 = &mapPieces[vp1->piece], *mp2 = &mapPieces[vp2->piece]; if (optUseOldFormat) { if (mp1->oldSymbol >= 0 && mp2->oldSymbol >= 0) return strcmp(mp1->oldDesc, mp2->oldDesc); else return -1; } else { if (mp1->symbol >= 0 && mp2->symbol >= 0) return strcmp(mp1->desc, mp2->desc); else return -1; } } int compareBySymbol(const void *p1, const void *p2) { statpiece_t *vp1 = (statpiece_t *) p1, *vp2 = (statpiece_t *) p2; const mappiece_t *mp1 = &mapPieces[vp1->piece], *mp2 = &mapPieces[vp2->piece]; if (optUseOldFormat) { if (mp1->oldSymbol >= 0 && mp2->oldSymbol >= 0) return mp1->oldSymbol - mp2->oldSymbol; else return -1; } else { if (mp1->symbol >= 0 && mp2->symbol >= 0) return mp1->symbol - mp2->symbol; else return -1; } } int compareByAmount(const void *p1, const void *p2) { statpiece_t *vp1 = (statpiece_t *) p1, *vp2 = (statpiece_t *) p2; if (vp1->n < vp2->n) return -1; else if (vp1->n > vp2->n) return 1; else return 0; } /* Main program */ int main(int argc, char *argv[]) { FILE *outFile; mapblock_t *map; int i, x, y; unsigned char *d; ulint_t statTotal, statUnknown; statpiece_t statPieces[nmapPieces]; /* Initialize */ th_init("mapstats", "ASCII map statistics generator", "0.2", NULL, NULL); th_verbosityLevel = 1; /* Parse arguments */ if (!th_args_process(argc, argv, optList, optListN, argHandleOpt, argHandleFile, TRUE)) exit(1); if (srcFilename == NULL) { THERR("Nothing to do. (try --help)\n"); exit(0); } /* Read input file */ THMSG(1, "Reading map file '%s'\n", srcFilename); if ((map = parseFile(srcFilename, optInputIsDiff)) == NULL) { THERR("Error reading map file '%s'!\n", srcFilename); exit(1); } THMSG(1, "Analyzing %dx%d area ...\n", map->w, map->h); for (i = 0; i < nmapPieces; i++) { statPieces[i].n = 0; statPieces[i].piece = i; } statTotal = statUnknown = 0; d = map->d; for (y = 0; y < map->h; y++) for (x = 0; x < map->w; x++) { int c; if ((c = mcGet(*d, optUseOldFormat, optCityFormat)) >= 0) { statPieces[c].n++; } else { statUnknown++; } statTotal++; d++; } /* Sort results, if needed */ if (optSortBy != SORT_NONE) { compareFunc tmpFunc; THMSG(2, "Sorting results ...\n"); switch (optSortBy) { case SORT_NAME: tmpFunc = compareByName; break; case SORT_SYMBOL: tmpFunc = compareBySymbol; break; case SORT_AMOUNT: tmpFunc = compareByAmount; break; default: THERR("Internal error, no sort function for sort type %d.\n", optSortBy); exit(2); break; } qsort(statPieces, nmapPieces, sizeof(statpiece_t), tmpFunc); } /* 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); } for (i = 0; i < nmapPieces; i++) { int p = statPieces[i].piece; char *desc, symbol; if (optUseOldFormat) { desc = mapPieces[p].oldDesc; symbol = mapPieces[p].oldSymbol; } else { desc = mapPieces[p].desc; symbol = mapPieces[p].symbol; } if (symbol >= 0) { fprintf(outFile, "%-20s [%c]: %6ld (%1.3f%%)\n", desc, symbol, statPieces[i].n, (statPieces[i].n * 100.0f / statTotal)); } } fprintf(outFile, " %ld total, %ld unknown.\n", statTotal, statUnknown); fclose(outFile); THMSG(1, "Done.\n"); exit(0); return 0; }