Deletes unused, unbuildable tools

Deletes create_images, cuter, exploder, schema_generator, schema_validator, and wesmage
This commit is contained in:
pentarctagon 2016-12-17 05:24:36 -06:00 committed by Celtic Minstrel
parent 0be99ede50
commit 9f79398ecf
31 changed files with 12 additions and 3470 deletions

View file

@ -46,7 +46,7 @@ def OptionalPath(key, val, env):
opts.AddVariables(
ListVariable('default_targets', 'Targets that will be built if no target is specified in command line.',
"wesnoth,wesnothd", Split("wesnoth wesnothd campaignd cutter exploder test")),
"wesnoth,wesnothd", Split("wesnoth wesnothd campaignd test")),
EnumVariable('build', 'Build variant: debug, release profile or base (no subdirectory)', "release", ["optimized", "release", "debug", "glibcxx_debug", "profile", "base"]),
PathVariable('build_dir', 'Build all intermediate files(objects, test programs, etc) under this dir', "build", PathVariable.PathAccept),
('extra_flags_config', "Extra compiler and linker flags to use for configuration and all builds. Whether they're compiler or linker is determined by env.ParseFlags. Unknown flags are compile flags by default. This applies to all extra_flags_* variables", ""),
@ -201,18 +201,16 @@ Important switches include:
With no arguments, the recipe builds wesnoth and wesnothd. Available
build targets include the individual binaries:
wesnoth wesnothd campaignd exploder cutter test
wesnoth wesnothd campaignd test
You can make the following special build targets:
all = wesnoth exploder cutter wesnothd campaignd test (*).
all = wesnoth wesnothd campaignd test (*).
TAGS = build tags for Emacs (*).
wesnoth-deps.png = project dependency graph
install = install all executables that currently exist, and any data needed
install-wesnothd = install the Wesnoth multiplayer server.
install-campaignd = install the Wesnoth campaign server.
install-cutter = install the castle cutter
install-exploder = install the castle exploder
install-pytools = install all Python tools and modules
uninstall = uninstall all executables, tools, modules, and servers.
pot-update = generate gettext message catalog templates and merge them with localized message catalogs
@ -378,7 +376,7 @@ if env["prereqs"]:
conf.CheckBoost("program_options", require_version = boost_version) & \
conf.CheckBoost("thread") & \
conf.CheckBoost("regex") \
or Warning("Client prerequisites are not met. wesnoth, cutter and exploder cannot be built")
or Warning("Client prerequisites are not met. wesnoth cannot be built")
have_X = False
if have_client_prereqs:
@ -526,14 +524,14 @@ except:
Export(Split("env client_env test_env have_client_prereqs have_server_prereqs have_test_prereqs"))
SConscript(dirs = Split("po doc packaging/windows packaging/systemd"))
binaries = Split("wesnoth wesnothd cutter exploder campaignd test")
binaries = Split("wesnoth wesnothd campaignd test")
builds = {
"base" : dict(CCFLAGS = Split("$OPT_FLAGS")), # Don't build in subdirectory
"debug" : dict(CCFLAGS = Split("$DEBUG_FLAGS")),
"base" : dict(CCFLAGS = Split("$OPT_FLAGS")), # Don't build in subdirectory
"debug" : dict(CCFLAGS = Split("$DEBUG_FLAGS")),
"glibcxx_debug" : dict(CPPDEFINES = Split("_GLIBCXX_DEBUG _GLIBCXX_DEBUG_PEDANTIC")),
"release" : dict(CCFLAGS = Split("$OPT_FLAGS")),
"profile" : dict(CCFLAGS = "-pg", LINKFLAGS = "-pg"),
"optimized" : dict(CCFLAGS = Split("$HIGH_OPT_COMP_FLAGS"), LINKFLAGS=Split("$HIGH_OPT_LINK_FLAGS"))
"release" : dict(CCFLAGS = Split("$OPT_FLAGS")),
"profile" : dict(CCFLAGS = "-pg", LINKFLAGS = "-pg"),
"optimized" : dict(CCFLAGS = Split("$HIGH_OPT_COMP_FLAGS"), LINKFLAGS=Split("$HIGH_OPT_LINK_FLAGS"))
}
builds["glibcxx_debug"].update(builds["debug"])
build = env["build"]
@ -643,15 +641,10 @@ if env["systemd"]:
# Wesnoth campaign server
env.InstallBinary(campaignd)
# And the artists' tools
env.InstallBinary(cutter)
env.InstallBinary(exploder)
# Compute things for default install based on which targets have been created.
install = env.Alias('install', [])
for installable in ('wesnoth',
'wesnothd', 'campaignd',
'exploder', 'cutter'):
'wesnothd', 'campaignd'):
if os.path.exists(installable + build_suffix) or installable in COMMAND_LINE_TARGETS or "all" in COMMAND_LINE_TARGETS:
env.Alias('install', env.Alias('install-'+installable))

View file

@ -1,5 +0,0 @@
sdl/utils.cpp
sdl/window.cpp
tests/create_images.cpp
tools/exploder_utils.cpp
tracer.cpp

View file

@ -1,5 +0,0 @@
sdl/utils.cpp
tools/cutter.cpp
tools/exploder_cutter.cpp
tools/exploder_utils.cpp
tracer.cpp

View file

@ -1,6 +0,0 @@
sdl/utils.cpp
tools/exploder.cpp
tools/exploder_composer.cpp
tools/exploder_cutter.cpp
tools/exploder_utils.cpp
tracer.cpp

View file

@ -1,6 +0,0 @@
filesystem_boost.cpp
filesystem_common.cpp
tools/schema/error_container.cpp
tools/schema/schema_generator.cpp
tools/schema/sourceparser.cpp
tools/schema/tag.cpp

View file

@ -1,8 +0,0 @@
config_cache.cpp
filesystem_boost.cpp
filesystem_common.cpp
serialization/schema_validator.cpp
serialization/validator.cpp
tools/schema/tag.cpp
tools/validator/validator_tool.cpp
utils/sha1.cpp

View file

@ -1,8 +0,0 @@
sdl/utils.cpp
sdl/window.cpp
tools/exploder_utils.cpp
tracer.cpp
wesmage/exit.cpp
wesmage/filter.cpp
wesmage/options.cpp
wesmage/wesmage.cpp

View file

@ -465,85 +465,6 @@ if(ENABLE_CAMPAIGN_SERVER)
endif(ENABLE_CAMPAIGN_SERVER)
########### Castle building helpers ###############
if(ENABLE_TOOLS)
# exploder
GetSources("exploder" exploder_SRC)
add_executable(exploder ${exploder_SRC})
target_link_libraries(exploder
wesnoth-core
wesnoth-sdl
png
${tools-external-libs}
)
set_target_properties(exploder PROPERTIES OUTPUT_NAME ${BINARY_PREFIX}exploder${BINARY_SUFFIX})
install(TARGETS exploder DESTINATION ${BINDIR})
# cutter
GetSources("cutter" cutter_SRC)
add_executable(cutter ${cutter_SRC})
target_link_libraries(cutter
wesnoth-core
wesnoth-sdl
png
${tools-external-libs}
)
set_target_properties(cutter PROPERTIES OUTPUT_NAME ${BINARY_PREFIX}cutter${BINARY_SUFFIX})
install(TARGETS cutter DESTINATION ${BINDIR})
# schema_generator
GetSources("schema_generator" schema_generator_SRC)
add_executable(schema_generator ${schema_generator_SRC})
target_link_libraries(schema_generator
wesnoth-core
wesnoth-sdl
${tools-external-libs}
${Boost_REGEX_LIBRARY}
)
set_target_properties(schema_generator PROPERTIES OUTPUT_NAME ${BINARY_PREFIX}schema_generator${BINARY_SUFFIX})
install(TARGETS schema_generator DESTINATION ${BINDIR})
# schema_validator
GetSources("schema_validator" schema_validator_SRC)
add_executable(schema_validator ${schema_validator_SRC})
target_link_libraries(schema_validator
wesnoth-core
wesnoth-sdl
${common-external-libs}
${Boost_SYSTEM_LIBRARIES}
${Boost_RANDOM_LIBRARY}
)
set_target_properties(schema_validator PROPERTIES OUTPUT_NAME ${BINARY_PREFIX}schema_validator${BINARY_SUFFIX}
COMPILE_DEFINITIONS VALIDATION_ERRORS_LOG)
install(TARGETS schema_validator DESTINATION ${BINDIR})
# wesmage
GetSources("wesmage" wesmage_SRC)
add_executable(wesmage ${wesmage_SRC})
target_link_libraries(wesmage
wesnoth-core
wesnoth-sdl
png
${tools-external-libs}
)
set_target_properties(wesmage PROPERTIES OUTPUT_NAME ${BINARY_PREFIX}wesmage${BINARY_SUFFIX})
install(TARGETS wesmage DESTINATION ${BINDIR})
endif(ENABLE_TOOLS)
########### Unit tests ###############
if(ENABLE_TESTS)
@ -591,20 +512,5 @@ if(ENABLE_TESTS)
PROPERTIES OUTPUT_NAME ${BINARY_PREFIX}test${BINARY_SUFFIX}
)
if(ENABLE_TOOLS)
# This tool is used to create the images for the sdl_utils unit test.
# Due to its unique nature the program is never installed.
GetSources("create_images" create_images_SRC)
add_executable(create_images ${create_images_SRC})
target_link_libraries(create_images
wesnoth-core
wesnoth-sdl
png
${tools-external-libs}
)
set_target_properties(create_images PROPERTIES OUTPUT_NAME ${BINARY_PREFIX}create_images${BINARY_SUFFIX})
endif(ENABLE_TOOLS)
endif(ENABLE_TESTS)

View file

