mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
The 'Big Whine' patch:
Any use of a file from another package without a declared dependency will give a warning; Also added some more _LOCALE_123_ macros so we need less format_string calls git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@753 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -70,7 +70,7 @@ void KeywordReminderTextValue::store() {
|
||||
String new_value = untag(value);
|
||||
// Try to parse the script
|
||||
vector<ScriptParseError> parse_errors;
|
||||
ScriptP new_script = parse(new_value, true, parse_errors);
|
||||
ScriptP new_script = parse(new_value, nullptr, true, parse_errors);
|
||||
if (parse_errors.empty()) {
|
||||
// parsed okay, assign
|
||||
errors.clear();
|
||||
|
||||
@@ -356,7 +356,7 @@ AddSymbolPartAction::AddSymbolPartAction(Symbol& symbol, const SymbolPartP& part
|
||||
{}
|
||||
|
||||
String AddSymbolPartAction::getName(bool to_undo) const {
|
||||
return format_string(_ACTION_("add part"), part->name);
|
||||
return _ACTION_1_("add part", part->name);
|
||||
}
|
||||
|
||||
void AddSymbolPartAction::perform(bool to_undo) {
|
||||
@@ -395,7 +395,7 @@ void RemoveSymbolPartsAction::check(SymbolGroup& group, const set<SymbolPartP>&
|
||||
}
|
||||
|
||||
String RemoveSymbolPartsAction::getName(bool to_undo) const {
|
||||
return format_string(_ACTION_("remove parts"), removals.size() == 1 ? _TYPE_("shape") : _TYPE_("shapes"));
|
||||
return _ACTION_1_("remove parts", removals.size() == 1 ? _TYPE_("shape") : _TYPE_("shapes"));
|
||||
}
|
||||
|
||||
void RemoveSymbolPartsAction::perform(bool to_undo) {
|
||||
@@ -433,7 +433,7 @@ DuplicateSymbolPartsAction::DuplicateSymbolPartsAction(Symbol& symbol, const set
|
||||
}
|
||||
|
||||
String DuplicateSymbolPartsAction::getName(bool to_undo) const {
|
||||
return format_string(_ACTION_("duplicate"), duplications.size() == 1 ? _TYPE_("shape") : _TYPE_("shapes"));
|
||||
return _ACTION_1_("duplicate", duplications.size() == 1 ? _TYPE_("shape") : _TYPE_("shapes"));
|
||||
}
|
||||
|
||||
void DuplicateSymbolPartsAction::perform(bool to_undo) {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
// ----------------------------------------------------------------------------- : ValueAction
|
||||
|
||||
String ValueAction::getName(bool to_undo) const {
|
||||
return format_string(_ACTION_("change"), valueP->fieldP->name);
|
||||
return _ACTION_1_("change", valueP->fieldP->name);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Simple
|
||||
|
||||
@@ -31,7 +31,7 @@ String serialize_for_clipboard(Package& package, T& object) {
|
||||
template <typename T>
|
||||
void deserialize_from_clipboard(T& object, Package& package, const String& data) {
|
||||
shared_ptr<wxStringInputStream> stream( new wxStringInputStream(data) );
|
||||
Reader reader(stream, _("clipboard"));
|
||||
Reader reader(stream, nullptr, _("clipboard"));
|
||||
WITH_DYNAMIC_ARG(clipboard_package, &package);
|
||||
reader.handle_greedy(object);
|
||||
}
|
||||
|
||||
+17
-13
@@ -42,12 +42,12 @@ void Installer::installFrom(const String& filename, bool message_on_success, boo
|
||||
i.open(filename);
|
||||
try {
|
||||
i.install(local);
|
||||
}
|
||||
catch (Error& e) {
|
||||
} catch (const Error& e) {
|
||||
handle_error(e);
|
||||
return;
|
||||
}
|
||||
if (message_on_success) {
|
||||
//wxMessageBox(_ERROR_2_("successful install", i.name(), String() << i.packaged.size(),
|
||||
wxMessageBox(String::Format(_("'%s' successfully installed %d package%s."), i.name().c_str(), i.packages.size(), i.packages.size() == 1 ? _("") : _("s")),
|
||||
_("Magic Set Editor"), wxOK | wxICON_INFORMATION);
|
||||
}
|
||||
@@ -65,15 +65,17 @@ struct dependency_check : public unary_function<bool, PackagedP> {
|
||||
void Installer::install(bool local) {
|
||||
// Destination directory
|
||||
String install_dir = local ? ::packages.getLocalDataDir() : ::packages.getGlobalDataDir();
|
||||
if (!wxDirExists(install_dir))
|
||||
if (!wxDirExists(install_dir)) {
|
||||
wxMkdir(install_dir, 0755);
|
||||
}
|
||||
|
||||
// All the packages we're installing.
|
||||
vector<PackagedP> new_packages;
|
||||
|
||||
FOR_EACH(p, packages) {
|
||||
if (wxDirExists(install_dir + _("/") + p) || wxFileExists(install_dir + _("/") + p))
|
||||
if (wxDirExists(install_dir + _("/") + p) || wxFileExists(install_dir + _("/") + p)) {
|
||||
throw PackageError(_("Package ") + p + _(" is already installed. Overwriting currently not supported."));
|
||||
}
|
||||
PackagedP pack;
|
||||
wxString fn(wxFileName(p).GetExt());
|
||||
if (fn == _("mse-game")) pack = new_intrusive<Game>();
|
||||
@@ -90,7 +92,6 @@ void Installer::install(bool local) {
|
||||
new_packages.push_back(pack);
|
||||
}
|
||||
|
||||
|
||||
// Check dependencies for each and every package.
|
||||
FOR_EACH(p, new_packages) {
|
||||
FOR_EACH(d, p->dependencies) {
|
||||
@@ -100,28 +101,31 @@ void Installer::install(bool local) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const FileInfos& file_infos = getFileInfos();
|
||||
for (FileInfos::const_iterator it = file_infos.begin() ; it != file_infos.end() ; ++it) {
|
||||
String file = it->first;
|
||||
|
||||
|
||||
wxFileName fn(file);
|
||||
wxArrayString dirs = fn.GetDirs();
|
||||
|
||||
if (fn.IsDir() || !dirs.GetCount() || find(packages.begin(), packages.end(), dirs[0]) == packages.end())
|
||||
|
||||
if (fn.IsDir() || !dirs.GetCount() || find(packages.begin(), packages.end(), dirs[0]) == packages.end()) {
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
String current_dir = install_dir;
|
||||
for (size_t j = 0; j < dirs.GetCount(); ++j) {
|
||||
current_dir += _("/") + dirs[j];
|
||||
if (!wxDirExists(current_dir) && !wxMkdir(current_dir, 0755))
|
||||
if (!wxDirExists(current_dir) && !wxMkdir(current_dir, 0755)) {
|
||||
throw PackageError(_("Cannot create folder ") + current_dir + _(" for install. Warning: some packages may have been installed anyway, and some may only be partially installed."));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
InputStreamP is = openIn(file);
|
||||
wxFileOutputStream os (install_dir + _("/") + file);
|
||||
if (!os.IsOk())
|
||||
if (!os.IsOk()) {
|
||||
throw PackageError(_("Cannot create file ") + install_dir + _("/") + file + _(" for install. Warning: some packages may have been installed anyway, and some may only be partially installed."));
|
||||
}
|
||||
os.Write(*is);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -206,7 +206,7 @@ DECLARE_TYPEOF(map<String COMMA KeyValidator>);
|
||||
void Locale::validate(Version ver) {
|
||||
// load locale validator
|
||||
LocaleValidator v;
|
||||
Reader r(load_resource_text(_("expected_locale_keys")), _("expected_locale_keys"));
|
||||
Reader r(load_resource_text(_("expected_locale_keys")), nullptr, _("expected_locale_keys"));
|
||||
r.handle_greedy(v);
|
||||
// validate
|
||||
String errors;
|
||||
|
||||
@@ -248,7 +248,7 @@ void Settings::read() {
|
||||
// settings file not existing is not an error
|
||||
shared_ptr<wxFileInputStream> file = new_shared1<wxFileInputStream>(filename);
|
||||
if (!file->Ok()) return; // failure is not an error
|
||||
Reader reader(file, filename);
|
||||
Reader reader(file, nullptr, filename);
|
||||
reader.handle_greedy(*this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ void ImagesExportWindow::onOk(wxCommandEvent&) {
|
||||
else if (sel == 2) gs.images_export_conflicts = CONFLICT_NUMBER;
|
||||
else gs.images_export_conflicts = CONFLICT_NUMBER_OVERWRITE;
|
||||
// Script
|
||||
ScriptP filename_script = parse(gs.images_export_filename, true);
|
||||
ScriptP filename_script = parse(gs.images_export_filename, nullptr, true);
|
||||
// Select filename
|
||||
String name = wxFileSelector(_TITLE_("export images"),_(""), _LABEL_("filename is ignored"),_(""),
|
||||
_LABEL_("filename is ignored")+_("|*"), wxSAVE, this);
|
||||
|
||||
+24
-11
@@ -35,7 +35,7 @@ DECLARE_POINTER_TYPE(PageLayout);
|
||||
*/
|
||||
class TextBufferDC : public wxMemoryDC {
|
||||
public:
|
||||
TextBufferDC(int width, int height);
|
||||
TextBufferDC(int width, int height, bool buffer_text);
|
||||
|
||||
virtual void DoDrawText(const String& str, int x, int y);
|
||||
virtual void DoDrawRotatedText(const String& str, int x, int y, double angle);
|
||||
@@ -62,24 +62,34 @@ class TextBufferDC : public wxMemoryDC {
|
||||
private:
|
||||
vector<TextDrawP> text;
|
||||
Bitmap buffer;
|
||||
bool buffer_text; ///< buffering text?
|
||||
};
|
||||
|
||||
TextBufferDC::TextBufferDC(int width, int height)
|
||||
TextBufferDC::TextBufferDC(int width, int height, bool buffer_text)
|
||||
: buffer(width, height, 32)
|
||||
, buffer_text(buffer_text)
|
||||
{
|
||||
SelectObject(buffer);
|
||||
// initialize to white
|
||||
clearDC(*this,*wxWHITE_BRUSH);
|
||||
}
|
||||
void TextBufferDC::DoDrawText(const String& str, int x, int y) {
|
||||
double usx,usy;
|
||||
GetUserScale(&usx, &usy);
|
||||
text.push_back( new_intrusive7<TextDraw>(GetFont(), GetTextForeground(), usx, usy, x, y, str) );
|
||||
if (buffer_text) {
|
||||
double usx,usy;
|
||||
GetUserScale(&usx, &usy);
|
||||
text.push_back( new_intrusive7<TextDraw>(GetFont(), GetTextForeground(), usx, usy, x, y, str) );
|
||||
} else {
|
||||
wxMemoryDC::DoDrawText(str,x,y);
|
||||
}
|
||||
}
|
||||
void TextBufferDC::DoDrawRotatedText(const String& str, int x, int y, double angle) {
|
||||
double usx,usy;
|
||||
GetUserScale(&usx, &usy);
|
||||
text.push_back( new_intrusive8<TextDraw>(GetFont(), GetTextForeground(), usx, usy, x, y, str, angle) );
|
||||
if (buffer_text) {
|
||||
double usx,usy;
|
||||
GetUserScale(&usx, &usy);
|
||||
text.push_back( new_intrusive8<TextDraw>(GetFont(), GetTextForeground(), usx, usy, x, y, str, angle) );
|
||||
} else {
|
||||
wxMemoryDC::DoDrawRotatedText(str,x,y,angle);
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(TextBufferDC::TextDrawP);
|
||||
@@ -219,13 +229,16 @@ void CardsPrintout::drawCard(DC& dc, const CardP& card, int card_nr) {
|
||||
// create buffers
|
||||
int w = stylesheet.card_width, h = stylesheet.card_height; // in pixels
|
||||
if (rotation == 90) swap(w,h);
|
||||
TextBufferDC bufferDC(w,h);
|
||||
RotatedDC rdc(bufferDC, rotation, RealRect(0,0,w,h), 1.0, QUALITY_SUB_PIXEL);
|
||||
// Draw using text buffer
|
||||
//TextBufferDC bufferDC(w,h,true);
|
||||
//RotatedDC rdc(bufferDC, rotation, RealRect(0,0,w,h), 1.0, QUALITY_SUB_PIXEL);
|
||||
TextBufferDC bufferDC(w*4,h*4,false);
|
||||
RotatedDC rdc(bufferDC, rotation, RealRect(0,0,w*4,h*4), 4.0, QUALITY_AA);
|
||||
// render card to dc
|
||||
viewer.setCard(card);
|
||||
viewer.draw(rdc, *wxWHITE);
|
||||
// render buffer to device
|
||||
double px_per_mm = stylesheet.card_dpi / 25.4;
|
||||
double px_per_mm = 4 * stylesheet.card_dpi / 25.4;
|
||||
dc.SetUserScale(scale_x / px_per_mm, scale_y / px_per_mm);
|
||||
dc.SetDeviceOrigin(scale_x * pos.x, scale_y * pos.y);
|
||||
bufferDC.drawToDevice(dc, 0, 0); // adjust for scaling
|
||||
|
||||
@@ -188,7 +188,7 @@ void CardsPanel::onUpdateUI(wxUpdateUIEvent& ev) {
|
||||
ev.Enable(menu);
|
||||
if (insertSymbolMenu->GetSubMenu() != menu || (menu && menu->GetParent() != menuFormat)) {
|
||||
// re-add the menu
|
||||
menuFormat->Remove(insertSymbolMenu);
|
||||
menuFormat->Remove(ID_INSERT_SYMBOL);
|
||||
insertSymbolMenu->SetSubMenu(menu);
|
||||
menuFormat->Append(insertSymbolMenu);
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ void KeywordsPanel::doPaste() { CUT_COPY_PASTE(doPaste, return (void), !
|
||||
void KeywordsPanel::onChangeSet() {
|
||||
list->setSet(set);
|
||||
// warning label (depends on game name)
|
||||
fixedL->SetLabel(format_string(_LABEL_("standard keyword"), set->game->short_name));
|
||||
fixedL->SetLabel(_LABEL_1_("standard keyword", set->game->short_name));
|
||||
// init text controls
|
||||
keyword ->setSet(set);
|
||||
keyword ->getStyle().font.size = 16;
|
||||
|
||||
@@ -286,7 +286,7 @@ void SetWindow::updateTitle() {
|
||||
if (identification.empty()) identification = set->name();
|
||||
if (identification.empty()) identification = _TITLE_("untitled");
|
||||
set->short_name = identification;
|
||||
SetTitle(format_string(_TITLE_("%s - magic set editor"),identification));
|
||||
SetTitle(_TITLE_1_("%s - magic set editor",identification));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,7 +335,7 @@ void SetWindow::onClose(wxCloseEvent& ev) {
|
||||
bool SetWindow::askSaveAndContinue() {
|
||||
if (set->actions.atSavePoint()) return true;
|
||||
// todo : if more then one window has the set selected it's ok to proceed
|
||||
int save = wxMessageBox(format_string(_LABEL_("save changes"), set->short_name), _TITLE_("save changes"), wxYES_NO | wxCANCEL | wxICON_EXCLAMATION);
|
||||
int save = wxMessageBox(_LABEL_1_("save changes", set->short_name), _TITLE_("save changes"), wxYES_NO | wxCANCEL | wxICON_EXCLAMATION);
|
||||
if (save == wxYES) {
|
||||
// save the set
|
||||
try {
|
||||
|
||||
@@ -29,7 +29,7 @@ SymbolWindow::SymbolWindow(Window* parent) {
|
||||
|
||||
SymbolWindow::SymbolWindow(Window* parent, const String& filename) {
|
||||
// open file
|
||||
Reader reader(new_shared1<wxFileInputStream>(filename), filename);
|
||||
Reader reader(new_shared1<wxFileInputStream>(filename), nullptr, filename);
|
||||
SymbolP symbol;
|
||||
reader.handle_greedy(symbol);
|
||||
init(parent, symbol);
|
||||
@@ -204,7 +204,7 @@ void SymbolWindow::onFileOpen(wxCommandEvent& ev) {
|
||||
String ext = n.GetExt();
|
||||
SymbolP symbol;
|
||||
if (ext.Lower() == _("mse-symbol")) {
|
||||
Reader reader(new_shared1<wxFileInputStream>(name), name);
|
||||
Reader reader(new_shared1<wxFileInputStream>(name), nullptr, name);
|
||||
reader.handle_greedy(symbol);
|
||||
} else {
|
||||
wxBusyCursor busy;
|
||||
|
||||
@@ -297,8 +297,7 @@ void DropDownWordList::select(size_t item) {
|
||||
tve.selection_start_i = pos->start;
|
||||
tve.selection_end_i = pos->end;
|
||||
tve.fixSelection(TYPE_INDEX);
|
||||
tve.replaceSelection(escape(new_value),
|
||||
format_string(_ACTION_("change"), tve.field().name));
|
||||
tve.replaceSelection(escape(new_value), _ACTION_1_("change", tve.field().name));
|
||||
// stay open?
|
||||
if (IsShown()) selection(); // update 'enabled'
|
||||
}
|
||||
|
||||
+3
-2
@@ -102,9 +102,10 @@ int MSE::OnRun() {
|
||||
InstallType type = settings.install_type;
|
||||
if (argc > 2) {
|
||||
String arg = argv[2];
|
||||
if (arg.Mid(0,2) == _("--"))
|
||||
parse_enum(arg.Mid(2), type);
|
||||
if (starts_with(argv[2], _("--"))) {
|
||||
parse_enum(String(argv[2]).substr(2), type);
|
||||
}
|
||||
}
|
||||
Installer::installFrom(argv[1], true, isInstallLocal(type));
|
||||
return EXIT_SUCCESS;
|
||||
} else if (arg == _("--symbol-editor")) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# This file contains the keys expected to be in MSE locales
|
||||
# It was automatically generated by tools/locale/locale.pl
|
||||
# Generated on Fri Sep 21 14:19:24 2007
|
||||
# Generated on Mon Sep 24 22:07:59 2007
|
||||
|
||||
action:
|
||||
add control point: 0
|
||||
@@ -82,9 +82,11 @@ error:
|
||||
checking updates: 0
|
||||
checking updates failed: 0
|
||||
coordinates for blending overlap: 0
|
||||
dependency not given: 4
|
||||
dimension not found: 1
|
||||
expected key: 1
|
||||
file not found: 2
|
||||
file not found package like: 2
|
||||
file parse error: 2
|
||||
has no member: 2
|
||||
has no member value: 2
|
||||
@@ -99,7 +101,9 @@ error:
|
||||
no updates: 0
|
||||
package not found: 1
|
||||
package out of date: 3
|
||||
package too new: 4
|
||||
stylesheet and set refer to different game: 0
|
||||
successful install: optional, 2
|
||||
unable to open output file: 0
|
||||
unable to store file: 0
|
||||
unrecognized value: 1
|
||||
|
||||
+11
-8
@@ -57,7 +57,7 @@ enum OpenBrace
|
||||
/** Also stores errors found when tokenizing or parsing */
|
||||
class TokenIterator {
|
||||
public:
|
||||
TokenIterator(const String& str, bool string_mode, vector<ScriptParseError>& errors);
|
||||
TokenIterator(const String& str, Packaged* package, bool string_mode, vector<ScriptParseError>& errors);
|
||||
|
||||
/// Peek at the next token, doesn't move to the one after that
|
||||
/** Can peek further forward by using higher values of offset.
|
||||
@@ -75,6 +75,7 @@ class TokenIterator {
|
||||
String input;
|
||||
size_t pos;
|
||||
String filename; ///< Filename of include files, "" for the main input
|
||||
Packaged* package; ///< Package the input is from
|
||||
vector<Token> buffer; ///< buffer of unread tokens, front() = current
|
||||
stack<OpenBrace> open_braces; ///< braces/quotes we entered from script mode
|
||||
bool newline; ///< Did we just pass a newline?
|
||||
@@ -83,6 +84,7 @@ class TokenIterator {
|
||||
String input;
|
||||
size_t pos;
|
||||
String filename;
|
||||
Package* package;
|
||||
};
|
||||
stack<MoreInput> more; ///< Read tokens from here when we are done with the current input
|
||||
|
||||
@@ -115,9 +117,10 @@ bool isLongOper(const String& s) { return s==_(":=") || s==_("==") || s==_("!=")
|
||||
|
||||
// ----------------------------------------------------------------------------- : Tokenizing
|
||||
|
||||
TokenIterator::TokenIterator(const String& str, bool string_mode, vector<ScriptParseError>& errors)
|
||||
TokenIterator::TokenIterator(const String& str, Packaged* package, bool string_mode, vector<ScriptParseError>& errors)
|
||||
: input(str)
|
||||
, pos(0)
|
||||
, package(package)
|
||||
, newline(false)
|
||||
, errors(errors)
|
||||
{
|
||||
@@ -183,12 +186,12 @@ void TokenIterator::readToken() {
|
||||
if (eol == String::npos) eol = input.size();
|
||||
String include_file = trim(input.substr(pos, eol - pos));
|
||||
// store the current input for later retrieval
|
||||
MoreInput m = {input, eol, filename};
|
||||
MoreInput m = {input, eol, filename, package};
|
||||
more.push(m);
|
||||
// read the entire file, and start at the beginning of it
|
||||
pos = 0;
|
||||
filename = include_file;
|
||||
InputStreamP is = packages.openFileFromPackage(include_file);
|
||||
InputStreamP is = packages.openFileFromPackage(package, include_file);
|
||||
input = read_utf8_line(*is, true, true);
|
||||
} else if (isAlpha(c) || c == _('_')) {
|
||||
// name
|
||||
@@ -345,10 +348,10 @@ void parseExpr(TokenIterator& input, Script& script, Precedence min_prec);
|
||||
void parseOper(TokenIterator& input, Script& script, Precedence min_prec, InstructionType close_with = I_NOP, int close_with_data = 0);
|
||||
|
||||
|
||||
ScriptP parse(const String& s, bool string_mode, vector<ScriptParseError>& errors_out) {
|
||||
ScriptP parse(const String& s, Packaged* package, bool string_mode, vector<ScriptParseError>& errors_out) {
|
||||
errors_out.clear();
|
||||
// parse
|
||||
TokenIterator input(s, string_mode, errors_out);
|
||||
TokenIterator input(s, package, string_mode, errors_out);
|
||||
ScriptP script(new Script);
|
||||
parseOper(input, *script, PREC_ALL, I_RET);
|
||||
Token eof = input.read();
|
||||
@@ -363,9 +366,9 @@ ScriptP parse(const String& s, bool string_mode, vector<ScriptParseError>& error
|
||||
}
|
||||
}
|
||||
|
||||
ScriptP parse(const String& s, bool string_mode) {
|
||||
ScriptP parse(const String& s, Packaged* package, bool string_mode) {
|
||||
vector<ScriptParseError> errors;
|
||||
ScriptP script = parse(s, string_mode, errors);
|
||||
ScriptP script = parse(s, package, string_mode, errors);
|
||||
if (!errors.empty()) {
|
||||
throw ScriptParseErrors(errors);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include <util/error.hpp>
|
||||
#include <script/script.hpp>
|
||||
|
||||
class Packaged;
|
||||
|
||||
// ----------------------------------------------------------------------------- : Parser
|
||||
|
||||
/// Parse a String to a Script
|
||||
@@ -21,8 +23,10 @@
|
||||
*
|
||||
* Errors are stored in the output vector.
|
||||
* If there are errors, the result is a null pointer
|
||||
*
|
||||
* The package is for loading included files, it may be null
|
||||
*/
|
||||
ScriptP parse(const String& s, bool string_mode, vector<ScriptParseError>& errors_out);
|
||||
ScriptP parse(const String& s, Packaged* package, bool string_mode, vector<ScriptParseError>& errors_out);
|
||||
|
||||
/// Parse a String to a Script
|
||||
/** If string_mode then s is interpreted as a string,
|
||||
@@ -30,7 +34,7 @@ ScriptP parse(const String& s, bool string_mode, vector<ScriptParseError>& error
|
||||
*
|
||||
* If an error is encountered, an exception is thrown.
|
||||
*/
|
||||
ScriptP parse(const String& s, bool string_mode = false);
|
||||
ScriptP parse(const String& s, Packaged* package = nullptr, bool string_mode = false);
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
#endif
|
||||
|
||||
@@ -46,7 +46,7 @@ ScriptValueP OptionalScript::invoke(Context& ctx, bool open_scope) const {
|
||||
|
||||
void OptionalScript::parse(Reader& reader, bool string_mode) {
|
||||
vector<ScriptParseError> errors;
|
||||
script = ::parse(unparsed, string_mode, errors);
|
||||
script = ::parse(unparsed, reader.getPackage(), string_mode, errors);
|
||||
// show parse errors as warnings
|
||||
String include_warnings;
|
||||
for (size_t i = 0 ; i < errors.size() ; ++i) {
|
||||
@@ -104,7 +104,7 @@ const String& StringScript::get() const {
|
||||
|
||||
void StringScript::set(const String& s) {
|
||||
unparsed = s;
|
||||
script = ::parse(unparsed, true);
|
||||
script = ::parse(unparsed, nullptr, true);
|
||||
}
|
||||
|
||||
template <> void Reader::handle(StringScript& os) {
|
||||
|
||||
@@ -112,7 +112,7 @@ class ScriptCollection : public ScriptValue {
|
||||
public:
|
||||
inline ScriptCollection(const Collection* v) : value(v) {}
|
||||
virtual ScriptType type() const { return SCRIPT_COLLECTION; }
|
||||
virtual String typeName() const { return format_string(_TYPE_("collection of"), type_name(*value->begin())); }
|
||||
virtual String typeName() const { return _TYPE_1_("collection of", type_name(*value->begin())); }
|
||||
virtual ScriptValueP getMember(const String& name) const {
|
||||
long index;
|
||||
if (name.ToLong(&index) && index >= 0 && (size_t)index < value->size()) {
|
||||
@@ -160,7 +160,7 @@ class ScriptMap : public ScriptValue {
|
||||
public:
|
||||
inline ScriptMap(const Collection* v) : value(v) {}
|
||||
virtual ScriptType type() const { return SCRIPT_COLLECTION; }
|
||||
virtual String typeName() const { return format_string(_TYPE_("collection of"), type_name(value->begin())); }
|
||||
virtual String typeName() const { return _TYPE_1_("collection of", type_name(value->begin())); }
|
||||
virtual ScriptValueP getMember(const String& name) const {
|
||||
return get_member(*value, name);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ IndexMap<Key,Value>& DelayedIndexMaps<Key,Value>::get(const String& name, const
|
||||
item->read_data.init(init_with);
|
||||
} else if (!item->unread_data.empty()) { // not read, read now
|
||||
item->read_data.init(init_with);
|
||||
Reader reader(new_shared1<wxStringInputStream>(item->unread_data), _("delayed data for ") + name);
|
||||
Reader reader(new_shared1<wxStringInputStream>(item->unread_data), nullptr, _("delayed data for ") + name);
|
||||
reader.handle_greedy(item->read_data);
|
||||
item->unread_data.clear();
|
||||
}
|
||||
|
||||
+27
-3
@@ -178,10 +178,15 @@ class BufferedFileInputStream : private BufferedFileInputStream_aux, public wxBu
|
||||
InputStreamP Package::openIn(const String& file) {
|
||||
if (!file.empty() && file.GetChar(0) == _('/')) {
|
||||
// absolute path, open file from another package
|
||||
return packages.openFileFromPackage(file);
|
||||
Packaged* p = dynamic_cast<Packaged*>(this);
|
||||
return packages.openFileFromPackage(p, file);
|
||||
}
|
||||
FileInfos::iterator it = files.find(toStandardName(file));
|
||||
if (it == files.end()) {
|
||||
// does it look like a relative filename?
|
||||
if (filename.find(_(".mse-")) != String::npos) {
|
||||
throw PackageError(_ERROR_2_("file not found package like", file, filename));
|
||||
}
|
||||
throw FileNotFoundError(file, filename);
|
||||
}
|
||||
InputStreamP stream;
|
||||
@@ -442,6 +447,7 @@ IMPLEMENT_REFLECTION(Packaged) {
|
||||
REFLECT_N("icon", icon_filename);
|
||||
REFLECT_NO_SCRIPT(position_hint);
|
||||
REFLECT(version);
|
||||
REFLECT(compatible_version);
|
||||
REFLECT_NO_SCRIPT_N("depends ons", dependencies); // hack for singular_form
|
||||
}
|
||||
|
||||
@@ -472,7 +478,7 @@ void Packaged::open(const String& package, bool just_header) {
|
||||
fully_loaded = false;
|
||||
if (just_header) {
|
||||
// Read just the header (the part common to all Packageds)
|
||||
Reader reader(openIn(typeName()), absoluteFilename() + _("/") + typeName(), true);
|
||||
Reader reader(openIn(typeName()), this, absoluteFilename() + _("/") + typeName(), true);
|
||||
try {
|
||||
JustAsPackageProxy proxy(this);
|
||||
reader.handle_greedy(proxy);
|
||||
@@ -487,7 +493,7 @@ void Packaged::open(const String& package, bool just_header) {
|
||||
void Packaged::loadFully() {
|
||||
if (fully_loaded) return;
|
||||
fully_loaded = true;
|
||||
Reader reader(openIn(typeName()), absoluteFilename() + _("/") + typeName());
|
||||
Reader reader(openIn(typeName()), this, absoluteFilename() + _("/") + typeName());
|
||||
try {
|
||||
reader.handle_greedy(*this);
|
||||
validate(reader.file_app_version);
|
||||
@@ -518,6 +524,24 @@ void Packaged::validate(Version) {
|
||||
}
|
||||
}
|
||||
|
||||
void Packaged::requireDependency(Packaged* package) {
|
||||
if (package == this) return; // dependency on self
|
||||
String n = package->relativeFilename();
|
||||
FOR_EACH(dep, dependencies) {
|
||||
if (dep->package == n) {
|
||||
if (package->version < dep->version) {
|
||||
handle_warning(_ERROR_3_("package out of date", n, package->version.toString(), dep->version.toString()), false);
|
||||
} else if (package->compatible_version > dep->version) {
|
||||
handle_warning(_ERROR_4_("package too new", n, package->version.toString(), dep->version.toString(), relativeFilename()), false);
|
||||
} else {
|
||||
return; // ok
|
||||
}
|
||||
}
|
||||
}
|
||||
// dependency not found
|
||||
handle_warning(_ERROR_4_("dependency not given", name(), package->relativeFilename(), package->relativeFilename(), package->version.toString()), false);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : IncludePackage
|
||||
|
||||
String IncludePackage::typeName() const { return _("include"); }
|
||||
|
||||
+11
-6
@@ -117,7 +117,7 @@ class Package : public IntrusivePtrVirtualBase {
|
||||
|
||||
template <typename T>
|
||||
void readFile(const String& file, T& obj) {
|
||||
Reader reader(openIn(file), absoluteFilename() + _("/") + file);
|
||||
Reader reader(openIn(file), dynamic_cast<Packaged*>(this), absoluteFilename() + _("/") + file);
|
||||
try {
|
||||
reader.handle_greedy(obj);
|
||||
} catch (const ParseError& err) {
|
||||
@@ -196,12 +196,13 @@ class Packaged : public Package {
|
||||
Packaged();
|
||||
virtual ~Packaged() {}
|
||||
|
||||
Version version; ///< Version number of this package
|
||||
String short_name; ///< Short name of this package
|
||||
String full_name; ///< Name of this package, for menus etc.
|
||||
String icon_filename; ///< Filename of icon to use in package lists
|
||||
Version version; ///< Version number of this package
|
||||
Version compatible_version; ///< Earliest version number this package is compatible with
|
||||
String short_name; ///< Short name of this package
|
||||
String full_name; ///< Name of this package, for menus etc.
|
||||
String icon_filename; ///< Filename of icon to use in package lists
|
||||
vector<PackageDependencyP> dependencies; ///< Dependencies of this package
|
||||
int position_hint; ///< A hint for the package list
|
||||
int position_hint; ///< A hint for the package list
|
||||
|
||||
/// Get an input stream for the package icon, if there is any
|
||||
InputStreamP openIconFile();
|
||||
@@ -215,6 +216,10 @@ class Packaged : public Package {
|
||||
void save();
|
||||
void saveAs(const String& package, bool remove_unused = true);
|
||||
|
||||
/// Check if this package lists a dependency on the given package
|
||||
/** This is done to force people to fill in the dependencies */
|
||||
void requireDependency(Packaged* package);
|
||||
|
||||
protected:
|
||||
/// filename of the data file, and extension of the package file
|
||||
virtual String typeName() const = 0;
|
||||
|
||||
@@ -101,17 +101,24 @@ void PackageManager::findMatching(const String& pattern, vector<PackagedP>& out)
|
||||
}
|
||||
}
|
||||
|
||||
InputStreamP PackageManager::openFileFromPackage(const String& name) {
|
||||
// we don't want an absolute path (for security reasons)
|
||||
String n;
|
||||
if (!name.empty() && name.GetChar(0) == _('/')) n = name.substr(1);
|
||||
else n = name;
|
||||
// break
|
||||
size_t pos = n.find_first_of(_("/\\"));
|
||||
if (pos == String::npos) throw FileNotFoundError(n, _("No package name specified, use 'package/filename'"));
|
||||
// open package and file
|
||||
PackagedP p = openAny(n.substr(0, pos));
|
||||
return p->openIn(n.substr(pos+1));
|
||||
InputStreamP PackageManager::openFileFromPackage(Packaged*& package, const String& name) {
|
||||
if (!name.empty() && name.GetChar(0) == _('/')) {
|
||||
// absolute name; break name
|
||||
size_t pos = name.find_first_of(_("/\\"), 1);
|
||||
if (pos != String::npos) {
|
||||
// open package
|
||||
PackagedP p = openAny(name.substr(1, pos-1));
|
||||
if (package) {
|
||||
package->requireDependency(p.get());
|
||||
}
|
||||
package = p.get();
|
||||
return p->openIn(name.substr(pos + 1));
|
||||
}
|
||||
} else if (package) {
|
||||
// relative name
|
||||
return package->openIn(name);
|
||||
}
|
||||
throw FileNotFoundError(name, _("No package name specified, use '/package/filename'"));
|
||||
}
|
||||
|
||||
bool PackageManager::checkDependency(const PackageDependency& dep, bool report_errors) {
|
||||
|
||||
@@ -66,12 +66,18 @@ class PackageManager {
|
||||
/** Only reads the package headers */
|
||||
void findMatching(const String& pattern, vector<PackagedP>& out);
|
||||
|
||||
/// Open a file from a package, with a name encoded as "package/file"
|
||||
InputStreamP openFileFromPackage(const String& name);
|
||||
/// Open a file from a package, with a name encoded as "/package/file"
|
||||
/** If 'package' is set then:
|
||||
* - tries to open a relative file from the package if the name is "file"
|
||||
* - verifies a dependency from that package if an absolute filename is used
|
||||
* this is to force people to fill in the dependencies
|
||||
* Afterwards, package will be set to the package the file is opened from
|
||||
*/
|
||||
InputStreamP openFileFromPackage(Packaged*& package, const String& name);
|
||||
|
||||
/// Check if the given dependency is currently installed
|
||||
bool checkDependency(const PackageDependency& dep, bool report_errors = false);
|
||||
|
||||
bool checkDependency(const PackageDependency& dep, bool report_errors = true);
|
||||
|
||||
inline String getGlobalDataDir() const { return global_data_directory; }
|
||||
inline String getLocalDataDir() const { return local_data_directory; }
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
|
||||
// ----------------------------------------------------------------------------- : Reader
|
||||
|
||||
Reader::Reader(const InputStreamP& input, const String& filename, bool ignore_invalid)
|
||||
Reader::Reader(const InputStreamP& input, Packaged* package, const String& filename, bool ignore_invalid)
|
||||
: indent(0), expected_indent(0), state(OUTSIDE)
|
||||
, filename(filename), line_number(0), previous_line_number(0)
|
||||
, package(package), filename(filename), line_number(0), previous_line_number(0)
|
||||
, ignore_invalid(ignore_invalid)
|
||||
, input(input)
|
||||
{
|
||||
@@ -24,12 +24,12 @@ Reader::Reader(const InputStreamP& input, const String& filename, bool ignore_in
|
||||
handleAppVersion();
|
||||
}
|
||||
|
||||
Reader::Reader(const String& filename)
|
||||
Reader::Reader(Packaged* pkg, const String& filename)
|
||||
: indent(0), expected_indent(0), state(OUTSIDE)
|
||||
, filename(filename), line_number(0), previous_line_number(0)
|
||||
, package(pkg), filename(filename), line_number(0), previous_line_number(0)
|
||||
, ignore_invalid(false)
|
||||
, input(packages.openFileFromPackage(filename))
|
||||
{
|
||||
input = packages.openFileFromPackage(package, filename);
|
||||
moveNext();
|
||||
handleAppVersion();
|
||||
}
|
||||
|
||||
+12
-4
@@ -16,6 +16,7 @@ template <typename T> class Defaultable;
|
||||
template <typename T> class Scriptable;
|
||||
DECLARE_POINTER_TYPE(Game);
|
||||
DECLARE_POINTER_TYPE(StyleSheet);
|
||||
class Packaged;
|
||||
|
||||
// ----------------------------------------------------------------------------- : Reader
|
||||
|
||||
@@ -35,11 +36,13 @@ class Reader {
|
||||
/// Construct a reader that reads from the given input stream
|
||||
/** filename is used only for error messages
|
||||
*/
|
||||
Reader(const InputStreamP& input, const String& filename = wxEmptyString, bool ignore_invalid = false);
|
||||
Reader(const InputStreamP& input, Packaged* package = nullptr, const String& filename = wxEmptyString, bool ignore_invalid = false);
|
||||
|
||||
/// Construct a reader that reads a file in a package
|
||||
/** Used for "include file" keys. */
|
||||
Reader(const String& filename);
|
||||
/** Used for "include file" keys.
|
||||
* package can be nullptr
|
||||
*/
|
||||
Reader(Packaged* package, const String& filename);
|
||||
|
||||
~Reader() { showWarnings(); }
|
||||
|
||||
@@ -108,6 +111,9 @@ class Reader {
|
||||
/// Indicate that the last value from getValue() was not handled, allowing it to be handled again
|
||||
void unhandle();
|
||||
|
||||
/// The package being read from
|
||||
inline Packaged* getPackage() const { return package; }
|
||||
|
||||
// --------------------------------------------------- : Data
|
||||
/// App version this file was made with
|
||||
Version file_app_version;
|
||||
@@ -141,6 +147,8 @@ class Reader {
|
||||
|
||||
/// Filename for error messages
|
||||
String filename;
|
||||
/// Package this file is from, if any
|
||||
Packaged* package;
|
||||
/// Line number of the current line for error messages
|
||||
int line_number;
|
||||
/// Line number of the previous_line
|
||||
@@ -172,7 +180,7 @@ class Reader {
|
||||
template <typename T>
|
||||
void unknownKey(T& v) {
|
||||
if (key == _("include file")) {
|
||||
Reader reader(value);
|
||||
Reader reader(package, value);
|
||||
reader.handle_greedy(v);
|
||||
moveNext();
|
||||
} else {
|
||||
|
||||
@@ -98,12 +98,23 @@ String tr(const SymbolFont&, const String& key, const String& def);
|
||||
/// A localized string for button text, with 1 argument (printf style)
|
||||
#define _BUTTON_1_(s,a) format_string(_BUTTON_(s), a)
|
||||
|
||||
/// A localized string for window titles, with 1 argument (printf style)
|
||||
#define _TITLE_1_(s,a) format_string(_TITLE_(s), a)
|
||||
|
||||
/// A localized string for type names in scripts, with 1 argument (printf style)
|
||||
#define _TYPE_1_(s,a) format_string(_TYPE_(s), a)
|
||||
|
||||
/// A localized string for action names, with 1 argument (printf style)
|
||||
#define _ACTION_1_(s,a) format_string(_ACTION_(s), a)
|
||||
|
||||
/// A localized string for error messages, with 1 argument (printf style)
|
||||
#define _ERROR_1_(s,a) format_string(_ERROR_(s), a)
|
||||
/// A localized string for error messages, with 2 argument (printf style)
|
||||
#define _ERROR_2_(s,a,b) format_string(_ERROR_(s), a, b)
|
||||
/// A localized string for error messages, with 3 argument (printf style)
|
||||
#define _ERROR_3_(s,a,b,c) format_string(_ERROR_(s), a, b, c)
|
||||
/// A localized string for error messages, with 4 argument (printf style)
|
||||
#define _ERROR_4_(s,a,b,c,d) format_string(_ERROR_(s), a, b, c, d)
|
||||
|
||||
/// Format a string
|
||||
/** Equivalent to sprintf / String::Format, but allows strings to be passed as arguments (gcc)
|
||||
@@ -124,6 +135,9 @@ inline String format_string(const String& format, const String& a0, const String
|
||||
inline String format_string(const String& format, const String& a0, const String& a1, const String& a2) {
|
||||
return String::Format(format, a0.c_str(), a1.c_str(), a2.c_str());
|
||||
}
|
||||
inline String format_string(const String& format, const String& a0, const String& a1, const String& a2, const String& a3) {
|
||||
return String::Format(format, a0.c_str(), a1.c_str(), a2.c_str(), a3.c_str());
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user