diff --git a/data/magic-spoiler.mse-export-template/export-template b/data/magic-spoiler.mse-export-template/export-template
index bacfa52b..da1673c4 100644
--- a/data/magic-spoiler.mse-export-template/export-template
+++ b/data/magic-spoiler.mse-export-template/export-template
@@ -11,6 +11,11 @@ depends on: magic.mse-game 2008-05-18
########################################################################################
+option field:
+ type: boolean
+ name: include set file
+ description: Should a link to the MSE set file be included in the spoiler?
+ initial: no
option field:
type: choice
name: grouping
@@ -203,6 +208,9 @@ script:
{ to_html(set.title) }
{ to_html(set.copyright) }
{ to_html(set.description) }
+ { if options.include_set_file then
+ ""
+ }
{ if options.grouping == "group by color" then
# Codes as by sort_index
write_group(title: "White", code:"A") +
diff --git a/doc/function/index.txt b/doc/function/index.txt
index 5a7b4ab9..01a98bd5 100644
--- a/doc/function/index.txt
+++ b/doc/function/index.txt
@@ -96,6 +96,7 @@ These functions are built into the program, other [[type:function]]s can be defi
| [[fun:copy_file]] Copy a file from the [[type:export template]] to the output directory.
| [[fun:write_text_file]] Write a text file to the output directory.
| [[fun:write_image_file]] Write an image file to the output directory.
+| [[fun:write_set_file]] Write a MSE set file to the output directory.
! Other functions <<<
| [[fun:trace]] Output a message for debugging purposes.
diff --git a/doc/function/write_image_file.txt b/doc/function/write_image_file.txt
index a454b623..19de6c8d 100644
--- a/doc/function/write_image_file.txt
+++ b/doc/function/write_image_file.txt
@@ -18,7 +18,7 @@ This function can only be used in an [[type:export template]], when create d
| @height@ [[type:int]] Height in pixels to use for the image, by default the size of the image is used if available.
--Examples--
-> write_image("image_out.png", linear_blend(...)) == "image_out.png" # image_out.png now contains the given image
+> write_image_file(file:"image_out.png", linear_blend(...)) == "image_out.png" # image_out.png now contains the given image
--See also--
| [[fun:write_text_file]] Write a text file to the output directory.
diff --git a/doc/function/write_set_file.txt b/doc/function/write_set_file.txt
new file mode 100644
index 00000000..3b4e4aef
--- /dev/null
+++ b/doc/function/write_set_file.txt
@@ -0,0 +1,23 @@
+Function: write_set_file
+
+--Usage--
+> write_set_file(set:the_set, file: filename)
+
+Write the current set to a file in the output directory.
+If a file with the given name already exists it is overwritten.
+
+Returns the name of the file written.
+
+This function can only be used in an [[type:export template]], when create directory is true.
+
+--Parameters--
+! Parameter Type Description
+| @set@ [[type:set]] Set to write to the file.
+| @file@ [[type:string]] Name of the file to write to
+
+--Examples--
+> write_set_file(file:"the-set.mse-set") == "the-set.mse-set" # the-set.mse-set now contains the set
+
+--See also--
+| [[fun:write_image_file]] Write an image file to the output directory.
+| [[fun:write_text_file]] Write a text file to the output directory.
diff --git a/doc/function/write_text_file.txt b/doc/function/write_text_file.txt
index fc578c6a..de2c7d0b 100644
--- a/doc/function/write_text_file.txt
+++ b/doc/function/write_text_file.txt
@@ -16,7 +16,7 @@ This function can only be used in an [[type:export template]], when create d
| @file@ [[type:string]] Name of the file to write to
--Examples--
-> write_file("index.html", lots_of_html_code) == "index.html" # index.html now contains the given text
+> write_text_file(file:"index.html", lots_of_html_code) == "index.html" # index.html now contains the given text
--See also--
| [[fun:write_image_file]] Write an image file to the output directory.
diff --git a/src/data/format/formats.cpp b/src/data/format/formats.cpp
index 1bc83b1d..b8bdd556 100644
--- a/src/data/format/formats.cpp
+++ b/src/data/format/formats.cpp
@@ -48,12 +48,12 @@ String export_formats(const Game& game) {
return type_strings;
}
-void export_set(Set& set, const String& filename, size_t format_type) {
- FileFormatP format = file_formats.at(format_type);
+void export_set(Set& set, const String& filename, size_t format_index, bool is_copy) {
+ FileFormatP format = file_formats.at(format_index);
if (!format->canExport(*set.game)) {
throw InternalError(_("File format doesn't apply to set"));
}
- format->exportSet(set, filename);
+ format->exportSet(set, filename, is_copy);
}
SetP import_set(String name) {
diff --git a/src/data/format/formats.hpp b/src/data/format/formats.hpp
index 7b456155..312c753b 100644
--- a/src/data/format/formats.hpp
+++ b/src/data/format/formats.hpp
@@ -37,7 +37,8 @@ class FileFormat : public IntrusivePtrVirtualBase {
throw InternalError(_("Import not supported by this file format"));
}
/// Export using this filter
- virtual void exportSet(Set& set, const String& filename) {
+ /** If is_copy, then the set should not be modified */
+ virtual void exportSet(Set& set, const String& filename, bool is_copy = false) {
throw InternalError(_("Export not supported by this file format"));
}
};
@@ -71,9 +72,9 @@ String export_formats(const Game& game);
SetP import_set(String name);
/// Save a set under the specified name.
-/** filterType specifies what format to use for saving, used as index in the list of file formats
+/** format_index specifies what format to use for saving, used as index in the list of file formats
*/
-void export_set(Set& set, const String& filename, size_t format_type);
+void export_set(Set& set, const String& filename, size_t format_index, bool is_copy = false);
// ----------------------------------------------------------------------------- : The formats
diff --git a/src/data/format/mse2.cpp b/src/data/format/mse2.cpp
index 8f7ae735..4e306ee5 100644
--- a/src/data/format/mse2.cpp
+++ b/src/data/format/mse2.cpp
@@ -26,10 +26,14 @@ class MSE2FileFormat : public FileFormat {
settings.addRecentFile(filename);
return set;
}
- virtual void exportSet(Set& set, const String& filename) {
- set.saveAs(filename);
- settings.addRecentFile(filename);
- set.actions.setSavePoint();
+ virtual void exportSet(Set& set, const String& filename, bool is_copy) {
+ if (is_copy) {
+ set.saveCopy(filename);
+ } else {
+ set.saveAs(filename);
+ settings.addRecentFile(filename);
+ set.actions.setSavePoint();
+ }
}
};
diff --git a/src/script/functions/export.cpp b/src/script/functions/export.cpp
index f0b42f32..4de6d517 100644
--- a/src/script/functions/export.cpp
+++ b/src/script/functions/export.cpp
@@ -431,6 +431,18 @@ SCRIPT_FUNCTION(write_image_file) {
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);
+
+}
+
// ----------------------------------------------------------------------------- : Init
void init_script_export_functions(Context& ctx) {
@@ -440,5 +452,5 @@ void init_script_export_functions(Context& ctx) {
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);//TODO
+ ctx.setVariable(_("write set file"), script_write_set_file);
}
diff --git a/src/util/io/package.cpp b/src/util/io/package.cpp
index 2bf8f22d..0bc59cd8 100644
--- a/src/util/io/package.cpp
+++ b/src/util/io/package.cpp
@@ -86,6 +86,18 @@ void Package::open(const String& n) {
}
}
+void Package::reopen() {
+ if (wxDirExists(filename)) {
+ // make sure we have no zip open
+ delete zipStream; zipStream = nullptr;
+ delete fileStream; fileStream = nullptr;
+ } else {
+ // reopen only needed for zipfile
+ openZipfile();
+ }
+}
+
+
void Package::save(bool remove_unused) {
assert(!needSaveAs());
saveAs(filename, remove_unused);
@@ -94,11 +106,21 @@ void Package::save(bool remove_unused) {
void Package::saveAs(const String& name, bool remove_unused) {
// type of package
if (wxDirExists(name)) {
- saveToDirectory(name, remove_unused);
+ saveToDirectory(name, remove_unused, false);
} else {
- saveToZipfile (name, remove_unused);
+ saveToZipfile (name, remove_unused, false);
}
filename = name;
+ removeTempFiles(remove_unused);
+ reopen();
+}
+
+void Package::saveCopy(const String& name) {
+ saveToZipfile(name, true, true);
+ clearKeepFlag();
+}
+
+void Package::removeTempFiles(bool remove_unused) {
// cleanup : remove temp files, remove deleted files from the list
FileInfos::iterator it = files.begin();
while (it != files.end()) {
@@ -108,9 +130,9 @@ void Package::saveAs(const String& name, bool remove_unused) {
}
if (!it->second.keep && remove_unused) {
// also remove the record of deleted files
- FileInfos::iterator toRemove = it;
+ FileInfos::iterator to_remove = it;
++it;
- files.erase(toRemove);
+ files.erase(to_remove);
} else {
// free zip entry, we will reopen the file
it->second.keep = false;
@@ -120,13 +142,11 @@ void Package::saveAs(const String& name, bool remove_unused) {
++it;
}
}
- // reopen only needed for zipfile
- if (!wxDirExists(name)) {
- openZipfile();
- } else {
- // make sure we have no zip open
- delete zipStream; zipStream = nullptr;
- delete fileStream; fileStream = nullptr;
+}
+
+void Package::clearKeepFlag() {
+ FOR_EACH(f, files) {
+ f.second.keep = false;
}
}
@@ -356,7 +376,7 @@ void Package::openZipfile() {
loadZipStream();
}
-void Package::saveToDirectory(const String& saveAs, bool remove_unused) {
+void Package::saveToDirectory(const String& saveAs, bool remove_unused, bool is_copy) {
// write to a directory
FOR_EACH(f, files) {
if (!f.second.keep && remove_unused) {
@@ -366,7 +386,8 @@ void Package::saveToDirectory(const String& saveAs, bool remove_unused) {
} else if (f.second.wasWritten()) {
// move files that were updated
wxRemoveFile(saveAs+_("/")+f.first);
- if (!wxRenameFile(f.second.tempName, saveAs+_("/")+f.first)) {
+ if (!(is_copy ? wxCopyFile (f.second.tempName, saveAs+_("/")+f.first)
+ : wxRenameFile(f.second.tempName, saveAs+_("/")+f.first))) {
throw PackageError(_ERROR_("unable to store file"));
}
} else if (filename != saveAs) {
@@ -380,7 +401,7 @@ void Package::saveToDirectory(const String& saveAs, bool remove_unused) {
}
}
-void Package::saveToZipfile(const String& saveAs, bool remove_unused) {
+void Package::saveToZipfile(const String& saveAs, bool remove_unused, bool is_copy) {
// create a temporary zip file name
String tempFile = saveAs + _(".tmp");
wxRemoveFile(tempFile);
@@ -395,8 +416,9 @@ void Package::saveToZipfile(const String& saveAs, bool remove_unused) {
FOR_EACH(f, files) {
if (!f.second.keep && remove_unused) {
// to remove a file simply don't copy it
- } else if (f.second.zipEntry && !f.second.wasWritten()) {
+ } else if (!is_copy && f.second.zipEntry && !f.second.wasWritten()) {
// old file, was also in zip, not changed
+ // can't do this when saving a copy, since it destroys the zip entry
zipStream->CloseEntry();
newZip->CopyEntry(f.second.zipEntry, *zipStream);
f.second.zipEntry = 0;
@@ -408,8 +430,10 @@ void Package::saveToZipfile(const String& saveAs, bool remove_unused) {
}
}
// close the old file
- delete zipStream; zipStream = nullptr;
- delete fileStream; fileStream = nullptr;
+ if (!is_copy) {
+ delete zipStream; zipStream = nullptr;
+ delete fileStream; fileStream = nullptr;
+ }
} catch (Error e) {
// when things go wrong delete the temp file
wxRemoveFile(tempFile);
@@ -540,6 +564,12 @@ void Packaged::saveAs(const String& package, bool remove_unused) {
referenceFile(typeName());
Package::saveAs(package, remove_unused);
}
+void Packaged::saveCopy(const String& package) {
+ WITH_DYNAMIC_ARG(writing_package, this);
+ writeFile(typeName(), *this, fileVersion());
+ referenceFile(typeName());
+ Package::saveCopy(package);
+}
void Packaged::validate(Version) {
// a default for the short name
diff --git a/src/util/io/package.hpp b/src/util/io/package.hpp
index 70692040..4513542a 100644
--- a/src/util/io/package.hpp
+++ b/src/util/io/package.hpp
@@ -83,6 +83,9 @@ class Package : public IntrusivePtrVirtualBase {
/// Saves the package under a different filename
void saveAs(const String& package, bool remove_unused = true);
+ /// Saves the package under a different filename, but keep the old one open
+ void saveCopy(const String& package);
+
// --------------------------------------------------- : Managing the inside of the package
@@ -175,8 +178,11 @@ class Package : public IntrusivePtrVirtualBase {
void openDirectory();
void openSubdir(const String&);
void openZipfile();
- void saveToZipfile(const String&, bool);
- void saveToDirectory(const String&, bool);
+ void reopen();
+ void removeTempFiles(bool remove_unused);
+ void clearKeepFlag();
+ void saveToZipfile(const String&, bool remove_unused, bool is_copy);
+ void saveToDirectory(const String&, bool remove_unused, bool is_copy);
FileInfos::iterator addFile(const String& file);
};
@@ -219,6 +225,7 @@ class Packaged : public Package {
void loadFully();
void save();
void saveAs(const String& package, bool remove_unused = true);
+ void saveCopy(const String& package);
/// Check if this package lists a dependency on the given package
/** This is done to force people to fill in the dependencies */
diff --git a/tools/website/drupal/mse-drupal-modules/highlight.inc b/tools/website/drupal/mse-drupal-modules/highlight.inc
index 654fb594..162f87d8 100644
--- a/tools/website/drupal/mse-drupal-modules/highlight.inc
+++ b/tools/website/drupal/mse-drupal-modules/highlight.inc
@@ -87,6 +87,7 @@ $built_in_functions = array(
'copy_file' =>'',
'write_text_file' =>'',
'write_image_file' =>'',
+ 'write_set_file' =>'',
// other
'trace' =>'',
'assert' =>'',