@ -123,7 +123,6 @@ libwesnoth_extras.extend(env_lua.Library("lua", objs_lua))
#
# Target declarations
#
#---start valid scons default_targets---#
def error_action(target, source, env):
from SCons.Errors import UserError
@ -149,6 +148,7 @@ def WesnothProgram(env, target, source, can_build, **kw):
for env in [test_env, client_env, env]:
env.AddMethod(WesnothProgram)
#---wesnoth---
wesnoth_objects = ["wesnoth.cpp", libwesnoth_extras, libwesnoth_core, libwesnoth,
libwesnoth_sdl, libwesnoth_extras, env["wesnoth_res"]]
if env["PLATFORM"] == 'darwin':
@ -163,36 +163,9 @@ env.WesnothProgram("wesnothd", wesnothd_sources + [libwesnoth_core, env["wesnoth
campaignd_sources = GetSources("campaignd")
env.WesnothProgram("campaignd", campaignd_sources + [libwesnoth_core], have_server_prereqs, OBJPREFIX = "campaignd_")
#---cutter---
cutter_sources = GetSources("cutter")
client_env.WesnothProgram("cutter", cutter_sources + [libwesnoth_core, libwesnoth_sdl, libwesnoth], have_client_prereqs, OBJPREFIX = "cutter_", LIBS = ["$LIBS", "png"])
#---exploder---
exploder_sources = GetSources("exploder")
client_env.WesnothProgram("exploder", exploder_sources + [libwesnoth_core, libwesnoth_sdl, libwesnoth], have_client_prereqs, OBJPREFIX = "exploder_", LIBS = ["$LIBS", "png"])
#---test---
test_sources = GetSources("test")
test = test_env.WesnothProgram("test", test_sources + [libwesnoth_extras, libwesnoth_core, libwesnoth, libwesnoth_sdl, libwesnoth_extras], have_test_prereqs)
#---end valid scons default_targets---#
#---start invalid scons default_targets---#
#---schema_generator---
schema_generator_sources = GetSources("schema_generator")
client_env.WesnothProgram("schema_generator", schema_generator_sources + [libwesnoth_core], have_client_prereqs, OBJPREFIX = "schema_generator_")
#---schema_validator---
schema_validator_sources = GetSources("schema_validator")
client_env.WesnothProgram("schema_validator", schema_validator_sources + [libwesnoth_core], have_client_prereqs, OBJPREFIX = "schema_validator_")
#---wesmage---
wesmage_sources = GetSources("wesmage")
client_env.WesnothProgram("wesmage", wesmage_sources + [libwesnoth_core], have_client_prereqs, OBJPREFIX = "wesmage_", LIBS = ["$LIBS", "png"])
#---create_images---
create_images_sources = GetSources("create_images")
env.WesnothProgram("create_images", create_images_sources + [libwesnoth_core], have_server_prereqs, OBJPREFIX = "create_images_", LIBS = ["$LIBS", "png"])
#---end invalid scons default_targets---#
#---end of getting sources---
if env.get("have_autorevision"):

View file

@ -1,152 +0,0 @@
/*
Copyright (C) 2012 - 2016 by Mark de Wever <koraq@xs4all.nl>
Part of the Battle for Wesnoth Project http://www.wesnoth.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file
* Tool to create the test images for the unit tests.
*/
#include "filesystem.hpp"
#include "tools/exploder_utils.hpp"
#include "tests/test_sdl_utils.hpp"
#include <SDL_image.h>
#include "utils/functional.hpp"
#include <iostream>
static void
show_usage()
{
std::cerr <<
"Usage:\n"
"test_images -h\n"
"test_images DIR\n"
"Helper program to create images for the unit tests.\n"
"\n"
"The DIR is the output directory, will be created if doesn't exist.\n"
"OPTIONS:\n"
"-h, --help Show this help and terminate the program.\n"
;
}
static surface
create_image_base(const std::string& filename)
{
surface result = SDL_CreateRGBSurface(
SDL_SWSURFACE
, 1024
, 1024
, 32
, 0xFF0000
, 0xFF00
, 0xFF
, 0);
surface_lock lock(result);
Uint32 *pixels = lock.pixels();
for(Uint32 r = 0; r < 256; r += 4) {
for(Uint32 g = 0; g < 256; g += 2) {
for(Uint32 b = 0; b < 256; b += 2, ++pixels) {
*pixels = (0xFF << 24) | (r << 16) | (g << 8) | b;
}
}
}
save_image(result, filename);
return result;
}
static void
create_image_blend_functor(
const surface& dst
, const std::string root
, const Uint8 amount
, const Uint32 color)
{
const std::string filename = blend_get_filename(root, amount, color);
save_image(dst, filename);
}
static void
create_image_blend(const surface& src, const std::string& root)
{
blend_image(
src
, std::bind(&create_image_blend_functor, _1, root, _2, _3));
}
typedef void (*functor_t) (const surface&, const std::string&);
typedef std::pair<std::string, functor_t> tcreator;
static const tcreator creators[] =
{
std::make_pair("/blend/", &create_image_blend)
};
int
main(int argc, char* argv[])
{
if(argc != 2) {
show_usage();
return EXIT_FAILURE;
}
const std::string root = argv[1];
if(root == "-h" || root == "--help") {
show_usage();
return EXIT_SUCCESS;
}
if(!filesystem::is_directory(root)) {
if(filesystem::file_exists(root)) {
std::cerr << "";
return EXIT_FAILURE;
}
if(!filesystem::make_directory(root)) {
std::cerr << "";
return EXIT_FAILURE;
}
}
for(const tcreator& creator : creators) {
if(!filesystem::make_directory(root + creator.first)) {
std::cerr << "";
return EXIT_FAILURE;
}
}
try {
const surface base_image = create_image_base(root + "/base.png");
for(const tcreator& creator : creators) {
creator.second(base_image, root + creator.first);
}
} catch(exploder_failure& err) {
std::cerr << "Error: Failed with error »" << err.message << "«.\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View file

@ -1,106 +0,0 @@
/*
Copyright (C) 2004 - 2016 by Philippe Plantier <ayin@anathas.org>
Part of the Battle for Wesnoth Project http://www.wesnoth.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file
* Standalone-Utility for images / tiles
*/
#include "game_config.hpp"
#include "tools/exploder_composer.hpp"
#include <SDL_image.h>
#include <iostream>
namespace {
void print_usage(std::string name)
{
std::cerr << "usage: " << name << " [source] [dest_directory]\n";
}
}
int main(int argc, char* argv[])
{
std::string src;
std::string dest_dir;
cutter cut;
// Parse arguments that shouldn't require a display device
int arg;
for(arg = 1; arg != argc; ++arg) {
const std::string val(argv[arg]);
if(val.empty()) {
continue;
}
if(val == "--help" || val == "-h") {
print_usage(argv[0]);
return 0;
} else if(val == "--verbose" || val == "-v") {
cut.set_verbose(true);
} else if(val == "--directory" || val == "-d" ) {
game_config::path = argv[++arg];
} else {
if(src.empty()) {
src = val;
} else if(dest_dir.empty()) {
dest_dir = val;
} else {
print_usage(argv[0]);
return 1;
}
}
}
if(src.empty() || dest_dir.empty()) {
print_usage(argv[0]);
return 1;
}
try {
const config conf = cut.load_config(src);
cut.load_masks(conf);
const surface src_surface(make_neutral_surface(IMG_Load(src.c_str())));
if(src_surface == nullptr)
throw exploder_failure("Unable to load the source image " + src);
const cutter::surface_map surfaces = cut.cut_surface(src_surface, conf);
for(cutter::surface_map::const_iterator itor = surfaces.begin();
itor != surfaces.end(); ++itor) {
const cutter::mask &mask = itor->second.mask;
surface surf = create_compatible_surface(
itor->second.image
, mask.cut.w
, mask.cut.h);
masked_overwrite_surface(surf, itor->second.image, mask.image,
mask.cut.x - mask.shift.x, mask.cut.y - mask.shift.y);
save_image(surf, dest_dir + "/" + mask.name + ".png");
}
} catch(exploder_failure& err) {
std::cerr << "Failed: " << err.message << "\n";
return 1;
}
return 0;
}

View file

@ -1,80 +0,0 @@
/*
Copyright (C) 2004 - 2016 by Philippe Plantier <ayin@anathas.org>
Part of the Battle for Wesnoth Project http://www.wesnoth.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "game_config.hpp"
#include "tools/exploder_composer.hpp"
#include <iostream>
namespace {
void print_usage(std::string name)
{
std::cerr << "usage: " << name << " [source] [destination]\n";
}
}
int main(int argc, char* argv[])
{
std::string src;
std::string dest;
composer comp;
//parse arguments that shouldn't require a display device
int arg;
for(arg = 1; arg != argc; ++arg) {
const std::string val(argv[arg]);
if(val.empty()) {
continue;
}
if(val == "--help" || val == "-h") {
print_usage(argv[0]);
return 0;
} else if(val == "--interactive" || val == "-i") {
comp.set_interactive(true);
} else if(val == "--verbose" || val == "-v") {
comp.set_verbose(true);
} else if(val == "--directory" || val == "-d" ) {
game_config::path = argv[++arg];
} else {
if(src.empty()) {
src = val;
} else if(dest.empty()) {
dest = val;
} else {
print_usage(argv[0]);
return 1;
}
}
}
if(src.empty() || dest.empty()) {
print_usage(argv[0]);
return 1;
}
try {
surface image = comp.compose(src, dest);
save_image(image, dest);
} catch(exploder_failure& err) {
std::cerr << "Failed: " << err.message << "\n";
return 1;
}
return 0;
}

View file

@ -1,96 +0,0 @@
/*
Copyright (C) 2004 - 2016 by Philippe Plantier <ayin@anathas.org>
Part of the Battle for Wesnoth Project http://www.wesnoth.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "tools/exploder_composer.hpp"
#include <SDL_image.h>
#include <iostream>
composer::composer() : interactive_(false), verbose_(false)
{
}
surface composer::compose(const std::string &src, const std::string &dest)
{
cutter cut;
cut.set_verbose(verbose_);
const config src_conf = cut.load_config(src);
const config dest_conf = cut.load_config(dest);
if(verbose_) {
std::cerr << "Loading masks...\n";
}
cut.load_masks(src_conf);
cut.load_masks(dest_conf);
if(verbose_) {
std::cerr << "Loading images...\n";
}
const surface src_surface(make_neutral_surface(IMG_Load(src.c_str())));
if(src_surface == nullptr)
throw exploder_failure("Unable to load the source image " + src);
const surface dest_surface(make_neutral_surface(IMG_Load(dest.c_str())));
if(dest_surface == nullptr)
throw exploder_failure("Unable to load the destination image " + dest);
if(verbose_) {
std::cerr << "Cutting images...\n";
}
const cutter::surface_map src_surfaces = cut.cut_surface(src_surface, src_conf);
const cutter::surface_map dest_surfaces = cut.cut_surface(dest_surface, dest_conf);
for(cutter::surface_map::const_iterator itor = dest_surfaces.begin();
itor != dest_surfaces.end(); ++itor) {
const std::string& name = itor->second.name;
if(src_surfaces.find(name) == src_surfaces.end())
continue;
const cutter::positioned_surface& src_ps = src_surfaces.find(name)->second;
const cutter::positioned_surface& dest_ps = itor->second;
if(!image_empty(dest_ps.image)) {
if(interactive_) {
//TODO: make "interactive" mode work
} else {
std::cerr << "Warning: element " << name << " not empty on destination image\n";
}
}
if(verbose_) {
std::cerr << "Inserting image " << name
<< " on position (" << dest_ps.pos.x
<< ", " << dest_ps.pos.y << ")\n";
}
masked_overwrite_surface(dest_surface, src_ps.image,
src_ps.mask.image,
dest_ps.pos.x, dest_ps.pos.y);
}
return dest_surface;
}
void composer::set_interactive(bool value)
{
interactive_ = value;
}
void composer::set_verbose(bool value)
{
verbose_ = value;
}

View file

@ -1,36 +0,0 @@
/*
Copyright (C) 2004 - 2016 by Philippe Plantier <ayin@anathas.org>
Part of the Battle for Wesnoth Project http://www.wesnoth.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#ifndef EXPLODER_COMPOSER_HPP_INCLUDED
#define EXPLODER_COMPOSER_HPP_INCLUDED
#include "exploder_utils.hpp"
#include "exploder_cutter.hpp"
class composer
{
public:
composer();
surface compose(const std::string &src, const std::string &dest);
void set_interactive(bool value);
void set_verbose(bool value);
private:
bool interactive_;
bool verbose_;
};
#endif

View file

@ -1,165 +0,0 @@
/*
Copyright (C) 2004 - 2016 by Philippe Plantier <ayin@anathas.org>
Part of the Battle for Wesnoth Project http://www.wesnoth.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "tools/exploder_cutter.hpp"
#include "filesystem.hpp"
#include "sdl/rect.hpp"
#include "serialization/parser.hpp"
#include "serialization/preprocessor.hpp"
#include "serialization/string_utils.hpp"
#include <SDL_image.h>
#include <iostream>
cutter::cutter()
: masks_()
, verbose_(false)
{
}
const config cutter::load_config(const std::string &filename)
{
const std::string conf_string = find_configuration(filename);
config res;
try {
filesystem::scoped_istream stream = preprocess_file(conf_string);
read(res, *stream);
} catch(config::error& err) {
throw exploder_failure("Unable to load the configuration for the file " + filename + ": "+ err.message);
}
return res;
}
void cutter::load_masks(const config& conf)
{
for(const config &m : conf.child_range("mask"))
{
const std::string name = m["name"];
const std::string image = get_mask_dir() + "/" + std::string(m["image"]);
if(verbose_) {
std::cerr << "Adding mask " << name << "\n";
}
if(image.empty())
throw exploder_failure("Missing image for mask " + name);
const exploder_point shift(m["shift"]);
const exploder_rect cut(m["cut"]);
if(masks_.find(name) != masks_.end() && masks_[name].filename != image) {
throw exploder_failure("Mask " + name +
" correspond to two different files: " +
name + " and " +
masks_.find(name)->second.filename);
}
if(masks_.find(name) == masks_.end()) {
mask& cur_mask = masks_[name];
cur_mask.name = name;
cur_mask.shift = shift;
cur_mask.cut = cut;
cur_mask.filename = image;
surface tmp(IMG_Load(image.c_str()));
if(tmp == nullptr)
throw exploder_failure("Unable to load mask image " + image);
cur_mask.image = make_neutral_surface(tmp);
}
if(masks_[name].image == nullptr)
throw exploder_failure("Unable to load mask image " + image);
}
}
cutter::surface_map cutter::cut_surface(surface surf, const config& conf)
{
surface_map res;
for(const config &part : conf.child_range("part")) {
add_sub_image(surf, res, &part);
}
return res;
}
std::string cutter::find_configuration(const std::string &file)
{
//finds the file prefix.
const std::string fname = filesystem::base_name(file);
const std::string::size_type dotpos = fname.rfind('.');
std::string basename;
if(dotpos == std::string::npos) {
basename = fname;
} else {
basename = fname.substr(0, dotpos);
}
return get_exploder_dir() + "/" + basename + ".cfg";
}
void cutter::add_sub_image(const surface &surf, surface_map &map, const config* config)
{
const std::string name = (*config)["name"];
if(name.empty())
throw exploder_failure("Un-named sub-image");
if(masks_.find(name) == masks_.end())
throw exploder_failure("Unable to find mask corresponding to " + name);
const cutter::mask& mask = masks_[name];
std::vector<std::string> pos = utils::split((*config)["pos"]);
if(pos.size() != 2)
throw exploder_failure("Invalid position " + (*config)["pos"].str());
int x = atoi(pos[0].c_str());
int y = atoi(pos[1].c_str());
const SDL_Rect cut = sdl::create_rect(x - mask.shift.x
, y - mask.shift.y
, mask.image->w
, mask.image->h);
typedef std::pair<std::string, positioned_surface> sme;
positioned_surface ps;
ps.image = ::cut_surface(surf, cut);
if(ps.image == nullptr)
throw exploder_failure("Unable to cut surface!");
ps.name = name;
ps.mask = mask;
ps.pos.x = x - mask.shift.x;
ps.pos.y = y - mask.shift.y;
map.insert(sme(name, ps));
if(verbose_) {
std::cerr << "Extracting sub-image " << name << ", position (" << x << ", " << y << ")\n";
}
}
void cutter::set_verbose(bool value)
{
verbose_ = value;
}

View file

@ -1,78 +0,0 @@
/*
Copyright (C) 2004 - 2016 by Philippe Plantier <ayin@anathas.org>
Part of the Battle for Wesnoth Project http://www.wesnoth.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#ifndef EXPLODER_CUTTER_HPP_INCLUDED
#define EXPLODER_CUTTER_HPP_INCLUDED
#include "sdl/surface.hpp"
#include "config.hpp"
#include "exploder_utils.hpp"
class cutter
{
public:
struct mask
{
mask()
: name()
, image(nullptr)
, filename()
, shift()
, cut()
{
}
std::string name;
surface image;
std::string filename;
exploder_point shift;
exploder_rect cut;
};
typedef std::map<std::string, mask> mask_map;
struct positioned_surface {
positioned_surface()
: name()
, pos()
, image(nullptr)
, mask()
{
}
std::string name;
exploder_point pos;
surface image;
cutter::mask mask;
};
typedef std::multimap<std::string, positioned_surface> surface_map;
cutter();
const config load_config(const std::string& filename);
void load_masks(const config& conf);
surface_map cut_surface(surface surf, const config& conf);
void set_verbose(bool value);
private:
std::string find_configuration(const std::string &file);
void add_sub_image(const surface &surf, surface_map &map, const config* config);
mask_map masks_;
bool verbose_;
};
#endif

View file

@ -1,241 +0,0 @@
/*
Copyright (C) 2004 - 2016 by Philippe Plantier <ayin@anathas.org>
Part of the Battle for Wesnoth Project http://www.wesnoth.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "tools/exploder_utils.hpp"
#include "game_config.hpp"
#include "serialization/string_utils.hpp"
#include <cstdio> //for FILE
#include <memory>
#include <png.h>
#include <zlib.h>
exploder_point::exploder_point(const std::string &s)
: x(0)
, y(0)
{
std::vector<std::string> items = utils::split(s);
if(items.size() == 2) {
x = atoi(items[0].c_str());
y = atoi(items[1].c_str());
}
}
exploder_rect::exploder_rect(const std::string &s)
: x(0)
, y(0)
, w(0)
, h(0)
{
std::vector<std::string> items = utils::split(s);
if(items.size() == 4) {
x = atoi(items[0].c_str());
y = atoi(items[1].c_str());
w = atoi(items[2].c_str());
h = atoi(items[3].c_str());
}
}
std::string get_mask_dir()
{
// return ".";
return game_config::path + "/images/tools/exploder";
}
std::string get_exploder_dir()
{
return game_config::path + "/data/tools/exploder";
}
//on pixels where mask is not white, overwrite dest with src. Mask and dest are
//translated to the position (x,y) on dest.
//All surfaces are supposed to be neutral surfaces, mask and src are supposed
//to be of identical size.
void masked_overwrite_surface(surface dest, surface src, surface mask, int x, int y)
{
surface_lock dest_lock(dest);
surface_lock src_lock(src);
surface_lock mask_lock(mask);
Uint32* dest_beg = dest_lock.pixels();
Uint32* src_beg = src_lock.pixels();
Uint32* mask_beg = mask_lock.pixels();
size_t small_shift_before;
size_t small_shift_after;
size_t dest_shift;
size_t src_width = src->w;
size_t src_height = src->h;
if(x < 0) {
small_shift_before = -x;
if (src_width < small_shift_before)
return;
src_width -= small_shift_before;
x = 0;
} else {
small_shift_before = 0;
}
if(x + src_width <= unsigned(dest->w)) {
small_shift_after = 0;
} else {
small_shift_after = src_width - (dest->w - x);
src_width = dest->w - x;
}
if(y >= 0) {
dest_beg += dest->w * y + x;
} else {
src_beg += (-y) * src->w;
mask_beg += (-y) * mask->w;
dest_beg += x;
if (src_height < static_cast<size_t>(-y))
return;
src_height += y;
y = 0;
}
if(y + src_height > unsigned(dest->h)) {
src_height = dest->h - y;
}
dest_shift = dest->w - src_width;
for(size_t j = 0; j < src_height; ++j) {
src_beg += small_shift_before;
mask_beg += small_shift_before;
for(size_t i = 0; i < src_width; ++i) {
//Assuming here alpha mask is 0xff000000
if((*mask_beg & 0x00ffffff) != 0x00ffffff) {
*dest_beg = *src_beg;
}
++dest_beg;
++src_beg;
++mask_beg;
}
src_beg += small_shift_after;
mask_beg += small_shift_after;
dest_beg += dest_shift;
}
}
//returns true if the image is empty. the surface surf is considered to be a
//neutral surface.
bool image_empty(surface surf)
{
//an image is considered empty if
// * all its pixels have 0 alpha, OR
// * all of its pixels have the same color (and the same alpha)
surface_lock lock(surf);
Uint32* beg = lock.pixels();
Uint32* end = beg + surf->w*surf->h;
Uint32 color = *beg;
while(beg != end) {
if((*beg & 0xff000000) != 0 && (*beg != color))
return false;
++beg;
}
return true;
}
namespace {
struct rgba {
Uint8 r;
Uint8 g;
Uint8 b;
Uint8 a;
};
}
static void close_FILE(std::FILE* f)
{
if(f != nullptr) { std::fclose(f); }
}
//saves the given SDL structure into a given filename.
void save_image(surface surf, const std::string &filename)
{
//opens the actual file
const std::unique_ptr<std::FILE, void(*)(std::FILE*)> file(fopen(filename.c_str(),"wb"), &close_FILE);
//initializes PNG write structures
//TODO: review whether providing nullptr error handlers is something
//sensible
png_struct* png_ptr = png_create_write_struct
(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if(!png_ptr)
throw exploder_failure("Unable to initialize the png write structure");
png_info* info_ptr = png_create_info_struct(png_ptr);
if(!info_ptr) {
png_destroy_write_struct(&png_ptr, nullptr);
throw exploder_failure("Unable to initialize the png info structure");
}
//instructs the PNG library to use the open file
png_init_io(png_ptr, file.get());
//sets compression level to the maximum
png_set_compression_level(png_ptr,
Z_BEST_COMPRESSION);
//configures the header
png_set_IHDR(png_ptr, info_ptr, surf->w, surf->h,
8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
//puts the actual image data in the row_pointers array
png_byte **row_pointers = new png_byte *[surf->h];
surface_lock lock(surf);
//converts the data to the RGBA format. We cannot pass SDL data
//directly to the png lib, even if we know its pixel format, because of
//endianness problems.
std::unique_ptr<rgba[]> rgba_data(new rgba[surf->w * surf->h]);
Uint32 *surf_data = lock.pixels();
int pos = 0;
for(int y = 0; y < surf->h; ++y) {
row_pointers[y] = reinterpret_cast<png_byte*>(&rgba_data[pos]);
for(int x = 0; x < surf->w; ++x) {
Uint8 red, green, blue, alpha;
SDL_GetRGBA(*surf_data, surf->format, &red, &green, &blue, &alpha);
rgba_data[pos].r = red;
rgba_data[pos].g = green;
rgba_data[pos].b = blue;
rgba_data[pos].a = alpha;
pos++;
surf_data++;
}
}
png_set_rows(png_ptr, info_ptr, row_pointers);
//writes the actual image data
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, nullptr);
//cleans everything
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, &info_ptr);
delete [] row_pointers;
}

View file

@ -1,58 +0,0 @@
/*
Copyright (C) 2004 - 2016 by Philippe Plantier <ayin@anathas.org>
Part of the Battle for Wesnoth Project http://www.wesnoth.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#ifndef EXPLODER_UTILS_HPP_INCLUDED
#define EXPLODER_UTILS_HPP_INCLUDED
#include "sdl/surface.hpp"
#include <string>
struct exploder_failure
{
exploder_failure(const std::string& message) :
message(message) {}
std::string message;
};
struct exploder_point
{
exploder_point() : x(0), y(0) {}
exploder_point(int x, int y) : x(x), y(y) {}
exploder_point(const std::string &s);
int x;
int y;
};
struct exploder_rect
{
exploder_rect() : x(0), y(0), w(0), h(0) {}
exploder_rect(int x,int y, int w, int h) : x(x), y(y), w(w), h(h) {}
exploder_rect(const std::string &s);
int x;
int y;
int w;
int h;
};
std::string get_mask_dir();
std::string get_exploder_dir();
void masked_overwrite_surface(surface dest, surface src, surface mask, int x, int y);
bool image_empty(surface surf);
void save_image(surface surf, const std::string &filename);
#endif

View file

@ -1,122 +0,0 @@
/*
Copyright (C) 2011 - 2016 by Sytyi Nick <nsytyi@gmail.com>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file
* This file contains implementation of error_container.hpp.
*/
#include "tools/schema/error_container.hpp"
namespace schema_validation{
void class_error_container::add_simple_error(const std::string & message){
list_.push_back(message);
}
void class_error_container::add_read_error(const std::string & file,int line){
std::ostringstream s;
s << file << ":" << line <<": Read error at line "<< line <<".\n";
list_.push_back(s.str());
}
void class_error_container::add_opened_entity_error(
const std::string & file,int line,const std::string & name){
std::ostringstream s;
s << file << ":" << line <<": Entity "<< name
<<" is opened but not closed.\n";
list_.push_back(s.str());
}
void class_error_container::add_unopened_entity_error(
const std::string & file,int line,const std::string & name){
std::ostringstream s;
s << file << ":" << line <<": Entity "<< name
<<" is being closed but was not opened.\n";
list_.push_back(s.str());
}
void class_error_container::add_second_parent_error(
const std::string & file,int line,const std::string & first,
const std::string & second){
std::ostringstream s;
s << file << ":" << line <<": Parent "<< first <<" is closed due to parent"
<< second << "is opened here. \n";
list_.push_back(s.str());
}
void class_error_container::add_orphan_error(const std::string & file,int line,
const std::string & name){
std::ostringstream s;
s << file << ":" << line <<": Tag "<< name <<" has no parent \n";
list_.push_back(s.str());
}
void class_error_container::wrong_type_error(const std::string & file,int line,
const std::string & name,
const std::string & value){
std::ostringstream s;
s << file << ":" << line <<": Type "<< name <<" has wrong value:"<<
value <<". Cannot create a regex\n";
list_.push_back(s.str());
}
void class_error_container::add_type_error(const std::string &file,int line,
const std::string &type){
types_[type].push_back(error_cache_element(file,line,type));
}
void class_error_container::remove_type_errors(const std::string &type){
types_.erase(type);
}
void class_error_container::overriding_type_error(const std::string &file,
int line,
const std::string &type){
std::ostringstream s;
s << file << ":" << line <<": Type "<< type <<" is overriding here \n";
list_.push_back(s.str());
}
void class_error_container::add_link_error(const std::string &file,int line,
const std::string &link){
links_[link].push_back(error_cache_element(file,line,link));
}
void class_error_container::remove_link_errors(const std::string &link){
links_.erase(link);
}
void class_error_container::print_errors(std::ostream & s) const{
for (std::vector<std::string>::const_iterator i = list_.begin();
i!= list_.end(); ++i){
s << *(i);
}
error_cache_map::const_iterator i = types_.begin() ;
for ( ; i != types_.end(); ++i){
for (std::vector<error_cache_element>::const_iterator ii=
i->second.begin(); ii != i->second.end();++ii){
s << ii->file << ":" << ii->line <<": Unknown type: "
<< ii->name <<"\n";
}
}
for (i = links_.begin() ; i != links_.end(); ++i){
for (std::vector<error_cache_element>::const_iterator ii =
i->second.begin(); ii != i->second.end();++ii){
s << ii->file << ":" << ii->line <<": Failed link: "
<< ii->name <<"\n";
}
}
}
}

View file

@ -1,181 +0,0 @@
/*
Copyright (C) 2011 - 2016 by Sytyi Nick <nsytyi@gmail.com>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file
* This file contains object "error_container", which are used to store error
* messages while annotation parsing.
* Also the another part of his job is to create GCC:styled error messages.
*/
#ifndef TOOLS_ERROR_CONTAINER_HPP_INCLUDED
#define TOOLS_ERROR_CONTAINER_HPP_INCLUDED
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>
namespace schema_validation{
/**
* Container of errors, which are generated while schema generator tool
* is parsing source files.
* These errors are collected here, to be print on screen after parsing.
*/
class class_error_container{
public:
class_error_container()
: list_(),types_(),links_()
{
}
/**
*Puts simple error message in container
* @param message Message to print.
*/
void add_simple_error(const std::string & message);
/**
* Generate and put GCC-style error message about error read file error
* @param file Filename
* @param line Number of line with error
*/
void add_read_error(const std::string & file,int line);
/**
* Generate and put GCC-style error message about annotation block
* somebody missed to close
* @param file Filename
* @param line Number of line with error
* @param name Name of open block
*/
void add_opened_entity_error(const std::string & file,int line,
const std::string & name);
/**
* Generate and put GCC-style error message about closing block
* that wasn't opened
* @param file Filename
* @param line Number of line with error
* @param name of block
*/
void add_unopened_entity_error(const std::string & file,int line,
const std::string & name);
/**
* Generate and put GCC-style error message about opening parent block
* before before closing previous block
* @param file Filename
* @param line Number with error
* @param first Name of open parent
* @param second Name of parent is opening
*/
void add_second_parent_error(
const std::string & file,int line, const std::string & first,
const std::string & second);
/**
* Generate and put GCC-style error message about tag without parent
* @param file Filename
* @param line Number with error
* @param name Name of tag
*/
void add_orphan_error(const std::string & file,int line,
const std::string & name);
/**
* Generate and put GCC-style error message about wrong type value
* @param file Filename
* @param line Number with error
* @param name Name of type
* @param value Name of value
*/
void wrong_type_error(const std::string & file,int line,
const std::string & name,const std::string & value);
/**
* Generate and put GCC-style error message about unknown type to type cache
* @param file Filename
* @param line Number with error
* @param type Name of type
*/
void add_type_error(const std::string & file,int line,
const std::string & type);
/**
* Clears type cache
* @param type Name of type
*/
void remove_type_errors(const std::string & type);
/**
* Generate and put GCC-style error message about overriding type
* Overriding means that that type was defined somewhere else,
* and it's old value is lost.
* @param file Filename
* @param line Number of line with error
* @param type Name of type
*/
void overriding_type_error(const std::string & file,int line,
const std::string & type);
/**
* Generate and put GCC-style error message about failed link to link cache
* @param file Filename
* @param line Number of line with error
* @param link Name of link
*/
void add_link_error(const std::string & file,int line,
const std::string & link);
/**
* Clears link cache
* @param link Name of link
*/
void remove_link_errors(const std::string & link);
/**
* Prints errors to output stream
* @param s Output
*/
void print_errors(std::ostream & s) const;
/** Checks, if container is empty.*/
bool is_empty() const {
return list_.empty() && types_.empty() && links_.empty();
}
private:
/** Container to store error messages.*/
std::vector<std::string> list_;
/**
* Container to cache type errors.
* Types are checked while keys are read.
* There is a possibility to have unknown type error just because file with
* it desription haven't been parsed yet.
* So every type warning adds to cache.
* When sourseparser finds new type, it clears that warning list
*/
struct error_cache_element{
std::string file;
int line;
std::string name;
error_cache_element(const std::string &f,int l,const std::string &n):
file(f),line(l),name(n){}
};
typedef std::map<std::string,
std::vector<error_cache_element> > error_cache_map;
error_cache_map types_;
error_cache_map links_;
};
}//namespace schema_generator
#endif // TOOLS_ERROR_CONTAINER_HPP_INCLUDED

View file

@ -1,188 +0,0 @@
/*
Copyright (C) 2011 - 2016 by Sytyi Nick <nsytyi@gmail.com>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file
* This file parses the input parameters, prepares a list of files to be parsed
* and calls parser for each of them.
*
*/
#include "tools/schema/sourceparser.hpp"
#include "filesystem.hpp"
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
std::string version = "0.6.0";
using namespace schema_validation;
/**
* Parses the command line.
* @retval 0 Everything's OK!
* @retval 1 Errors found. User decided to exit.
* @retval 2 No input files found. Please, check your input directory.
* @retval 3 Output file for schema cannot be created.
* @retval 4 Output file for regex list cannot be created.
*/
int main(int argc, char *argv[]){
std::string input_dir = "";
std::string output_file = "./data/gui/schema.cfg";
std::string regex_file = "./utils/regex_list.txt";
bool expand = false;
for (int arg = 1; arg != argc; ++arg) {
const std::string val(argv[arg]);
if (val.empty()) {
continue;
}
else if ((val == "--src-dir" || val == "-s") && arg+1 != argc) {
input_dir = argv[++arg];
}
else if ((val == "--output" || val == "-o") && arg+1 != argc) {
output_file = argv[++arg];
}
else if ((val == "--regex" || val == "-r") ) {
if (arg+1 != argc){
regex_file = argv[++arg];
}
std::fstream f;
f.open(regex_file.c_str(),std::ios::out|std::ios::trunc);
if (f.fail()){
return 4;
}
test_regex(f);
f.close();
return 0;
}
else if (val == "--help" || val == "-h") {
std::cout << "usage: " << argv[0]
<< " [-erhV] [-s <input_dir>] [-o <output_file>]\n"
<< " -r, --regex <regex_file>\t"
<< "List of used regexes.\n"
<< " -e, --expand \t"
<< "Expands all tags due to their super-tags."
<< "Useful to debug schema markup.\n"
<< " -h, --help\t\t\t"
<< "Shows this usage message.\n"
<< " -s, --src-dir <input_dir>\t"
<<"Select the input directory.\n"
<< " -o, --output <output_file>\t"
<<"Select the output file.\n"
<< " -V, --version\t\t\t"
<< "Version of tool\n";
return 0;
} else if (val == "--version" || val == "-V") {
std::cout << "Battle for Wesnoth schema generator tool, version "
<< version << "\n";
return 0;
} else if (val == "--expand" || val == "-e") {
expand = true;
}
}
if(input_dir.empty()){
std::cout << "No input was selected. Processing \"./src\"\n";
input_dir = "./src";
}
if (! filesystem::file_exists(input_dir)){
return 2;
}
std::vector<std::string> files;
std::vector<std::string> dirs;
if (filesystem::is_directory(input_dir)){
filesystem::get_files_in_dir(input_dir, &files, &dirs, filesystem::ENTIRE_FILE_PATH);
if (files.empty() && dirs.empty()){
std::cout << "Some problem with input directory "
<< input_dir << "\n"
<< "No files found\n";
return 2;
}
/** Getting full list of files recursively.*/
while (!dirs.empty()){
std::string temp_dir = dirs.back();
dirs.pop_back();
filesystem::get_files_in_dir(temp_dir, &files, &dirs, filesystem::ENTIRE_FILE_PATH);
}
}else{
files.push_back(input_dir);
}
class_source_parser parser;
parser.set_output(output_file);
std::vector<std::string>::iterator i = files.begin();
unsigned int counter = 0;
for (;i != files.end(); ++i){
bool ok = false;
if (filesystem::base_name((*i)).find(".cpp")!=std::string::npos){
ok = true;
} else
if (filesystem::base_name((*i)).find(".hpp")!=std::string::npos){
ok = true;
} else
if (filesystem::base_name((*i)).find(".schema")!=std::string::npos){
ok = true;
}
if (ok){
++counter;
parser.set_input((*i));
parser.parse_source();
}
}
std::cout << "Processed " << counter << " files in " << input_dir << "\n";
// check errors
if (! parser.see_errors().is_empty()) {
/**
* Let the user decide whether error are great or just misprints.
* If any error found, waits for a Yy or Nn to continue or not.
*/
std::cout << "There are some errors\n";
parser.see_errors().print_errors(std::cout);
// Take user response
char c;
std::cout << "Continue with errors? Y/N ";
while (true) {
std::cin.get(c);
const char *r = strchr("yYnN",c);
if (r == nullptr){
std::cout << "Please, choose your answer " << std::endl;
continue;
}
if (c == 'n' || c=='N'){
std::cout << "I'll take that as a NO" << std::endl;
return 1;
}
if (c == 'y' || c=='Y'){
std::cout << "I'll take that as a Yes" << std::endl;
break;
}
}
}
if (expand) {
parser.expand();
}
// save schema information
if ( ! parser.save_schema()){
return 4;
}
std::cout << "Schema written to "<< output_file << "\n";
return 0;
}

View file

@ -1,620 +0,0 @@
/*
Copyright (C) 2011 - 2016 by Sytyi Nick <nsytyi@gmail.com>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file
* This file contains implementation of sourceparser.cpp.
*/
#include "tools/schema/sourceparser.hpp"
#include <boost/regex.hpp>
#include <stack>
namespace schema_validation{
/** Little parts of regex templates used to parse Wml annoations.
*For details, look http://wiki.wesnoth.org/WML_Annotation_Format , please
*/
/** line is valid*/
const std::string valid = R"""(^\s*\*\s*)""";
/** begining of wiki block*/
const std::string wiki_begin = R"""(^\s*/\*(?:WIKI|SCHEMA))""";
/** whitespace is possible*/
const std::string space ="\\s*";
/** sigh "="*/
const std::string equals ="=";
/** non-mandatory sign "*/
const std::string quote_symbol ="\"?";
/** begining of the block.*/
const std::string block_begin="@begin" ;
/** end of block*/
const std::string block_end ="@end";
/** allow directive*/
const std::string allow="@allow";
/** remove directive*/
const std::string remove="@remove";
/** sign "{" - curly bracket*/
const std::string property_open="\\{";
/** sign "}" - another curly bracket*/
const std::string property_close= "\\}";
/** type of possible name identificator*/
const std::string name_type= "[a-z][a-zA-Z0-9_-]*" ;
/** type of possible parent indentificator*/
const std::string parent_type= "/|(?:[a-z][a-zA-Z0-9_-]*/)+";
/** type of possible link indentificator*/
const std::string link_type="(?:[a-z][a-zA-Z0-9_-]*/)*(?:[a-z][a-zA-Z0-9_-]*)";
/** template to number regex*/
const std::string number="\\d*";
/** sign "-" - hyphen-minus used to set sign of signed integer*/
const std::string sign="-?";
/**
* end of line + possible various character before.
* Used to close template. ".*" is used cause I dont want to get error
* every misprint whitespace
* after annotation element
*/
const std::string eol=".*$";
/** Private function to surround an argument with brackets.
* This allows substitutions :-)
*/
static std::string sub (const std::string & s){
return "(" + s + ")";
}
/** Private function to surround argument with not mandatory quotes.
* Is used when creating properties
*/
static std::string quote(const std::string & s){
return quote_symbol + s + quote_symbol ;
}
/**
* Creates a property template
* @param name Name of property
* @param value Type of property value
* If value is empty creates simple property like {table}
* Else creates a named property like {name="[name_type_template]"}
*/
static std::string property(const std::string & name,
const std::string & value = ""){
if (value.empty()){
return property_open + name + property_close;
}
return property_open + name + equals + quote(value) + property_close;
}
const std::string & get_valid() {
return valid;
}
const std::string & get_wiki() {
static std::string wiki = wiki_begin + eol;
return wiki;
}
const std::string & get_parent_begin() {
static std::string parent_begin = valid + block_begin
+ property("parent")
+ property("name",sub(parent_type))
+ eol;
return parent_begin;
}
const std::string & get_parent_end() {
static std::string parent_end = valid + block_end + property("parent")
+ property("name",sub(parent_type))+ eol;
return parent_end;
}
const std::string & get_tag_begin() {
static std::string tag_begin = valid + block_begin + property("tag")
+ property("name",sub(name_type))
+ property("min",sub(number))
+ property("max",sub(sign + number))
+ sub(property("super",sub(link_type)))
+"?" + eol;
/* sub(property("super"),sub(link_type))+"?"
* property super is not mandatory
*/
return tag_begin;
}
const std::string & get_tag_end() {
static std::string tag_end = valid + block_end + property("tag")
+ property("name",sub(name_type)) + eol;
return tag_end;
}
const std::string & get_allow_link(){
static std::string allow_link = valid + allow + property("link")
+property("name",sub(link_type)) + eol;
return allow_link;
}
const std::string & get_allow_global(){
static std::string global_link = valid + allow + property("global")
+property("name",sub(name_type)) + eol;
return global_link;
}
static const std::string & get_allow_type(){
static std::string allow_type = valid + allow + property("type")
+property("name",sub(name_type))
+property("value",sub("\\^.+\\$"))
+ eol;
return allow_type;
}
static const std::string & get_remove_type(){
static std::string remove_type = valid + remove + property("type")
+property("name",sub(name_type))
+ eol;
return remove_type;
}
static const std::string & get_remove_key(){
static std::string remove_key = valid + remove + property("key")
+property("name",sub(name_type))
+ eol;
return remove_key;
}
const std::string & get_table_key_begin() {
static std::string keys_begin = valid + block_begin + property("table")
+ property("config")+ eol;
return keys_begin;
}
const std::string & get_table_end() {
static std::string table_end = valid + block_end + property("table")
+ eol;
return table_end;
}
const std::string & get_key_value(){
static std::string key_value = valid + sub("[a-zA-z][a-zA-Z\\d_+-]*")
+ "\\s*&\\s*"+sub(name_type)
+"\\s*&\\s?"+ sub(quote("[a-zA-Z._0-9+-]*"))
+"\\s&"+ eol;
return key_value;
}
void test_regex( std::ostream & f ){
f << get_valid() << "\n"
<< get_wiki() << "\n"
<< get_parent_begin() << "\n"
<< get_parent_end() << "\n"
<< get_tag_begin() << "\n"
<< get_tag_end() << "\n"
<< get_allow_link() << "\n"
<< get_allow_global() << "\n"
<< get_table_key_begin() << "\n"
<< get_table_end() << "\n"
<< get_key_value() << "\n"
<< get_allow_type() << "\n"
<< std::endl;
}
bool class_source_parser::save_schema(){
std::fstream out;
if (output_.empty()){
return false;
}
out.open(output_.c_str(),std::ios::out|std::ios::trunc);
if (out.fail()){
errors_.add_simple_error("Cannot open file "+output_+
"\n Output would not be stored\n");
return false;
}
// remove all forbidden keys
for (std::vector<std::string>::const_iterator i= forbidden_.begin ();
i != forbidden_.end (); ++i){
root_.remove_keys_by_type (*i);
types_.erase (*i);
}
out << "[wml_schema]\n";
for (std::map<std::string,std::string>::iterator i=types_.begin();
i!= types_.end();++i){
out << " [type]\n"
<< " name=" << i->first << "\n"
<< " value=\""<< i->second << "\"\n"
<<" [/type]\n";
}
root_.print(out);
out << "[/wml_schema]\n";
out.close();
return true; // @TODO add error support
}
bool class_source_parser::getline(std::string &s){
if (f_.fail()){
errors_.add_read_error(input_,line_);
return false;
}
std::getline(f_,s);
line_ ++;
if (! f_.eof()){
if (f_.fail()){
errors_.add_read_error(input_,line_);
return false;
}
}
return true;
}
// call without arg when you want to closethem all
void class_source_parser::add_open_tag_error(int i = INT_MAX){
std::vector<class_tag>::iterator it;
for (it = current_.begin(); it != current_.end() && i > 0; ++it){
errors_.add_opened_entity_error(input_,line_,it->get_name());
--i;
}
}
// call without arg when you want to closethem all
void class_source_parser::close_opened_tags(int i = INT_MAX){
if (current_.empty()){
return;
}
std::stack<std::string> error_cache ;
while (current_.size() > 1){
if (i==0){
break;
}
class_tag tag (current_.back());
current_.pop_back();
current_.back().add_tag(tag);
error_cache.push(tag.get_name());
i--;
}
if (i!=0){
//adding to parent
if (parent_name_.empty()) {
orphan_tags_.push_back(current_.back());
errors_.add_orphan_error(input_,line_,current_.back().get_name());
}else{
error_cache.push(current_.back().get_name());
root_.add_tag(parent_name_,current_.back(),root_);
}
current_.pop_back();
}
std::string name_to_remove_from_cache = parent_name_;
for (std::vector<class_tag>::const_iterator ii = current_.begin();
ii!= current_.end();++ii){
name_to_remove_from_cache += ii->get_name() + "/";
}
while (! error_cache.empty()){
name_to_remove_from_cache += error_cache.top();
errors_.remove_link_errors(name_to_remove_from_cache);
error_cache.pop();
name_to_remove_from_cache += "/";
}
}
bool class_source_parser::parse_source(){
if (input_.empty()){
errors_.add_simple_error("File was not defined\n");
// Use to hack sorting errors.
// Item with will be at the end of error list.
return false;
}
f_.open(input_.c_str(),std::ios::in);
if (f_.fail()){
errors_.add_simple_error("File "+input_ + " cannot be opened\n");
return false;
}
line_ = 0;
bool result = true;
while (!f_.eof()){
std::string line;
if (! getline(line) ) {
f_.close();
f_.clear();
close_opened_tags();
parent_name_.clear();
return false;
} // is used to avoid exceptions.
if (check_wiki(line)) {
result = parse_block();
if (! result) {
break;
}
}
}
f_.close();
// Clear all flags ( eg the eof flag ) after closing the file.
// This will let us reuse the same fstream variable for different files.
f_.clear();
close_opened_tags();
parent_name_.clear();
return result;
}
bool class_source_parser::parse_block(){
while (!f_.eof()){
std::string line;
if (! getline(line) ) { return false; }
if ( check_valid(line)) {
if (check_allow_type(line)) continue;
if (check_remove_type(line)) continue;
if (check_parent_begin(line)) continue;
if (check_tag_begin(line)){
parse_tag();
continue;
}
check_parent_end(line);
}
else{
// wiki-block is closed. checking stack of opened tags
if (!current_.empty()){
add_open_tag_error();
close_opened_tags();
// continue working
}
// block is closed and all tags are closed.
return true;
}
}// end while
return false;
}
bool class_source_parser::parse_tag(){
while (!f_.eof()){
std::string line;
if (! getline(line) ) { return false; }
if (check_valid(line)) {
if (check_tag_begin(line)){
parse_tag();
}
if (check_tag_end(line)){
return true;
}
if (check_keys_begin(line)){
parse_keys();
}
if (check_allow_link(line)){
continue;
}
if (check_allow_global(line)){
continue;
}
if (check_remove_key(line)){
}
}else{
if (!current_.empty()){
// adding error messages for each unclosed entity
add_open_tag_error();
close_opened_tags();
}
return true;
}
}
return true;
}
bool class_source_parser::parse_keys(){
std::string line;
do{
if (! getline(line) ) { return false; }
if (! check_valid(line)) {
errors_.add_opened_entity_error(input_,line_,"Table config");
add_open_tag_error();
close_opened_tags();
return false;
}
static const boost::regex value (get_key_value() );
boost::smatch sub;
bool res = boost::regex_match(line,sub,value);
if (res){
std::string type = sub[2];
class_key key (sub[1],type,sub[3]);
current_.back().add_key(key);
if (types_.find(type) == types_.end()){
errors_.add_type_error(input_,line_,type);
}
}
}while (! check_keys_end(line));
return true;
}
bool class_source_parser::check_valid(const std::string &s){
// s must be like " *" or "*"
static const boost::regex valid (get_valid());
return boost::regex_search(s,valid);
}
bool class_source_parser::check_wiki(const std::string& s){
boost::regex wiki (get_wiki());
return boost::regex_match(s,wiki);
}
bool class_source_parser::check_tag_begin(const std::string &s){
// read tag;
static boost::regex tag (get_tag_begin());
boost::smatch sub;
bool res = boost::regex_match(s,sub,tag);
if (res){
std::string link = sub[5];
class_tag new_tag;
new_tag.set_name(sub[1]);
new_tag.set_min(sub[2]);
new_tag.set_max(sub[3]);
new_tag.set_super(link);
current_.push_back(new_tag);
if (! link.empty() &&
! static_cast<const class_tag>(root_).find_tag(link,root_)){
errors_.add_link_error(input_,line_,link);
}
return true;
}
return false;
}
bool class_source_parser::check_tag_end(const std::string &s){
static const boost::regex endtag (get_tag_end());
boost::smatch sub;
bool res = boost::regex_match(s,sub,endtag);
if (res){
std::string name = sub[1];
if (current_.empty()){
errors_.add_unopened_entity_error(input_,line_,name);
return false;
}
std::vector<class_tag>::iterator ii = current_.end();
int count_opened = 0;
do{
--ii;
if (ii->get_name() == name){
add_open_tag_error(count_opened);
close_opened_tags(++count_opened);
return true;
}else{
count_opened ++;
}
}while (ii != current_.begin()) ;
}
return false;
}
bool class_source_parser::check_allow_link(const std::string &s){
static const boost::regex allow_link (get_allow_link());
boost::smatch sub;
bool res = boost::regex_match(s,sub,allow_link);
if (res){
if (!current_.empty()){
std::string link = sub[1];
current_.back().add_link(link);
if (static_cast<const class_tag>(root_).find_tag(link,root_) == nullptr){
errors_.add_link_error(input_,line_,link);
}
}
}
return res;
}
bool class_source_parser::check_allow_global(const std::string &s){
static const boost::regex allow_global (get_allow_global());
boost::smatch sub;
bool res = boost::regex_match(s,sub,allow_global);
if (res){
if (!current_.empty()){
current_.back().add_link("global/"+sub[1]);
}
}
return res;
}
bool class_source_parser::check_parent_begin(const std::string &s){
static const boost::regex parent (get_parent_begin());
boost::smatch sub;
bool res = boost::regex_match(s,sub,parent);
if (res){
std::string name = sub[1];
if (!parent_name_.empty()) {
errors_.add_second_parent_error(input_,line_,parent_name_,name);
}
parent_name_ = name;
}
return res;
}
bool class_source_parser::check_parent_end(const std::string &s){
static const boost::regex parent (get_parent_end());
boost::smatch sub;
bool res = boost::regex_match(s,sub,parent);
if (res){
std::string name = sub[1];
if (parent_name_ == name) {
parent_name_.clear();
}else{
errors_.add_unopened_entity_error(input_,line_,name);
}
}
return true;
}
bool class_source_parser::check_keys_begin(const std::string &s){
static const boost::regex keys (get_table_key_begin());
return boost::regex_match(s,keys);
}
bool class_source_parser::check_keys_end(const std::string &s){
static const boost::regex endkeys (get_table_end());
bool res = boost::regex_match(s,endkeys);
return res;
}
bool class_source_parser::check_allow_type(const std::string &s){
static const boost::regex allow_type (get_allow_type());
boost::smatch sub;
bool res = boost::regex_match(s,sub,allow_type);
if (res){
std::string name = sub[1];
std::string value = sub[2];
try{
boost::regex tmp (value);
}catch(std::exception ){
errors_.wrong_type_error(input_,line_,name,value);
return true;
}
if(types_.find(name)!=types_.end()){
errors_.overriding_type_error(input_,line_,name);
}
types_[name]=value;
errors_.remove_type_errors(name);
}
return res;
}
bool class_source_parser::check_remove_type(const std::string &s){
static const boost::regex remove_type (get_remove_type());
boost::smatch sub;
bool res = boost::regex_match(s,sub,remove_type);
if (res){
std::string name = sub[1];
types_[name]="";
forbidden_.push_back (name);
errors_.remove_type_errors (name);
}
return res;
}
bool class_source_parser::check_remove_key(const std::string &s){
static const boost::regex remove_key (get_remove_key());
boost::smatch sub;
bool res = boost::regex_match(s,sub,remove_key);
if (res){
if (! current_.empty ()){
current_.back ().remove_key_by_name(sub[1]);
}
}
return res;
}
} // namespace schema_generator

View file

@ -1,222 +0,0 @@
/*
Copyright (C) 2011 - 2016 by Sytyi Nick <nsytyi@gmail.com>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file
* This file contains sourceparser object, collecting annotations
* and building a tag tree.
* Also here are declared fuctions that return regex templates.
* And a fuction to create a file with list of templates.
*/
#ifndef TOOLS_SCHEMA_SOURCEPARSER_HPP_INCLUDED
#define TOOLS_SCHEMA_SOURCEPARSER_HPP_INCLUDED
#include "tools/schema/error_container.hpp"
#include "tools/schema/tag.hpp"
#include <iostream>
#include <fstream>
#include <map>
#include <queue>
#include <string>
#include <vector>
namespace schema_validation{
/** A few regex templates. Please notice, that adding any regex template,
* schould be called in test_regexes()
*/
/** Template to check line of beeing valid*/
const std::string & get_valid();
/** Template to check line is beginnnig of Wiki block*/
const std::string & get_wiki();
/** Template to check begining of parent block*/
const std::string & get_parent_begin() ;
/** Template to check closing of parent block*/
const std::string & get_parent_end() ;
/** Template to check if line contains opening of tag block*/
const std::string & get_tag_begin() ;
/** Template to check end of tag block*/
const std::string & get_tag_end() ;
/** Template to check allow{link} block*/
const std::string & get_allow_link();
/** Template to check allow{global} block*/
const std::string & get_allow_global();
/** Template to check begining of table{config} storing key values*/
const std::string & get_table_key_begin() ;
/** Template to check if table is closed*/
const std::string & get_table_end() ;
/** Template to get key value*/
const std::string & get_key_value();
/** Writes to the file regex templates list.*/
void test_regex(std::ostream & f );
class class_source_parser{
public:
class_source_parser():
input_ (""),
output_(""),
f_(),
line_(0),
current_(),
root_(class_tag("root",1,1)),
parent_name_(""),
orphan_tags_(),
errors_(),
types_(),
forbidden_()
{
}
~class_source_parser(){
}
void set_input(const std::string &s){
input_ = s;
}
void set_output(const std::string &s){
output_ = s;
}
/**
* Parses file line-by-line, checking every line to open WIKI block
* Please, notice that main input work is made in check_*** methods.
* Methods parse_*** are used to organize alhoritm and set which
* regex template can be used in this context.
* The only exception is parse_keys, where table of keys is read
* and add to top of stack tags.
*/
bool parse_source();
/**
* Saves tag tree to schema file.
*/
bool save_schema();
/**
* Expands all tags.
* While expanding tag copies list of keys and links from super-tag
* And adds links to super-tag children to links list.
* Useful when debugging the schema_markup
*/
void expand(){
root_.expand_all(root_);
}
const std::vector<class_tag> & see_orphans() const{
return orphan_tags_;
}
/** Grants access to error container*/
const class_error_container & see_errors() const{
return errors_;
}
private:
/** name of input file to be parsed*/
std::string input_;
/** name of output file to print schema*/
std::string output_;
std::fstream f_;
//current line number
/** number of current read line. Is used when generating errors*/
int line_;
//vector-based stack. The element on top is current opened tag.
/** Stack of opened tags.*/
std::vector<class_tag> current_;
/** Root of the schema tree*/
class_tag root_;
/** Name of current parent*/
std::string parent_name_;
/** List of tags without parents.*/
std::vector<class_tag> orphan_tags_;
/** used to store errors*/
class_error_container errors_;
/** Allowed types*/
std::map<std::string,std::string> types_;
/** Types to remove*/
std::vector<std::string> forbidden_;
/**
* Parses WIKI block line-by-line, checking every line
* to open annotation block
*/
bool parse_block();
/**
* Parses lines inside tag block.
* Calls checkers that are allowed in tag block
*/
bool parse_tag();
/**
* Read key table and add keys to tag on the top of the stack.
*/
bool parse_keys();
/** check the input line with a template
* check if the line is valid (still in block)
*/
bool check_valid(const std::string& s);
/**
* Gets a line from file and returns it.
* Is used to manage exceptions while IO.
*/
bool getline(std::string & s);
/**
* Сhecks stack of opened tags. If any tags is opened - closes it
*and adds to sublist of next tag in stack.
* Add last tag in stack to parent
* @param i number of tags in stack to close.
*/
void close_opened_tags(int i);
/** Generates errors for each opened tag.
* @param i number of tags in stack to complain.
*/
void add_open_tag_error(int i);
/**
* Read tag form the line and add it to stack
*/
bool check_wiki(const std::string& s);
/** Checks line for tag annotation. Reads tag and puts in into stack.*/
bool check_tag_begin(const std::string& s);
/**
* Puts closed tag to child list of previous tag.
* Also closes all opened child tags, if they are, and generates warnings.
*/
bool check_tag_end(const std::string& s);
/** Opens parrent block*/
bool check_parent_begin(const std::string& s);
/** Closes parent block*/
bool check_parent_end(const std::string& s);
/** Checks beginning of keys*/
bool check_keys_begin(const std::string&s);
/** Checks end of keys*/
bool check_keys_end(const std::string&s);
/** Checks links*/
bool check_allow_link(const std::string & s);
/** Checks allowed global tags*/
bool check_allow_global(const std::string &s);
/** Checks allowed types*/
bool check_allow_type(const std::string &s);
/** Checks removed types*/
bool check_remove_type(const std::string &s);
/** Checks removed keys*/
bool check_remove_key(const std::string &s);
};
} // namespace schema_validation
#endif // TOOLS_SCHEMA_SOURCEPARSER_HPP_INCLUDED

View file

@ -1,75 +0,0 @@
/*
Copyright (C) 2011 - 2016 by Sytyi Nick <nsytyi@gmail.com>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "serialization/schema_validator.hpp"
std::string version = "0.2.0";
#include <iostream>
#include "filesystem.hpp"
#include "serialization/parser.hpp"
#include "serialization/preprocessor.hpp"
#include "config.hpp"
#include "config_cache.hpp"
using namespace schema_validation;
int main(int argc, char *argv[]){
std::string default_schema ("data/gui/schema.cfg");
std::string input ;
for (int arg = 1; arg != argc; ++arg) {
const std::string val(argv[arg]);
if (val.empty()) {
continue;
}
else if ((val == "--schema" || val == "-s") && arg+1 != argc) {
default_schema = argv[++arg];
}
else if ((val == "--input" || val == "-i") && arg+1 != argc) {
input = argv[++arg];
}
else if (val == "--help" || val == "-h") {
std::cout << "usage: " << argv[0]
<< " [-hV] [-i <input_file>] [-s <schema_file>]\n"
<< " -h, --help\t\t\t"
<< "Shows this usage message.\n"
<< " -s, --schema <schema_file>\t"
<<"Select the file with schema information.\n"
<< " -i, --input <input_file>\t"
<<"Select the config file.\n"
<< " -V, --version\t\t\t"
<< "Version of tool\n";
return 0;
} else if (val == "--version" || val == "-V") {
std::cout << "Battle for Wesnoth schema validator tool, version "
<< version << "\n";
return 0;
}
}
schema_validator validator (default_schema);
if (input.empty()) input = "./data/gui/default.cfg";
std::cout << "Processing "<< input <<"\n";
config cfg;
try {
preproc_map preproc(
game_config::config_cache::instance().get_preproc_map());
filesystem::scoped_istream stream = preprocess_file(input,
&preproc);
read(cfg, *stream, &validator);
} catch(config::error & t) {
std::cout << t.message;
return 1;
}
return 0;
}

View file

@ -1,20 +0,0 @@
/*
Copyright (C) 2012 - 2016 by Mark de Wever <koraq@xs4all.nl>
Part of the Battle for Wesnoth Project http://www.wesnoth.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "wesmage/exit.hpp"
exiter::exiter(const int status__)
: status(status__)
{
}

View file

@ -1,38 +0,0 @@
/*
Copyright (C) 2012 - 2016 by Mark de Wever <koraq@xs4all.nl>
Part of the Battle for Wesnoth Project http://www.wesnoth.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file
* Exit exception.
*/
#ifndef WESMAGE_EXIT_HPP_INCLUDED
#define WESMAGE_EXIT_HPP_INCLUDED
/**
* This exception when throw should terminate the application.
*
* The application should terminate with @ref exiter::status as its exit
* status.
*/
struct exiter
{
exiter(const int status__);
/** The exit status for the application. */
int status;
};
#endif

View file

@ -1,247 +0,0 @@
/*
Copyright (C) 2012 - 2016 by Mark de Wever <koraq@xs4all.nl>
Part of the Battle for Wesnoth Project http://www.wesnoth.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "wesmage/filter.hpp"
#include "serialization/string_utils.hpp"
#include "wesmage/exit.hpp"
#include "utils/functional.hpp"
#include <iostream>
#include <cassert>
/** Contains the definition of a filter. */
struct filter
{
/**
* The functor to call for the filter.
*
* @p surf The surface to apply the filter to.
* @p parameters A string with the parameters for the
* functor. The code is expected to be
* supplied on the command line. So it should
* be validated.
*/
typedef std::function<void(
surface& surf
, const std::string& parameters
)>
functor_t;
filter(
const std::string& name__
, const std::string& description__
, const functor_t& functor__)
: name(name__)
, description(description__)
, functor(functor__)
{
}
/**
* The name of the filter.
*
* This value must be unique.
*/
std::string name;
/**
* Description of the filter.
*
* The exact format of the string is documented at @ref filter_list.
*/
filter_description description;
/** The functor to call for the filter. */
functor_t functor;
};
/**
* The list of the available filters.
*
* The map contains:
* * @p first The name of the filter.
* * @p second The filter itself.
*/
static std::map<std::string, filter> filters;
/** Helper structure to register a filter to the @ref filters. */
struct register_filter
{
register_filter(const std::pair<std::string, filter>& filter)
{
filters.insert(filter);
}
};
/**
* Register macro for a filter.
*
* @param name The name of the filter.
* @param description A pipe-symbol separated list with the
* description. The name is automatically
* prefixed, so the item should start with a
* pipe-symbol. When the list is splitted in
* to a vector of string its contents should
* be compatible with the constructor of
* @ref filter_description.
*/
#define REGISTER(name, description) \
register_filter register_filter_##name(std::make_pair( \
#name \
, filter(#name, #name description, std::bind(name, _1, _2))));
static void
scale(surface& surf, const std::string& parameters)
{
unsigned width, height;
const int count = sscanf(parameters.c_str(), "%u,%u", &width, &height);
if(count != 2) {
std::cerr << "Error: Arguments to scale »"
<< parameters
<< "« are not compatible.\n";
throw exiter(EXIT_FAILURE);
}
surf = scale_surface(surf, width, height);
}
REGISTER(scale,
"|Scales the size of an image."
"|new_width"
"|unsigned"
"|The width in pixel of the image after scaling."
"|new_height"
"|unsigned"
"|The height in pixel of the image after scaling.")
static void
brighten(surface& surf, const std::string& parameters)
{
float amount;
const int count = sscanf(parameters.c_str(), "%f", &amount);
if(count != 1) {
std::cerr << "Error: Arguments to brighten »"
<< parameters
<< "« are not compatible.\n";
throw exiter(EXIT_FAILURE);
}
surf = brighten_image(surf, amount);
}
REGISTER(brighten,
"|Brightens an image."
"|amount"
"|float"
"|The amount the image should be brightened. The value of the every "
"color channel is multiplied by this value. Value less than zero "
"are set to zero. The alpha channel is not modified.")
static void
blend(surface& surf, const std::string& parameters)
{
float amount;
unsigned color;
const int count = sscanf(parameters.c_str(), "%f,%x", &amount, &color);
if(count != 2) {
std::cerr << "Error: Arguments to blend »"
<< parameters
<< "« are not compatible.\n";
throw exiter(EXIT_FAILURE);
}
surf = blend_surface(surf, amount, color);
}
REGISTER(blend,
"|Blends an image with another color."
"|amount"
"|float"
"|The amount every pixel needs to be blended with its original value. "
"The formula is:\n"
"result = amount * color + (1 - amount) * original\n"
"The value needs to be in the range [0, 1]."
"|color"
"|unsigned"
"|The color to blend with. The value should be given as 32-bit "
"hexadecimal value. The first fields should look like AARRGGBB, "
"where AA is the alpha channel, RR is the red channel, GG is the "
"green channel and BB is the blue channel. (Note the alpha channel "
"is ignored.")
void
filter_apply(surface& surf, const std::string& filter_string)
{
std::vector<std::string> f = utils::split(filter_string, ':', utils::STRIP_SPACES);
if(f.size() != 2) {
std::cerr << "Error: Filter »"
<< filter_string
<< "« doesn't contain the expected separator »:«\n";
throw exiter(EXIT_FAILURE);
}
std::map<std::string, filter>::iterator itor = filters.find(f[0]);
if(itor == filters.end()) {
std::cerr << "Error: Filter »" << f[0] << "« is unknown.\n";
throw exiter(EXIT_FAILURE);
}
itor->second.functor(surf, f[1]);
}
filter_description::filter_description(const std::string& fmt)
: name()
, description()
, parameters()
{
std::vector<std::string> elements(utils::split(fmt, '|'));
/* Validate there is at least a header part. */
assert(elements.size() >= 2);
name = elements[0];
description = elements[1];
/* Validate every parameter indeed has three fields. */
assert((elements.size() - 2) % 3 == 0);
for(size_t i = 2; i < elements.size(); i += 3) {
filter_description::parameter parameter =
{
elements[i]
, elements[i + 1]
, elements[i + 2]
};
parameters.push_back(parameter);
}
}
std::vector<filter_description>
filter_list()
{
std::vector<filter_description> result;
for(const auto& filter : filters) {
result.push_back(filter.second.description);
}
return result;
}

View file

@ -1,92 +0,0 @@
/*
Copyright (C) 2012 - 2016 by Mark de Wever <koraq@xs4all.nl>
Part of the Battle for Wesnoth Project http://www.wesnoth.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file
* Filters for wesmage
*/
#ifndef WESMAGE_FILTER_HPP_INCLUDED
#define WESMAGE_FILTER_HPP_INCLUDED
#include "sdl/surface.hpp"
#include <string>
#include <vector>
void
filter_apply(surface& surf, const std::string& filter);
/**
* Helper structure to describe what a filter does.
*
* This structure should make it easier to create help messages.
*/
struct filter_description
{
/**
* Constructor.
*
* Creates an object from a specially formated string. The string
* contains of a number of fields seperated by a pipe-symbol. The number
* of fields should be 2 + 3 * params, where params is the number of
* parameters of the filter. The fields are:
* * 1 The @ref filter_description::name
* * 2 The @ref filter_description::description
* After these two fields there are three fields per parameter, the
* fields are:
* * 1 The @ref filter_description::parameter::name
* * 2 The @ref filter_description::parameter::type
* * 3 The @ref filter_description::parameter::description
*
* @param fmt The format string as described above.
*/
explicit filter_description(const std::string& fmt);
/**
* Name of the filter.
*
* This is the ID parameter given on the command line.
*/
std::string name;
/**
* Description of the filter.
*
* Shortly describes what the filter does.
*/
std::string description;
/** Describes a filter parameter. */
struct parameter
{
/** The name of the parameter. */
std::string name;
/** The C type of the parameter. */
std::string type;
/** Describes what the parameter does. */
std::string descripton;
};
/** The list of filter parameters. */
std::vector<parameter> parameters;
};
/** Returns the list of available filters. */
std::vector<filter_description>
filter_list();
#endif

View file

@ -1,269 +0,0 @@
/*
Copyright (C) 2012 - 2016 by Mark de Wever <koraq@xs4all.nl>
Part of the Battle for Wesnoth Project http://www.wesnoth.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "wesmage/options.hpp"
#include "wesmage/exit.hpp"
#include "wesmage/filter.hpp"
#include <cassert>
#include <cstdlib>
#include <ctime>
#include <iostream>
cmdline_options::cmdline_options()
: input_filename()
, output_filename()
, filters()
, time(false)
, count(1)
{
}
/*
* This function prints the option and its description in a nice fashion.
*
* * The description is indented at column tab_offset.
* * If the option text is short enough the description starts after it,
* properly indented. Else starts at the next line, again properly
* indented.
* * If the text of the description doesn't fit at a single line it split at
* space and continues on the next line, obviously indented again.
*/
static void
print_option(
std::ostream& stream
, const std::string& option
, std::string description)
{
const unsigned line_length = 80;
const unsigned tab_offset = 25;
const unsigned description_length = line_length - tab_offset;
const std::string tab_filler(tab_offset - 1, ' ');
assert(!option.empty());
assert(!description.empty());
stream << option;
if(option.length() < tab_offset - 1) {
stream << std::string(tab_offset - 1 - option.length(), ' ');
} else {
stream << '\n' << tab_filler;
}
while(!description.empty()) {
size_t eol = description.find('\n');
if(eol <= description_length) {
stream << description.substr(0, eol);
description.erase(0, eol + 1);
} else if(description.size() <= description_length) {
stream << description;
description.clear();
} else {
int offset = description_length + 1;
while(description[offset] != ' ' && offset >= 0) {
--offset;
}
assert(offset != 0);
assert(description[offset] == ' ');
stream << description.substr(0, offset);
description.erase(0, offset + 1);
}
stream << '\n';
if(!description.empty()) {
stream << tab_filler;
}
}
}
static std::ostream&
operator<<(
std::ostream& stream
, const filter_description& fd)
{
print_option(stream, fd.name, fd.description);
for(const filter_description::parameter& p : fd.parameters) {
print_option(
stream
, " * " + p.name + " (" + p.type + ")"
, p.descripton);
}
return stream;
}
static void
print_help(const int exit_status)
{
std::cout <<
"Usage wesmage [OPTION...] [FILE]\n"
"Helper program to test image manipulation algorithms.\n"
"\n"
"The FILE is the name of the input file to be converted.\n"
"OPTIONS:\n"
"-o, --output FILE The name of the output file to be written.\n"
"-n, --dry-run No output is written.\n"
"-t, --time Show the time it took to apply the filters.\n"
" The resolution of the time depends on the platform.\n"
"-c, --count COUNT The number of times the filter needs to be applied.\n"
" This feature is mainly for timing an algorithm and\n"
" is applied on a new image every iteration.\n"
"-f, --filter FILTER Filters to be applied to the image. See FILTERS.\n"
"-h, --help Show this help and terminate the program.\n"
"\n"
"FILTERS:\n"
"A filter applies a modification to an image. The program can handle\n"
"multiple filters. They are applied from the command line. The are applied\n"
"in the left to right order they appear on the command line.\n"
"A filter has the following syntax ID:PARAMETERS where:\n"
"ID The id of the filter.\n"
"PARAMETERS Zero or more parameters. Multiple parameters are\n"
" separated by a comma. The number parameters required\n"
" depend on the filter.\n"
"\n"
"The following filters are currently implemented:\n"
;
for(const filter_description& filter : filter_list()) {
std::cout << filter;
}
throw exiter(exit_status);
}
#define VALIDATE_NOT_PAST_END \
do { \
if(i >= argc) { \
std::cerr << "Error: Required argument for the option »" \
<< option \
<< "« is not supplied.\n"; \
\
throw exiter(EXIT_FAILURE); \
} \
} while(0)
const cmdline_options&
cmdline_options::parse(int argc, char* argv[])
{
cmdline_options& result = singleton(false);
bool help = false;
bool dry_run = false;
/* argv[0] is the name of the program, not a command-line argument. */
for(int i = 1; i < argc; ++i) {
const std::string option(argv[i]);
if(option == "-h" || option == "--help") {
help = true;
} else if(option == "-n" || option == "--dry-run") {
dry_run = true;
} else if(option == "-t" || option == "--time") {
result.time = true;
} else if(option == "-c" || option == "--count") {
++i;
VALIDATE_NOT_PAST_END;
char* end;
result.count = strtol(argv[i], &end, 10);
if(*end || result.count <= 0) {
std::cerr << "Error: Parameter of count »"
<< argv[i]
<< "« should be a positive number.\n";
print_help(EXIT_FAILURE);
}
} else if(option.substr(0, 2) == "-c") {
char* end;
result.count = strtol(option.substr(2).c_str(), &end, 10);
if(*end || result.count <= 0) {
std::cerr << "Error: Parameter of count »"
<< option.substr(2).c_str()
<< "« should be a positive number.\n";
print_help(EXIT_FAILURE);
}
} else if(option == "-o" || option == "--output") {
++i;
VALIDATE_NOT_PAST_END;
result.output_filename = argv[i];
} else if(option.substr(0, 2) == "-o") {
result.output_filename = option.substr(2);
} else if(option == "-f" || option == "--filter") {
++i;
VALIDATE_NOT_PAST_END;
result.filters.push_back(argv[i]);
} else if(option.substr(0, 2) == "-f") {
result.filters.push_back(option.substr(2));
} else {
if(!result.input_filename.empty()) {
std::cerr << "Error: Command line argument »"
<< option
<< "« is not recognised.\n";
print_help(EXIT_FAILURE);
}
result.input_filename = option;
}
}
if(help) {
print_help(EXIT_SUCCESS);
}
if(dry_run && !result.output_filename.empty()) {
std::cerr << "Error: Dry run with an output file is not allowed.\n";
print_help(EXIT_FAILURE);
}
if(result.input_filename.empty()) {
std::cerr << "Error: Input filename omitted.\n";
print_help(EXIT_FAILURE);
}
if(result.output_filename.empty() && !dry_run) {
std::cerr << "Error: Output filename omitted.\n";
print_help(EXIT_FAILURE);
}
if(result.time && (std::clock() == -1)) {
std::cerr
<< "Error: No timing available on your platform, "
<< "option disabled.\n";
result.time = false;
}
/*
* No filter implies a copy, or conversion to png, which is a valid
* way to use the program, so do not complain.
*/
return result;
}
const cmdline_options&
cmdline_options::options()
{
return singleton(true);
}
cmdline_options&
cmdline_options::singleton(const bool is_initialized)
{
static bool initialized = false;
assert(is_initialized == initialized);
initialized = true;
static cmdline_options result;
return result;
}

View file

@ -1,96 +0,0 @@
/*
Copyright (C) 2012 - 2016 by Mark de Wever <koraq@xs4all.nl>
Part of the Battle for Wesnoth Project http://www.wesnoth.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file
* Command line parameters for wesmage.
*/
#ifndef WESMAGE_OPTIONS_HPP_INCLUDED
#define WESMAGE_OPTIONS_HPP_INCLUDED
#include <string>
#include <vector>
/** A singleton class containing the parsed command line parameters. */
struct cmdline_options
{
private:
cmdline_options(const cmdline_options&) = delete;
cmdline_options& operator=(const cmdline_options&) = delete;
cmdline_options();
public:
/**
* Parses the command line.
*
* This function shall be called once at the beginning of the program.
*
* @param argc The @p argc to @ref main.
* @param argv The @p argv to @ref main.
*
* @returns The parsed options.
*/
static const cmdline_options&
parse(int argc, char* argv[]);
/**
* Returns the cached parsed command line parameters.
*
* This function shall only be called after @ref cmdline_options::parse has
* been called.
*
* @returns The parsed options.
*/
static const cmdline_options&
options();
/** The filename of the input file. */
std::string input_filename;
/** The filename of the output file. */
std::string output_filename;
/** The filters to apply to the input file. */
std::vector<std::string> filters;
/** Display the time that applying the filters took. */
bool time;
/**
* The number of times the filter has to be applied.
*
* This feature is for performance testing only.
*/
int count;
private:
/**
* Helper which contains the single instance of this class.
*
* @param is_initialized Helper variable to track whether
* @ref cmdline_options::parse is only called once
* and whether @ref options::options isn't
* called before @ref options::parse.
*
* @returns The single instance of this class.
*/
static cmdline_options&
singleton(const bool is_initialized);
};
#endif

View file

@ -1,110 +0,0 @@
/*
Copyright (C) 2012 - 2016 by Mark de Wever <koraq@xs4all.nl>
Part of the Battle for Wesnoth Project http://www.wesnoth.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file
* Tool to test the image conversion functions.
*/
#include "tools/exploder_utils.hpp"
#include "wesmage/exit.hpp"
#include "wesmage/filter.hpp"
#include "wesmage/options.hpp"
#include <SDL_image.h>
#include <ctime>
#include <iostream>
static clock_t
get_begin_time()
{
clock_t begin = std::clock();
clock_t end = std::clock();
while(begin == (end = std::clock())) {
/* DO NOTHING */
}
std::cout << "Clock resolution "
<< end - begin
<< " ticks, using " << CLOCKS_PER_SEC << " ticks/second.\n"
<< "This give resolution of about "
<<static_cast<double>(end - begin) / CLOCKS_PER_SEC
<< " seconds.\n";
/* IO might be slow so wait until the next value. */
begin = std::clock();
while(begin == (end = std::clock())) {
/* DO NOTHING */
}
return begin;
}
int
main(int argc, char* argv[])
{
try {
const cmdline_options& options = cmdline_options::parse(argc, argv);
surface surf(make_neutral_surface(
IMG_Load(options.input_filename.c_str())));
if(!surf) {
std::cerr << "Error: Failed to load input file »"
<< options.input_filename
<< "«.\n";
return EXIT_FAILURE;
}
std::vector<surface> surfaces;
if(options.count != 1) {
for(int i = 1; i < options.count; ++i) {
// make_neutral_surface make a deep-copy of the image.
surfaces.push_back(make_neutral_surface(surf));
}
}
surfaces.push_back(surf);
const clock_t begin = options.time ? get_begin_time() : 0;
for(int i = 0; i < options.count; ++i) {
for(const std::string& filter : options.filters) {
filter_apply(surfaces[i], filter);
}
}
if(options.time) {
const clock_t end = std::clock();
std::cout << "Applying the filters took "
<< end - begin
<< " ticks, "
<< static_cast<double>(end - begin) / CLOCKS_PER_SEC
<< " seconds.\n";
}
if(!options.output_filename.empty()) {
save_image(surfaces[0], options.output_filename);
}
} catch(const exiter& exit) {
return exit.status;
} catch(exploder_failure& err) {
std::cerr << "Error: Failed with error »" << err.message << "«.\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}