diff options
author | Ben Longbons <b.r.longbons@gmail.com> | 2011-09-16 14:36:23 -0700 |
---|---|---|
committer | Ben Longbons <b.r.longbons@gmail.com> | 2011-09-16 14:48:22 -0700 |
commit | ed81f91ac3c470e00df0d5c5cf9c274ce30f47b3 (patch) | |
tree | c4a59cd3e42a717f611be3acef3bf0009dc5192c | |
parent | bfc8f192f99e6afcb5b0910f8800a76b85910e73 (diff) | |
download | serverdata-ed81f91ac3c470e00df0d5c5cf9c274ce30f47b3.tar.gz serverdata-ed81f91ac3c470e00df0d5c5cf9c274ce30f47b3.tar.bz2 serverdata-ed81f91ac3c470e00df0d5c5cf9c274ce30f47b3.tar.xz serverdata-ed81f91ac3c470e00df0d5c5cf9c274ce30f47b3.zip |
Reimplement aligncsv in C++ instead of python.
The main advantage of the new one is that it properly handles
{script arg1, arg2;}
-rw-r--r-- | GNUmakefile | 24 | ||||
-rw-r--r-- | Makefile | 15 | ||||
-rw-r--r-- | tools/.gitignore | 1 | ||||
-rw-r--r-- | tools/aligncsv.cpp | 177 | ||||
-rwxr-xr-x | tools/aligncsv.py | 88 |
5 files changed, 202 insertions, 103 deletions
diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 00000000..4746eddd --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,24 @@ +.PHONY: all maps conf mobxp mobxp-impl indent indent-items indent-mobs +# Can't be parallel due to the mobxp/indent-mobs conflict +.NOTPARALLEL: +all: maps conf +maps: + ant -f tools/tmwcon/build.xml + java -jar tools/tmwcon/converter.jar client-data/ world/map/ +% : | %.example + cp "$|" "$@" +conf: \ +login/conf/login_local.conf login/conf/ladmin_local.conf login/save/gm_account.txt login/save/account.txt \ +world/map/conf/map_local.conf world/map/conf/battle_local.conf world/map/conf/motd.txt world/map/conf/help.txt world/map/conf/atcommand_local.conf \ +world/conf/char_local.conf + +mobxp: mobxp-impl indent-mobs +mobxp-impl: + mv world/map/db/mob_db.txt world/map/db/mob_db.old + tools/mobxp < world/map/db/mob_db.old > world/map/db/mob_db.txt + rm world/map/db/mob_db.old +indent: indent-mobs indent-items +indent-items: + tools/aligncsv world/map/db/item_db.txt +indent-mobs: + tools/aligncsv world/map/db/mob_db.txt diff --git a/Makefile b/Makefile deleted file mode 100644 index 66ef000b..00000000 --- a/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -.PHONY: all maps conf -all: maps conf -maps: - ant -f tools/tmwcon/build.xml - java -jar tools/tmwcon/converter.jar client-data/ world/map/ -% : | %.example - cp "$|" "$@" -conf: \ -login/conf/login_local.conf login/conf/ladmin_local.conf login/save/gm_account.txt login/save/account.txt \ -world/map/conf/map_local.conf world/map/conf/battle_local.conf world/map/conf/motd.txt world/map/conf/help.txt world/map/conf/atcommand_local.conf \ -world/conf/char_local.conf - -mobxp: - tools/mobxp < world/map/db/mob_db.txt | tools/aligncsv.py /dev/stdin world/map/db/mob_db.txt - sed 's/[[:space:]]*$$//' -i world/map/db/mob_db.txt diff --git a/tools/.gitignore b/tools/.gitignore new file mode 100644 index 00000000..00e2a6af --- /dev/null +++ b/tools/.gitignore @@ -0,0 +1 @@ +/aligncsv diff --git a/tools/aligncsv.cpp b/tools/aligncsv.cpp new file mode 100644 index 00000000..e65c2605 --- /dev/null +++ b/tools/aligncsv.cpp @@ -0,0 +1,177 @@ +#include <cerrno> +#include <cstdio> +#include <cstddef> + +#include <vector> +#include <string> + +// this configuration puts 3-6 spaces between entries (excluding headers) +// and rounds the start of each field up to 4, for easier manual indenting +const size_t min_pad = 3; +const size_t align_pad = 4; + +void add_pieces(std::vector<std::string>& line, std::vector<size_t>& sizes) +{ + // This would get rid of trailing commas, + // but that would break certain db.txt files. + // Instead we'll have to manually check whether it's empty when checking length +// if (!line.empty() && line.back().empty()) +// line.pop_back(); + size_t num_sizes = line.size(); + if (!num_sizes) // line.empty() + return; + if (line[0].size() >= 2 + && (line[0][0] == '#' + || (line[0][0] == '/' + && line[0][1] == '/'))) + return; + + if (num_sizes > sizes.size()) + sizes.resize(num_sizes, 1UL); + for (size_t i = 0; i < num_sizes; ++i) + { + size_t elt_size = line[i].size(); + if (!elt_size)// line[i].empty() + continue; + if (line[i][elt_size - 1] == ' ') + line[i].resize(--elt_size); + // mandatory padding and comma + elt_size += min_pad + 1; + if (elt_size > sizes[i]) + // always true if we expanded sizes + sizes[i] = elt_size; + } +} + +// the arguments may be the same file - the whole file is stored in memory +void aligncsv(FILE *in, FILE *out, const char *name) +{ + bool newline = true; + bool can_split = true; + bool can_have_whitespace = false; + int c; + std::vector<std::vector<std::string> > contents; + + while ((c = fgetc(in)) != -1) + { + if (c == '}' || c == '\n') + can_split = true; + if (c == '\n') + { + if (newline) + { + // preserve consecutive blank lines + contents.push_back(std::vector<std::string>()); + } + newline = true; + continue; + } + if (c == '{') + can_split = false; + if (c == '\t') + c = ' '; + if (c == ' ') + { + if (!can_have_whitespace) + continue; + can_have_whitespace = false; + } + else + can_have_whitespace = true; + if (newline) + { + contents.push_back(std::vector<std::string>(1, std::string(1, c))); + newline = false; + } + else + { + if (can_split && c == ',') + { + can_have_whitespace = false; + contents.back().push_back(std::string()); + } + else + contents.back().back() += c; + } + } + + typedef std::vector<std::vector<std::string> >::iterator outer_it; + typedef std::vector<std::vector<std::string> >::const_iterator outer_cit; + typedef std::vector<size_t>::iterator pieces_it; + // at this point, each entry in a line: + // * does not start with whitespace + // * has one space in place of any previous run of whitespace + // * may end in a single space + // The last is fixed during add_pieces + std::vector<size_t> pieces; + for (outer_it it = contents.begin(), end = contents.end(); it != end; ++it) + add_pieces(*it, pieces); + for (pieces_it it = pieces.begin(), end = pieces.end(); it != end; ++it) + if (size_t trail = *it % align_pad) + *it += align_pad - trail; + + if (in == out) + { + //rewind(out); + if (fseek(out, 0, SEEK_SET) == -1) + { + perror(name); + return; + } + if (ftruncate(fileno(out), 0) == -1) + { + perror(name); + return; + } + } + for (outer_cit oit = contents.begin(), oend = contents.end(); oit != oend; ++oit) + { + const std::vector<std::string>& inner = *oit; + size_t num_elems = inner.size(); + // we have previously guaranteed that pieces[i].size() >= num_elems + for (size_t i = 0; i < num_elems; ++i) + { + // FIXME handle UTF-8 characters (here AND above?) + if (fputs(inner[i].c_str(), out) == -1) + { + perror(name); + return; + } + if (i != num_elems - 1) + { + if (fputc(',', out) == -1) + { + perror(name); + return; + } + size_t elem_length = inner[i].size() + 1; + while (elem_length++ < pieces[i]) + { + if (fputc(' ', out) == -1) + { + perror(name); + return; + } + } + } + } + fputc('\n', out); + } +} + +int main(int argc, char **argv) +{ + if (argc == 1) + aligncsv(stdin, stdout, "<stdio>"); + for (int i = 1; i < argc; ++i) + { + FILE *f = fopen(argv[i], "r+"); + if (!f) + { + perror(argv[i]); + continue; + } + aligncsv(f, f, argv[i]); + fclose(f); + } +} diff --git a/tools/aligncsv.py b/tools/aligncsv.py deleted file mode 100755 index 54bcd9d4..00000000 --- a/tools/aligncsv.py +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/python -# this formats a csv file to a serious whitespace intended format. - -import os -import sys - -tabs=True -additionalspaces = 5 - -fname = sys.argv[1] -if not os.path.exists(fname): - print "that file doesn't exist" - exit(0); - -f=open(fname,"r"); -lines=f.readlines() -f.close(); -length=0 - -for line in lines: - length=max(length, len(line.split(","))) - -print "# number of entries =",length - - -#setup text array -textarray=range(len(lines)+1) -for x in range(len(lines)+1): - textarray[x] = range(length) - -for x in range(length): - textarray[-1][x] = 0 - -#find the longest entry in each line in each position -for lineno in range(len(lines)): - if not lines[lineno].strip().startswith("//") or lines[lineno].strip().startswith("//id"): - sp=lines[lineno].split(",") - for pieceno in range(len(sp)): - sp[pieceno] = sp[pieceno].strip() + "," #for the comma add a char - textarray[-1][pieceno] = max(len(sp[pieceno]),textarray[-1][pieceno]) - -if tabs: - #make it divisable by 8 (tabs work then) - for pieceno in range(length): - if (textarray[-1][pieceno] %8) !=0: - textarray[-1][pieceno] = (((textarray[-1][pieceno])/8)*8)+8 - -for lineno in range(len(lines)): - if not lines[lineno].strip().startswith("//") or lines[lineno].strip().startswith("//id"): - sp=lines[lineno].split(",") - for pieceno in range(length): - textarray[lineno][pieceno] = "" - if pieceno<len(sp): - sp[pieceno]= sp[pieceno].strip() - if pieceno<len(sp)-1: - sp[pieceno]= sp[pieceno] + "," - - if (tabs): - n=(textarray[-1][pieceno]-len(sp[pieceno])) - textarray[lineno][pieceno] = sp[pieceno] - if (n%8) != 0: - textarray[lineno][pieceno] += "\t"*((n/8)+1) - else: - textarray[lineno][pieceno] += "\t"*((n/8)) - else: - n=(textarray[-1][pieceno]-len(sp[pieceno])+additionalspaces) - textarray[lineno][pieceno] = " "*(n) + sp[pieceno] - else: - for pieceno in range(length): - textarray[lineno][pieceno] = "" - textarray[lineno][0]=lines[lineno].strip() - - -fname = sys.argv[2] -if not os.path.exists(fname): - print "that file doesn't exist" - exit(0); -else: - f=open(fname,"w"); - for line in textarray[:-1]: - for piece in line: - f.write(piece) - f.write("\n") - f.close() - - - - |