diff --git a/src/data/field/choice.cpp b/src/data/field/choice.cpp index cdd7809a..311b9a46 100644 --- a/src/data/field/choice.cpp +++ b/src/data/field/choice.cpp @@ -207,7 +207,7 @@ void ChoiceStyle::initImage() { } Script& script = image.getScript(); script.addInstruction(I_PUSH_CONST, lookup); - script.addInstruction(I_GET_VAR, string_to_variable(_("input"))); + script.addInstruction(I_GET_VAR, SCRIPT_VAR_input); script.addInstruction(I_BINARY, I_MEMBER); script.addInstruction(I_CALL, 0); script.addInstruction(I_PUSH_CONST, script_nil); diff --git a/src/data/game.cpp b/src/data/game.cpp index 20e9ea78..496e0d8b 100644 --- a/src/data/game.cpp +++ b/src/data/game.cpp @@ -93,7 +93,7 @@ void Game::initCardListColorScript() { // initialize script: field.colors[card.field-name] or else rgb(0,0,0) Script& s = card_list_color_script.getScript(); s.addInstruction(I_PUSH_CONST, to_script(&cf->choice_colors_cardlist)); - s.addInstruction(I_GET_VAR, string_to_variable(_("card"))); + s.addInstruction(I_GET_VAR, SCRIPT_VAR_card); s.addInstruction(I_MEMBER_C, cf->name); s.addInstruction(I_BINARY, I_MEMBER); s.addInstruction(I_PUSH_CONST, to_script(Color(0,0,0))); diff --git a/src/data/keyword.cpp b/src/data/keyword.cpp index a3722cde..06cb3789 100644 --- a/src/data/keyword.cpp +++ b/src/data/keyword.cpp @@ -462,7 +462,9 @@ String KeywordDatabase::expand(const String& text, } // next becomes current swap(current, next); - next.clear(); + // in the MSVC stl clear frees memory, that is a waste, because we need it again in the next iteration + //next.clear(); + next.resize(0); closure(current); // are we done? FOR_EACH(n, current) { diff --git a/src/data/statistics.cpp b/src/data/statistics.cpp index 99b829ba..79dfaf96 100644 --- a/src/data/statistics.cpp +++ b/src/data/statistics.cpp @@ -51,15 +51,15 @@ StatsDimension::StatsDimension(const Field& field) // initialize script: primary_choice(card.{field_name}) Script& s = script.getScript(); s.addInstruction(I_PUSH_CONST, script_primary_choice); - s.addInstruction(I_GET_VAR, string_to_variable(_("card"))); + s.addInstruction(I_GET_VAR, SCRIPT_VAR_card); s.addInstruction(I_MEMBER_C, field.name); s.addInstruction(I_CALL, 1); - s.addInstruction(I_NOP, string_to_variable(_("input"))); + s.addInstruction(I_NOP, SCRIPT_VAR_input); s.addInstruction(I_RET); } else { // initialize script, card.{field_name} Script& s = script.getScript(); - s.addInstruction(I_GET_VAR, string_to_variable(_("card"))); + s.addInstruction(I_GET_VAR, SCRIPT_VAR_card); s.addInstruction(I_MEMBER_C, field.name); s.addInstruction(I_RET); } diff --git a/src/gui/set/keywords_panel.cpp b/src/gui/set/keywords_panel.cpp index 6e8778c2..6197c83d 100644 --- a/src/gui/set/keywords_panel.cpp +++ b/src/gui/set/keywords_panel.cpp @@ -216,7 +216,7 @@ String KeywordsPanel::runRefScript(int find_i) { FOR_EACH(r, p->refer_scripts) { if (i++ == find_i) { Context& ctx = set->getContext(); - ctx.setVariable(_("input"), to_script(param_s)); + ctx.setVariable(SCRIPT_VAR_input, to_script(param_s)); return r->script.invoke(ctx)->toString(); } } diff --git a/src/main.cpp b/src/main.cpp index 7cf543ac..0ecfd1cf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -76,6 +76,7 @@ int MSE::OnRun() { #endif wxInitAllImageHandlers(); wxFileSystem::AddHandler(new wxInternetFSHandler); // needed for update checker + init_script_variables(); init_file_formats(); packages.init(); settings.read(); @@ -128,22 +129,27 @@ int MSE::OnRun() { } else if (arg == _("--help") || arg == _("-?")) { // command line help write_stdout( String(_("Magic Set Editor\n\n")) - + _("Usage: ") + argv[0] + _("[OPTIONS]\n\n") - + _(" no options \tStart the MSE user interface showing the welcome window.\n") - + _(" FILE.mse-set,\n") - + _(" FILE.set,\n") - + _(" FILE.mse \tLoad the set file in the MSE user interface.\n") - + _(" FILE.mse-symbol \tLoad the symbol into the MSE symbol editor.\n") - + _(" FILE.mse-installer\tInstall the packages from the installer.\n") - + _(" --local \tInstall packages for this user only.\n") - + _(" -? --help \tShows this help screen.\n") - + _(" -v --version \tShow version information.\n") - + _(" --symbol-editor \tShow the symbol editor instead of the welcome window.\n") - + _(" --create-installer\n") - + _(" FILE [FILE]...\tCreate an instaler named FILE, containing the listed packges.\n") - + _(" --export\n") - + _(" FILE IMAGE \tExport the cards in a set to image files,\n") - + _(" \tIMAGE is the same format as for 'export all card images'.\n") ); + + _("Usage: ") + argv[0] + _(" [OPTIONS]\n\n") + + _(" no options\n") + + _(" \tStart the MSE user interface showing the welcome window.\n\n") + + _(" -? or --help\n") + + _(" \tShows this help screen.\n\n") + + _(" -v or --version\n") + + _(" \tShow version information.\n\n") + + _(" FILE.mse-set, FILE.set, FILE.mse\n") + + _(" \tLoad the set file in the MSE user interface.\n\n") + + _(" FILE.mse-symbol\n") + + _(" \tLoad the symbol into the MSE symbol editor.\n\n") + + _(" FILE.mse-installer [--local]\n") + + _(" \tInstall the packages from the installer.\n") + + _(" \tIf the --local flag is passed, install packages for this user only.\n\n") + + _(" --symbol-editor\n") + + _(" \tShow the symbol editor instead of the welcome window.\n\n") + + _(" --create-installer FILE [PACKAGE [PACKAGE ...]]\n") + + _(" \tCreate an instaler named FILE, containing the listed packages.\n\n") + + _(" --export FILE [IMAGE]\n") + + _(" \tExport the cards in a set to image files,\n") + + _(" \tIMAGE is the same format as for 'export all card images'.\n") ); return EXIT_SUCCESS; } else if (arg == _("--version") || arg == _("-v")) { // dump version diff --git a/src/render/value/choice.cpp b/src/render/value/choice.cpp index 3ea4bdd7..2e882e24 100644 --- a/src/render/value/choice.cpp +++ b/src/render/value/choice.cpp @@ -17,7 +17,7 @@ bool ChoiceValueViewer::prepare(RotatedDC& dc) { style().initImage(); CachedScriptableImage& img = style().image; Context& ctx = viewer.getContext(); - ctx.setVariable(_("input"), to_script(value().value())); + ctx.setVariable(SCRIPT_VAR_input, to_script(value().value())); // generate to determine the size if (img.update(ctx) && img.isReady()) { GeneratedImage::Options img_options; diff --git a/src/render/value/multiple_choice.cpp b/src/render/value/multiple_choice.cpp index bbb9feb9..f1a73703 100644 --- a/src/render/value/multiple_choice.cpp +++ b/src/render/value/multiple_choice.cpp @@ -46,7 +46,7 @@ void MultipleChoiceValueViewer::draw(RotatedDC& dc) { style().initImage(); CachedScriptableImage& img = style().image; Context& ctx = viewer.getContext(); - ctx.setVariable(_("input"), to_script(value().value())); + ctx.setVariable(SCRIPT_VAR_input, to_script(value().value())); img.update(ctx); if (img.isReady()) { GeneratedImage::Options img_options; diff --git a/src/script/context.cpp b/src/script/context.cpp index 1b6d571c..56365c01 100644 --- a/src/script/context.cpp +++ b/src/script/context.cpp @@ -73,13 +73,13 @@ ScriptValueP Context::eval(const Script& script, bool useScope) { // Get a variable case I_GET_VAR: { ScriptValueP value = variables[i.data].value; - if (!value) throw ScriptError(_("Variable not set: ") + variable_to_string(i.data)); + if (!value) throw ScriptError(_("Variable not set: ") + variable_to_string((Variable)i.data)); stack.push_back(value); break; } // Set a variable case I_SET_VAR: { - setVariable(i.data, stack.back()); + setVariable((Variable)i.data, stack.back()); break; } @@ -112,7 +112,7 @@ ScriptValueP Context::eval(const Script& script, bool useScope) { size_t scope = openScope(); // prepare arguments for (unsigned int j = 0 ; j < i.data ; ++j) { - setVariable(instr[i.data - j - 1].data, stack.back()); + setVariable((Variable)instr[i.data - j - 1].data, stack.back()); stack.pop_back(); } instr += i.data; // skip arguments @@ -189,8 +189,8 @@ void Context::setVariable(const String& name, const ScriptValueP& value) { setVariable(string_to_variable(name), value); } -void Context::setVariable(int name, const ScriptValueP& value) { - Variable& var = variables[name]; +void Context::setVariable(Variable name, const ScriptValueP& value) { + VariableValue& var = variables[name]; if (var.level < level) { // keep shadow copy Binding bind = {name, var}; @@ -209,6 +209,10 @@ ScriptValueP Context::getVariable(const String& name) { ScriptValueP Context::getVariableOpt(const String& name) { return variables[string_to_variable(name)].value; } +ScriptValueP Context::getVariable(Variable var) { + if (variables[var].value) return variables[var].value; + throw ScriptError(_("Variable not set: ") + variable_to_string(var)); +} size_t Context::openScope() { @@ -290,13 +294,13 @@ class ScriptCompose : public ScriptValue { ScriptCompose(ScriptValueP a, ScriptValueP b) : a(a), b(b) {} virtual ScriptType type() const { return SCRIPT_FUNCTION; } - virtual String typeName() const { return _("replace_rule"); } + virtual String typeName() const { return _("function composition"); } virtual ScriptValueP eval(Context& ctx) const { - ctx.setVariable(_("input"), a->eval(ctx)); + ctx.setVariable(SCRIPT_VAR_input, a->eval(ctx)); return b->eval(ctx); } virtual ScriptValueP dependencies(Context& ctx, const Dependency& dep) const { - ctx.setVariable(_("input"), a->dependencies(ctx, dep)); + ctx.setVariable(SCRIPT_VAR_input, a->dependencies(ctx, dep)); return b->dependencies(ctx, dep); } private: diff --git a/src/script/context.hpp b/src/script/context.hpp index 07557aeb..d44c046f 100644 --- a/src/script/context.hpp +++ b/src/script/context.hpp @@ -51,11 +51,17 @@ class Context { /// Set a variable to a new value (in the current scope) void setVariable(const String& name, const ScriptValueP& value); + /// Set a variable to a new value (in the current scope) + void setVariable(Variable name, const ScriptValueP& value); /// Get the value of a variable, throws if it not set ScriptValueP getVariable(const String& name); /// Get the value of a variable, returns ScriptValue() if it is not set ScriptValueP getVariableOpt(const String& name); + /// Get the value of a variable, throws if it not set + ScriptValueP getVariable(Variable var); + /// Get the value of a variable, returns ScriptValue() if it is not set + inline ScriptValueP getVariableOpt(Variable var) { return variables[var].value; } /// Open a new scope /** returns the number of shadowed binding before that scope */ @@ -65,19 +71,19 @@ class Context { public:// public for FOR_EACH /// Record of a variable - struct Variable { - Variable() : level(0) {} + struct VariableValue { + VariableValue() : level(0) {} unsigned int level; ///< Scope level on which this variable was set ScriptValueP value; ///< Value of this variable }; /// Record of a variable binding that is being shadowed (overwritten) by another binding struct Binding { - int variable; ///< Name of the overwritten variable. - Variable value; ///< Old value of that variable. + Variable variable; ///< Name of the overwritten variable. + VariableValue value; ///< Old value of that variable. }; private: /// Variables, indexed by integer name (using string_to_variable) - VectorIntMap variables; + VectorIntMap variables; /// Shadowed variable bindings vector shadowed; /// Number of scopes opened @@ -89,8 +95,6 @@ class Context { struct Jump; struct JumpOrder; - /// Set a variable to a new value (in the current scope) - void setVariable(int name, const ScriptValueP& value); /// Return the bindings in the current scope void getBindings(size_t scope, vector&); /// Remove all bindings made in the current scope diff --git a/src/script/dependency.cpp b/src/script/dependency.cpp index 1be27977..eaec2716 100644 --- a/src/script/dependency.cpp +++ b/src/script/dependency.cpp @@ -242,7 +242,7 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script) size_t scope = openScope(); // prepare arguments for (unsigned int j = 0 ; j < i.data ; ++j) { - setVariable(instr[i.data - j - 1].data, stack.back()); + setVariable((Variable)instr[i.data - j - 1].data, stack.back()); stack.pop_back(); } instr += i.data; // skip arguments, there had better not be any jumps into the argument list @@ -267,14 +267,14 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script) case I_GET_VAR: { ScriptValueP value = variables[i.data].value; if (!value) { - value = new_intrusive1(variable_to_string(i.data)); // no errors here + value = new_intrusive1(variable_to_string((Variable)i.data)); // no errors here } stack.push_back(value); break; } // Set a variable (as normal) case I_SET_VAR: { - setVariable(i.data, stack.back()); + setVariable((Variable)i.data, stack.back()); break; } diff --git a/src/script/functions/basic.cpp b/src/script/functions/basic.cpp index f0387bf9..09bccb68 100644 --- a/src/script/functions/basic.cpp +++ b/src/script/functions/basic.cpp @@ -21,9 +21,12 @@ DECLARE_TYPEOF_COLLECTION(pair); // ----------------------------------------------------------------------------- : Debugging SCRIPT_FUNCTION(trace) { - SCRIPT_PARAM(String, input); - //handle_warning(_("Trace:\t") + input, false); - wxLogDebug(_("Trace:\t") + input); + SCRIPT_PARAM_C(String, input); + #ifdef _DEBUG + wxLogDebug(_("Trace:\t") + input); + #else + handle_warning(_("Trace:\t") + input, false); + #endif SCRIPT_RETURN(input); } @@ -31,38 +34,38 @@ SCRIPT_FUNCTION(trace) { // convert a string to upper case SCRIPT_FUNCTION(to_upper) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); SCRIPT_RETURN(input.Upper()); } // convert a string to lower case SCRIPT_FUNCTION(to_lower) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); SCRIPT_RETURN(input.Lower()); } // convert a string to title case SCRIPT_FUNCTION(to_title) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); SCRIPT_RETURN(capitalize(input)); } // reverse a string SCRIPT_FUNCTION(reverse) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); reverse(input.begin(), input.end()); SCRIPT_RETURN(input); } // remove leading and trailing whitespace from a string SCRIPT_FUNCTION(trim) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); SCRIPT_RETURN(trim(input)); } // extract a substring SCRIPT_FUNCTION(substring) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); SCRIPT_PARAM_DEFAULT(int, begin, 0); SCRIPT_PARAM_DEFAULT(int, end, INT_MAX); if (begin < 0) begin = 0; @@ -78,22 +81,22 @@ SCRIPT_FUNCTION(substring) { // does a string contain a substring? SCRIPT_FUNCTION(contains) { - SCRIPT_PARAM(String, input); - SCRIPT_PARAM(String, match); + SCRIPT_PARAM_C(String, input); + SCRIPT_PARAM_C(String, match); SCRIPT_RETURN(input.find(match) != String::npos); } -SCRIPT_RULE_1(format, String, format) { +SCRIPT_RULE_1_C(format, String, format) { String fmt = _("%") + replace_all(format, _("%"), _("")); // determine type expected by format string if (format.find_first_of(_("DdIiOoXx")) != String::npos) { - SCRIPT_PARAM(int, input); + SCRIPT_PARAM_C(int, input); SCRIPT_RETURN(String::Format(fmt, input)); } else if (format.find_first_of(_("EeFfGg")) != String::npos) { - SCRIPT_PARAM(double, input); + SCRIPT_PARAM_C(double, input); SCRIPT_RETURN(String::Format(fmt, input)); } else if (format.find_first_of(_("Ss")) != String::npos) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); SCRIPT_RETURN(format_string(fmt, input)); } else { throw ScriptError(_ERROR_1_("unsupported format", format)); @@ -101,7 +104,7 @@ SCRIPT_RULE_1(format, String, format) { } SCRIPT_FUNCTION(curly_quotes) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); bool open = true, in_tag = false; FOR_EACH(c, input) { if (c == _('\'') || c == LEFT_SINGLE_QUOTE || c == RIGHT_SINGLE_QUOTE) { @@ -122,7 +125,7 @@ SCRIPT_FUNCTION(curly_quotes) { // regex escape a string SCRIPT_FUNCTION(regex_escape) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); SCRIPT_RETURN(regex_escape(input)); } @@ -152,18 +155,18 @@ String replace_tag_contents(String input, const String& tag, const ScriptValueP& } // Replace the contents of a specific tag -SCRIPT_RULE_2(tag_contents, String, tag, ScriptValueP, contents) { - SCRIPT_PARAM(String, input); +SCRIPT_RULE_2_C(tag_contents, String, tag, ScriptValueP, contents) { + SCRIPT_PARAM_C(String, input); SCRIPT_RETURN(replace_tag_contents(input, tag, contents, ctx)); } -SCRIPT_RULE_1(tag_remove, String, tag) { - SCRIPT_PARAM(String, input); +SCRIPT_RULE_1_C(tag_remove, String, tag) { + SCRIPT_PARAM_C(String, input); SCRIPT_RETURN(remove_tag(input, tag)); } SCRIPT_FUNCTION(remove_tags) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); SCRIPT_RETURN(untag_no_escape(input)); } @@ -278,30 +281,30 @@ SCRIPT_FUNCTION_DEPENDENCIES(position_of) { int script_length_of(Context& ctx, const ScriptValueP& collection) { if (ScriptObject* setobj = dynamic_cast*>(collection.get())) { Set* set = setobj->getValue(); - SCRIPT_OPTIONAL_PARAM_(ScriptValueP, filter); + SCRIPT_OPTIONAL_PARAM_C_(ScriptValueP, filter); return set->numberOfCards(filter); } else { return collection->itemCount(); } } SCRIPT_FUNCTION(length) { - SCRIPT_PARAM(ScriptValueP, input); + SCRIPT_PARAM_C(ScriptValueP, input); SCRIPT_RETURN(script_length_of(ctx, input)); } SCRIPT_FUNCTION(number_of_items) { - SCRIPT_PARAM(ScriptValueP, in); + SCRIPT_PARAM_C(ScriptValueP, in); SCRIPT_RETURN(script_length_of(ctx, in)); } // filtering items from a list SCRIPT_FUNCTION(filter_list) { - SCRIPT_PARAM(ScriptValueP, input); - SCRIPT_PARAM(ScriptValueP, filter); + SCRIPT_PARAM_C(ScriptValueP, input); + SCRIPT_PARAM_C(ScriptValueP, filter); // filter a collection intrusive_ptr ret(new ScriptCustomCollection()); ScriptValueP it = input->makeIterator(input); while (ScriptValueP v = it->next()) { - ctx.setVariable(_("input"), v); + ctx.setVariable(SCRIPT_VAR_input, v); if (*filter->eval(ctx)) { ret->value.push_back(v); } @@ -311,7 +314,7 @@ SCRIPT_FUNCTION(filter_list) { } SCRIPT_FUNCTION(sort_list) { - SCRIPT_PARAM(ScriptValueP, input); + SCRIPT_PARAM_C(ScriptValueP, input); SCRIPT_PARAM_N(ScriptValueP, _("order by"), order_by); return sort_script(ctx, input, *order_by); } @@ -320,8 +323,8 @@ SCRIPT_FUNCTION(sort_list) { SCRIPT_RULE_2_N_DEP(expand_keywords, ScriptValueP, _("default expand"), default_expand, ScriptValueP, _("combine"), combine) { - SCRIPT_PARAM(String, input); - SCRIPT_PARAM(Set*, set); + SCRIPT_PARAM_C(String, input); + SCRIPT_PARAM_C(Set*, set); KeywordDatabase& db = set->keyword_db; if (db.empty()) { db.prepare_parameters(set->game->keyword_parameter_types, set->game->keywords); @@ -329,20 +332,20 @@ SCRIPT_RULE_2_N_DEP(expand_keywords, ScriptValueP, _("default expand"), default_ db.add(set->game->keywords); db.add(set->keywords); } - SCRIPT_OPTIONAL_PARAM_(CardP, card); + SCRIPT_OPTIONAL_PARAM_C_(CardP, card); WITH_DYNAMIC_ARG(keyword_usage_statistics, card ? &card->keyword_usage : nullptr); SCRIPT_RETURN(db.expand(input, default_expand, combine, ctx)); } SCRIPT_RULE_2_DEPENDENCIES(expand_keywords) { default_expand->dependencies(ctx, dep); combine ->dependencies(ctx, dep); - SCRIPT_PARAM(Set*, set); + SCRIPT_PARAM_C(Set*, set); set->game->dependent_scripts_keywords.add(dep); // this depends on the set's keywords SCRIPT_RETURN(_("")); } SCRIPT_FUNCTION(keyword_usage) { - SCRIPT_PARAM(CardP, card); + SCRIPT_PARAM_C(CardP, card); SCRIPT_OPTIONAL_PARAM_(bool, unique); // make a list "kw1, kw2, kw3" of keywords used on card String ret; @@ -372,7 +375,7 @@ class ScriptReplaceRule : public ScriptValue { virtual ScriptType type() const { return SCRIPT_FUNCTION; } virtual String typeName() const { return _("replace_rule"); } virtual ScriptValueP eval(Context& ctx) const { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); if (context.IsValid() || replacement_function || recursive) { SCRIPT_RETURN(apply(ctx, input)); } else { @@ -431,12 +434,12 @@ class ScriptReplaceRule : public ScriptValue { ScriptValueP replace_rule(Context& ctx) { intrusive_ptr ret(new ScriptReplaceRule); // match - SCRIPT_PARAM(String, match); + SCRIPT_PARAM_C(String, match); if (!ret->regex.Compile(match, wxRE_ADVANCED)) { throw ScriptError(_("Error while compiling regular expression: '")+match+_("'")); } // replace - SCRIPT_PARAM(ScriptValueP, replace); + SCRIPT_PARAM_C(ScriptValueP, replace); if (replace->type() == SCRIPT_FUNCTION) { ret->replacement_function = replace; } else { @@ -467,7 +470,7 @@ class ScriptFilterRule : public ScriptValue { virtual ScriptType type() const { return SCRIPT_FUNCTION; } virtual String typeName() const { return _("filter_rule"); } virtual ScriptValueP eval(Context& ctx) const { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); String ret; while (regex.Matches(input)) { // match, append to result @@ -493,7 +496,7 @@ class ScriptFilterRule : public ScriptValue { ScriptValueP filter_rule(Context& ctx) { intrusive_ptr ret(new ScriptFilterRule); // match - SCRIPT_PARAM(String, match); + SCRIPT_PARAM_C(String, match); if (!ret->regex.Compile(match, wxRE_ADVANCED)) { throw ScriptError(_("Error while compiling regular expression: '")+match+_("'")); } @@ -520,7 +523,7 @@ class ScriptMatchRule : public ScriptValue { virtual ScriptType type() const { return SCRIPT_FUNCTION; } virtual String typeName() const { return _("match_rule"); } virtual ScriptValueP eval(Context& ctx) const { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); SCRIPT_RETURN(regex.Matches(input)); } @@ -531,7 +534,7 @@ class ScriptMatchRule : public ScriptValue { ScriptValueP match_rule(Context& ctx) { intrusive_ptr ret(new ScriptMatchRule); // match - SCRIPT_PARAM(String, match); + SCRIPT_PARAM_C(String, match); if (!ret->regex.Compile(match, wxRE_ADVANCED)) { throw ScriptError(_("Error while compiling regular expression: '")+match+_("'")); } @@ -554,7 +557,7 @@ class ScriptRule_sort_order: public ScriptValue { virtual ScriptType type() const { return SCRIPT_FUNCTION; } virtual String typeName() const { return _("sort_rule"); } virtual ScriptValueP eval(Context& ctx) const { - SCRIPT_PARAM(ScriptValueP, input); + SCRIPT_PARAM_C(ScriptValueP, input); if (input->type() == SCRIPT_COLLECTION) { handle_warning(_("Sorting a collection as a string, this is probably not intended, if it is use 'collection+\"\"' to force conversion"), false); } @@ -569,7 +572,7 @@ class ScriptRule_sort: public ScriptValue { virtual ScriptType type() const { return SCRIPT_FUNCTION; } virtual String typeName() const { return _("sort_rule"); } virtual ScriptValueP eval(Context& ctx) const { - SCRIPT_PARAM(ScriptValueP, input); + SCRIPT_PARAM_C(ScriptValueP, input); if (input->type() == SCRIPT_COLLECTION) { handle_warning(_("Sorting a collection as a string, this is probably not intended, if it is use 'collection+\"\"' to force conversion"), false); } @@ -582,13 +585,13 @@ class ScriptRule_sort: public ScriptValue { }; SCRIPT_FUNCTION(sort_rule) { - SCRIPT_OPTIONAL_PARAM(String, order) { + SCRIPT_OPTIONAL_PARAM_C(String, order) { return new_intrusive1(order); } return new_intrusive (); } SCRIPT_FUNCTION(sort_text) { - SCRIPT_OPTIONAL_PARAM(String, order) { + SCRIPT_OPTIONAL_PARAM_C(String, order) { return ScriptRule_sort_order(order).eval(ctx); } return ScriptRule_sort().eval(ctx); diff --git a/src/script/functions/editor.cpp b/src/script/functions/editor.cpp index bfc36006..e6b3f7b3 100644 --- a/src/script/functions/editor.cpp +++ b/src/script/functions/editor.cpp @@ -53,7 +53,7 @@ SCRIPT_FUNCTION_WITH_DEP(combined_editor) { throw ScriptError(String::Format(_("Not enough separators for combine_editor, expected %d"), values.size()-1)); } // the value - SCRIPT_PARAM(String, value); + SCRIPT_PARAM_C(String, value); // remove suffix/prefix SCRIPT_OPTIONAL_PARAM_(String, prefix); SCRIPT_OPTIONAL_PARAM_(String, suffix); @@ -147,7 +147,7 @@ SCRIPT_FUNCTION_DEPENDENCIES(combined_editor) { } else if (i > 0) break; } // Find the target field - SCRIPT_PARAM(Set*, set); + SCRIPT_PARAM_C(Set*, set); GameP game = set->game; FieldP target_field; if (dep.type == DEP_CARD_FIELD) target_field = game->card_fields[dep.index]; @@ -183,7 +183,7 @@ SCRIPT_FUNCTION_DEPENDENCIES(combined_editor) { // convert a full choice name into the name of the top level group it is in SCRIPT_FUNCTION(primary_choice) { - SCRIPT_PARAM(ValueP,input); + SCRIPT_PARAM_C(ValueP,input); ChoiceValueP value = dynamic_pointer_cast(input); if (!value) { throw ScriptError(_("Argument to 'primary_choice' should be a choice value")); @@ -222,8 +222,8 @@ bool chosen(const String& choice, const String& input) { // is the given choice active? SCRIPT_FUNCTION(chosen) { - SCRIPT_PARAM(String,choice); - SCRIPT_PARAM(String,input); + SCRIPT_PARAM_C(String,choice); + SCRIPT_PARAM_C(String,input); SCRIPT_RETURN(chosen(choice, input)); } @@ -311,7 +311,7 @@ void read_choices_param(Context& ctx, vector& choices) { // add the given choice if it is not already active SCRIPT_FUNCTION(require_choice) { - SCRIPT_PARAM(String,input); + SCRIPT_PARAM_C(String,input); SCRIPT_OPTIONAL_PARAM_N_(String,_("last change"),last_change); vector choices; read_choices_param(ctx, choices); @@ -320,7 +320,7 @@ SCRIPT_FUNCTION(require_choice) { // make sure at most one of the choices is active SCRIPT_FUNCTION(exclusive_choice) { - SCRIPT_PARAM(String,input); + SCRIPT_PARAM_C(String,input); SCRIPT_OPTIONAL_PARAM_N_(String,_("last change"),last_change); vector choices; read_choices_param(ctx, choices); @@ -329,7 +329,7 @@ SCRIPT_FUNCTION(exclusive_choice) { // make sure exactly one of the choices is active SCRIPT_FUNCTION(require_exclusive_choice) { - SCRIPT_PARAM(String,input); + SCRIPT_PARAM_C(String,input); SCRIPT_OPTIONAL_PARAM_N_(String,_("last change"),last_change); vector choices; read_choices_param(ctx, choices); @@ -338,7 +338,7 @@ SCRIPT_FUNCTION(require_exclusive_choice) { // make sure none of the choices are active SCRIPT_FUNCTION(remove_choice) { - SCRIPT_PARAM(String,input); + SCRIPT_PARAM_C(String,input); vector choices; read_choices_param(ctx, choices); SCRIPT_RETURN(filter_choices(input, choices, 0, 0, _(""))); diff --git a/src/script/functions/english.cpp b/src/script/functions/english.cpp index 67f4f7c2..c5a867a1 100644 --- a/src/script/functions/english.cpp +++ b/src/script/functions/english.cpp @@ -133,19 +133,19 @@ String do_english_num(String input, String(*fun)(int)) { } SCRIPT_FUNCTION(english_number) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); SCRIPT_RETURN(do_english_num(input, english_number)); } SCRIPT_FUNCTION(english_number_a) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); SCRIPT_RETURN(do_english_num(input, english_number_a)); } SCRIPT_FUNCTION(english_number_multiple) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); SCRIPT_RETURN(do_english_num(input, english_number_multiple)); } SCRIPT_FUNCTION(english_number_ordinal) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); SCRIPT_RETURN(do_english_num(input, english_ordinal)); } @@ -210,11 +210,11 @@ String do_english(String input, String(*fun)(const String&)) { } SCRIPT_FUNCTION(english_singular) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); SCRIPT_RETURN(do_english(input, english_singular)); } SCRIPT_FUNCTION(english_plural) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); SCRIPT_RETURN(do_english(input, english_plural)); } @@ -308,7 +308,7 @@ String process_english_hints(const String& str) { } SCRIPT_FUNCTION(process_english_hints) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); SCRIPT_RETURN(process_english_hints(input)); } diff --git a/src/script/functions/export.cpp b/src/script/functions/export.cpp index 0f97b088..2644a81a 100644 --- a/src/script/functions/export.cpp +++ b/src/script/functions/export.cpp @@ -252,7 +252,7 @@ String to_html(const String& str_in, const SymbolFontP& symbol_font, double symb // convert a tagged string to html SCRIPT_FUNCTION(to_html) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); // symbol font? SymbolFontP symbol_font; SCRIPT_OPTIONAL_PARAM_N(String, _("symbol font"), font_name) { @@ -266,7 +266,7 @@ SCRIPT_FUNCTION(to_html) { // convert a symbol string to html SCRIPT_FUNCTION(symbols_to_html) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); SCRIPT_PARAM_N(String, _("symbol font"), font_name); SCRIPT_OPTIONAL_PARAM_N_(double, _("symbol font size"), symbol_font_size); SymbolFontP symbol_font = SymbolFont::byName(font_name); @@ -331,7 +331,7 @@ String to_bbcode(const String& str_in) { // convert a tagged string to BBCode SCRIPT_FUNCTION(to_bbcode) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); throw "TODO"; // SCRIPT_RETURN(to_bbcode(input, symbol_font)); } @@ -340,7 +340,7 @@ SCRIPT_FUNCTION(to_bbcode) { // convert a tagged string to plain text SCRIPT_FUNCTION(to_text) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); SCRIPT_RETURN(untag_hide_sep(input)); } @@ -349,7 +349,7 @@ SCRIPT_FUNCTION(to_text) { // copy from source package -> destination directory, return new filename (relative) SCRIPT_FUNCTION(copy_file) { guard_export_info(_("copy_file")); - SCRIPT_PARAM(String, input); // file to copy + SCRIPT_PARAM_C(String, input); // file to copy ExportInfo& ei = *export_info(); wxFileName fn(input); fn.SetPath(ei.directory_absolute); @@ -364,7 +364,7 @@ SCRIPT_FUNCTION(copy_file) { // write a file to the destination directory SCRIPT_FUNCTION(write_text_file) { guard_export_info(_("write_text_file")); - SCRIPT_PARAM(String, input); // text to write + SCRIPT_PARAM_C(String, input); // text to write SCRIPT_PARAM(String, file); // file to write to // filename wxFileName fn; @@ -391,7 +391,7 @@ SCRIPT_FUNCTION(write_image_file) { SCRIPT_RETURN(fn.GetFullName()); // already written an image with this name } // get image - SCRIPT_PARAM(ScriptValueP, input); + SCRIPT_PARAM_C(ScriptValueP, input); SCRIPT_OPTIONAL_PARAM_(int, width); SCRIPT_OPTIONAL_PARAM_(int, height); ScriptObject* card = dynamic_cast*>(input.get()); // is it a card? diff --git a/src/script/functions/image.cpp b/src/script/functions/image.cpp index 799f29f7..716527e1 100644 --- a/src/script/functions/image.cpp +++ b/src/script/functions/image.cpp @@ -63,14 +63,14 @@ SCRIPT_FUNCTION(set_mask) { } SCRIPT_FUNCTION(set_alpha) { - SCRIPT_PARAM(GeneratedImageP, input); + SCRIPT_PARAM_C(GeneratedImageP, input); SCRIPT_PARAM(double, alpha); return new_intrusive2(input, alpha); } SCRIPT_FUNCTION(set_combine) { SCRIPT_PARAM(String, combine); - SCRIPT_PARAM(GeneratedImageP, input); + SCRIPT_PARAM_C(GeneratedImageP, input); ImageCombine image_combine; if (!parse_enum(combine, image_combine)) { throw ScriptError(_("Not a valid combine mode: '") + combine + _("'")); @@ -79,13 +79,13 @@ SCRIPT_FUNCTION(set_combine) { } SCRIPT_FUNCTION(enlarge) { - SCRIPT_PARAM(GeneratedImageP, input); + SCRIPT_PARAM_C(GeneratedImageP, input); SCRIPT_PARAM_N(double, _("border size"), border_size); return new_intrusive2(input, border_size); } SCRIPT_FUNCTION(crop) { - SCRIPT_PARAM(GeneratedImageP, input); + SCRIPT_PARAM_C(GeneratedImageP, input); SCRIPT_PARAM_N(int, _("width"), width); SCRIPT_PARAM_N(int, _("height"), height); SCRIPT_PARAM_N(double, _("offset x"), offset_x); @@ -94,7 +94,7 @@ SCRIPT_FUNCTION(crop) { } SCRIPT_FUNCTION(drop_shadow) { - SCRIPT_PARAM(GeneratedImageP, input); + SCRIPT_PARAM_C(GeneratedImageP, input); SCRIPT_OPTIONAL_PARAM_N_(double, _("offset x"), offset_x); SCRIPT_OPTIONAL_PARAM_N_(double, _("offset y"), offset_y); SCRIPT_OPTIONAL_PARAM_N_(double, _("alpha"), alpha); @@ -156,7 +156,7 @@ SCRIPT_FUNCTION(symbol_variation) { } SCRIPT_FUNCTION(built_in_image) { - SCRIPT_PARAM(String, input); + SCRIPT_PARAM_C(String, input); return new_intrusive1(input); } diff --git a/src/script/functions/util.hpp b/src/script/functions/util.hpp index 7d72e123..8ad50609 100644 --- a/src/script/functions/util.hpp +++ b/src/script/functions/util.hpp @@ -70,6 +70,14 @@ inline Type from_script(const ScriptValueP& v, const String& str) { throw ScriptError(_ERROR_2_("in parameter", str, e.what())); } } +template +inline Type from_script(const ScriptValueP& v, Variable var) { + try { + return from_script(v); + } catch (ScriptError& e) { + throw ScriptError(_ERROR_2_("in parameter", variable_to_string(var), e.what())); + } +} /// Retrieve a parameter to a SCRIPT_FUNCTION with the given name and type /** Usage: @@ -85,6 +93,10 @@ inline Type from_script(const ScriptValueP& v, const String& str) { SCRIPT_PARAM_N(Type, _(#name), name) #define SCRIPT_PARAM_N(Type, str, name) \ Type name = from_script(ctx.getVariable(str), str) +/// Faster variant of SCRIPT_PARAM when name is a CommonScriptVariable +/** Doesn't require a runtime lookup of the name */ +#define SCRIPT_PARAM_C(Type, name) \ + SCRIPT_PARAM_N(Type, SCRIPT_VAR_ ## name, name) /// Retrieve an optional parameter /** Usage: @@ -103,6 +115,8 @@ inline Type from_script(const ScriptValueP& v, const String& str) { #define SCRIPT_OPTIONAL_PARAM_N(Type, str, name) \ SCRIPT_OPTIONAL_PARAM_N_(Type, str, name) \ if (name##_) +#define SCRIPT_OPTIONAL_PARAM_C(Type, name) \ + SCRIPT_OPTIONAL_PARAM_N(Type, SCRIPT_VAR_ ## name, name) /// Retrieve an optional parameter, can't be used as an if statement #define SCRIPT_OPTIONAL_PARAM_(Type, name) \ @@ -112,6 +126,8 @@ inline Type from_script(const ScriptValueP& v, const String& str) { ScriptValueP name##_ = ctx.getVariableOpt(str); \ Type name = name##_ && name##_ != script_nil \ ? from_script(name##_, str) : Type(); +#define SCRIPT_OPTIONAL_PARAM_C_(Type, name) \ + SCRIPT_OPTIONAL_PARAM_N_(Type, SCRIPT_VAR_ ## name, name) /// Retrieve an optional parameter with a default value #define SCRIPT_PARAM_DEFAULT(Type, name, def) \ @@ -126,6 +142,8 @@ inline Type from_script(const ScriptValueP& v, const String& str) { /// Utility for defining a script rule with a single parameter #define SCRIPT_RULE_1(funname, type1, name1) \ SCRIPT_RULE_1_N(funname, type1, _(#name1), name1) +#define SCRIPT_RULE_1_C(funname, type1, name1) \ + SCRIPT_RULE_1_N(funname, type1, SCRIPT_VAR_ ## name1, name1) /// Utility for defining a script rule with a single named parameter #define SCRIPT_RULE_1_N(funname, type1, str1, name1) \ class ScriptRule_##funname: public ScriptValue { \ @@ -150,6 +168,8 @@ inline Type from_script(const ScriptValueP& v, const String& str) { /// Utility for defining a script rule with two parameters #define SCRIPT_RULE_2(funname, type1, name1, type2, name2) \ SCRIPT_RULE_2_N(funname, type1, _(#name1), name1, type2, _(#name2), name2) +#define SCRIPT_RULE_2_C(funname, type1, name1, type2, name2) \ + SCRIPT_RULE_2_N(funname, type1, SCRIPT_VAR_ ## name1, name1, type2, SCRIPT_VAR_ ## name2, name2) /// Utility for defining a script rule with two named parameters #define SCRIPT_RULE_2_N(funname, type1, str1, name1, type2, str2, name2) \ SCRIPT_RULE_2_N_AUX(funname, type1, str1, name1, type2, str2, name2, ;) diff --git a/src/script/parser.cpp b/src/script/parser.cpp index 18704c41..59275913 100644 --- a/src/script/parser.cpp +++ b/src/script/parser.cpp @@ -45,6 +45,8 @@ struct Token { inline bool operator != (TokenType t) const { return type != t; } inline bool operator == (const String& s) const { return type != TOK_STRING && value == s; } inline bool operator != (const String& s) const { return type == TOK_STRING || value != s; } + inline bool operator == (const Char* s) const { return type != TOK_STRING && value == s; } + inline bool operator != (const Char* s) const { return type == TOK_STRING || value != s; } }; enum OpenBrace @@ -639,7 +641,7 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc parseOper(input, script, PREC_SEQ); } else { // implicit "input" argument - arguments.push_back(string_to_variable(_("input"))); + arguments.push_back(SCRIPT_VAR_input); parseOper(input, script, PREC_SEQ); } t = input.peek(); diff --git a/src/script/script.cpp b/src/script/script.cpp index 4b25663e..663f2c0d 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -22,7 +22,7 @@ DECLARE_TYPEOF(Variables); /// Return a unique name for a variable to allow for faster loopups Variable string_to_variable(const String& s) { - map::iterator it = variables.find(s); + Variables::iterator it = variables.find(s); if (it == variables.end()) { #ifdef _DEBUG variable_names.push_back(s); @@ -45,6 +45,31 @@ String variable_to_string(Variable v) { throw InternalError(String(_("Variable not found: ")) << v); } +// ----------------------------------------------------------------------------- : CommonVariables + +void init_script_variables() { + #define VarN(X,name) if (SCRIPT_VAR_##X != string_to_variable(name)) assert(false); + #define Var(X) VarN(X,_(#X)) + Var(input); + Var(in); + Var(match); + Var(replace); + Var(order); + Var(filter); + Var(choice); + Var(format); + Var(tag); + Var(contents); + Var(set); + Var(game); + Var(stylesheet); + VarN(card_style,_("card style")); + Var(card); + Var(styling); + Var(value); + assert(variables.size() == SCRIPT_VAR_CUSTOM_FIRST); +} + // ----------------------------------------------------------------------------- : Script ScriptType Script::type() const { @@ -172,7 +197,7 @@ String Script::dumpInstr(unsigned int pos, Instruction i) const { ret += String::Format(_("\t%d"), i.data); break; case I_GET_VAR: case I_SET_VAR: case I_NOP: // variable - ret += _("\t") + variable_to_string(i.data); + ret += _("\t") + variable_to_string((Variable)i.data); break; } return ret; @@ -260,7 +285,7 @@ const Instruction* Script::backtraceSkip(const Instruction* instr, int to_skip) String Script::instructionName(const Instruction* instr) const { if (instr < &instructions[0] || instr >= &instructions[instructions.size()]) return _("??\?"); if (instr->instr == I_GET_VAR) { - return variable_to_string(instr->data); + return variable_to_string((Variable)instr->data); } else if (instr->instr == I_MEMBER_C) { return instructionName(backtraceSkip(instr - 1, 0)) + _(".") diff --git a/src/script/script.hpp b/src/script/script.hpp index 612f3fab..c518a3dc 100644 --- a/src/script/script.hpp +++ b/src/script/script.hpp @@ -98,7 +98,28 @@ struct Instruction { // ----------------------------------------------------------------------------- : Variables -typedef unsigned int Variable; +// for faster lookup from code +enum Variable +{ SCRIPT_VAR_input +, SCRIPT_VAR_in +, SCRIPT_VAR_match +, SCRIPT_VAR_replace +, SCRIPT_VAR_order +, SCRIPT_VAR_filter +, SCRIPT_VAR_choice +, SCRIPT_VAR_format +, SCRIPT_VAR_tag +, SCRIPT_VAR_contents +, SCRIPT_VAR_set +, SCRIPT_VAR_game +, SCRIPT_VAR_stylesheet +, SCRIPT_VAR_card_style +, SCRIPT_VAR_card +, SCRIPT_VAR_styling +, SCRIPT_VAR_value +, SCRIPT_VAR_CUSTOM_FIRST // other variables start from here +, SCRIPT_VAR_CUSTOM_LOTS = 0xFFFFFF // ensure that sizeof(Variable) is large enough +}; /// Return a unique name for a variable to allow for faster loopups Variable string_to_variable(const String& s); @@ -108,6 +129,10 @@ Variable string_to_variable(const String& s); */ String variable_to_string(Variable v); +/// initialze the script variables +void init_script_variables(); + + // ----------------------------------------------------------------------------- : Script /// A script that can be executed diff --git a/src/script/script_manager.cpp b/src/script/script_manager.cpp index aaab0929..33441c1c 100644 --- a/src/script/script_manager.cpp +++ b/src/script/script_manager.cpp @@ -54,12 +54,12 @@ Context& SetScriptContext::getContext(const StyleSheetP& stylesheet) { // NOTE: do not use a smart pointer for the pointer to the set, because the set owns this // which would lead to a reference cycle. init_script_functions(*ctx); - ctx->setVariable(_("set"), new_intrusive1 >(&set)); - ctx->setVariable(_("game"), to_script(set.game)); - ctx->setVariable(_("stylesheet"), to_script(stylesheet)); - ctx->setVariable(_("card style"), to_script(&stylesheet->card_style)); - ctx->setVariable(_("card"), set.cards.empty() ? script_nil : to_script(set.cards.front())); // dummy value - ctx->setVariable(_("styling"), to_script(&set.stylingDataFor(*stylesheet))); + ctx->setVariable(SCRIPT_VAR_set, new_intrusive1 >(&set)); + ctx->setVariable(SCRIPT_VAR_game, to_script(set.game)); + ctx->setVariable(SCRIPT_VAR_stylesheet, to_script(stylesheet)); + ctx->setVariable(SCRIPT_VAR_card_style, to_script(&stylesheet->card_style)); + ctx->setVariable(SCRIPT_VAR_card, set.cards.empty() ? script_nil : to_script(set.cards.front())); // dummy value + ctx->setVariable(SCRIPT_VAR_styling, to_script(&set.stylingDataFor(*stylesheet))); try { // perform init scripts, don't use a scope, variables stay bound in the context set.game ->init_script.invoke(*ctx, false); @@ -75,11 +75,11 @@ Context& SetScriptContext::getContext(const CardP& card) { StyleSheetP stylesheet = set.stylesheetForP(card); Context& ctx = getContext(stylesheet); if (card) { - ctx.setVariable(_("card"), to_script(card)); - ctx.setVariable(_("styling"), to_script(&set.stylingDataFor(card))); + ctx.setVariable(SCRIPT_VAR_card, to_script(card)); + ctx.setVariable(SCRIPT_VAR_styling, to_script(&set.stylingDataFor(card))); } else { - ctx.setVariable(_("card"), script_nil); - ctx.setVariable(_("styling"), to_script(&set.stylingDataFor(*stylesheet))); + ctx.setVariable(SCRIPT_VAR_card, script_nil); + ctx.setVariable(SCRIPT_VAR_styling, to_script(&set.stylingDataFor(*stylesheet))); } return ctx; } diff --git a/src/script/scriptable.hpp b/src/script/scriptable.hpp index 52291005..e5f52008 100644 --- a/src/script/scriptable.hpp +++ b/src/script/scriptable.hpp @@ -59,7 +59,7 @@ class OptionalScript { bool invokeOn(Context& ctx, T& value) const { if (script) { T new_value; - ctx.setVariable(_("value"), to_script(value)); + ctx.setVariable(SCRIPT_VAR_value, to_script(value)); store(ctx.eval(*script), new_value); if (value != new_value) { change(value, new_value); diff --git a/src/util/string.hpp b/src/util/string.hpp index 7768dd92..d052818f 100644 --- a/src/util/string.hpp +++ b/src/util/string.hpp @@ -82,7 +82,6 @@ void writeUTF8(wxTextOutputStream& stream, const String& str); // ----------------------------------------------------------------------------- : Char functions // Character set tests -inline bool isSpace(Char c) { return IF_UNICODE( iswspace(c) , isspace((unsigned char)c) ) || c == CONNECTION_SPACE; } inline bool isAlpha(Char c) { return IF_UNICODE( iswalpha(c) , isalpha((unsigned char)c) ); } inline bool isDigit(Char c) { return IF_UNICODE( iswdigit(c) , isdigit((unsigned char)c) ); } inline bool isAlnum(Char c) { return IF_UNICODE( iswalnum(c) , isalnum((unsigned char)c) ); } @@ -98,9 +97,17 @@ inline bool isPunct(Char c) { return IF_UNICODE( iswpunct(c) , ispunct((unsigned // If also in other compilers, they can also use these routines. Char toLower(Char c); Char toUpper(Char c); + inline bool isSpace(Char c) { + if (c <= 128) { + return (c >= 0x09 && c <= 0x0D) || c == 0x20; + } else { + return IF_UNICODE( iswspace(c) , isspace((unsigned char)c) ) || c == CONNECTION_SPACE; + } + } #else inline Char toLower(Char c) { return IF_UNICODE( towlower(c) , tolower(c) ); } inline Char toUpper(Char c) { return IF_UNICODE( towupper(c) , toupper(c) ); } + inline bool isSpace(Char c) { return IF_UNICODE( iswspace(c) , isspace((unsigned char)c) ) || c == CONNECTION_SPACE; } #endif // ----------------------------------------------------------------------------- : String utilities