Change tabs to two spaces.

This commit is contained in:
Lymia Aluysia
2017-01-18 08:43:21 -06:00
parent d7f5f0dc3b
commit d2c635f739
329 changed files with 41307 additions and 41496 deletions
File diff suppressed because it is too large Load Diff
+30 -30
View File
@@ -21,39 +21,39 @@
// ----------------------------------------------------------------------------- : new_card
SCRIPT_FUNCTION(new_card) {
SCRIPT_PARAM(GameP, game);
CardP new_card = intrusive(new Card(*game));
// set field values
SCRIPT_PARAM(ScriptValueP, input);
ScriptValueP it = input->makeIterator(input);
ScriptValueP key;
while (ScriptValueP v = it->next(&key)) {
assert(key);
String name = key->toString();
// find value to update
IndexMap<FieldP,ValueP>::const_iterator value_it = new_card->data.find(name);
if (value_it == new_card->data.end()) {
throw ScriptError(format_string(_("Card doesn't have a field named '%s'"),name));
}
Value* value = value_it->get();
// set the value
if (TextValue* tvalue = dynamic_cast<TextValue*>(value)) {
tvalue->value = v->toString();
} else if (ChoiceValue* cvalue = dynamic_cast<ChoiceValue*>(value)) {
cvalue->value = v->toString();
} else if (PackageChoiceValue* pvalue = dynamic_cast<PackageChoiceValue*>(value)) {
pvalue->package_name = v->toString();
} else if (ColorValue* cvalue = dynamic_cast<ColorValue*>(value)) {
cvalue->value = (AColor)*v;
} else {
throw ScriptError(format_string(_("Can not set value '%s', it is not of the right type"),name));
}
}
SCRIPT_RETURN(new_card);
SCRIPT_PARAM(GameP, game);
CardP new_card = intrusive(new Card(*game));
// set field values
SCRIPT_PARAM(ScriptValueP, input);
ScriptValueP it = input->makeIterator(input);
ScriptValueP key;
while (ScriptValueP v = it->next(&key)) {
assert(key);
String name = key->toString();
// find value to update
IndexMap<FieldP,ValueP>::const_iterator value_it = new_card->data.find(name);
if (value_it == new_card->data.end()) {
throw ScriptError(format_string(_("Card doesn't have a field named '%s'"),name));
}
Value* value = value_it->get();
// set the value
if (TextValue* tvalue = dynamic_cast<TextValue*>(value)) {
tvalue->value = v->toString();
} else if (ChoiceValue* cvalue = dynamic_cast<ChoiceValue*>(value)) {
cvalue->value = v->toString();
} else if (PackageChoiceValue* pvalue = dynamic_cast<PackageChoiceValue*>(value)) {
pvalue->package_name = v->toString();
} else if (ColorValue* cvalue = dynamic_cast<ColorValue*>(value)) {
cvalue->value = (AColor)*v;
} else {
throw ScriptError(format_string(_("Can not set value '%s', it is not of the right type"),name));
}
}
SCRIPT_RETURN(new_card);
}
// ----------------------------------------------------------------------------- : Init
void init_script_construction_functions(Context& ctx) {
ctx.setVariable(_("new card"), script_new_card);
ctx.setVariable(_("new card"), script_new_card);
}
+311 -311
View File
@@ -32,219 +32,219 @@ DECLARE_TYPEOF_COLLECTION(ChoiceField::ChoiceP);
//
SCRIPT_FUNCTION_WITH_DEP(combined_editor) {
// read 'field#' arguments
vector<TextValue*> values;
for (int i = 0 ; ; ++i) {
String name = _("field"); if (i > 0) name = name << i;
SCRIPT_OPTIONAL_PARAM_N(ValueP, name, value) {
TextValue* text_value = dynamic_cast<TextValue*>(value.get());
if (!text_value) throw ScriptError(_("Argument '")+name+_("' should be a text field"));
values.push_back(text_value);
} else if (i > 0) break;
}
if (values.empty()) {
throw ScriptError(_("No fields specified for combined_editor"));
}
// read 'separator#' arguments
vector<String> separators;
for (int i = 0 ; ; ++i) {
String name = _("separator"); if (i > 0) name = name << i;
SCRIPT_OPTIONAL_PARAM_N(String, name, separator) {
separators.push_back(separator);
} else if (i > 0) break;
}
if (separators.size() < values.size() - 1) {
throw ScriptError(String::Format(_("Not enough separators for combine_editor, expected %d"), values.size()-1));
}
// the value
SCRIPT_PARAM_C(String, value);
// remove suffix/prefix
SCRIPT_OPTIONAL_PARAM_(String, prefix);
SCRIPT_OPTIONAL_PARAM_(String, suffix);
if (is_substr(value,0,_("<prefix"))) {
value = value.substr(min(value.size(), match_close_tag_end(value, 0)));
}
size_t pos = value.rfind(_("<suffix"));
if (pos != String::npos && match_close_tag_end(value,pos) >= value.size()) {
value = value.substr(0, pos);
}
// split the value
vector<pair<String,bool> > value_parts; // (value part, is empty)
pos = value.find(_("<sep"));
while (pos != String::npos) {
String part = value.substr(0, pos);
value_parts.push_back(make_pair(part, false));
value = value.substr(min(match_close_tag_end(value,pos), value.size()));
pos = value.find(_("<sep"));
}
value_parts.push_back(make_pair(value, false));
value_parts.resize(values.size()); // TODO: what if there are more value_parts than values?
// update the values if our input value is newer?
Age new_value_update = last_update_age();
FOR_EACH_2(v, values, nv, value_parts) {
//if (v->value() != nv.first && v->last_update < new_value_update) {
if (v->last_update < new_value_update) {
bool changed = v->value() != nv.first;
v->value.assign(nv.first);
changed |= v->update(ctx);
v->last_update = new_value_update;
if (changed) { // notify of change
SCRIPT_OPTIONAL_PARAM_(CardP, card);
SCRIPT_PARAM(Set*, set);
ScriptValueEvent change(card.get(), v);
set->actions.tellListeners(change, false);
}
}
nv.first = v->value();
nv.second = index_to_untagged(nv.first, nv.first.size()) == 0;
}
// options
SCRIPT_PARAM_DEFAULT_N(bool, _("hide when empty"), hide_when_empty, false);
SCRIPT_PARAM_DEFAULT_N(bool, _("soft before empty"), soft_before_empty, false);
// recombine the parts
String new_value = value_parts.front().first;
bool new_value_empty = value_parts.front().second;
size_t size_before_last = 0;
for (size_t i = 1 ; i < value_parts.size() ; ++i) {
size_before_last = new_value.size();
if (value_parts[i].second && new_value_empty && hide_when_empty) {
// no separator
} else if (value_parts[i].second && soft_before_empty) {
// soft separator
new_value += _("<sep-soft>") + separators[i - 1] + _("</sep-soft>");
new_value_empty = false;
} else {
// normal separator
new_value += _("<sep>") + separators[i - 1] + _("</sep>");
new_value_empty = false;
}
new_value += value_parts[i].first;
}
if (!new_value_empty || !hide_when_empty) {
if (!suffix.empty()) {
if (is_substr(new_value, size_before_last, _("<sep-soft>")) && value_parts.size() >= 2) {
// If the value ends in a soft separator, we have this situation:
// [blah]<sep-soft>ABC</sep-soft><suffix>XYZ</suffix>
// This renderes as:
// [blah] XYZ
// Which looks bad, so instead change the text to
// [blah]<sep>XYZ<soft>ABC</soft></sep>
// Which might be slightly incorrect, but soft text doesn't matter anyway.
size_t after = min(new_value.size(), match_close_tag_end(new_value, size_before_last));
new_value = new_value.substr(0, size_before_last)
+ _("<sep>")
+ suffix
+ _("<soft>")
+ separators[value_parts.size() - 2]
+ _("</soft></sep>")
+ new_value.substr(after);
} else {
new_value += _("<suffix>") + suffix + _("</suffix>");
}
}
if (!prefix.empty()) {
new_value = _("<prefix>") + prefix + _("</prefix>") + new_value;
}
}
SCRIPT_RETURN(new_value);
// read 'field#' arguments
vector<TextValue*> values;
for (int i = 0 ; ; ++i) {
String name = _("field"); if (i > 0) name = name << i;
SCRIPT_OPTIONAL_PARAM_N(ValueP, name, value) {
TextValue* text_value = dynamic_cast<TextValue*>(value.get());
if (!text_value) throw ScriptError(_("Argument '")+name+_("' should be a text field"));
values.push_back(text_value);
} else if (i > 0) break;
}
if (values.empty()) {
throw ScriptError(_("No fields specified for combined_editor"));
}
// read 'separator#' arguments
vector<String> separators;
for (int i = 0 ; ; ++i) {
String name = _("separator"); if (i > 0) name = name << i;
SCRIPT_OPTIONAL_PARAM_N(String, name, separator) {
separators.push_back(separator);
} else if (i > 0) break;
}
if (separators.size() < values.size() - 1) {
throw ScriptError(String::Format(_("Not enough separators for combine_editor, expected %d"), values.size()-1));
}
// the value
SCRIPT_PARAM_C(String, value);
// remove suffix/prefix
SCRIPT_OPTIONAL_PARAM_(String, prefix);
SCRIPT_OPTIONAL_PARAM_(String, suffix);
if (is_substr(value,0,_("<prefix"))) {
value = value.substr(min(value.size(), match_close_tag_end(value, 0)));
}
size_t pos = value.rfind(_("<suffix"));
if (pos != String::npos && match_close_tag_end(value,pos) >= value.size()) {
value = value.substr(0, pos);
}
// split the value
vector<pair<String,bool> > value_parts; // (value part, is empty)
pos = value.find(_("<sep"));
while (pos != String::npos) {
String part = value.substr(0, pos);
value_parts.push_back(make_pair(part, false));
value = value.substr(min(match_close_tag_end(value,pos), value.size()));
pos = value.find(_("<sep"));
}
value_parts.push_back(make_pair(value, false));
value_parts.resize(values.size()); // TODO: what if there are more value_parts than values?
// update the values if our input value is newer?
Age new_value_update = last_update_age();
FOR_EACH_2(v, values, nv, value_parts) {
//if (v->value() != nv.first && v->last_update < new_value_update) {
if (v->last_update < new_value_update) {
bool changed = v->value() != nv.first;
v->value.assign(nv.first);
changed |= v->update(ctx);
v->last_update = new_value_update;
if (changed) { // notify of change
SCRIPT_OPTIONAL_PARAM_(CardP, card);
SCRIPT_PARAM(Set*, set);
ScriptValueEvent change(card.get(), v);
set->actions.tellListeners(change, false);
}
}
nv.first = v->value();
nv.second = index_to_untagged(nv.first, nv.first.size()) == 0;
}
// options
SCRIPT_PARAM_DEFAULT_N(bool, _("hide when empty"), hide_when_empty, false);
SCRIPT_PARAM_DEFAULT_N(bool, _("soft before empty"), soft_before_empty, false);
// recombine the parts
String new_value = value_parts.front().first;
bool new_value_empty = value_parts.front().second;
size_t size_before_last = 0;
for (size_t i = 1 ; i < value_parts.size() ; ++i) {
size_before_last = new_value.size();
if (value_parts[i].second && new_value_empty && hide_when_empty) {
// no separator
} else if (value_parts[i].second && soft_before_empty) {
// soft separator
new_value += _("<sep-soft>") + separators[i - 1] + _("</sep-soft>");
new_value_empty = false;
} else {
// normal separator
new_value += _("<sep>") + separators[i - 1] + _("</sep>");
new_value_empty = false;
}
new_value += value_parts[i].first;
}
if (!new_value_empty || !hide_when_empty) {
if (!suffix.empty()) {
if (is_substr(new_value, size_before_last, _("<sep-soft>")) && value_parts.size() >= 2) {
// If the value ends in a soft separator, we have this situation:
// [blah]<sep-soft>ABC</sep-soft><suffix>XYZ</suffix>
// This renderes as:
// [blah] XYZ
// Which looks bad, so instead change the text to
// [blah]<sep>XYZ<soft>ABC</soft></sep>
// Which might be slightly incorrect, but soft text doesn't matter anyway.
size_t after = min(new_value.size(), match_close_tag_end(new_value, size_before_last));
new_value = new_value.substr(0, size_before_last)
+ _("<sep>")
+ suffix
+ _("<soft>")
+ separators[value_parts.size() - 2]
+ _("</soft></sep>")
+ new_value.substr(after);
} else {
new_value += _("<suffix>") + suffix + _("</suffix>");
}
}
if (!prefix.empty()) {
new_value = _("<prefix>") + prefix + _("</prefix>") + new_value;
}
}
SCRIPT_RETURN(new_value);
}
SCRIPT_FUNCTION_DEPENDENCIES(combined_editor) {
// read 'field#' arguments
vector<FieldP> fields;
for (int i = 0 ; ; ++i) {
String name = _("field"); if (i > 0) name = name << i;
SCRIPT_OPTIONAL_PARAM_N(ValueP, name, value) {
fields.push_back(value->fieldP);
} else if (i > 0) break;
}
// Find the target field
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];
else if (dep.type == DEP_SET_FIELD) target_field = game->set_fields[dep.index];
else if (dep.type == DEP_EXTRA_CARD_FIELD) {
SCRIPT_PARAM_C(StyleSheetP, stylesheet);
target_field = stylesheet->extra_card_fields[dep.index];
}
else throw InternalError(_("Finding dependencies of combined error for non card/set field"));
// Add dependencies, from target_field on field#
// For card fields
size_t j = 0;
FOR_EACH(f, game->card_fields) {
Dependency dep(DEP_CARD_COPY_DEP, j++);
FOR_EACH(fn, fields) {
if (f == fn) {
target_field->dependent_scripts.add(dep);
break;
}
}
}
// For set fields
j = 0;
FOR_EACH(f, game->set_fields) {
Dependency dep(DEP_SET_COPY_DEP, j++);
FOR_EACH(fn, fields) {
if (f == fn) {
target_field->dependent_scripts.add(dep);
break;
}
}
}
return dependency_dummy;
// read 'field#' arguments
vector<FieldP> fields;
for (int i = 0 ; ; ++i) {
String name = _("field"); if (i > 0) name = name << i;
SCRIPT_OPTIONAL_PARAM_N(ValueP, name, value) {
fields.push_back(value->fieldP);
} else if (i > 0) break;
}
// Find the target field
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];
else if (dep.type == DEP_SET_FIELD) target_field = game->set_fields[dep.index];
else if (dep.type == DEP_EXTRA_CARD_FIELD) {
SCRIPT_PARAM_C(StyleSheetP, stylesheet);
target_field = stylesheet->extra_card_fields[dep.index];
}
else throw InternalError(_("Finding dependencies of combined error for non card/set field"));
// Add dependencies, from target_field on field#
// For card fields
size_t j = 0;
FOR_EACH(f, game->card_fields) {
Dependency dep(DEP_CARD_COPY_DEP, j++);
FOR_EACH(fn, fields) {
if (f == fn) {
target_field->dependent_scripts.add(dep);
break;
}
}
}
// For set fields
j = 0;
FOR_EACH(f, game->set_fields) {
Dependency dep(DEP_SET_COPY_DEP, j++);
FOR_EACH(fn, fields) {
if (f == fn) {
target_field->dependent_scripts.add(dep);
break;
}
}
}
return dependency_dummy;
}
// ----------------------------------------------------------------------------- : Choice values
// convert a full choice name into the name of the top level group it is in
SCRIPT_FUNCTION(primary_choice) {
SCRIPT_PARAM_C(ValueP,input);
ChoiceValueP value = dynamic_pointer_cast<ChoiceValue>(input);
if (!value) {
throw ScriptError(_("Argument to 'primary_choice' should be a choice value"));
}
// determine choice
int id = value->field().choices->choiceId(value->value);
// find the last group that still contains id
const vector<ChoiceField::ChoiceP>& choices = value->field().choices->choices;
FOR_EACH_CONST_REVERSE(c, choices) {
if (id >= c->first_id) {
SCRIPT_RETURN(c->name);
}
}
SCRIPT_RETURN(_(""));
SCRIPT_PARAM_C(ValueP,input);
ChoiceValueP value = dynamic_pointer_cast<ChoiceValue>(input);
if (!value) {
throw ScriptError(_("Argument to 'primary_choice' should be a choice value"));
}
// determine choice
int id = value->field().choices->choiceId(value->value);
// find the last group that still contains id
const vector<ChoiceField::ChoiceP>& choices = value->field().choices->choices;
FOR_EACH_CONST_REVERSE(c, choices) {
if (id >= c->first_id) {
SCRIPT_RETURN(c->name);
}
}
SCRIPT_RETURN(_(""));
}
// ----------------------------------------------------------------------------- : Multiple choice values
/// Iterate over a comma separated list
bool next_choice(size_t& start, size_t& end, const String& input) {
if (start >= input.size()) return false;
// ingore whitespace
while (start < input.size() && input.GetChar(start) == _(' ')) ++start;
// find end
end = input.find_first_of(_(','), start);
if (end == String::npos) end = input.size();
return true;
if (start >= input.size()) return false;
// ingore whitespace
while (start < input.size() && input.GetChar(start) == _(' ')) ++start;
// find end
end = input.find_first_of(_(','), start);
if (end == String::npos) end = input.size();
return true;
}
/// Is the given choice active?
bool chosen(const String& choice, const String& input) {
for (size_t start = 0, end = 0 ; next_choice(start,end,input) ; start = end+1 ) {
// does this choice match the one asked about?
if (end - start == choice.size() && is_substr(input, start, choice)) {
return true;
}
}
return false;
for (size_t start = 0, end = 0 ; next_choice(start,end,input) ; start = end+1 ) {
// does this choice match the one asked about?
if (end - start == choice.size() && is_substr(input, start, choice)) {
return true;
}
}
return false;
}
// is the given choice active?
SCRIPT_FUNCTION(chosen) {
SCRIPT_PARAM_C(String,choice);
SCRIPT_PARAM_C(String,input);
SCRIPT_RETURN(chosen(choice, input));
SCRIPT_PARAM_C(String,choice);
SCRIPT_PARAM_C(String,input);
SCRIPT_RETURN(chosen(choice, input));
}
/// Filter the choices
@@ -252,154 +252,154 @@ SCRIPT_FUNCTION(chosen) {
* and at least min. Use prefered as choice to add/keep in case of conflicts.
*/
String filter_choices(const String& input, const vector<String>& choices, int min, int max, String prefered) {
if (choices.empty()) return input; // do nothing, shouldn't happen, but better make sure
String ret;
int count = 0;
vector<bool> seen(choices.size()); // which choices have we seen in input?
// walk over the input
for (size_t start = 0, end = 0 ; next_choice(start,end,input) ; start = end +1) {
// is this choice in choices
bool in_choices = false;
for (size_t i = 0 ; i < choices.size() ; ++i) {
if (!seen[i] && is_substr(input, start, choices[i])) {
seen[i] = true; ++count;
in_choices = true;
break;
}
}
// is this choice unaffected?
if (!in_choices) {
if (!ret.empty()) ret += _(", ");
ret += input.substr(start, end - start);
}
}
// keep more choices
if (count < min) {
// add prefered choice
for (size_t i = 0 ; i < choices.size() ; ++i) {
if (choices[i] == prefered) {
if (!seen[i]) {
seen[i] = true; ++count;
}
break;
}
}
// add more choices
for (size_t i = 0 ; i < choices.size() ; ++i) {
if (count >= min) break;
if (!seen[i]) {
seen[i] = true; ++count;
}
}
}
// keep less choices
if (count > max) {
for (size_t i = choices.size() - 1 ; i >= 0 ; --i) {
if (count <= max) break;
if (seen[i]) {
if (max > 0 && choices[i] == prefered) continue; // we would rather not remove prefered choice
seen[i] = false; --count;
}
}
}
// add the 'seen' choices to ret
for (size_t i = 0 ; i < choices.size() ; ++i) {
if (seen[i]) {
if (!ret.empty()) ret += _(", ");
ret += choices[i];
}
}
return ret;
if (choices.empty()) return input; // do nothing, shouldn't happen, but better make sure
String ret;
int count = 0;
vector<bool> seen(choices.size()); // which choices have we seen in input?
// walk over the input
for (size_t start = 0, end = 0 ; next_choice(start,end,input) ; start = end +1) {
// is this choice in choices
bool in_choices = false;
for (size_t i = 0 ; i < choices.size() ; ++i) {
if (!seen[i] && is_substr(input, start, choices[i])) {
seen[i] = true; ++count;
in_choices = true;
break;
}
}
// is this choice unaffected?
if (!in_choices) {
if (!ret.empty()) ret += _(", ");
ret += input.substr(start, end - start);
}
}
// keep more choices
if (count < min) {
// add prefered choice
for (size_t i = 0 ; i < choices.size() ; ++i) {
if (choices[i] == prefered) {
if (!seen[i]) {
seen[i] = true; ++count;
}
break;
}
}
// add more choices
for (size_t i = 0 ; i < choices.size() ; ++i) {
if (count >= min) break;
if (!seen[i]) {
seen[i] = true; ++count;
}
}
}
// keep less choices
if (count > max) {
for (size_t i = choices.size() - 1 ; i >= 0 ; --i) {
if (count <= max) break;
if (seen[i]) {
if (max > 0 && choices[i] == prefered) continue; // we would rather not remove prefered choice
seen[i] = false; --count;
}
}
}
// add the 'seen' choices to ret
for (size_t i = 0 ; i < choices.size() ; ++i) {
if (seen[i]) {
if (!ret.empty()) ret += _(", ");
ret += choices[i];
}
}
return ret;
}
// read 'choice#' arguments
void read_choices_param(Context& ctx, vector<String>& choices_out) {
SCRIPT_OPTIONAL_PARAM_C(String,choices) {
for (size_t start = 0, end = 0 ; next_choice(start,end,choices) ; start = end + 1) {
choices_out.push_back(choices.substr(start,end-start));
}
} else {
// old style: separate arguments
SCRIPT_OPTIONAL_PARAM_C(String,choice) {
choices_out.push_back(choice);
} else {
for (int i = 1 ; ; ++i) {
String name = _("choice");
SCRIPT_OPTIONAL_PARAM_N(String, name << i, choice) {
choices_out.push_back(choice);
} else break;
}
}
}
SCRIPT_OPTIONAL_PARAM_C(String,choices) {
for (size_t start = 0, end = 0 ; next_choice(start,end,choices) ; start = end + 1) {
choices_out.push_back(choices.substr(start,end-start));
}
} else {
// old style: separate arguments
SCRIPT_OPTIONAL_PARAM_C(String,choice) {
choices_out.push_back(choice);
} else {
for (int i = 1 ; ; ++i) {
String name = _("choice");
SCRIPT_OPTIONAL_PARAM_N(String, name << i, choice) {
choices_out.push_back(choice);
} else break;
}
}
}
}
// add the given choice if it is not already active
SCRIPT_FUNCTION(require_choice) {
SCRIPT_PARAM_C(String,input);
SCRIPT_OPTIONAL_PARAM_N_(String,_("last change"),last_change);
vector<String> choices;
read_choices_param(ctx, choices);
SCRIPT_RETURN(filter_choices(input, choices, 1, (int)choices.size(), last_change));
SCRIPT_PARAM_C(String,input);
SCRIPT_OPTIONAL_PARAM_N_(String,_("last change"),last_change);
vector<String> choices;
read_choices_param(ctx, choices);
SCRIPT_RETURN(filter_choices(input, choices, 1, (int)choices.size(), last_change));
}
// make sure at most one of the choices is active
SCRIPT_FUNCTION(exclusive_choice) {
SCRIPT_PARAM_C(String,input);
SCRIPT_OPTIONAL_PARAM_N_(String,_("last change"),last_change);
vector<String> choices;
read_choices_param(ctx, choices);
SCRIPT_RETURN(filter_choices(input, choices, 0, 1, last_change));
SCRIPT_PARAM_C(String,input);
SCRIPT_OPTIONAL_PARAM_N_(String,_("last change"),last_change);
vector<String> choices;
read_choices_param(ctx, choices);
SCRIPT_RETURN(filter_choices(input, choices, 0, 1, last_change));
}
// make sure exactly one of the choices is active
SCRIPT_FUNCTION(require_exclusive_choice) {
SCRIPT_PARAM_C(String,input);
SCRIPT_OPTIONAL_PARAM_N_(String,_("last change"),last_change);
vector<String> choices;
read_choices_param(ctx, choices);
SCRIPT_RETURN(filter_choices(input, choices, 1, 1, last_change));
SCRIPT_PARAM_C(String,input);
SCRIPT_OPTIONAL_PARAM_N_(String,_("last change"),last_change);
vector<String> choices;
read_choices_param(ctx, choices);
SCRIPT_RETURN(filter_choices(input, choices, 1, 1, last_change));
}
// make sure none of the choices are active
SCRIPT_FUNCTION(remove_choice) {
SCRIPT_PARAM_C(String,input);
vector<String> choices;
read_choices_param(ctx, choices);
SCRIPT_RETURN(filter_choices(input, choices, 0, 0, _("")));
SCRIPT_PARAM_C(String,input);
vector<String> choices;
read_choices_param(ctx, choices);
SCRIPT_RETURN(filter_choices(input, choices, 0, 0, _("")));
}
// count how many choices are active
SCRIPT_FUNCTION(count_chosen) {
SCRIPT_PARAM_C(String,input);
SCRIPT_OPTIONAL_PARAM_C(String,choices) {
// only count specific choices
int count = 0;
for (size_t start = 0, end = 0 ; next_choice(start,end,choices) ; start = end + 1) {
if (chosen(choices.substr(start,end-start),input)) ++count;
}
SCRIPT_RETURN(count);
} else {
// count all choices => count comma's + 1
if (input.empty()) {
SCRIPT_RETURN(0);
} else {
int count = 1;
FOR_EACH(c, input) if (c == _(',')) ++count;
SCRIPT_RETURN(count);
}
}
SCRIPT_PARAM_C(String,input);
SCRIPT_OPTIONAL_PARAM_C(String,choices) {
// only count specific choices
int count = 0;
for (size_t start = 0, end = 0 ; next_choice(start,end,choices) ; start = end + 1) {
if (chosen(choices.substr(start,end-start),input)) ++count;
}
SCRIPT_RETURN(count);
} else {
// count all choices => count comma's + 1
if (input.empty()) {
SCRIPT_RETURN(0);
} else {
int count = 1;
FOR_EACH(c, input) if (c == _(',')) ++count;
SCRIPT_RETURN(count);
}
}
}
// ----------------------------------------------------------------------------- : Init
void init_script_editor_functions(Context& ctx) {
ctx.setVariable(_("forward editor"), script_combined_editor); // compatability
ctx.setVariable(_("combined editor"), script_combined_editor);
ctx.setVariable(_("primary choice"), script_primary_choice);
ctx.setVariable(_("chosen"), script_chosen);
ctx.setVariable(_("count chosen"), script_count_chosen);
ctx.setVariable(_("require choice"), script_require_choice);
ctx.setVariable(_("exclusive choice"), script_exclusive_choice);
ctx.setVariable(_("require exclusive choice"), script_require_exclusive_choice);
ctx.setVariable(_("remove choice"), script_remove_choice);
ctx.setVariable(_("forward editor"), script_combined_editor); // compatability
ctx.setVariable(_("combined editor"), script_combined_editor);
ctx.setVariable(_("primary choice"), script_primary_choice);
ctx.setVariable(_("chosen"), script_chosen);
ctx.setVariable(_("count chosen"), script_count_chosen);
ctx.setVariable(_("require choice"), script_require_choice);
ctx.setVariable(_("exclusive choice"), script_exclusive_choice);
ctx.setVariable(_("require exclusive choice"), script_require_exclusive_choice);
ctx.setVariable(_("remove choice"), script_remove_choice);
}
+251 -251
View File
@@ -15,208 +15,208 @@
// ----------------------------------------------------------------------------- : Util
bool is_vowel(Char c) {
return c == _('a') || c == _('e') || c == _('i') || c == _('o') || c == _('u')
|| c == _('A') || c == _('E') || c == _('I') || c == _('O') || c == _('U');
return c == _('a') || c == _('e') || c == _('i') || c == _('o') || c == _('u')
|| c == _('A') || c == _('E') || c == _('I') || c == _('O') || c == _('U');
}
inline bool is_constant(Char c) {
return !is_vowel(c);
return !is_vowel(c);
}
// ----------------------------------------------------------------------------- : Numbers
/// Write a number using words, for example 23 -> "twenty-three"
String english_number(int i) {
switch (i) {
case 0: return _("zero");
case 1: return _("one");
case 2: return _("two");
case 3: return _("three");
case 4: return _("four");
case 5: return _("five");
case 6: return _("six");
case 7: return _("seven");
case 8: return _("eight");
case 9: return _("nine");
case 10: return _("ten");
case 11: return _("eleven");
case 12: return _("twelve");
case 13: return _("thirteen");
case 15: return _("fifteen");
case 18: return _("eighteen");
case 20: return _("twenty");
case 30: return _("thirty");
case 40: return _("forty");
case 50: return _("fifty");
case 80: return _("eighty");
default: {
if (i < 0 || i >= 100) {
// number too large, keep as digits
return (String() << i);
} else if (i < 20) {
return english_number(i%10) + _("teen");
} else if (i % 10 == 0) {
return english_number(i/10) + _("ty");
} else {
// <a>ty-<b>
return english_number(i/10*10) + _("-") + english_number(i%10);
}
}
}
switch (i) {
case 0: return _("zero");
case 1: return _("one");
case 2: return _("two");
case 3: return _("three");
case 4: return _("four");
case 5: return _("five");
case 6: return _("six");
case 7: return _("seven");
case 8: return _("eight");
case 9: return _("nine");
case 10: return _("ten");
case 11: return _("eleven");
case 12: return _("twelve");
case 13: return _("thirteen");
case 15: return _("fifteen");
case 18: return _("eighteen");
case 20: return _("twenty");
case 30: return _("thirty");
case 40: return _("forty");
case 50: return _("fifty");
case 80: return _("eighty");
default: {
if (i < 0 || i >= 100) {
// number too large, keep as digits
return (String() << i);
} else if (i < 20) {
return english_number(i%10) + _("teen");
} else if (i % 10 == 0) {
return english_number(i/10) + _("ty");
} else {
// <a>ty-<b>
return english_number(i/10*10) + _("-") + english_number(i%10);
}
}
}
}
/// Write an ordinal number using words, for example 23 -> "twenty-third"
String english_ordinal(int i) {
switch (i) {
case 1: return _("first");
case 2: return _("second");
case 3: return _("third");
case 5: return _("fifth");
case 8: return _("eighth");
case 9: return _("ninth");
case 11: return _("eleventh");
case 12: return _("twelfth");
default: {
if (i <= 0 || i >= 100) {
// number too large, keep as digits
return String::Format(_("%dth"), i);
} else if (i < 20) {
return english_number(i) + _("th");
} else if (i % 10 == 0) {
String num = english_number(i);
return num.substr(0,num.size()-1) + _("ieth"); // twentieth
} else {
// <a>ty-<b>th
return english_number(i/10*10) + _("-") + english_ordinal(i%10);
}
}
}
switch (i) {
case 1: return _("first");
case 2: return _("second");
case 3: return _("third");
case 5: return _("fifth");
case 8: return _("eighth");
case 9: return _("ninth");
case 11: return _("eleventh");
case 12: return _("twelfth");
default: {
if (i <= 0 || i >= 100) {
// number too large, keep as digits
return String::Format(_("%dth"), i);
} else if (i < 20) {
return english_number(i) + _("th");
} else if (i % 10 == 0) {
String num = english_number(i);
return num.substr(0,num.size()-1) + _("ieth"); // twentieth
} else {
// <a>ty-<b>th
return english_number(i/10*10) + _("-") + english_ordinal(i%10);
}
}
}
}
/// Write a number using words, use "a" for 1
String english_number_a(int i) {
if (i == 1) return _("a");
else return english_number(i);
if (i == 1) return _("a");
else return english_number(i);
}
/// Write a number using words, use "" for 1
String english_number_multiple(int i) {
if (i == 1) return _("");
else return english_number(i);
if (i == 1) return _("");
else return english_number(i);
}
// script_english_number_*
String do_english_num(String input, String(*fun)(int)) {
if (is_substr(input, 0, _("<param-"))) {
// a keyword parameter, of the form "<param->123</param->"
size_t start = skip_tag(input, 0);
if (start != String::npos) {
size_t end = input.find_first_of(_('<'), start);
if (end != String::npos) {
String is = input.substr(start, end - start);
long i = 0;
if (is.ToLong(&i)) {
if (i == 1) {
return _("<hint-1>") + substr_replace(input, start, end, fun(i));
} else {
return _("<hint-2>") + substr_replace(input, start, end, fun(i));
}
}
}
}
return _("<hint-2>") + input;
} else {
long i = 0;
if (input.ToLong(&i)) {
return fun(i);
}
return input;
}
if (is_substr(input, 0, _("<param-"))) {
// a keyword parameter, of the form "<param->123</param->"
size_t start = skip_tag(input, 0);
if (start != String::npos) {
size_t end = input.find_first_of(_('<'), start);
if (end != String::npos) {
String is = input.substr(start, end - start);
long i = 0;
if (is.ToLong(&i)) {
if (i == 1) {
return _("<hint-1>") + substr_replace(input, start, end, fun(i));
} else {
return _("<hint-2>") + substr_replace(input, start, end, fun(i));
}
}
}
}
return _("<hint-2>") + input;
} else {
long i = 0;
if (input.ToLong(&i)) {
return fun(i);
}
return input;
}
}
SCRIPT_FUNCTION(english_number) {
SCRIPT_PARAM_C(String, input);
SCRIPT_RETURN(do_english_num(input, english_number));
SCRIPT_PARAM_C(String, input);
SCRIPT_RETURN(do_english_num(input, english_number));
}
SCRIPT_FUNCTION(english_number_a) {
SCRIPT_PARAM_C(String, input);
SCRIPT_RETURN(do_english_num(input, english_number_a));
SCRIPT_PARAM_C(String, input);
SCRIPT_RETURN(do_english_num(input, english_number_a));
}
SCRIPT_FUNCTION(english_number_multiple) {
SCRIPT_PARAM_C(String, input);
SCRIPT_RETURN(do_english_num(input, english_number_multiple));
SCRIPT_PARAM_C(String, input);
SCRIPT_RETURN(do_english_num(input, english_number_multiple));
}
SCRIPT_FUNCTION(english_number_ordinal) {
SCRIPT_PARAM_C(String, input);
SCRIPT_RETURN(do_english_num(input, english_ordinal));
SCRIPT_PARAM_C(String, input);
SCRIPT_RETURN(do_english_num(input, english_ordinal));
}
// ----------------------------------------------------------------------------- : Singular/plural
String english_singular(const String& str) {
if (str.size() > 3 && is_substr(str, str.size()-3, _("ies"))) {
return str.substr(0, str.size() - 3) + _("y");
} else if (str.size() > 3 && is_substr(str, str.size()-3, _("oes"))) {
return str.substr(0, str.size() - 2);
} else if (str.size() > 4 && is_substr(str, str.size()-4, _("ches"))) {
return str.substr(0, str.size() - 2);
} else if (str.size() > 4 && is_substr(str, str.size()-4, _("shes"))) {
return str.substr(0, str.size() - 2);
} else if (str.size() > 4 && is_substr(str, str.size()-4, _("sses"))) {
return str.substr(0, str.size() - 2);
} else if (str.size() > 5 && is_substr(str, str.size()-3, _("ves")) && (is_substr(str, str.size()-5, _("el")) || is_substr(str, str.size()-5, _("ar")) )) {
return str.substr(0, str.size() - 3) + _("f");
} else if (str.size() > 1 && str.GetChar(str.size() - 1) == _('s')) {
return str.substr(0, str.size() - 1);
} else if (str.size() >= 3 && is_substr(str, str.size()-3, _("men"))) {
return str.substr(0, str.size() - 2) + _("an");
} else {
return str;
}
if (str.size() > 3 && is_substr(str, str.size()-3, _("ies"))) {
return str.substr(0, str.size() - 3) + _("y");
} else if (str.size() > 3 && is_substr(str, str.size()-3, _("oes"))) {
return str.substr(0, str.size() - 2);
} else if (str.size() > 4 && is_substr(str, str.size()-4, _("ches"))) {
return str.substr(0, str.size() - 2);
} else if (str.size() > 4 && is_substr(str, str.size()-4, _("shes"))) {
return str.substr(0, str.size() - 2);
} else if (str.size() > 4 && is_substr(str, str.size()-4, _("sses"))) {
return str.substr(0, str.size() - 2);
} else if (str.size() > 5 && is_substr(str, str.size()-3, _("ves")) && (is_substr(str, str.size()-5, _("el")) || is_substr(str, str.size()-5, _("ar")) )) {
return str.substr(0, str.size() - 3) + _("f");
} else if (str.size() > 1 && str.GetChar(str.size() - 1) == _('s')) {
return str.substr(0, str.size() - 1);
} else if (str.size() >= 3 && is_substr(str, str.size()-3, _("men"))) {
return str.substr(0, str.size() - 2) + _("an");
} else {
return str;
}
}
String english_plural(const String& str) {
if (str.size() > 2) {
Char a = str.GetChar(str.size() - 2);
Char b = str.GetChar(str.size() - 1);
if (b == _('y') && is_constant(a)) {
return str.substr(0, str.size() - 1) + _("ies");
} else if (b == _('o') && is_constant(a)) {
return str + _("es");
} else if ((a == _('s') || a == _('c')) && b == _('h')) {
return str + _("es");
} else if (b == _('s')) {
return str + _("es");
} else {
return str + _("s");
}
}
return str + _("s");
if (str.size() > 2) {
Char a = str.GetChar(str.size() - 2);
Char b = str.GetChar(str.size() - 1);
if (b == _('y') && is_constant(a)) {
return str.substr(0, str.size() - 1) + _("ies");
} else if (b == _('o') && is_constant(a)) {
return str + _("es");
} else if ((a == _('s') || a == _('c')) && b == _('h')) {
return str + _("es");
} else if (b == _('s')) {
return str + _("es");
} else {
return str + _("s");
}
}
return str + _("s");
}
// script_english_singular/plural/singplur
String do_english(String input, String(*fun)(const String&)) {
if (is_substr(input, 0, _("<param-"))) {
// a keyword parameter, of the form "<param->123</param->"
size_t start = skip_tag(input, 0);
if (start != String::npos) {
size_t end = input.find_first_of(_('<'), start);
if (end != String::npos) {
String is = input.substr(start, end - start);
return substr_replace(input, start, end, fun(is));
}
}
return input; // failed
} else {
return fun(input);
}
if (is_substr(input, 0, _("<param-"))) {
// a keyword parameter, of the form "<param->123</param->"
size_t start = skip_tag(input, 0);
if (start != String::npos) {
size_t end = input.find_first_of(_('<'), start);
if (end != String::npos) {
String is = input.substr(start, end - start);
return substr_replace(input, start, end, fun(is));
}
}
return input; // failed
} else {
return fun(input);
}
}
SCRIPT_FUNCTION(english_singular) {
SCRIPT_PARAM_C(String, input);
SCRIPT_RETURN(do_english(input, english_singular));
SCRIPT_PARAM_C(String, input);
SCRIPT_RETURN(do_english(input, english_singular));
}
SCRIPT_FUNCTION(english_plural) {
SCRIPT_PARAM_C(String, input);
SCRIPT_RETURN(do_english(input, english_plural));
SCRIPT_PARAM_C(String, input);
SCRIPT_RETURN(do_english(input, english_plural));
}
// ----------------------------------------------------------------------------- : Hints
@@ -235,110 +235,110 @@ SCRIPT_FUNCTION(english_plural) {
* Note: there is no close tags for hints
*/
String process_english_hints(const String& str) {
String ret; ret.reserve(str.size());
// have we seen a <hint-1/2>?
// 1 for singular, 2 for plural
int singplur = 0;
for (size_t i = 0 ; i < str.size() ; ) {
Char c = str.GetChar(i);
if (is_substr(str, i, _("<hint-"))) {
Char h = str.GetChar(i + 6); // hint code
if (h == _('1')) {
singplur = 1;
} else if (h == _('2')) {
singplur = 2;
}
i = skip_tag(str, i);
} else if (is_substr(str, i, _("<param-"))) {
size_t after = skip_tag(str, i);
if (after != String::npos) {
Char c = str.GetChar(after);
if (singplur == 1 && is_substr(str, after, _("a</param-"))) {
// a -> an, where the a originates from english_number_a(1)
size_t after_end = skip_tag(str,after+1);
if (after_end == String::npos) {
throw Error(_("Incomplete </param> tag"));
}
if (after_end != String::npos && after_end + 1 < str.size()
&& isSpace(str.GetChar(after_end)) && is_vowel(str.GetChar(after_end+1))) {
ret.append(str,i,after-i);
ret += _("an");
i = after + 1;
continue;
}
} else if (is_vowel(c) && ret.size() >= 2) {
// a -> an?
// is there "a" before this?
String last = ret.substr(ret.size() - 2);
if ( (ret.size() == 2 || !isAlpha(ret.GetChar(ret.size() - 3))) &&
(last == _("a ") || last == _("A ")) ) {
ret.insert(ret.size() - 1, _('n'));
}
} else if (is_substr(str, after, _("</param-")) && ret.size() >= 1 &&
ret.GetChar(ret.size() - 1) == _(' ')) {
// empty param, drop space before it
ret.resize(ret.size() - 1);
}
}
ret.append(str,i,min(after,str.size())-i);
i = after;
} else if (is_substr(str, i, _("<singular>"))) {
// singular -> keep, plural -> drop
size_t start = skip_tag(str, i);
size_t end = match_close_tag(str, start);
if (singplur == 1 && end != String::npos) {
ret += str.substr(start, end - start);
}
singplur = 0;
i = skip_tag(str, end);
} else if (is_substr(str, i, _("<plural>"))) {
// singular -> drop, plural -> keep
size_t start = skip_tag(str, i);
size_t end = match_close_tag(str, start);
if (singplur == 2 && end != String::npos) {
ret += str.substr(start, end - start);
}
singplur = 0;
i = skip_tag(str, end);
} else if (c == _('(') && singplur) {
// singular -> drop (...), plural -> keep it
size_t end = str.find_first_of(_(')'), i);
if (end != String::npos) {
if (singplur == 2) {
ret += str.substr(i + 1, end - i - 1);
}
i = end + 1;
} else { // handle like normal
ret += c;
++i;
}
singplur = 0;
} else if (c == _('<')) {
size_t after = skip_tag(str, i);
ret.append(str,i,min(after,str.size())-i);
i = after;
} else {
ret += c;
++i;
}
}
return ret;
String ret; ret.reserve(str.size());
// have we seen a <hint-1/2>?
// 1 for singular, 2 for plural
int singplur = 0;
for (size_t i = 0 ; i < str.size() ; ) {
Char c = str.GetChar(i);
if (is_substr(str, i, _("<hint-"))) {
Char h = str.GetChar(i + 6); // hint code
if (h == _('1')) {
singplur = 1;
} else if (h == _('2')) {
singplur = 2;
}
i = skip_tag(str, i);
} else if (is_substr(str, i, _("<param-"))) {
size_t after = skip_tag(str, i);
if (after != String::npos) {
Char c = str.GetChar(after);
if (singplur == 1 && is_substr(str, after, _("a</param-"))) {
// a -> an, where the a originates from english_number_a(1)
size_t after_end = skip_tag(str,after+1);
if (after_end == String::npos) {
throw Error(_("Incomplete </param> tag"));
}
if (after_end != String::npos && after_end + 1 < str.size()
&& isSpace(str.GetChar(after_end)) && is_vowel(str.GetChar(after_end+1))) {
ret.append(str,i,after-i);
ret += _("an");
i = after + 1;
continue;
}
} else if (is_vowel(c) && ret.size() >= 2) {
// a -> an?
// is there "a" before this?
String last = ret.substr(ret.size() - 2);
if ( (ret.size() == 2 || !isAlpha(ret.GetChar(ret.size() - 3))) &&
(last == _("a ") || last == _("A ")) ) {
ret.insert(ret.size() - 1, _('n'));
}
} else if (is_substr(str, after, _("</param-")) && ret.size() >= 1 &&
ret.GetChar(ret.size() - 1) == _(' ')) {
// empty param, drop space before it
ret.resize(ret.size() - 1);
}
}
ret.append(str,i,min(after,str.size())-i);
i = after;
} else if (is_substr(str, i, _("<singular>"))) {
// singular -> keep, plural -> drop
size_t start = skip_tag(str, i);
size_t end = match_close_tag(str, start);
if (singplur == 1 && end != String::npos) {
ret += str.substr(start, end - start);
}
singplur = 0;
i = skip_tag(str, end);
} else if (is_substr(str, i, _("<plural>"))) {
// singular -> drop, plural -> keep
size_t start = skip_tag(str, i);
size_t end = match_close_tag(str, start);
if (singplur == 2 && end != String::npos) {
ret += str.substr(start, end - start);
}
singplur = 0;
i = skip_tag(str, end);
} else if (c == _('(') && singplur) {
// singular -> drop (...), plural -> keep it
size_t end = str.find_first_of(_(')'), i);
if (end != String::npos) {
if (singplur == 2) {
ret += str.substr(i + 1, end - i - 1);
}
i = end + 1;
} else { // handle like normal
ret += c;
++i;
}
singplur = 0;
} else if (c == _('<')) {
size_t after = skip_tag(str, i);
ret.append(str,i,min(after,str.size())-i);
i = after;
} else {
ret += c;
++i;
}
}
return ret;
}
SCRIPT_FUNCTION(process_english_hints) {
SCRIPT_PARAM_C(String, input);
assert_tagged(input);
SCRIPT_RETURN(process_english_hints(input));
SCRIPT_PARAM_C(String, input);
assert_tagged(input);
SCRIPT_RETURN(process_english_hints(input));
}
// ----------------------------------------------------------------------------- : Init
void init_script_english_functions(Context& ctx) {
ctx.setVariable(_("english number"), script_english_number);
ctx.setVariable(_("english number a"), script_english_number_a);
ctx.setVariable(_("english number multiple"), script_english_number_multiple);
ctx.setVariable(_("english number ordinal"), script_english_number_ordinal);
ctx.setVariable(_("english singular"), script_english_singular);
ctx.setVariable(_("english plural"), script_english_plural);
ctx.setVariable(_("process english hints"), script_process_english_hints);
ctx.setVariable(_("english number"), script_english_number);
ctx.setVariable(_("english number a"), script_english_number_a);
ctx.setVariable(_("english number multiple"), script_english_number_multiple);
ctx.setVariable(_("english number ordinal"), script_english_number_ordinal);
ctx.setVariable(_("english singular"), script_english_singular);
ctx.setVariable(_("english plural"), script_english_plural);
ctx.setVariable(_("process english hints"), script_process_english_hints);
}
+349 -349
View File
@@ -27,65 +27,65 @@ DECLARE_TYPEOF_COLLECTION(SymbolFont::DrawableSymbol);
// Make sure we can export files to a data directory
void guard_export_info(const String& fun, bool need_template = false) {
if (!export_info() && (!need_template || export_info()->export_template)) {
throw ScriptError(_("Can only use ") + fun + _(" from export templates"));
} else if (export_info()->directory_relative.empty()) {
throw ScriptError(_("Can only use ") + fun + _(" when 'create directory' is set to true"));
}
if (!export_info() && (!need_template || export_info()->export_template)) {
throw ScriptError(_("Can only use ") + fun + _(" from export templates"));
} else if (export_info()->directory_relative.empty()) {
throw ScriptError(_("Can only use ") + fun + _(" when 'create directory' is set to true"));
}
}
/// Find an absolute filename for a relative filename from an export template,
/// Returns the absolute filename, and may modify the relative name.
String get_export_full_path(String& rel_name) {
ExportInfo& ei = *export_info();
// the absolute path
wxFileName fn(rel_name);
fn.Normalize(wxPATH_NORM_ALL, ei.directory_absolute);
if (!ei.allow_writes_outside) {
// check if path is okay
wxFileName fn2(_("x"));
fn2.SetPath(ei.directory_absolute);
fn2.Normalize(wxPATH_NORM_ALL, ei.directory_absolute);
String p1 = fn.GetFullPath();
String p2 = fn2.GetFullPath();
p2.resize(p2.size() - 1); // drop the x
if (p2.empty() || p1.size() < p2.size() || p1.substr(0,p2.size()-1) != p2.substr(0,p2.size()-1)) {
throw ScriptError(_("Not a relative filename: ") + rel_name);
}
}
rel_name = fn.GetFullName();
return fn.GetFullPath();
ExportInfo& ei = *export_info();
// the absolute path
wxFileName fn(rel_name);
fn.Normalize(wxPATH_NORM_ALL, ei.directory_absolute);
if (!ei.allow_writes_outside) {
// check if path is okay
wxFileName fn2(_("x"));
fn2.SetPath(ei.directory_absolute);
fn2.Normalize(wxPATH_NORM_ALL, ei.directory_absolute);
String p1 = fn.GetFullPath();
String p2 = fn2.GetFullPath();
p2.resize(p2.size() - 1); // drop the x
if (p2.empty() || p1.size() < p2.size() || p1.substr(0,p2.size()-1) != p2.substr(0,p2.size()-1)) {
throw ScriptError(_("Not a relative filename: ") + rel_name);
}
}
rel_name = fn.GetFullName();
return fn.GetFullPath();
}
// ----------------------------------------------------------------------------- : HTML
// An HTML tag
struct Tag {
Tag(const Char* open_tag, const Char* close_tag)
: open_tag(open_tag), close_tag(close_tag), opened(0)
{}
const Char* open_tag; ///< The tags to insert in HTML "<tag>"
const Char* close_tag; ///< The tags to insert in HTML "</tag>"
int opened; ///< How often is the tag opened in the input?
/// Write an open or close tag to a string if needed
void write(String& ret, bool close) {
if (close) {
if (--opened == 0) {
ret += close_tag;
}
} else {
if (++opened == 1) {
ret += open_tag;
}
}
}
Tag(const Char* open_tag, const Char* close_tag)
: open_tag(open_tag), close_tag(close_tag), opened(0)
{}
const Char* open_tag; ///< The tags to insert in HTML "<tag>"
const Char* close_tag; ///< The tags to insert in HTML "</tag>"
int opened; ///< How often is the tag opened in the input?
/// Write an open or close tag to a string if needed
void write(String& ret, bool close) {
if (close) {
if (--opened == 0) {
ret += close_tag;
}
} else {
if (++opened == 1) {
ret += open_tag;
}
}
}
};
// A tag, or a close tag
struct NegTag {
Tag* tag;
bool neg; // a close tag instead of an open tag
NegTag(Tag* tag, bool neg) : tag(tag), neg(neg) {}
Tag* tag;
bool neg; // a close tag instead of an open tag
NegTag(Tag* tag, bool neg) : tag(tag), neg(neg) {}
};
DECLARE_TYPEOF_COLLECTION(NegTag);
@@ -93,371 +93,371 @@ DECLARE_TYPEOF_COLLECTION(NegTag);
/// A stack of opened HTML tags
class TagStack {
public:
void open(String& ret, Tag& tag) {
add(ret, NegTag(&tag, false));
}
void close(String& ret, Tag& tag) {
add(ret, NegTag(&tag, true));
}
// Close all tags, should be called at end of input
void close_all(String& ret) {
// cancel out tags with pending tags
write_pending_tags(ret);
// close all open tags
while (!tags.empty()) {
tags.back()->write(ret, true);
tags.pop_back();
}
}
// Write all pending tags, should be called before non-tag output
void write_pending_tags(String& ret) {
FOR_EACH(t, pending_tags) {
t.tag->write(ret, t.neg);
if (!t.neg) tags.push_back(t.tag);
}
pending_tags.clear();
}
void open(String& ret, Tag& tag) {
add(ret, NegTag(&tag, false));
}
void close(String& ret, Tag& tag) {
add(ret, NegTag(&tag, true));
}
// Close all tags, should be called at end of input
void close_all(String& ret) {
// cancel out tags with pending tags
write_pending_tags(ret);
// close all open tags
while (!tags.empty()) {
tags.back()->write(ret, true);
tags.pop_back();
}
}
// Write all pending tags, should be called before non-tag output
void write_pending_tags(String& ret) {
FOR_EACH(t, pending_tags) {
t.tag->write(ret, t.neg);
if (!t.neg) tags.push_back(t.tag);
}
pending_tags.clear();
}
private:
vector<Tag*> tags; ///< Tags opened in the html output
vector<NegTag> pending_tags; ///< Tags opened in the tagged string, but not (yet) in the output
void add(String& ret, const NegTag& tag) {
// Cancel out with pending tag?
for (int i = (int)pending_tags.size() - 1 ; i >= 0 ; --i) {
if (pending_tags[i].tag == tag.tag) {
if (pending_tags[i].neg != tag.neg) {
pending_tags.erase(pending_tags.begin() + i);
return;
} else {
break; // look no further
}
}
}
// Cancel out with existing tag?
if (tag.neg) {
for (int i = (int)tags.size() - 1 ; i >= 0 ; --i) {
if (tags[i] == tag.tag) {
// cancel out with existing tag i, e.g. <b>:
// situation was <a><b><c>text
// situation will become <a><b><c>text</c></b><c>
vector<NegTag> reopen;
for (int j = (int)tags.size() - 1 ; j > i ; --j) {
pending_tags.push_back(NegTag(tags[j], true)); // close tag, top down
tags.pop_back();
}
pending_tags.push_back(tag); // now close tag i
for (int j = i + 1 ; j < (int)tags.size() ; ++j) {
pending_tags.push_back(NegTag(tags[j], false)); // reopen later, bottom up
tags.pop_back();
}
tags.resize(i);
return;
}
}
}
// Just insert normally
pending_tags.push_back(tag);
}
vector<Tag*> tags; ///< Tags opened in the html output
vector<NegTag> pending_tags; ///< Tags opened in the tagged string, but not (yet) in the output
void add(String& ret, const NegTag& tag) {
// Cancel out with pending tag?
for (int i = (int)pending_tags.size() - 1 ; i >= 0 ; --i) {
if (pending_tags[i].tag == tag.tag) {
if (pending_tags[i].neg != tag.neg) {
pending_tags.erase(pending_tags.begin() + i);
return;
} else {
break; // look no further
}
}
}
// Cancel out with existing tag?
if (tag.neg) {
for (int i = (int)tags.size() - 1 ; i >= 0 ; --i) {
if (tags[i] == tag.tag) {
// cancel out with existing tag i, e.g. <b>:
// situation was <a><b><c>text
// situation will become <a><b><c>text</c></b><c>
vector<NegTag> reopen;
for (int j = (int)tags.size() - 1 ; j > i ; --j) {
pending_tags.push_back(NegTag(tags[j], true)); // close tag, top down
tags.pop_back();
}
pending_tags.push_back(tag); // now close tag i
for (int j = i + 1 ; j < (int)tags.size() ; ++j) {
pending_tags.push_back(NegTag(tags[j], false)); // reopen later, bottom up
tags.pop_back();
}
tags.resize(i);
return;
}
}
}
// Just insert normally
pending_tags.push_back(tag);
}
};
// html-escape a string
String html_escape(const String& str) {
String ret;
FOR_EACH_CONST(c, str) {
if (c == _('\1') || c == _('<')) { // escape <
ret += _("&lt;");
} else if (c == _('>')) { // escape >
ret += _("&gt;");
} else if (c == _('&')) { // escape &
ret += _("&amp;");
} else if (c == _('\'')) { // escape '
ret += _("&#39;");
} else if (c == _('\"')) { // escape "
ret += _("&quot;");
} else if (c >= 0x80) { // escape non ascii
ret += String(_("&#")) << (int)c << _(';');
} else {
ret += c;
}
}
return ret;
String ret;
FOR_EACH_CONST(c, str) {
if (c == _('\1') || c == _('<')) { // escape <
ret += _("&lt;");
} else if (c == _('>')) { // escape >
ret += _("&gt;");
} else if (c == _('&')) { // escape &
ret += _("&amp;");
} else if (c == _('\'')) { // escape '
ret += _("&#39;");
} else if (c == _('\"')) { // escape "
ret += _("&quot;");
} else if (c >= 0x80) { // escape non ascii
ret += String(_("&#")) << (int)c << _(';');
} else {
ret += c;
}
}
return ret;
}
// write symbols to html
String symbols_to_html(const String& str, SymbolFont& symbol_font, double size) {
guard_export_info(_("symbols_to_html"));
ExportInfo& ei = *export_info();
vector<SymbolFont::DrawableSymbol> symbols;
symbol_font.split(str, symbols);
String html;
FOR_EACH(sym, symbols) {
String filename = symbol_font.name() + _("-") + clean_filename(sym.text) + _(".png");
map<String,wxSize>::iterator it = ei.exported_images.find(filename);
if (it == ei.exported_images.end()) {
// save symbol image
Image img = symbol_font.getImage(size, sym);
wxFileName fn;
fn.SetPath(ei.directory_absolute);
fn.SetFullName(filename);
img.SaveFile(fn.GetFullPath());
it = ei.exported_images.insert(make_pair(filename, wxSize(img.GetWidth(), img.GetHeight()))).first;
}
html += _("<img src='") + filename + _("' alt='") + html_escape(sym.text)
+ _("' width='") + (String() << it->second.x)
+ _("' height='") + (String() << it->second.y) + _("'>");
}
return html;
guard_export_info(_("symbols_to_html"));
ExportInfo& ei = *export_info();
vector<SymbolFont::DrawableSymbol> symbols;
symbol_font.split(str, symbols);
String html;
FOR_EACH(sym, symbols) {
String filename = symbol_font.name() + _("-") + clean_filename(sym.text) + _(".png");
map<String,wxSize>::iterator it = ei.exported_images.find(filename);
if (it == ei.exported_images.end()) {
// save symbol image
Image img = symbol_font.getImage(size, sym);
wxFileName fn;
fn.SetPath(ei.directory_absolute);
fn.SetFullName(filename);
img.SaveFile(fn.GetFullPath());
it = ei.exported_images.insert(make_pair(filename, wxSize(img.GetWidth(), img.GetHeight()))).first;
}
html += _("<img src='") + filename + _("' alt='") + html_escape(sym.text)
+ _("' width='") + (String() << it->second.x)
+ _("' height='") + (String() << it->second.y) + _("'>");
}
return html;
}
String to_html(const String& str_in, const SymbolFontP& symbol_font, double symbol_size) {
String str = remove_tag_contents(str_in,_("<sep-soft"));
String ret;
Tag bold (_("<b>"), _("</b>")),
String str = remove_tag_contents(str_in,_("<sep-soft"));
String ret;
Tag bold (_("<b>"), _("</b>")),
italic(_("<i>"), _("</i>")),
symbol(_("<span class=\"symbol\">"), _("</span>"));
TagStack tags;
String symbols;
for (size_t i = 0 ; i < str.size() ; ) {
Char c = str.GetChar(i);
if (c == _('<')) {
++i;
if (is_substr(str, i, _("b"))) {
tags.open (ret, bold);
} else if (is_substr(str, i, _("/b"))) {
tags.close(ret, bold);
} else if (is_substr(str, i, _("i"))) {
tags.open (ret, italic);
} else if (is_substr(str, i, _("/i"))) {
tags.close(ret, italic);
} else if (is_substr(str, i, _("sym"))) {
tags.open (ret, symbol);
} else if (is_substr(str, i, _("/sym"))) {
if (!symbols.empty()) {
// write symbols in a special way
tags.write_pending_tags(ret);
ret += symbols_to_html(symbols, *symbol_font, symbol_size);
symbols.clear();
}
tags.close(ret, symbol);
}
i = skip_tag(str, i-1);
} else {
// normal character
tags.write_pending_tags(ret);
++i;
if (symbol.opened > 0 && symbol_font) {
symbols += c; // write as symbols instead
} else {
c = untag_char(c);
if (c == _('<')) { // escape <
ret += _("&lt;");
} else if (c == _('&')) { // escape &
ret += _("&amp;");
} else if (c >= 0x80) { // escape non ascii
ret += String(_("&#")) << (int)c << _(';');
} else if (c == _('\n')) {
ret += _("<br>\n");
} else {
ret += c;
}
}
}
}
// end of input
if (!symbols.empty()) {
tags.write_pending_tags(ret);
ret += symbols_to_html(symbols, *symbol_font, symbol_size);
symbols.clear();
}
tags.close_all(ret);
return ret;
TagStack tags;
String symbols;
for (size_t i = 0 ; i < str.size() ; ) {
Char c = str.GetChar(i);
if (c == _('<')) {
++i;
if (is_substr(str, i, _("b"))) {
tags.open (ret, bold);
} else if (is_substr(str, i, _("/b"))) {
tags.close(ret, bold);
} else if (is_substr(str, i, _("i"))) {
tags.open (ret, italic);
} else if (is_substr(str, i, _("/i"))) {
tags.close(ret, italic);
} else if (is_substr(str, i, _("sym"))) {
tags.open (ret, symbol);
} else if (is_substr(str, i, _("/sym"))) {
if (!symbols.empty()) {
// write symbols in a special way
tags.write_pending_tags(ret);
ret += symbols_to_html(symbols, *symbol_font, symbol_size);
symbols.clear();
}
tags.close(ret, symbol);
}
i = skip_tag(str, i-1);
} else {
// normal character
tags.write_pending_tags(ret);
++i;
if (symbol.opened > 0 && symbol_font) {
symbols += c; // write as symbols instead
} else {
c = untag_char(c);
if (c == _('<')) { // escape <
ret += _("&lt;");
} else if (c == _('&')) { // escape &
ret += _("&amp;");
} else if (c >= 0x80) { // escape non ascii
ret += String(_("&#")) << (int)c << _(';');
} else if (c == _('\n')) {
ret += _("<br>\n");
} else {
ret += c;
}
}
}
}
// end of input
if (!symbols.empty()) {
tags.write_pending_tags(ret);
ret += symbols_to_html(symbols, *symbol_font, symbol_size);
symbols.clear();
}
tags.close_all(ret);
return ret;
}
// convert a tagged string to html
SCRIPT_FUNCTION(to_html) {
SCRIPT_PARAM_C(String, input);
// symbol font?
SymbolFontP symbol_font;
SCRIPT_OPTIONAL_PARAM_N(String, _("symbol font"), font_name) {
symbol_font = SymbolFont::byName(font_name);
symbol_font->update(ctx);
}
SCRIPT_OPTIONAL_PARAM_N_(double, _("symbol font size"), symbol_font_size);
if (symbol_font_size <= 0) symbol_font_size = 12; // a default
SCRIPT_RETURN(to_html(input, symbol_font, symbol_font_size));
SCRIPT_PARAM_C(String, input);
// symbol font?
SymbolFontP symbol_font;
SCRIPT_OPTIONAL_PARAM_N(String, _("symbol font"), font_name) {
symbol_font = SymbolFont::byName(font_name);
symbol_font->update(ctx);
}
SCRIPT_OPTIONAL_PARAM_N_(double, _("symbol font size"), symbol_font_size);
if (symbol_font_size <= 0) symbol_font_size = 12; // a default
SCRIPT_RETURN(to_html(input, symbol_font, symbol_font_size));
}
// convert a symbol string to html
SCRIPT_FUNCTION(symbols_to_html) {
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);
symbol_font->update(ctx);
if (symbol_font_size <= 0) symbol_font_size = 12; // a default
SCRIPT_RETURN(symbols_to_html(input, *symbol_font, symbol_font_size));
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);
symbol_font->update(ctx);
if (symbol_font_size <= 0) symbol_font_size = 12; // a default
SCRIPT_RETURN(symbols_to_html(input, *symbol_font, symbol_font_size));
}
// ----------------------------------------------------------------------------- : BB Code
String to_bbcode(const String& str_in) {
String str = remove_tag_contents(str_in,_("<sep-soft"));
String ret;
Tag bold (_("[b]"), _("[/b]")),
String str = remove_tag_contents(str_in,_("<sep-soft"));
String ret;
Tag bold (_("[b]"), _("[/b]")),
italic(_("[i]"), _("[/i]"));
TagStack tags;
String symbols;
for (size_t i = 0 ; i < str.size() ; ) {
Char c = str.GetChar(i);
if (c == _('<')) {
++i;
if (is_substr(str, i, _("b"))) {
tags.open (ret, bold);
} else if (is_substr(str, i, _("/b"))) {
tags.close(ret, bold);
} else if (is_substr(str, i, _("i"))) {
tags.open (ret, italic);
} else if (is_substr(str, i, _("/i"))) {
tags.close(ret, italic);
} /*else if (is_substr(str, i, _("sym"))) {
tags.open (ret, symbol);
} else if (is_substr(str, i, _("/sym"))) {
if (!symbols.empty()) {
// write symbols in a special way
tags.write_pending_tags(ret);
ret += symbols_to_html(symbols, symbol_font);
symbols.clear();
}
tags.close(ret, symbol);
}*/
i = skip_tag(str, i-1);
} else {
// normal character
tags.write_pending_tags(ret);
++i;
// if (symbol.opened > 0 && symbol_font) {
// symbols += c; // write as symbols instead
// } else {
ret += untag_char(c);
// }
}
}
// end of input
/* if (!symbols.empty()) {
tags.write_pending_tags(ret);
ret += symbols_to_html(symbols, symbol_font);
symbols.clear();
}*/
tags.close_all(ret);
return ret;
TagStack tags;
String symbols;
for (size_t i = 0 ; i < str.size() ; ) {
Char c = str.GetChar(i);
if (c == _('<')) {
++i;
if (is_substr(str, i, _("b"))) {
tags.open (ret, bold);
} else if (is_substr(str, i, _("/b"))) {
tags.close(ret, bold);
} else if (is_substr(str, i, _("i"))) {
tags.open (ret, italic);
} else if (is_substr(str, i, _("/i"))) {
tags.close(ret, italic);
} /*else if (is_substr(str, i, _("sym"))) {
tags.open (ret, symbol);
} else if (is_substr(str, i, _("/sym"))) {
if (!symbols.empty()) {
// write symbols in a special way
tags.write_pending_tags(ret);
ret += symbols_to_html(symbols, symbol_font);
symbols.clear();
}
tags.close(ret, symbol);
}*/
i = skip_tag(str, i-1);
} else {
// normal character
tags.write_pending_tags(ret);
++i;
// if (symbol.opened > 0 && symbol_font) {
// symbols += c; // write as symbols instead
// } else {
ret += untag_char(c);
// }
}
}
// end of input
/* if (!symbols.empty()) {
tags.write_pending_tags(ret);
ret += symbols_to_html(symbols, symbol_font);
symbols.clear();
}*/
tags.close_all(ret);
return ret;
}
// convert a tagged string to BBCode
SCRIPT_FUNCTION(to_bbcode) {
SCRIPT_PARAM_C(String, input);
throw "TODO";
// SCRIPT_RETURN(to_bbcode(input, symbol_font));
SCRIPT_PARAM_C(String, input);
throw "TODO";
// SCRIPT_RETURN(to_bbcode(input, symbol_font));
}
// ----------------------------------------------------------------------------- : Text
// convert a tagged string to plain text
SCRIPT_FUNCTION(to_text) {
SCRIPT_PARAM_C(String, input);
SCRIPT_RETURN(untag_hide_sep(input));
SCRIPT_PARAM_C(String, input);
SCRIPT_RETURN(untag_hide_sep(input));
}
// ----------------------------------------------------------------------------- : Files
// copy from source package -> destination directory, return new filename (relative)
SCRIPT_FUNCTION(copy_file) {
guard_export_info(_("copy_file"));
SCRIPT_PARAM_C(String, input); // file to copy
// output path
String out_name = input;
String out_path = get_export_full_path(out_name);
// copy
ExportInfo& ei = *export_info();
InputStreamP in = ei.export_template->openIn(input);
wxFileOutputStream out(out_path);
if (!out.Ok()) throw Error(_("Unable to open file '") + out_path + _("' for output"));
out.Write(*in);
SCRIPT_RETURN(out_name);
guard_export_info(_("copy_file"));
SCRIPT_PARAM_C(String, input); // file to copy
// output path
String out_name = input;
String out_path = get_export_full_path(out_name);
// copy
ExportInfo& ei = *export_info();
InputStreamP in = ei.export_template->openIn(input);
wxFileOutputStream out(out_path);
if (!out.Ok()) throw Error(_("Unable to open file '") + out_path + _("' for output"));
out.Write(*in);
SCRIPT_RETURN(out_name);
}
// write a file to the destination directory
SCRIPT_FUNCTION(write_text_file) {
guard_export_info(_("write_text_file"));
SCRIPT_PARAM_C(String, input); // text to write
SCRIPT_PARAM(String, file); // file to write to
// output path
String out_path = get_export_full_path(file);
// write
wxFileOutputStream out(out_path);
if (!out.Ok()) throw Error(_("Unable to open file '") + out_path + _("' for output"));
wxTextOutputStream tout(out);
tout.WriteString(BYTE_ORDER_MARK);
tout.WriteString(input);
SCRIPT_RETURN(file);
guard_export_info(_("write_text_file"));
SCRIPT_PARAM_C(String, input); // text to write
SCRIPT_PARAM(String, file); // file to write to
// output path
String out_path = get_export_full_path(file);
// write
wxFileOutputStream out(out_path);
if (!out.Ok()) throw Error(_("Unable to open file '") + out_path + _("' for output"));
wxTextOutputStream tout(out);
tout.WriteString(BYTE_ORDER_MARK);
tout.WriteString(input);
SCRIPT_RETURN(file);
}
SCRIPT_FUNCTION(write_image_file) {
guard_export_info(_("write_image_file"));
// output path
SCRIPT_PARAM(String, file); // file to write to
String out_path = get_export_full_path(file);
// duplicates?
ExportInfo& ei = *export_info();
if (ei.exported_images.find(file) != ei.exported_images.end()) {
SCRIPT_RETURN(file); // already written an image with this name
}
// get image
SCRIPT_PARAM_C(ScriptValueP, input);
SCRIPT_OPTIONAL_PARAM_(int, width);
SCRIPT_OPTIONAL_PARAM_(int, height);
ScriptObject<CardP>* card = dynamic_cast<ScriptObject<CardP>*>(input.get()); // is it a card?
Image image;
GeneratedImage::Options options(width, height, ei.export_template.get(), ei.set.get());
if (card) {
image = conform_image(export_bitmap(ei.set, card->getValue()).ConvertToImage(), options);
} else {
image = image_from_script(input)->generateConform(options);
}
if (!image.Ok()) throw Error(_("Unable to generate image for file ") + file);
// write
image.SaveFile(out_path);
ei.exported_images.insert(make_pair(file, wxSize(image.GetWidth(), image.GetHeight())));
SCRIPT_RETURN(file);
guard_export_info(_("write_image_file"));
// output path
SCRIPT_PARAM(String, file); // file to write to
String out_path = get_export_full_path(file);
// duplicates?
ExportInfo& ei = *export_info();
if (ei.exported_images.find(file) != ei.exported_images.end()) {
SCRIPT_RETURN(file); // already written an image with this name
}
// get image
SCRIPT_PARAM_C(ScriptValueP, input);
SCRIPT_OPTIONAL_PARAM_(int, width);
SCRIPT_OPTIONAL_PARAM_(int, height);
ScriptObject<CardP>* card = dynamic_cast<ScriptObject<CardP>*>(input.get()); // is it a card?
Image image;
GeneratedImage::Options options(width, height, ei.export_template.get(), ei.set.get());
if (card) {
image = conform_image(export_bitmap(ei.set, card->getValue()).ConvertToImage(), options);
} else {
image = image_from_script(input)->generateConform(options);
}
if (!image.Ok()) throw Error(_("Unable to generate image for file ") + file);
// write
image.SaveFile(out_path);
ei.exported_images.insert(make_pair(file, wxSize(image.GetWidth(), image.GetHeight())));
SCRIPT_RETURN(file);
}
SCRIPT_FUNCTION(write_set_file) {
guard_export_info(_("write_set_file"));
// output path
SCRIPT_PARAM(String, file); // file to write to
String out_path = get_export_full_path(file);
// export
SCRIPT_PARAM_C(Set*, set);
set->saveCopy(out_path); // TODO: use export_set instead?
SCRIPT_RETURN(file);
guard_export_info(_("write_set_file"));
// output path
SCRIPT_PARAM(String, file); // file to write to
String out_path = get_export_full_path(file);
// export
SCRIPT_PARAM_C(Set*, set);
set->saveCopy(out_path); // TODO: use export_set instead?
SCRIPT_RETURN(file);
}
SCRIPT_FUNCTION(sanitize) {
SCRIPT_PARAM_C(String, input);
//TODO
SCRIPT_RETURN(input);
SCRIPT_PARAM_C(String, input);
//TODO
SCRIPT_RETURN(input);
}
// ----------------------------------------------------------------------------- : Init
void init_script_export_functions(Context& ctx) {
ctx.setVariable(_("to html"), script_to_html);
ctx.setVariable(_("symbols to html"), script_symbols_to_html);
ctx.setVariable(_("to text"), script_to_text);
ctx.setVariable(_("copy file"), script_copy_file);
ctx.setVariable(_("write text file"), script_write_text_file);
ctx.setVariable(_("write image file"), script_write_image_file);
ctx.setVariable(_("write set file"), script_write_set_file);
ctx.setVariable(_("sanitize"), script_sanitize);
ctx.setVariable(_("to html"), script_to_html);
ctx.setVariable(_("symbols to html"), script_symbols_to_html);
ctx.setVariable(_("to text"), script_to_text);
ctx.setVariable(_("copy file"), script_copy_file);
ctx.setVariable(_("write text file"), script_write_text_file);
ctx.setVariable(_("write image file"), script_write_image_file);
ctx.setVariable(_("write set file"), script_write_set_file);
ctx.setVariable(_("sanitize"), script_sanitize);
}
+8 -8
View File
@@ -31,14 +31,14 @@ void init_script_construction_functions(Context& ctx);
/// Initialize all built in functions for a context
inline void init_script_functions(Context& ctx) {
init_script_basic_functions(ctx);
init_script_regex_functions(ctx);
init_script_image_functions(ctx);
init_script_editor_functions(ctx);
init_script_export_functions(ctx);
init_script_english_functions(ctx);
init_script_spelling_functions(ctx);
init_script_construction_functions(ctx);
init_script_basic_functions(ctx);
init_script_regex_functions(ctx);
init_script_image_functions(ctx);
init_script_editor_functions(ctx);
init_script_export_functions(ctx);
init_script_english_functions(ctx);
init_script_spelling_functions(ctx);
init_script_construction_functions(ctx);
}
// ----------------------------------------------------------------------------- : EOF
+147 -147
View File
@@ -26,212 +26,212 @@ void parse_enum(const String&, ImageCombine& out);
// ----------------------------------------------------------------------------- : Utility
template <> inline GeneratedImageP from_script<GeneratedImageP>(const ScriptValueP& value) {
return image_from_script(value);
return image_from_script(value);
}
SCRIPT_FUNCTION(to_image) {
SCRIPT_PARAM_C(GeneratedImageP, input);
return input;
SCRIPT_PARAM_C(GeneratedImageP, input);
return input;
}
// ----------------------------------------------------------------------------- : Image functions
SCRIPT_FUNCTION(linear_blend) {
SCRIPT_PARAM(GeneratedImageP, image1);
SCRIPT_PARAM(GeneratedImageP, image2);
SCRIPT_PARAM(double, x1); SCRIPT_PARAM(double, y1);
SCRIPT_PARAM(double, x2); SCRIPT_PARAM(double, y2);
return intrusive(new LinearBlendImage(image1, image2, x1,y1, x2,y2));
SCRIPT_PARAM(GeneratedImageP, image1);
SCRIPT_PARAM(GeneratedImageP, image2);
SCRIPT_PARAM(double, x1); SCRIPT_PARAM(double, y1);
SCRIPT_PARAM(double, x2); SCRIPT_PARAM(double, y2);
return intrusive(new LinearBlendImage(image1, image2, x1,y1, x2,y2));
}
SCRIPT_FUNCTION(masked_blend) {
SCRIPT_PARAM(GeneratedImageP, light);
SCRIPT_PARAM(GeneratedImageP, dark);
SCRIPT_PARAM(GeneratedImageP, mask);
return intrusive(new MaskedBlendImage(light, dark, mask));
SCRIPT_PARAM(GeneratedImageP, light);
SCRIPT_PARAM(GeneratedImageP, dark);
SCRIPT_PARAM(GeneratedImageP, mask);
return intrusive(new MaskedBlendImage(light, dark, mask));
}
SCRIPT_FUNCTION(combine_blend) {
SCRIPT_PARAM(String, combine);
SCRIPT_PARAM(GeneratedImageP, image1);
SCRIPT_PARAM(GeneratedImageP, image2);
ImageCombine image_combine;
parse_enum(combine, image_combine);
return intrusive(new CombineBlendImage(image1, image2, image_combine));
SCRIPT_PARAM(String, combine);
SCRIPT_PARAM(GeneratedImageP, image1);
SCRIPT_PARAM(GeneratedImageP, image2);
ImageCombine image_combine;
parse_enum(combine, image_combine);
return intrusive(new CombineBlendImage(image1, image2, image_combine));
}
SCRIPT_FUNCTION(set_mask) {
SCRIPT_PARAM(GeneratedImageP, image);
SCRIPT_PARAM(GeneratedImageP, mask);
return intrusive(new SetMaskImage(image, mask));
SCRIPT_PARAM(GeneratedImageP, image);
SCRIPT_PARAM(GeneratedImageP, mask);
return intrusive(new SetMaskImage(image, mask));
}
SCRIPT_FUNCTION(set_alpha) {
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_PARAM(double, alpha);
return intrusive(new SetAlphaImage(input, alpha));
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_PARAM(double, alpha);
return intrusive(new SetAlphaImage(input, alpha));
}
SCRIPT_FUNCTION(set_combine) {
SCRIPT_PARAM(String, combine);
SCRIPT_PARAM_C(GeneratedImageP, input);
ImageCombine image_combine;
parse_enum(combine, image_combine);
return intrusive(new SetCombineImage(input, image_combine));
SCRIPT_PARAM(String, combine);
SCRIPT_PARAM_C(GeneratedImageP, input);
ImageCombine image_combine;
parse_enum(combine, image_combine);
return intrusive(new SetCombineImage(input, image_combine));
}
SCRIPT_FUNCTION(saturate) {
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_PARAM(double, amount);
return intrusive(new SaturateImage(input, amount));
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_PARAM(double, amount);
return intrusive(new SaturateImage(input, amount));
}
SCRIPT_FUNCTION(invert_image) {
SCRIPT_PARAM_C(GeneratedImageP, input);
return intrusive(new InvertImage(input));
SCRIPT_PARAM_C(GeneratedImageP, input);
return intrusive(new InvertImage(input));
}
SCRIPT_FUNCTION(recolor_image) {
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_OPTIONAL_PARAM(Color, red) {
SCRIPT_PARAM(Color, green);
SCRIPT_PARAM(Color, blue);
SCRIPT_PARAM_DEFAULT(Color, white, *wxWHITE);
return intrusive(new RecolorImage2(input,red,green,blue,white));
} else {
SCRIPT_PARAM(Color, color);
return intrusive(new RecolorImage(input,color));
}
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_OPTIONAL_PARAM(Color, red) {
SCRIPT_PARAM(Color, green);
SCRIPT_PARAM(Color, blue);
SCRIPT_PARAM_DEFAULT(Color, white, *wxWHITE);
return intrusive(new RecolorImage2(input,red,green,blue,white));
} else {
SCRIPT_PARAM(Color, color);
return intrusive(new RecolorImage(input,color));
}
}
SCRIPT_FUNCTION(enlarge) {
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_PARAM_N(double, _("border size"), border_size);
return intrusive(new EnlargeImage(input, border_size));
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_PARAM_N(double, _("border size"), border_size);
return intrusive(new EnlargeImage(input, border_size));
}
SCRIPT_FUNCTION(crop) {
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);
SCRIPT_PARAM_N(double, _("offset y"), offset_y);
return intrusive(new CropImage(input, width, height, offset_x, offset_y));
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);
SCRIPT_PARAM_N(double, _("offset y"), offset_y);
return intrusive(new CropImage(input, width, height, offset_x, offset_y));
}
SCRIPT_FUNCTION(flip_horizontal) {
SCRIPT_PARAM_C(GeneratedImageP, input);
return intrusive(new FlipImageHorizontal(input));
SCRIPT_PARAM_C(GeneratedImageP, input);
return intrusive(new FlipImageHorizontal(input));
}
SCRIPT_FUNCTION(flip_vertical) {
SCRIPT_PARAM_C(GeneratedImageP, input);
return intrusive(new FlipImageVertical(input));
SCRIPT_PARAM_C(GeneratedImageP, input);
return intrusive(new FlipImageVertical(input));
}
SCRIPT_FUNCTION(rotate) {
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_PARAM_N(Degrees, _("angle"), angle);
return intrusive(new RotateImage(input,deg_to_rad(angle)));
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_PARAM_N(Degrees, _("angle"), angle);
return intrusive(new RotateImage(input,deg_to_rad(angle)));
}
SCRIPT_FUNCTION(drop_shadow) {
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);
SCRIPT_OPTIONAL_PARAM_N_(double, _("blur radius"), blur_radius);
SCRIPT_OPTIONAL_PARAM_N_(Color, _("color"), color);
return intrusive(new DropShadowImage(input, offset_x, offset_y, alpha, blur_radius, color));
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);
SCRIPT_OPTIONAL_PARAM_N_(double, _("blur radius"), blur_radius);
SCRIPT_OPTIONAL_PARAM_N_(Color, _("color"), color);
return intrusive(new DropShadowImage(input, offset_x, offset_y, alpha, blur_radius, color));
}
SCRIPT_FUNCTION(symbol_variation) {
// find symbol
SCRIPT_PARAM(ScriptValueP, symbol); // TODO: change to input?
ScriptObject<ValueP>* valueO = dynamic_cast<ScriptObject<ValueP>*>(symbol.get());
SymbolValue* value = valueO ? dynamic_cast<SymbolValue*>(valueO->getValue().get()) : nullptr;
String filename;
if (value) {
filename = value->filename;
} else if (valueO) {
throw ScriptErrorConversion(valueO->typeName(), _TYPE_("symbol" ));
} else {
filename = from_script<String>(symbol);
}
// known variation?
SCRIPT_OPTIONAL_PARAM_(String, variation)
if (value && variation_) {
// find style
SCRIPT_PARAM(Set*, set);
SCRIPT_OPTIONAL_PARAM_(CardP, card);
SymbolStyleP style = dynamic_pointer_cast<SymbolStyle>(set->stylesheetForP(card)->styleFor(value->fieldP));
if (!style) throw InternalError(_("Symbol value has a style of the wrong type"));
// find variation
FOR_EACH(v, style->variations) {
if (v->name == variation) {
// found it
return intrusive(new SymbolToImage(value, filename, value->last_update, v));
}
}
throw ScriptError(_("Variation of symbol not found ('") + variation + _("')"));
} else {
// custom variation
SCRIPT_PARAM_N(double, _("border radius"), border_radius);
SCRIPT_OPTIONAL_PARAM_N_(String, _("fill type"), fill_type);
SymbolVariationP var(new SymbolVariation);
var->border_radius = border_radius;
if (fill_type == _("solid") || fill_type.empty()) {
SCRIPT_PARAM_N(Color, _("fill color"), fill_color);
SCRIPT_PARAM_N(Color, _("border color"), border_color);
var->filter = intrusive(new SolidFillSymbolFilter(fill_color, border_color));
} else if (fill_type == _("linear gradient")) {
SCRIPT_PARAM_N(Color, _("fill color 1"), fill_color_1);
SCRIPT_PARAM_N(Color, _("border color 1"), border_color_1);
SCRIPT_PARAM_N(Color, _("fill color 2"), fill_color_2);
SCRIPT_PARAM_N(Color, _("border color 2"), border_color_2);
SCRIPT_PARAM_N(double, _("center x"), center_x);
SCRIPT_PARAM_N(double, _("center y"), center_y);
SCRIPT_PARAM_N(double, _("end x"), end_x);
SCRIPT_PARAM_N(double, _("end y"), end_y);
var->filter = intrusive(new LinearGradientSymbolFilter(fill_color_1, border_color_1, fill_color_2, border_color_2
,center_x, center_y, end_x, end_y));
} else if (fill_type == _("radial gradient")) {
SCRIPT_PARAM_N(Color, _("fill color 1"), fill_color_1);
SCRIPT_PARAM_N(Color, _("border color 1"), border_color_1);
SCRIPT_PARAM_N(Color, _("fill color 2"), fill_color_2);
SCRIPT_PARAM_N(Color, _("border color 2"), border_color_2);
var->filter = intrusive(new RadialGradientSymbolFilter(fill_color_1, border_color_1, fill_color_2, border_color_2));
} else {
throw ScriptError(_("Unknown fill type for symbol_variation: ") + fill_type);
}
return intrusive(new SymbolToImage(value, filename, value ? value->last_update : Age(0), var));
}
// find symbol
SCRIPT_PARAM(ScriptValueP, symbol); // TODO: change to input?
ScriptObject<ValueP>* valueO = dynamic_cast<ScriptObject<ValueP>*>(symbol.get());
SymbolValue* value = valueO ? dynamic_cast<SymbolValue*>(valueO->getValue().get()) : nullptr;
String filename;
if (value) {
filename = value->filename;
} else if (valueO) {
throw ScriptErrorConversion(valueO->typeName(), _TYPE_("symbol" ));
} else {
filename = from_script<String>(symbol);
}
// known variation?
SCRIPT_OPTIONAL_PARAM_(String, variation)
if (value && variation_) {
// find style
SCRIPT_PARAM(Set*, set);
SCRIPT_OPTIONAL_PARAM_(CardP, card);
SymbolStyleP style = dynamic_pointer_cast<SymbolStyle>(set->stylesheetForP(card)->styleFor(value->fieldP));
if (!style) throw InternalError(_("Symbol value has a style of the wrong type"));
// find variation
FOR_EACH(v, style->variations) {
if (v->name == variation) {
// found it
return intrusive(new SymbolToImage(value, filename, value->last_update, v));
}
}
throw ScriptError(_("Variation of symbol not found ('") + variation + _("')"));
} else {
// custom variation
SCRIPT_PARAM_N(double, _("border radius"), border_radius);
SCRIPT_OPTIONAL_PARAM_N_(String, _("fill type"), fill_type);
SymbolVariationP var(new SymbolVariation);
var->border_radius = border_radius;
if (fill_type == _("solid") || fill_type.empty()) {
SCRIPT_PARAM_N(Color, _("fill color"), fill_color);
SCRIPT_PARAM_N(Color, _("border color"), border_color);
var->filter = intrusive(new SolidFillSymbolFilter(fill_color, border_color));
} else if (fill_type == _("linear gradient")) {
SCRIPT_PARAM_N(Color, _("fill color 1"), fill_color_1);
SCRIPT_PARAM_N(Color, _("border color 1"), border_color_1);
SCRIPT_PARAM_N(Color, _("fill color 2"), fill_color_2);
SCRIPT_PARAM_N(Color, _("border color 2"), border_color_2);
SCRIPT_PARAM_N(double, _("center x"), center_x);
SCRIPT_PARAM_N(double, _("center y"), center_y);
SCRIPT_PARAM_N(double, _("end x"), end_x);
SCRIPT_PARAM_N(double, _("end y"), end_y);
var->filter = intrusive(new LinearGradientSymbolFilter(fill_color_1, border_color_1, fill_color_2, border_color_2
,center_x, center_y, end_x, end_y));
} else if (fill_type == _("radial gradient")) {
SCRIPT_PARAM_N(Color, _("fill color 1"), fill_color_1);
SCRIPT_PARAM_N(Color, _("border color 1"), border_color_1);
SCRIPT_PARAM_N(Color, _("fill color 2"), fill_color_2);
SCRIPT_PARAM_N(Color, _("border color 2"), border_color_2);
var->filter = intrusive(new RadialGradientSymbolFilter(fill_color_1, border_color_1, fill_color_2, border_color_2));
} else {
throw ScriptError(_("Unknown fill type for symbol_variation: ") + fill_type);
}
return intrusive(new SymbolToImage(value, filename, value ? value->last_update : Age(0), var));
}
}
SCRIPT_FUNCTION(built_in_image) {
SCRIPT_PARAM_C(String, input);
return intrusive(new BuiltInImage(input));
SCRIPT_PARAM_C(String, input);
return intrusive(new BuiltInImage(input));
}
// ----------------------------------------------------------------------------- : Init
void init_script_image_functions(Context& ctx) {
ctx.setVariable(_("to image"), script_to_image);
ctx.setVariable(_("linear blend"), script_linear_blend);
ctx.setVariable(_("masked blend"), script_masked_blend);
ctx.setVariable(_("combine blend"), script_combine_blend);
ctx.setVariable(_("set mask"), script_set_mask);
ctx.setVariable(_("set alpha"), script_set_alpha);
ctx.setVariable(_("set combine"), script_set_combine);
ctx.setVariable(_("saturate"), script_saturate);
ctx.setVariable(_("invert image"), script_invert_image);
ctx.setVariable(_("recolor image"), script_recolor_image);
ctx.setVariable(_("enlarge"), script_enlarge);
ctx.setVariable(_("crop"), script_crop);
ctx.setVariable(_("flip horizontal"), script_flip_horizontal);
ctx.setVariable(_("flip vertical"), script_flip_vertical);
ctx.setVariable(_("rotate"), script_rotate);
ctx.setVariable(_("drop shadow"), script_drop_shadow);
ctx.setVariable(_("symbol variation"), script_symbol_variation);
ctx.setVariable(_("built in image"), script_built_in_image);
ctx.setVariable(_("to image"), script_to_image);
ctx.setVariable(_("linear blend"), script_linear_blend);
ctx.setVariable(_("masked blend"), script_masked_blend);
ctx.setVariable(_("combine blend"), script_combine_blend);
ctx.setVariable(_("set mask"), script_set_mask);
ctx.setVariable(_("set alpha"), script_set_alpha);
ctx.setVariable(_("set combine"), script_set_combine);
ctx.setVariable(_("saturate"), script_saturate);
ctx.setVariable(_("invert image"), script_invert_image);
ctx.setVariable(_("recolor image"), script_recolor_image);
ctx.setVariable(_("enlarge"), script_enlarge);
ctx.setVariable(_("crop"), script_crop);
ctx.setVariable(_("flip horizontal"), script_flip_horizontal);
ctx.setVariable(_("flip vertical"), script_flip_vertical);
ctx.setVariable(_("rotate"), script_rotate);
ctx.setVariable(_("drop shadow"), script_drop_shadow);
ctx.setVariable(_("symbol variation"), script_symbol_variation);
ctx.setVariable(_("built in image"), script_built_in_image);
}
+185 -185
View File
@@ -20,238 +20,238 @@ DECLARE_TYPEOF_COLLECTION(pair<Variable COMMA ScriptValueP>);
/// A regular expression for use in a script
class ScriptRegex : public ScriptValue, public Regex {
public:
virtual ScriptType type() const { return SCRIPT_REGEX; }
virtual String typeName() const { return _("regex"); }
ScriptRegex(const String& code) {
assign(code);
}
/// Match only if in_context also matches
bool matches(Results& results, const String& str, String::const_iterator begin, const ScriptRegexP& in_context) {
if (!in_context) {
return matches(results, begin, str.end());
} else {
while (matches(results, begin, str.end())) {
Results::const_reference match = results[0];
String context_str(str.begin(), match.first); // before
context_str += _("<match>");
context_str.append(match.second, str.end()); // after
if (in_context->matches(context_str)) {
return true; // the context matches, done
}
begin = match.second; // skip
}
return false;
}
}
using Regex::matches;
virtual ScriptType type() const { return SCRIPT_REGEX; }
virtual String typeName() const { return _("regex"); }
ScriptRegex(const String& code) {
assign(code);
}
/// Match only if in_context also matches
bool matches(Results& results, const String& str, String::const_iterator begin, const ScriptRegexP& in_context) {
if (!in_context) {
return matches(results, begin, str.end());
} else {
while (matches(results, begin, str.end())) {
Results::const_reference match = results[0];
String context_str(str.begin(), match.first); // before
context_str += _("<match>");
context_str.append(match.second, str.end()); // after
if (in_context->matches(context_str)) {
return true; // the context matches, done
}
begin = match.second; // skip
}
return false;
}
}
using Regex::matches;
};
ScriptRegexP regex_from_script(const ScriptValueP& value) {
// is it a regex already?
ScriptRegexP regex = dynamic_pointer_cast<ScriptRegex>(value);
if (!regex) {
// TODO: introduce some kind of caching?
regex = intrusive(new ScriptRegex(*value));
}
return regex;
// is it a regex already?
ScriptRegexP regex = dynamic_pointer_cast<ScriptRegex>(value);
if (!regex) {
// TODO: introduce some kind of caching?
regex = intrusive(new ScriptRegex(*value));
}
return regex;
}
template <> inline ScriptRegexP from_script<ScriptRegexP>(const ScriptValueP& value) {
return regex_from_script(value);
return regex_from_script(value);
}
// ----------------------------------------------------------------------------- : Rules : regex replace
struct RegexReplacer {
ScriptRegexP match; ///< Regex to match
ScriptRegexP context; ///< Match only in a given context, optional
String replacement_string; ///< Replacement
ScriptValueP replacement_function; ///< Replacement function instead of a simple string, optional
bool recursive; ///< Recurse into the replacement
String apply(Context& ctx, const String& input, int level = 0) const {
String ret;
String::const_iterator start = input.begin();
ScriptRegex::Results results;
while (match->matches(results, input, start, context)) {
// for each match ...
ScriptRegex::Results::const_reference pos = results[0];
ret.append(start, pos.first); // everything before the match position stays
// determine replacement
String inside;
if (replacement_function) {
// set match results in context
for (UInt sub = 0 ; sub < results.size() ; ++sub) {
String name = sub == 0 ? _("input") : String(_("_")) << sub;
ctx.setVariable(name, to_script(results.str(sub)));
}
// call
inside = replacement_function->eval(ctx)->toString();
} else {
inside = results.format(replacement_string);
}
// append replaced inside
if (recursive && level < 20) {
ret += apply(ctx, inside, level + 1);
} else {
ret += inside;
}
start = pos.second;
}
ret.append(start, input.end());
return ret;
}
ScriptRegexP match; ///< Regex to match
ScriptRegexP context; ///< Match only in a given context, optional
String replacement_string; ///< Replacement
ScriptValueP replacement_function; ///< Replacement function instead of a simple string, optional
bool recursive; ///< Recurse into the replacement
String apply(Context& ctx, const String& input, int level = 0) const {
String ret;
String::const_iterator start = input.begin();
ScriptRegex::Results results;
while (match->matches(results, input, start, context)) {
// for each match ...
ScriptRegex::Results::const_reference pos = results[0];
ret.append(start, pos.first); // everything before the match position stays
// determine replacement
String inside;
if (replacement_function) {
// set match results in context
for (UInt sub = 0 ; sub < results.size() ; ++sub) {
String name = sub == 0 ? _("input") : String(_("_")) << sub;
ctx.setVariable(name, to_script(results.str(sub)));
}
// call
inside = replacement_function->eval(ctx)->toString();
} else {
inside = results.format(replacement_string);
}
// append replaced inside
if (recursive && level < 20) {
ret += apply(ctx, inside, level + 1);
} else {
ret += inside;
}
start = pos.second;
}
ret.append(start, input.end());
return ret;
}
};
SCRIPT_FUNCTION_WITH_SIMPLIFY(replace) {
// construct replacer
RegexReplacer replacer;
replacer.match = from_script<ScriptRegexP>(ctx.getVariable(SCRIPT_VAR_match), SCRIPT_VAR_match);
if (ctx.getVariableOpt(SCRIPT_VAR_in_context)) {
replacer.context = from_script<ScriptRegexP>(ctx.getVariableOpt(SCRIPT_VAR_in_context), SCRIPT_VAR_in_context);
}
if (ctx.getVariableOpt(SCRIPT_VAR_recursive)) {
replacer.recursive = from_script<bool>(ctx.getVariableOpt(SCRIPT_VAR_recursive), SCRIPT_VAR_recursive);
} else {
replacer.recursive = false;
}
replacer.replacement_function = ctx.getVariable(SCRIPT_VAR_replace);
if (replacer.replacement_function->type() != SCRIPT_FUNCTION) {
replacer.replacement_string = replacer.replacement_function->toString();
replacer.replacement_function = ScriptValueP();
}
// run
SCRIPT_PARAM_C(String, input);
if (replacer.context || replacer.replacement_function || replacer.recursive) {
SCRIPT_RETURN(replacer.apply(ctx, input));
} else {
// simple replacing
replacer.match->replace_all(&input, replacer.replacement_string);
SCRIPT_RETURN(input);
}
// construct replacer
RegexReplacer replacer;
replacer.match = from_script<ScriptRegexP>(ctx.getVariable(SCRIPT_VAR_match), SCRIPT_VAR_match);
if (ctx.getVariableOpt(SCRIPT_VAR_in_context)) {
replacer.context = from_script<ScriptRegexP>(ctx.getVariableOpt(SCRIPT_VAR_in_context), SCRIPT_VAR_in_context);
}
if (ctx.getVariableOpt(SCRIPT_VAR_recursive)) {
replacer.recursive = from_script<bool>(ctx.getVariableOpt(SCRIPT_VAR_recursive), SCRIPT_VAR_recursive);
} else {
replacer.recursive = false;
}
replacer.replacement_function = ctx.getVariable(SCRIPT_VAR_replace);
if (replacer.replacement_function->type() != SCRIPT_FUNCTION) {
replacer.replacement_string = replacer.replacement_function->toString();
replacer.replacement_function = ScriptValueP();
}
// run
SCRIPT_PARAM_C(String, input);
if (replacer.context || replacer.replacement_function || replacer.recursive) {
SCRIPT_RETURN(replacer.apply(ctx, input));
} else {
// simple replacing
replacer.match->replace_all(&input, replacer.replacement_string);
SCRIPT_RETURN(input);
}
}
SCRIPT_FUNCTION_SIMPLIFY_CLOSURE(replace) {
FOR_EACH(b, closure.bindings) {
if (b.first == SCRIPT_VAR_match || b.first == SCRIPT_VAR_in_context) {
b.second = regex_from_script(b.second); // pre-compile
}
}
return ScriptValueP();
FOR_EACH(b, closure.bindings) {
if (b.first == SCRIPT_VAR_match || b.first == SCRIPT_VAR_in_context) {
b.second = regex_from_script(b.second); // pre-compile
}
}
return ScriptValueP();
}
// ----------------------------------------------------------------------------- : Rules : regex filter
SCRIPT_FUNCTION_WITH_SIMPLIFY(filter_text) {
SCRIPT_PARAM_C(String, input);
SCRIPT_PARAM_C(ScriptRegexP, match);
SCRIPT_OPTIONAL_PARAM_C_(ScriptRegexP, in_context);
String ret;
// find all matches
String::const_iterator start = input.begin();
ScriptRegex::Results results;
while (match->matches(results, input, start, in_context)) {
// match, append to result
ScriptRegex::Results::const_reference pos = results[0];
ret.append(pos.first, pos.second); // the match
start = pos.second;
}
SCRIPT_RETURN(ret);
SCRIPT_PARAM_C(String, input);
SCRIPT_PARAM_C(ScriptRegexP, match);
SCRIPT_OPTIONAL_PARAM_C_(ScriptRegexP, in_context);
String ret;
// find all matches
String::const_iterator start = input.begin();
ScriptRegex::Results results;
while (match->matches(results, input, start, in_context)) {
// match, append to result
ScriptRegex::Results::const_reference pos = results[0];
ret.append(pos.first, pos.second); // the match
start = pos.second;
}
SCRIPT_RETURN(ret);
}
SCRIPT_FUNCTION_SIMPLIFY_CLOSURE(filter_text) {
FOR_EACH(b, closure.bindings) {
if (b.first == SCRIPT_VAR_match || b.first == SCRIPT_VAR_in_context) {
b.second = regex_from_script(b.second); // pre-compile
}
}
return ScriptValueP();
FOR_EACH(b, closure.bindings) {
if (b.first == SCRIPT_VAR_match || b.first == SCRIPT_VAR_in_context) {
b.second = regex_from_script(b.second); // pre-compile
}
}
return ScriptValueP();
}
// ----------------------------------------------------------------------------- : Rules : regex break
SCRIPT_FUNCTION_WITH_SIMPLIFY(break_text) {
SCRIPT_PARAM_C(String, input);
SCRIPT_PARAM_C(ScriptRegexP, match);
SCRIPT_OPTIONAL_PARAM_C_(ScriptRegexP, in_context);
ScriptCustomCollectionP ret(new ScriptCustomCollection);
// find all matches
String::const_iterator start = input.begin();
ScriptRegex::Results results;
while (match->matches(results, input, start, in_context)) {
// match, append to result
ret->value.push_back(to_script(results.str()));
start = results[0].second;
}
return ret;
SCRIPT_PARAM_C(String, input);
SCRIPT_PARAM_C(ScriptRegexP, match);
SCRIPT_OPTIONAL_PARAM_C_(ScriptRegexP, in_context);
ScriptCustomCollectionP ret(new ScriptCustomCollection);
// find all matches
String::const_iterator start = input.begin();
ScriptRegex::Results results;
while (match->matches(results, input, start, in_context)) {
// match, append to result
ret->value.push_back(to_script(results.str()));
start = results[0].second;
}
return ret;
}
SCRIPT_FUNCTION_SIMPLIFY_CLOSURE(break_text) {
FOR_EACH(b, closure.bindings) {
if (b.first == SCRIPT_VAR_match || b.first == SCRIPT_VAR_in_context) {
b.second = regex_from_script(b.second); // pre-compile
}
}
return ScriptValueP();
FOR_EACH(b, closure.bindings) {
if (b.first == SCRIPT_VAR_match || b.first == SCRIPT_VAR_in_context) {
b.second = regex_from_script(b.second); // pre-compile
}
}
return ScriptValueP();
}
// ----------------------------------------------------------------------------- : Rules : regex split
SCRIPT_FUNCTION_WITH_SIMPLIFY(split_text) {
SCRIPT_PARAM_C(String, input);
SCRIPT_PARAM_C(ScriptRegexP, match);
SCRIPT_PARAM_DEFAULT_N(bool, _("include empty"), include_empty, true);
ScriptCustomCollectionP ret(new ScriptCustomCollection);
// find all matches
String::const_iterator start = input.begin();
ScriptRegex::Results results;
while (match->matches(results, start, input.end())) {
// match, append the part before it to the result
ScriptRegex::Results::const_reference pos = results[0];
if (include_empty || pos.first != start) {
ret->value.push_back(to_script( String(start,pos.first) ));
}
start = pos.second;
}
if (include_empty || start != input.end()) {
ret->value.push_back(to_script( String(start,input.end()) ));
}
return ret;
SCRIPT_PARAM_C(String, input);
SCRIPT_PARAM_C(ScriptRegexP, match);
SCRIPT_PARAM_DEFAULT_N(bool, _("include empty"), include_empty, true);
ScriptCustomCollectionP ret(new ScriptCustomCollection);
// find all matches
String::const_iterator start = input.begin();
ScriptRegex::Results results;
while (match->matches(results, start, input.end())) {
// match, append the part before it to the result
ScriptRegex::Results::const_reference pos = results[0];
if (include_empty || pos.first != start) {
ret->value.push_back(to_script( String(start,pos.first) ));
}
start = pos.second;
}
if (include_empty || start != input.end()) {
ret->value.push_back(to_script( String(start,input.end()) ));
}
return ret;
}
SCRIPT_FUNCTION_SIMPLIFY_CLOSURE(split_text) {
FOR_EACH(b, closure.bindings) {
if (b.first == SCRIPT_VAR_match) {
b.second = regex_from_script(b.second); // pre-compile
}
}
return ScriptValueP();
FOR_EACH(b, closure.bindings) {
if (b.first == SCRIPT_VAR_match) {
b.second = regex_from_script(b.second); // pre-compile
}
}
return ScriptValueP();
}
// ----------------------------------------------------------------------------- : Rules : regex match
SCRIPT_FUNCTION_WITH_SIMPLIFY(match) {
SCRIPT_PARAM_C(String, input);
SCRIPT_PARAM_C(ScriptRegexP, match);
SCRIPT_RETURN(match->matches(input));
SCRIPT_PARAM_C(String, input);
SCRIPT_PARAM_C(ScriptRegexP, match);
SCRIPT_RETURN(match->matches(input));
}
SCRIPT_FUNCTION_SIMPLIFY_CLOSURE(match) {
FOR_EACH(b, closure.bindings) {
if (b.first == SCRIPT_VAR_match) {
b.second = regex_from_script(b.second); // pre-compile
}
}
return ScriptValueP();
FOR_EACH(b, closure.bindings) {
if (b.first == SCRIPT_VAR_match) {
b.second = regex_from_script(b.second); // pre-compile
}
}
return ScriptValueP();
}
// ----------------------------------------------------------------------------- : Init
void init_script_regex_functions(Context& ctx) {
ctx.setVariable(_("replace"), script_replace);
ctx.setVariable(_("filter text"), script_filter_text);
ctx.setVariable(_("break text"), script_break_text);
ctx.setVariable(_("split text"), script_split_text);
ctx.setVariable(_("match"), script_match);
ctx.setVariable(_("replace rule"), intrusive(new ScriptRule(script_replace)));
ctx.setVariable(_("filter rule"), intrusive(new ScriptRule(script_filter_text)));
ctx.setVariable(_("break rule"), intrusive(new ScriptRule(script_break_text)));
ctx.setVariable(_("match rule"), intrusive(new ScriptRule(script_match)));
ctx.setVariable(_("replace"), script_replace);
ctx.setVariable(_("filter text"), script_filter_text);
ctx.setVariable(_("break text"), script_break_text);
ctx.setVariable(_("split text"), script_split_text);
ctx.setVariable(_("match"), script_match);
ctx.setVariable(_("replace rule"), intrusive(new ScriptRule(script_replace)));
ctx.setVariable(_("filter rule"), intrusive(new ScriptRule(script_filter_text)));
ctx.setVariable(_("break rule"), intrusive(new ScriptRule(script_break_text)));
ctx.setVariable(_("match rule"), intrusive(new ScriptRule(script_match)));
}
+144 -144
View File
@@ -17,165 +17,165 @@
// ----------------------------------------------------------------------------- : Functions
inline size_t spelled_correctly(const String& input, size_t start, size_t end, SpellChecker** checkers, const ScriptValueP& extra_test, Context& ctx) {
// untag
String word = untag(input.substr(start,end-start));
if (word.empty()) return true;
// symbol?
if (is_in_tag(input,_("<sym"),start,end) ||
is_in_tag(input,_("<nospellcheck"),start,end)) {
// symbols are always spelled correctly
// and <nospellcheck> tags should prevent spellcheck
return true;
}
// run through spellchecker(s)
for (size_t i = 0 ; checkers[i] ; ++i) {
if (checkers[i]->spell(word)) {
return true;
}
}
// run through additional words regex
if (extra_test) {
// try on untagged
ctx.setVariable(SCRIPT_VAR_input, to_script(word));
if (*extra_test->eval(ctx)) {
return true;
}
// try on tagged
ctx.setVariable(SCRIPT_VAR_input, to_script(input.substr(start,end-start)));
if (*extra_test->eval(ctx)) {
return true;
}
}
return false;
// untag
String word = untag(input.substr(start,end-start));
if (word.empty()) return true;
// symbol?
if (is_in_tag(input,_("<sym"),start,end) ||
is_in_tag(input,_("<nospellcheck"),start,end)) {
// symbols are always spelled correctly
// and <nospellcheck> tags should prevent spellcheck
return true;
}
// run through spellchecker(s)
for (size_t i = 0 ; checkers[i] ; ++i) {
if (checkers[i]->spell(word)) {
return true;
}
}
// run through additional words regex
if (extra_test) {
// try on untagged
ctx.setVariable(SCRIPT_VAR_input, to_script(word));
if (*extra_test->eval(ctx)) {
return true;
}
// try on tagged
ctx.setVariable(SCRIPT_VAR_input, to_script(input.substr(start,end-start)));
if (*extra_test->eval(ctx)) {
return true;
}
}
return false;
}
void check_word(const String& tag, const String& input, String& out, size_t start, size_t end, SpellChecker** checkers, const ScriptValueP& extra_test, Context& ctx) {
if (start >= end) return;
bool good = spelled_correctly(input, start, end, checkers, extra_test, ctx);
if (!good) out += _("<") + tag;
out.append(input, start, end-start);
if (!good) out += _("</") + tag;
if (start >= end) return;
bool good = spelled_correctly(input, start, end, checkers, extra_test, ctx);
if (!good) out += _("<") + tag;
out.append(input, start, end-start);
if (!good) out += _("</") + tag;
}
void check_word(const String& tag, const String& input, String& out, Char sep, size_t prev, size_t start, size_t end, size_t after, SpellChecker** checkers, const ScriptValueP& extra_test, Context& ctx) {
if (start == end) {
// word consisting of whitespace/punctuation only
if (untag(input.substr(prev,after-prev)).empty()) {
if (isSpace(sep) && (after == input.size() || isSpace(input.GetChar(after)))) {
// double space
out += _("<error-spelling>");
out.append(sep);
out.append(input, prev, after-prev);
out += _("</error-spelling>");
} else {
if (sep) out.append(sep);
out.append(input, prev, after-prev);
}
} else {
// stand alone punctuation
if (sep) out.append(sep);
out += _("<error-spelling>");
out.append(input, prev, after-prev);
out += _("</error-spelling>");
}
} else {
// before the word
if (sep) out.append(sep);
out.append(input, prev, start-prev);
// the word itself
check_word(tag, input, out, start, end, checkers, extra_test, ctx);
// after the word
out.append(input, end, after-end);
}
if (start == end) {
// word consisting of whitespace/punctuation only
if (untag(input.substr(prev,after-prev)).empty()) {
if (isSpace(sep) && (after == input.size() || isSpace(input.GetChar(after)))) {
// double space
out += _("<error-spelling>");
out.append(sep);
out.append(input, prev, after-prev);
out += _("</error-spelling>");
} else {
if (sep) out.append(sep);
out.append(input, prev, after-prev);
}
} else {
// stand alone punctuation
if (sep) out.append(sep);
out += _("<error-spelling>");
out.append(input, prev, after-prev);
out += _("</error-spelling>");
}
} else {
// before the word
if (sep) out.append(sep);
out.append(input, prev, start-prev);
// the word itself
check_word(tag, input, out, start, end, checkers, extra_test, ctx);
// after the word
out.append(input, end, after-end);
}
}
SCRIPT_FUNCTION(check_spelling) {
SCRIPT_PARAM_C(StyleSheetP,stylesheet);
SCRIPT_PARAM_C(String,language);
SCRIPT_PARAM_C(String,input);
assert_tagged(input);
if (!settings.stylesheetSettingsFor(*stylesheet).card_spellcheck_enabled)
SCRIPT_RETURN(input);
SCRIPT_OPTIONAL_PARAM_N_(String,_("extra dictionary"),extra_dictionary);
SCRIPT_OPTIONAL_PARAM_N_(ScriptValueP,_("extra match"),extra_match);
// remove old spelling error tags
input = remove_tag(input, _("<error-spelling"));
// no language -> spelling checking
if (language.empty()) {
SCRIPT_RETURN(input);
}
SpellChecker* checkers[3] = {nullptr};
checkers[0] = &SpellChecker::get(language);
if (!extra_dictionary.empty()) {
checkers[1] = &SpellChecker::get(extra_dictionary,language);
}
// what will the missspelling tag be?
String tag = _("error-spelling:");
tag += language;
if (!extra_dictionary.empty()) {
tag += _(":") + extra_dictionary;
}
tag += _(">");
// now walk over the words in the input, and mark misspellings
String result;
Char sep = 0;
// indices are used as follows (at the time of check_word call):
// input: "previous <tag>(<tag>word<tag>)<tag>next"
// ^^ ^ ^ ^
// || | | |
// sep | | word_end pos
// prev_end word_start
//
size_t prev_end = 0, word_start = 0, word_end = 0, pos = 0;
while (pos < input.size()) {
Char c = input.GetChar(pos);
if (c == _('<')) {
if (word_start == pos) {
// prefer to place word start inside tags, i.e. as late as possible
word_end = word_start = pos = skip_tag(input,pos);
} else {
pos = skip_tag(input,pos);
}
} else if (isSpace(c) || c == EM_DASH || c == EN_DASH) {
// word boundary => check the word
check_word(tag, input, result, sep, prev_end, word_start, word_end, pos, checkers, extra_match, ctx);
// next
sep = c;
prev_end = word_start = word_end = pos = pos + 1;
} else {
pos++;
if (word_start == pos-1 && is_word_start_punctuation(c)) {
// skip punctuation at start of word
word_end = word_start = pos;
} else if (is_word_end_punctuation(c)) {
// skip punctuation at end of word
} else {
word_end = pos;
}
}
}
// last word
check_word(tag, input, result, sep, prev_end, word_start, word_end, pos, checkers, extra_match, ctx);
// done
assert_tagged(result);
SCRIPT_RETURN(result);
SCRIPT_PARAM_C(StyleSheetP,stylesheet);
SCRIPT_PARAM_C(String,language);
SCRIPT_PARAM_C(String,input);
assert_tagged(input);
if (!settings.stylesheetSettingsFor(*stylesheet).card_spellcheck_enabled)
SCRIPT_RETURN(input);
SCRIPT_OPTIONAL_PARAM_N_(String,_("extra dictionary"),extra_dictionary);
SCRIPT_OPTIONAL_PARAM_N_(ScriptValueP,_("extra match"),extra_match);
// remove old spelling error tags
input = remove_tag(input, _("<error-spelling"));
// no language -> spelling checking
if (language.empty()) {
SCRIPT_RETURN(input);
}
SpellChecker* checkers[3] = {nullptr};
checkers[0] = &SpellChecker::get(language);
if (!extra_dictionary.empty()) {
checkers[1] = &SpellChecker::get(extra_dictionary,language);
}
// what will the missspelling tag be?
String tag = _("error-spelling:");
tag += language;
if (!extra_dictionary.empty()) {
tag += _(":") + extra_dictionary;
}
tag += _(">");
// now walk over the words in the input, and mark misspellings
String result;
Char sep = 0;
// indices are used as follows (at the time of check_word call):
// input: "previous <tag>(<tag>word<tag>)<tag>next"
// ^^ ^ ^ ^
// || | | |
// sep | | word_end pos
// prev_end word_start
//
size_t prev_end = 0, word_start = 0, word_end = 0, pos = 0;
while (pos < input.size()) {
Char c = input.GetChar(pos);
if (c == _('<')) {
if (word_start == pos) {
// prefer to place word start inside tags, i.e. as late as possible
word_end = word_start = pos = skip_tag(input,pos);
} else {
pos = skip_tag(input,pos);
}
} else if (isSpace(c) || c == EM_DASH || c == EN_DASH) {
// word boundary => check the word
check_word(tag, input, result, sep, prev_end, word_start, word_end, pos, checkers, extra_match, ctx);
// next
sep = c;
prev_end = word_start = word_end = pos = pos + 1;
} else {
pos++;
if (word_start == pos-1 && is_word_start_punctuation(c)) {
// skip punctuation at start of word
word_end = word_start = pos;
} else if (is_word_end_punctuation(c)) {
// skip punctuation at end of word
} else {
word_end = pos;
}
}
}
// last word
check_word(tag, input, result, sep, prev_end, word_start, word_end, pos, checkers, extra_match, ctx);
// done
assert_tagged(result);
SCRIPT_RETURN(result);
}
SCRIPT_FUNCTION(check_spelling_word) {
SCRIPT_PARAM_C(String,language);
SCRIPT_PARAM_C(String,input);
if (language.empty()) {
// no language -> spelling checking
SCRIPT_RETURN(true);
} else {
bool correct = SpellChecker::get(language).spell(input);
SCRIPT_RETURN(correct);
}
SCRIPT_PARAM_C(String,language);
SCRIPT_PARAM_C(String,input);
if (language.empty()) {
// no language -> spelling checking
SCRIPT_RETURN(true);
} else {
bool correct = SpellChecker::get(language).spell(input);
SCRIPT_RETURN(correct);
}
}
// ----------------------------------------------------------------------------- : Init
void init_script_spelling_functions(Context& ctx) {
ctx.setVariable(_("check spelling"), script_check_spelling);
ctx.setVariable(_("check spelling word"), script_check_spelling_word);
ctx.setVariable(_("check spelling"), script_check_spelling);
ctx.setVariable(_("check spelling word"), script_check_spelling_word);
}
+118 -118
View File
@@ -38,31 +38,31 @@
#define SCRIPT_FUNCTION(name) SCRIPT_FUNCTION_AUX(name,;)
/// Macro to declare a new script function with custom dependency handling
#define SCRIPT_FUNCTION_WITH_DEP(name) \
SCRIPT_FUNCTION_AUX(name, virtual ScriptValueP dependencies(Context&, const Dependency&) const;)
#define SCRIPT_FUNCTION_WITH_DEP(name) \
SCRIPT_FUNCTION_AUX(name, virtual ScriptValueP dependencies(Context&, const Dependency&) const;)
#define SCRIPT_FUNCTION_DEPENDENCIES(name) \
ScriptValueP ScriptBuiltIn_##name::dependencies(Context& ctx, const Dependency& dep) const
#define SCRIPT_FUNCTION_DEPENDENCIES(name) \
ScriptValueP ScriptBuiltIn_##name::dependencies(Context& ctx, const Dependency& dep) const
/// Macro to declare a new script function with custom closure simplification
#define SCRIPT_FUNCTION_WITH_SIMPLIFY(name) \
SCRIPT_FUNCTION_AUX(name, virtual ScriptValueP simplifyClosure(ScriptClosure&) const;)
#define SCRIPT_FUNCTION_WITH_SIMPLIFY(name) \
SCRIPT_FUNCTION_AUX(name, virtual ScriptValueP simplifyClosure(ScriptClosure&) const;)
#define SCRIPT_FUNCTION_SIMPLIFY_CLOSURE(name) \
ScriptValueP ScriptBuiltIn_##name::simplifyClosure(ScriptClosure& closure) const
#define SCRIPT_FUNCTION_SIMPLIFY_CLOSURE(name) \
ScriptValueP ScriptBuiltIn_##name::simplifyClosure(ScriptClosure& closure) const
// helper for SCRIPT_FUNCTION and SCRIPT_FUNCTION_DEP
#define SCRIPT_FUNCTION_AUX(name,dep) \
class ScriptBuiltIn_##name : public ScriptValue { \
dep \
virtual ScriptType type() const \
{ return SCRIPT_FUNCTION; } \
virtual String typeName() const \
{ return _("built-in function '") _(#name) _("'"); } \
virtual ScriptValueP do_eval(Context&, bool) const; \
}; \
ScriptValueP script_##name(new ScriptBuiltIn_##name); \
ScriptValueP ScriptBuiltIn_##name::do_eval(Context& ctx, bool) const
#define SCRIPT_FUNCTION_AUX(name,dep) \
class ScriptBuiltIn_##name : public ScriptValue { \
dep \
virtual ScriptType type() const \
{ return SCRIPT_FUNCTION; } \
virtual String typeName() const \
{ return _("built-in function '") _(#name) _("'"); } \
virtual ScriptValueP do_eval(Context&, bool) const; \
}; \
ScriptValueP script_##name(new ScriptBuiltIn_##name); \
ScriptValueP ScriptBuiltIn_##name::do_eval(Context& ctx, bool) const
/// Return a value from a SCRIPT_FUNCTION
#define SCRIPT_RETURN(value) return to_script(value)
@@ -71,19 +71,19 @@
template <typename Type>
inline Type from_script(const ScriptValueP& v, const String& str) {
try {
return from_script<Type>(v);
} catch (ScriptError& e) {
throw ScriptError(_ERROR_2_("in parameter", str, e.what()));
}
try {
return from_script<Type>(v);
} catch (ScriptError& e) {
throw ScriptError(_ERROR_2_("in parameter", str, e.what()));
}
}
template <typename Type>
inline Type from_script(const ScriptValueP& v, Variable var) {
try {
return from_script<Type>(v);
} catch (ScriptError& e) {
throw ScriptError(_ERROR_2_("in parameter", variable_to_string(var), e.what()));
}
try {
return from_script<Type>(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
@@ -96,14 +96,14 @@ inline Type from_script(const ScriptValueP& v, Variable var) {
* @endcode
* Throws an error if the parameter is not found.
*/
#define SCRIPT_PARAM(Type, name) \
SCRIPT_PARAM_N(Type, _(#name), name)
#define SCRIPT_PARAM_N(Type, str, name) \
Type name = from_script<Type>(ctx.getVariable(str), str)
#define SCRIPT_PARAM(Type, name) \
SCRIPT_PARAM_N(Type, _(#name), name)
#define SCRIPT_PARAM_N(Type, str, name) \
Type name = from_script<Type>(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)
#define SCRIPT_PARAM_C(Type, name) \
SCRIPT_PARAM_N(Type, SCRIPT_VAR_ ## name, name)
/// Retrieve an optional parameter
/** Usage:
@@ -116,112 +116,112 @@ inline Type from_script(const ScriptValueP& v, Variable var) {
* }
* @endcode
*/
#define SCRIPT_OPTIONAL_PARAM(Type, name) \
SCRIPT_OPTIONAL_PARAM_N(Type, _(#name), name)
#define SCRIPT_OPTIONAL_PARAM(Type, name) \
SCRIPT_OPTIONAL_PARAM_N(Type, _(#name), name)
/// Retrieve a named optional parameter
#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)
#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) \
SCRIPT_OPTIONAL_PARAM_N_(Type, _(#name), name)
#define SCRIPT_OPTIONAL_PARAM_(Type, name) \
SCRIPT_OPTIONAL_PARAM_N_(Type, _(#name), name)
/// Retrieve a named optional parameter, can't be used as an if statement
#define SCRIPT_OPTIONAL_PARAM_N_(Type, str, name) \
ScriptValueP name##_ = ctx.getVariableOpt(str); \
Type name = name##_ && name##_ != script_nil \
? from_script<Type>(name##_, str) : Type();
#define SCRIPT_OPTIONAL_PARAM_C_(Type, name) \
SCRIPT_OPTIONAL_PARAM_N_(Type, SCRIPT_VAR_ ## name, name)
#define SCRIPT_OPTIONAL_PARAM_N_(Type, str, name) \
ScriptValueP name##_ = ctx.getVariableOpt(str); \
Type name = name##_ && name##_ != script_nil \
? from_script<Type>(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) \
SCRIPT_PARAM_DEFAULT_N(Type, _(#name), name, def)
#define SCRIPT_PARAM_DEFAULT(Type, name, def) \
SCRIPT_PARAM_DEFAULT_N(Type, _(#name), name, def)
/// Retrieve a named optional parameter with a default value
#define SCRIPT_PARAM_DEFAULT_N(Type, str, name, def) \
ScriptValueP name##_ = ctx.getVariableOpt(str); \
Type name = name##_ ? from_script<Type>(name##_, str) : def
#define SCRIPT_PARAM_DEFAULT_C(Type, name, def) \
SCRIPT_PARAM_DEFAULT_N(Type, SCRIPT_VAR_ ## name, name, def)
#define SCRIPT_PARAM_DEFAULT_N(Type, str, name, def) \
ScriptValueP name##_ = ctx.getVariableOpt(str); \
Type name = name##_ ? from_script<Type>(name##_, str) : def
#define SCRIPT_PARAM_DEFAULT_C(Type, name, def) \
SCRIPT_PARAM_DEFAULT_N(Type, SCRIPT_VAR_ ## name, name, def)
// ----------------------------------------------------------------------------- : Rules
/// Utility for defining a script rule with a single parameter
#define SCRIPT_RULE_1(funname, type1, name1) \
#define SCRIPT_RULE_1(funname, type1, name1) \
SCRIPT_RULE_1_N(funname, type1, _(#name1), name1)
#define SCRIPT_RULE_1_C(funname, type1, 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 { \
public: \
inline ScriptRule_##funname(const type1& name1) : name1(name1) {} \
virtual ScriptType type() const { return SCRIPT_FUNCTION; } \
virtual String typeName() const { return _(#funname)_("_rule"); } \
protected: \
virtual ScriptValueP do_eval(Context& ctx, bool) const; \
private: \
type1 name1; \
}; \
SCRIPT_FUNCTION(funname##_rule) { \
SCRIPT_PARAM_N(type1, str1, name1); \
return intrusive(new ScriptRule_##funname(name1)); \
} \
SCRIPT_FUNCTION(funname) { \
SCRIPT_PARAM_N(type1, str1, name1); \
return ScriptRule_##funname(name1).eval(ctx); \
} \
ScriptValueP ScriptRule_##funname::do_eval(Context& ctx, bool) const
#define SCRIPT_RULE_1_N(funname, type1, str1, name1) \
class ScriptRule_##funname: public ScriptValue { \
public: \
inline ScriptRule_##funname(const type1& name1) : name1(name1) {} \
virtual ScriptType type() const { return SCRIPT_FUNCTION; } \
virtual String typeName() const { return _(#funname)_("_rule"); } \
protected: \
virtual ScriptValueP do_eval(Context& ctx, bool) const; \
private: \
type1 name1; \
}; \
SCRIPT_FUNCTION(funname##_rule) { \
SCRIPT_PARAM_N(type1, str1, name1); \
return intrusive(new ScriptRule_##funname(name1)); \
} \
SCRIPT_FUNCTION(funname) { \
SCRIPT_PARAM_N(type1, str1, name1); \
return ScriptRule_##funname(name1).eval(ctx); \
} \
ScriptValueP ScriptRule_##funname::do_eval(Context& ctx, bool) const
/// Utility for defining a script rule with two parameters
#define SCRIPT_RULE_2(funname, type1, name1, type2, name2) \
#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) \
#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, ;, ;)
#define SCRIPT_RULE_2_N(funname, type1, str1, name1, type2, str2, name2) \
SCRIPT_RULE_2_N_AUX(funname, type1, str1, name1, type2, str2, name2, ;, ;)
/// Utility for defining a script rule with two named parameters, with dependencies
#define SCRIPT_RULE_2_N_DEP(funname, type1, str1, name1, type2, str2, name2) \
SCRIPT_RULE_2_N_AUX( funname, type1, str1, name1, type2, str2, name2, \
virtual ScriptValueP dependencies(Context&, const Dependency&) const;, \
SCRIPT_FUNCTION_DEPENDENCIES(funname) { \
SCRIPT_PARAM_N(type1, str1, name1); \
SCRIPT_PARAM_N(type2, str2, name2); \
return ScriptRule_##funname(name1, name2).dependencies(ctx, dep); \
})
#define SCRIPT_RULE_2_N_DEP(funname, type1, str1, name1, type2, str2, name2) \
SCRIPT_RULE_2_N_AUX( funname, type1, str1, name1, type2, str2, name2, \
virtual ScriptValueP dependencies(Context&, const Dependency&) const;, \
SCRIPT_FUNCTION_DEPENDENCIES(funname) { \
SCRIPT_PARAM_N(type1, str1, name1); \
SCRIPT_PARAM_N(type2, str2, name2); \
return ScriptRule_##funname(name1, name2).dependencies(ctx, dep); \
})
#define SCRIPT_RULE_2_N_AUX(funname, type1, str1, name1, type2, str2, name2, dep, more) \
class ScriptRule_##funname: public ScriptValue { \
public: \
inline ScriptRule_##funname(const type1& name1, const type2& name2) \
: name1(name1), name2(name2) {} \
virtual ScriptType type() const { return SCRIPT_FUNCTION; } \
virtual String typeName() const { return _(#funname)_("_rule"); } \
dep \
protected: \
virtual ScriptValueP do_eval(Context& ctx, bool) const; \
private: \
type1 name1; \
type2 name2; \
}; \
SCRIPT_FUNCTION(funname##_rule) { \
SCRIPT_PARAM_N(type1, str1, name1); \
SCRIPT_PARAM_N(type2, str2, name2); \
return intrusive(new ScriptRule_##funname(name1, name2)); \
} \
SCRIPT_FUNCTION_AUX(funname, dep) { \
SCRIPT_PARAM_N(type1, str1, name1); \
SCRIPT_PARAM_N(type2, str2, name2); \
return ScriptRule_##funname(name1, name2).eval(ctx); \
} \
more \
ScriptValueP ScriptRule_##funname::do_eval(Context& ctx, bool) const
class ScriptRule_##funname: public ScriptValue { \
public: \
inline ScriptRule_##funname(const type1& name1, const type2& name2) \
: name1(name1), name2(name2) {} \
virtual ScriptType type() const { return SCRIPT_FUNCTION; } \
virtual String typeName() const { return _(#funname)_("_rule"); } \
dep \
protected: \
virtual ScriptValueP do_eval(Context& ctx, bool) const; \
private: \
type1 name1; \
type2 name2; \
}; \
SCRIPT_FUNCTION(funname##_rule) { \
SCRIPT_PARAM_N(type1, str1, name1); \
SCRIPT_PARAM_N(type2, str2, name2); \
return intrusive(new ScriptRule_##funname(name1, name2)); \
} \
SCRIPT_FUNCTION_AUX(funname, dep) { \
SCRIPT_PARAM_N(type1, str1, name1); \
SCRIPT_PARAM_N(type2, str2, name2); \
return ScriptRule_##funname(name1, name2).eval(ctx); \
} \
more \
ScriptValueP ScriptRule_##funname::do_eval(Context& ctx, bool) const
#define SCRIPT_RULE_2_DEPENDENCIES(name) \
ScriptValueP ScriptRule_##name::dependencies(Context& ctx, const Dependency& dep) const
#define SCRIPT_RULE_2_DEPENDENCIES(name) \
ScriptValueP ScriptRule_##name::dependencies(Context& ctx, const Dependency& dep) const
// ----------------------------------------------------------------------------- : EOF