From 1a51ff6499f37285fe2df9c2458bd5c4f117f4d5 Mon Sep 17 00:00:00 2001 From: Graham Nelson Date: Sun, 21 Feb 2021 12:44:25 +0000 Subject: [PATCH] Completed work on multimedia --- docs/core-module/1-cp.html | 14 +- docs/core-module/1-htc.html | 2 +- docs/index-module/2-ifs.html | 4 +- docs/index-module/3-ef.html | 128 ++++++ docs/index-module/3-fgr.html | 2 +- docs/index-module/3-se.html | 2 +- docs/index-module/index.html | 5 + docs/multimedia-module/1-mm.html | 41 +- docs/multimedia-module/2-ef.html | 402 +++++++----------- docs/multimedia-module/2-fgr.html | 10 +- docs/multimedia-module/2-se.html | 6 +- docs/multimedia-module/P-wtmd.html | 98 +++++ docs/multimedia-module/index.html | 12 +- docs/runtime-module/2-emt.html | 64 +-- docs/runtime-module/2-hrr.html | 8 +- docs/runtime-module/5-ef.html | 139 ++++++ docs/runtime-module/5-fgr.html | 2 +- docs/runtime-module/5-se.html | 2 +- docs/runtime-module/index.html | 5 + inform7/Figures/memory-diagnostics.txt | 34 +- inform7/Figures/timings-diagnostics.txt | 29 +- .../Chapter 1/Class Predeclarations.w | 13 +- .../core-module/Chapter 1/How To Compile.w | 2 +- .../Chapter 2/Index File Services.w | 2 +- .../index-module/Chapter 3/External Files.w | 48 +++ inform7/index-module/Contents.w | 1 + .../Chapter 1/Multimedia Module.w | 35 +- .../Chapter 2/External Files.w | 351 ++++++--------- inform7/multimedia-module/Chapter 2/Figures.w | 6 +- .../Chapter 2/Sound Effects.w | 2 +- inform7/multimedia-module/Contents.w | 5 +- .../runtime-module/Chapter 5/External Files.w | 66 +++ inform7/runtime-module/Contents.w | 1 + 33 files changed, 939 insertions(+), 602 deletions(-) create mode 100644 docs/index-module/3-ef.html create mode 100644 docs/multimedia-module/P-wtmd.html create mode 100644 docs/runtime-module/5-ef.html create mode 100644 inform7/index-module/Chapter 3/External Files.w create mode 100644 inform7/runtime-module/Chapter 5/External Files.w diff --git a/docs/core-module/1-cp.html b/docs/core-module/1-cp.html index 7a67e8d6d..3ccdc9a17 100644 --- a/docs/core-module/1-cp.html +++ b/docs/core-module/1-cp.html @@ -276,7 +276,7 @@ We begin with core itself. DECLARE_CLASS(runtime_kind_structure) DECLARE_CLASS(test_scenario) -

§7. And finally index — +

§7. index

enum contents_entry_CLASS
@@ -292,6 +292,18 @@ We begin with core itself.
 DECLARE_CLASS(index_page)
 DECLARE_CLASS(index_lexicon_entry)
 
+

§8. multimedia — +

+ +
enum figures_data_CLASS
+enum sounds_data_CLASS
+enum files_data_CLASS
+
+
+DECLARE_CLASS(figures_data)
+DECLARE_CLASS(sounds_data)
+DECLARE_CLASS(files_data)
+
diff --git a/docs/core-module/1-htc.html b/docs/core-module/1-htc.html index 5a9d7ed42..25cdb670a 100644 --- a/docs/core-module/1-htc.html +++ b/docs/core-module/1-htc.html @@ -325,7 +325,7 @@ so on. Those absolute basics are made here. BENCH(Phrases::Manager::rulebooks_array) BENCH_IF(scenes_plugin, PL::Scenes::DetectSceneChange_routine) BENCH_IF(scenes_plugin, PL::Scenes::ShowSceneStatus_routine) - BENCH(ExternalFiles::arrays) + BENCH(RTExternalFiles::arrays) BENCH(Rulebooks::rulebook_var_creators) BENCH(Activities::activity_var_creators) BENCH(RTRelations::IterateRelations) diff --git a/docs/index-module/2-ifs.html b/docs/index-module/2-ifs.html index a33f3bf84..77bc34a1c 100644 --- a/docs/index-module/2-ifs.html +++ b/docs/index-module/2-ifs.html @@ -758,7 +758,7 @@ to show, hide and colour things: #ifdef MULTIMEDIA_MODULE IXFigures::index_all(OUT); IXSounds::index_all(OUT); - ExternalFiles::index_all(OUT); + IXExternalFiles::index_all(OUT); #endif return; } @@ -943,7 +943,7 @@ the source text in the application.

-void Index::link(OUTPUT_STREAM, int wn) {
+void Index::link(OUTPUT_STREAM, int wn) {
     Index::link_to_location(OUT, Lexer::word_location(wn), TRUE);
 }
 
diff --git a/docs/index-module/3-ef.html b/docs/index-module/3-ef.html
new file mode 100644
index 000000000..1bfca8456
--- /dev/null
+++ b/docs/index-module/3-ef.html
@@ -0,0 +1,128 @@
+
+
+	
+		External Files
+
+		
+		
+		
+
+
+
+
+
+
+
+
+
+
+		
+	
+	
+		
+		
+ + +

To produce the index of external files.

+ +

§1. This is more or less perfunctory, but still of some use, if only as a list. +

+ +
+void IXExternalFiles::index_all(OUTPUT_STREAM) {
+    if (PluginManager::active(files_plugin) == FALSE) return;
+    files_data *exf;
+    if (NUMBER_CREATED(files_data) == 0) {
+        HTML_OPEN("p");
+        WRITE("This project doesn't read or write external files.");
+        HTML_CLOSE("p");
+        return;
+    }
+    HTML_OPEN("p");
+    WRITE("<b>List of External Files</b>");
+    HTML_CLOSE("p");
+    HTML::begin_html_table(OUT, "#ffffff", TRUE, 0, 0, 0, 0, 0);
+    LOOP_OVER(exf, files_data) {
+        HTML::first_html_column(OUT, THUMBNAIL_WIDTH+10);
+        if (exf->file_is_binary) {
+            HTML_TAG_WITH("img", "border=\"0\" src=\"inform:/doc_images/exf_binary.png\"");
+        } else {
+            HTML_TAG_WITH("img", "border=\"0\" src=\"inform:/doc_images/exf_text.png\"");
+        }
+        WRITE("&nbsp;");
+        HTML::next_html_column(OUT, 0);
+        WRITE("%+W", exf->name);
+        Index::link(OUT, Wordings::first_wn(exf->name));
+        HTML_TAG("br");
+        WRITE("Filename: %s %N- owned by ",
+            (exf->file_is_binary)?"- binary ":"",
+            exf->unextended_filename);
+        switch (exf->file_ownership) {
+            case OWNED_BY_THIS_PROJECT: WRITE("this project"); break;
+            case OWNED_BY_ANOTHER_PROJECT: WRITE("another project"); break;
+            case OWNED_BY_SPECIFIC_PROJECT:
+                WRITE("project with IFID number <b>%S</b>",
+                    exf->IFID_of_owner);
+                break;
+        }
+        HTML::end_html_row(OUT);
+    }
+    HTML::end_html_table(OUT);
+    HTML_OPEN("p");
+}
+
+ + +
+ + + diff --git a/docs/index-module/3-fgr.html b/docs/index-module/3-fgr.html index d8c1b1e47..eda5394e3 100644 --- a/docs/index-module/3-fgr.html +++ b/docs/index-module/3-fgr.html @@ -165,7 +165,7 @@ to match this width, preserving the aspect ratio. }
diff --git a/docs/index-module/3-se.html b/docs/index-module/3-se.html index a0d4989ef..135b9f862 100644 --- a/docs/index-module/3-se.html +++ b/docs/index-module/3-se.html @@ -191,7 +191,7 @@ function togglePopup(material_id) { } diff --git a/docs/index-module/index.html b/docs/index-module/index.html index 0f732384b..0f9c62cf6 100644 --- a/docs/index-module/index.html +++ b/docs/index-module/index.html @@ -154,6 +154,11 @@ Sound Effects - To produce the index of sound effects.

+
  • +

    + External Files - + To produce the index of external files.

    +
  • diff --git a/docs/multimedia-module/1-mm.html b/docs/multimedia-module/1-mm.html index 21ab1c4e7..6e8e1f36a 100644 --- a/docs/multimedia-module/1-mm.html +++ b/docs/multimedia-module/1-mm.html @@ -71,42 +71,35 @@ which use this module:
    define MULTIMEDIA_MODULE TRUE
     
    -

    §2. This module defines the following classes: +

    §2. Like all modules, this one must define a start and end function:

    -
    enum figures_data_CLASS
    -enum sounds_data_CLASS
    -enum external_file_CLASS
    -
    -
    -DECLARE_CLASS(figures_data)
    -DECLARE_CLASS(sounds_data)
    -DECLARE_CLASS(external_file)
    -
    -

    §3.

    - -
    -plugin *multimedia_plugin, *figures_plugin, *sounds_plugin, *files_plugin;
    -
    -

    §4. Like all modules, this one must define a start and end function: -

    - -
    enum FIGURE_CREATIONS_DA
    +
    enum MULTIMEDIA_CREATIONS_DA
     
     void MultimediaModule::start(void) {
         multimedia_plugin = PluginManager::new(NULL, I"multimedia", NULL);
    -    figures_plugin = PluginManager::new(&Figures::start, I"figures", multimedia_plugin);
    -    sounds_plugin = PluginManager::new(&Sounds::start, I"sounds", multimedia_plugin);
    -    files_plugin = PluginManager::new(&ExternalFiles::start, I"glulx external files", multimedia_plugin);
    +    figures_plugin = PluginManager::new(&Figures::start, I"figures",
    +        multimedia_plugin);
    +    sounds_plugin = PluginManager::new(&Sounds::start, I"sounds",
    +        multimedia_plugin);
    +    files_plugin = PluginManager::new(&ExternalFiles::start, I"glulx external files",
    +        multimedia_plugin);
     
    -    Log::declare_aspect(FIGURE_CREATIONS_DA, L"figure creations", FALSE, FALSE);
    +    Log::declare_aspect(MULTIMEDIA_CREATIONS_DA, L"figure creations", FALSE, FALSE);
     }
     void MultimediaModule::end(void) {
     }
     
    +

    §3. Note that the "multimedia" plugin itself does nothihg except to be a parent +to the other three; it doesn't even have an activation function. +

    + +
    +plugin *multimedia_plugin, *figures_plugin, *sounds_plugin, *files_plugin;
    +
    diff --git a/docs/multimedia-module/2-ef.html b/docs/multimedia-module/2-ef.html index 3c3ba5462..a4c6f3c8f 100644 --- a/docs/multimedia-module/2-ef.html +++ b/docs/multimedia-module/2-ef.html @@ -73,97 +73,55 @@ function togglePopup(material_id) {

    To register the names associated with external files, and build the small I6 arrays associated with each.

    -
    +
    -

    §1. The test group :files exercises the features below. +

    §1. The test group :files exercises the features in this plugin.

    -

    §2. Each file can be text or binary, has a name, and can be owned by a this -project, by an unspecified other project, or by a project named by IFID. -

    - -
    define OWNED_BY_THIS_PROJECT 1
    -define OWNED_BY_ANOTHER_PROJECT 2
    -define OWNED_BY_SPECIFIC_PROJECT 3
    -define files_data external_file
    -
    -
    -typedef struct external_file {
    -    struct wording name;  text of name
    -    int unextended_filename;  word number of text like "bones"
    -    struct text_stream *exf_I6_identifier;  an I6 identifier
    -    int file_is_binary;  true or false
    -    int file_ownership;  one of the above
    -    struct text_stream *IFID_of_owner;  an I6 identifier
    -    struct inter_name *exf_iname;
    -    struct inter_name *IFID_array_iname;
    -    CLASS_DEFINITION
    -} external_file;
    -
    -
    • The structure external_file is accessed in 2/fgr, 2/se and here.
    -

    §3. A --> array to a run-time data structure associated -with an external file, read or written by the story file during play. +

    The following is called to activate the plugin:

    -kind *K_external_file = NULL;
    -
    -

    §4.

    - -
    -void ExternalFiles::start(void) {
    -    PluginManager::plug(MAKE_SPECIAL_MEANINGS_PLUG, ExternalFiles::make_special_meanings);
    -    PluginManager::plug(NEW_BASE_KIND_NOTIFY_PLUG, ExternalFiles::files_new_base_kind_notify);
    -    PluginManager::plug(NEW_INSTANCE_NOTIFY_PLUG, ExternalFiles::files_new_named_instance_notify);
    +void ExternalFiles::start(void) {
    +    PluginManager::plug(MAKE_SPECIAL_MEANINGS_PLUG, ExternalFiles::make_special_meanings);
    +    PluginManager::plug(NEW_BASE_KIND_NOTIFY_PLUG, ExternalFiles::files_new_base_kind_notify);
    +    PluginManager::plug(NEW_INSTANCE_NOTIFY_PLUG, ExternalFiles::files_new_named_instance_notify);
     }
     
    -

    §5.

    - -
    -int ExternalFiles::make_special_meanings(void) {
    -    SpecialMeanings::declare(ExternalFiles::new_file_SMF, I"new-file", 2);
    -    return FALSE;
    -}
    -
    -int ExternalFiles::files_new_base_kind_notify(kind *new_base, text_stream *name, wording W) {
    -    if (Str::eq_wide_string(name, L"EXTERNAL_FILE_TY")) {
    -        K_external_file = new_base; return TRUE;
    -    }
    -    return FALSE;
    -}
    -
    -int allow_exf_creations = FALSE;
    -int ExternalFiles::files_new_named_instance_notify(instance *nc) {
    -    if (K_external_file == NULL) return FALSE;
    -    kind *K = Instances::to_kind(nc);
    -    if (Kinds::eq(K, K_external_file)) {
    -        if (allow_exf_creations == FALSE)
    -            StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_BackdoorFileCreation),
    -                "this is not the way to create a new external file",
    -                "which should be done with a special 'The File ... is called ...' "
    -                "sentence.");
    -        ATTACH_PLUGIN_DATA_TO_SUBJECT(files, nc->as_subject, ExternalFiles::new_external_file(nc));
    -        return TRUE;
    -    }
    -    return FALSE;
    -}
    -
    -

    §6.

    - -
    -external_file *ExternalFiles::new_external_file(instance *nc) {
    -    external_file *exf = CREATE(external_file);
    -    return exf;
    -}
    -
    -

    §7. External files are created with a special sentence: +

    §2. One special meaning. We add one special meaning for assertions, to catch sentences with the shape:

    The File of Wisdom (owned by another project) is called "wisdom".

    -

    Here is the subject: +

    +int ExternalFiles::make_special_meanings(void) {
    +    SpecialMeanings::declare(ExternalFiles::new_file_SMF, I"new-file", 2);
    +    return FALSE;
    +}
    +int ExternalFiles::new_file_SMF(int task, parse_node *V, wording *NPs) {
    +    wording SW = (NPs)?(NPs[0]):EMPTY_WORDING;
    +    wording OW = (NPs)?(NPs[1]):EMPTY_WORDING;
    +    switch (task) {  "File... is the file..."
    +        case ACCEPT_SMFT:
    +            if ((<nounphrase-external-file>(SW)) && (<new-file-sentence-object>(OW))) {
    +                parse_node *O = <<rp>>;
    +                <np-unparsed>(SW);
    +                V->next = <<rp>>;
    +                V->next->next = O;
    +                return TRUE;
    +            }
    +            break;
    +        case PASS_1_SMFT:
    +            ExternalFiles::register_file(Node::get_text(V->next),
    +                Node::get_text(V->next->next));
    +            break;
    +    }
    +    return FALSE;
    +}
    +
    +

    §3. And this is the Preform grammar needed for the subject phrase:

    @@ -180,10 +138,10 @@ with an external file, read or written by the story file during play.
     <external-file-owner> ::=
         another project |                                      ==> { FALSE, - }
         project {<quoted-text-without-subs>} |                 ==> { TRUE, - }
    -    ...                                                    ==> Issue PM_BadFileOwner problem7.1
    +    ...                                                    ==> Issue PM_BadFileOwner problem3.1
     
    -

    §7.1. Issue PM_BadFileOwner problem7.1 = +

    §3.1. Issue PM_BadFileOwner problem3.1 =

    @@ -200,8 +158,8 @@ with an external file, read or written by the story file during play.
             "is called \"wisdom\".'");
         ==> { NOT_APPLICABLE, - };
     
    -
    • This code is used in §7.
    -

    §8. The object NP is simply quoted text. Although the Preform grammar doesn't +

    • This code is used in §3.
    +

    §4. The object phrase is simply quoted text. Although the Preform grammar doesn't go into this level of detail, it's actually required to have 3 to 23 English letters or digits, with the first being a letter.

    @@ -209,23 +167,8 @@ letters or digits, with the first being a letter.
     <external-file-sentence-object> ::=
         <quoted-text> |  ==> { pass 1 }
    -    ...              ==> Issue PM_FilenameNotTextual problem8.1
    -
    - -

    §8.1. Issue PM_FilenameNotTextual problem8.1 = -

    + ... ==> Issue PM_FilenameNotTextual problem4.1 -
    -    StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_FilenameNotTextual),
    -        "a file can only be called with a single quoted piece of text",
    -        "as in: 'The File of Wisdom is called \"wisdom\".'");
    -    ==> { -1, - };
    -
    -
    • This code is used in §8.
    -

    §9. This handles the special meaning "File... is the file...". -

    - -
     <new-file-sentence-object> ::=
         <indefinite-article> <new-file-sentence-object-unarticled> |  ==> { pass 2 }
         <new-file-sentence-object-unarticled>                         ==> { pass 1 }
    @@ -237,38 +180,46 @@ letters or digits, with the first being a letter.
         <external-file-sentence-subject>    ==> { 0, Diagrams::new_UNPARSED_NOUN(W) }
     
    -

    §10.

    +

    §4.1. Issue PM_FilenameNotTextual problem4.1 = +

    -int ExternalFiles::new_file_SMF(int task, parse_node *V, wording *NPs) {
    -    wording SW = (NPs)?(NPs[0]):EMPTY_WORDING;
    -    wording OW = (NPs)?(NPs[1]):EMPTY_WORDING;
    -    switch (task) {  "File... is the file..."
    -        case ACCEPT_SMFT:
    -            if ((<nounphrase-external-file>(SW)) && (<new-file-sentence-object>(OW))) {
    -                parse_node *O = <<rp>>;
    -                <np-unparsed>(SW);
    -                V->next = <<rp>>;
    -                V->next->next = O;
    -                return TRUE;
    -            }
    -            break;
    -        case PASS_1_SMFT:
    -            if (PluginManager::active(files_plugin) == FALSE)
    -                internal_error("Files plugin inactive");
    -            ExternalFiles::register_file(Node::get_text(V->next),
    -                Node::get_text(V->next->next));
    -            break;
    -    }
    -    return FALSE;
    -}
    +    StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_FilenameNotTextual),
    +        "a file can only be called with a single quoted piece of text",
    +        "as in: 'The File of Wisdom is called \"wisdom\".'");
    +    ==> { -1, - };
    +
    +
    • This code is used in §4.
    +

    §5. In assertion pass 1, then, the following is called on any sentence which +has been found to create a file: +

    -void ExternalFiles::register_file(wording F, wording FN) { - int bad_filename = FALSE; +
    +void ExternalFiles::register_file(wording W, wording FN) {
         <external-file-sentence-object>(FN);
         FN = Wordings::from(FN, <<r>>);
         if (Wordings::empty(FN)) return;
         wchar_t *p = Lexer::word_text(Wordings::first_wn(FN));
    +    Vet the filename5.1;
    +    int binary = FALSE;
    +    int ownership = OWNED_BY_THIS_PROJECT;
    +    TEMPORARY_TEXT(ifid_of_file)
    +    Determine the ownership5.2;
    +
    +    ExternalFiles::files_create(W, binary, ownership, ifid_of_file, FN);
    +
    +    LOGIF(MULTIMEDIA_CREATIONS, "Created external file <%W> = filename '%N'\n", W, FN);
    +    DISCARD_TEXT(ifid_of_file)
    +}
    +
    +

    §5.1. The restrictions here are really very conservative. +

    + +

    Vet the filename5.1 = +

    + +
    +    int bad_filename = FALSE;
         if (Wide::len(p) < 5) bad_filename = TRUE;
         if (Characters::isalpha(p[1]) == FALSE) bad_filename = TRUE;
         for (int i=0; p[i]; i++) {
    @@ -291,13 +242,24 @@ letters or digits, with the first being a letter.
                 "automatically: this is invisible to Inform.)");
             return;
         }
    +
    +
    • This code is used in §5.
    +

    §5.2. Each file can be text or binary, has a name, and can be owned by this project, +by an unspecified other project, or by a project identified by its IFID. +

    - int ownership = OWNED_BY_THIS_PROJECT; - TEMPORARY_TEXT(ifid_of_file) +
    define OWNED_BY_THIS_PROJECT 1
    +define OWNED_BY_ANOTHER_PROJECT 2
    +define OWNED_BY_SPECIFIC_PROJECT 3
    +
    +

    Determine the ownership5.2 = +

    - if (<external-file-sentence-subject>(F) == FALSE) internal_error("bad ef grammar"); - F = GET_RW(<external-file-name>, 1); - int binary = <<r>>; +
    +    if (<external-file-sentence-subject>(W) == FALSE) internal_error("bad ef grammar");
    +    binary = <<r>>;
    +    W = GET_RW(<external-file-name>, 1);
    +    Make sure W can be the name of a new file anyway5.2.1;
         if (<<ownership>> == TRUE) {
             wording OW = GET_RW(<external-file-owner>, 1);
             int j, invalid = FALSE;
    @@ -310,152 +272,106 @@ letters or digits, with the first being a letter.
                 invalid = TRUE;
                 LOG("Objected to character %c\n", p[j]);
             }
    -        if ((invalid) || (j==47)) {
    +        if ((invalid) || (j==47))
                 StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_BadFileIFID),
                     "the owner of the file should be specified "
                     "using a valid double-quoted IFID",
                     "as in: 'The File of Wisdom (owned by project "
                     "\"4122DDA8-A153-46BC-8F57-42220F9D8795\") "
                     "is called \"wisdom\".'");
    -        } else
    +        else
                 ownership = OWNED_BY_SPECIFIC_PROJECT;
         }
    -    if (<<ownership>> == FALSE) {
    -        ownership = OWNED_BY_ANOTHER_PROJECT;
    -    }
    +    if (<<ownership>> == FALSE) ownership = OWNED_BY_ANOTHER_PROJECT;
    +
    +
    • This code is used in §5.
    +

    §5.2.1. Make sure W can be the name of a new file anyway5.2.1 = +

    - Assertions::Creator::vet_name_for_noun(F); - - if ((<s-value>(F)) && +
    +    Assertions::Creator::vet_name_for_noun(W);
    +    if ((<s-value>(W)) &&
             (Rvalues::is_CONSTANT_of_kind(<<rp>>, K_external_file))) {
             StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_FilenameDuplicate),
                 "this is already the name of a file",
                 "so there must be some duplication somewhere.");
             return;
         }
    +
    +
    • This code is used in §5.2.
    +

    §6. One significant kind.

    - allow_exf_creations = TRUE; - pcalc_prop *prop = Propositions::Abstract::to_create_something( - K_external_file, F); - Assert::true(prop, CERTAIN_CE); - allow_exf_creations = FALSE; - external_file *exf = PLUGIN_DATA_ON_INSTANCE(files, Instances::latest()); - exf->name = F; - exf->unextended_filename = Wordings::first_wn(FN); - exf->file_is_binary = binary; - exf->file_ownership = ownership; - exf->IFID_of_owner = Str::duplicate(ifid_of_file); +
    +kind *K_external_file = NULL;
    +
    +

    §7.

    - package_request *P = Hierarchy::local_package(EXTERNAL_FILES_HAP); - exf->exf_iname = Hierarchy::make_iname_with_memo(FILE_HL, P, exf->name); - exf->IFID_array_iname = Hierarchy::make_iname_with_memo(IFID_HL, P, exf->name); - - LOGIF(FIGURE_CREATIONS, "Created external file <%W> = filename '%N'\n", - F, exf->unextended_filename); - DISCARD_TEXT(ifid_of_file) +
    +int ExternalFiles::files_new_base_kind_notify(kind *new_base, text_stream *name, wording W) {
    +    if (Str::eq_wide_string(name, L"EXTERNAL_FILE_TY")) {
    +        K_external_file = new_base; return TRUE;
    +    }
    +    return FALSE;
     }
     
    -

    §11. I6 arrays of file structures. External files are written in I6 as their array names: +

    §8. Significant new instances. This structure of additional data is attached to each figure instance.

    -void ExternalFiles::arrays(void) {
    -    if (PluginManager::active(files_plugin) == FALSE) return;
    -
    -    inter_name *iname = Hierarchy::find(NO_EXTERNAL_FILES_HL);
    -    Emit::named_numeric_constant(iname, (inter_ti) (NUMBER_CREATED(external_file)));
    -    Hierarchy::make_available(Emit::tree(), iname);
    -
    -    external_file *exf;
    -    LOOP_OVER(exf, external_file) {
    -        if (exf->file_ownership == OWNED_BY_SPECIFIC_PROJECT) {
    -            packaging_state save = Emit::named_string_array_begin(exf->IFID_array_iname, K_value);
    -            TEMPORARY_TEXT(II)
    -            WRITE_TO(II, "//%S", exf->IFID_of_owner);
    -            Emit::array_text_entry(II);
    -            DISCARD_TEXT(II)
    -            Emit::array_end(save);
    -        }
    -    }
    -
    -    LOOP_OVER(exf, external_file) {
    -        packaging_state save = Emit::named_array_begin(exf->exf_iname, K_value);
    -        Emit::array_iname_entry(Hierarchy::find(AUXF_MAGIC_VALUE_HL));
    -        Emit::array_iname_entry(Hierarchy::find(AUXF_STATUS_IS_CLOSED_HL));
    -        if (exf->file_is_binary) Emit::array_numeric_entry(1);
    -        else Emit::array_numeric_entry(0);
    -        Emit::array_numeric_entry(0);
    -        TEMPORARY_TEXT(WW)
    -        WRITE_TO(WW, "%w", Lexer::word_raw_text(exf->unextended_filename));
    -        Str::delete_first_character(WW);
    -        Str::delete_last_character(WW);
    -        Emit::array_text_entry(WW);
    -        DISCARD_TEXT(WW)
    -        switch (exf->file_ownership) {
    -            case OWNED_BY_THIS_PROJECT: Emit::array_iname_entry(PL::Bibliographic::IFID::UUID()); break;
    -            case OWNED_BY_ANOTHER_PROJECT: Emit::array_null_entry(); break;
    -            case OWNED_BY_SPECIFIC_PROJECT: Emit::array_iname_entry(exf->IFID_array_iname); break;
    -        }
    -        Emit::array_end(save);
    -    }
    -
    -    iname = Hierarchy::find(TABLEOFEXTERNALFILES_HL);
    -    packaging_state save = Emit::named_array_begin(iname, K_value);
    -    Emit::array_numeric_entry(0);
    -    LOOP_OVER(exf, external_file) Emit::array_iname_entry(exf->exf_iname);
    -    Emit::array_numeric_entry(0);
    -    Emit::array_end(save);
    -    Hierarchy::make_available(Emit::tree(), iname);
    -}
    +typedef struct files_data {
    +    struct wording name;  text of name
    +    int unextended_filename;  word number of text like "bones"
    +    struct text_stream *exf_identifier;  an Inter identifier
    +    int file_is_binary;  true or false
    +    int file_ownership;  one of the OWNED_BY_* values above
    +    struct text_stream *IFID_of_owner;  if we know that
    +    struct external_file_compilation_data compilation_data;
    +    CLASS_DEFINITION
    +} files_data;
     
    -

    §12. External Files Index. More or less perfunctory, but still of some use, if only as a list. +

    • The structure files_data is accessed in 2/fgr, 2/se and here.
    +

    §9. We allow instances of "external file" to be created only through the above +code calling Figures::figures_create. If any other proposition somehow +manages to make a figure, a problem message is thrown.

    -void ExternalFiles::index_all(OUTPUT_STREAM) {
    -    if (PluginManager::active(files_plugin) == FALSE) return;
    -    external_file *exf;
    -    if (NUMBER_CREATED(external_file) == 0) {
    -        HTML_OPEN("p");
    -        WRITE("This project doesn't read or write external files.");
    -        HTML_CLOSE("p");
    -        return;
    +int allow_exf_creations = FALSE;
    +
    +instance *ExternalFiles::files_create(wording W, int binary, int ownership,
    +    text_stream *ifid_of_file, wording FN) {
    +    allow_exf_creations = TRUE;
    +    Assert::true(Propositions::Abstract::to_create_something(K_external_file, W), CERTAIN_CE);
    +    allow_exf_creations = FALSE;
    +    instance *I = Instances::latest();
    +    files_data *fd = PLUGIN_DATA_ON_INSTANCE(files, I);
    +    fd->name = W;
    +    fd->unextended_filename = Wordings::first_wn(FN);
    +    fd->file_is_binary = binary;
    +    fd->file_ownership = ownership;
    +    fd->IFID_of_owner = Str::duplicate(ifid_of_file);
    +    fd->compilation_data = RTExternalFiles::new_data(W);
    +    return I;
    +}
    +
    +int ExternalFiles::files_new_named_instance_notify(instance *I) {
    +    if (K_external_file == NULL) return FALSE;
    +    kind *K = Instances::to_kind(I);
    +    if (Kinds::eq(K, K_external_file)) {
    +        if (allow_exf_creations == FALSE)
    +            StandardProblems::sentence_problem(Task::syntax_tree(),
    +                _p_(PM_BackdoorFileCreation),
    +                "this is not the way to create a new external file",
    +                "which should be done with a special 'The File ... is called ...' "
    +                "sentence.");
    +        ATTACH_PLUGIN_DATA_TO_SUBJECT(files, I->as_subject, CREATE(files_data));
    +        return TRUE;
         }
    -    HTML_OPEN("p");
    -    WRITE("<b>List of External Files</b>");
    -    HTML_CLOSE("p");
    -    HTML::begin_html_table(OUT, "#ffffff", TRUE, 0, 0, 0, 0, 0);
    -    LOOP_OVER(exf, external_file) {
    -        HTML::first_html_column(OUT, THUMBNAIL_WIDTH+10);
    -        if (exf->file_is_binary) {
    -            HTML_TAG_WITH("img", "border=\"0\" src=\"inform:/doc_images/exf_binary.png\"");
    -        } else {
    -            HTML_TAG_WITH("img", "border=\"0\" src=\"inform:/doc_images/exf_text.png\"");
    -        }
    -        WRITE("&nbsp;");
    -        HTML::next_html_column(OUT, 0);
    -        WRITE("%+W", exf->name);
    -        Index::link(OUT, Wordings::first_wn(exf->name));
    -        HTML_TAG("br");
    -        WRITE("Filename: %s %N- owned by ",
    -            (exf->file_is_binary)?"- binary ":"",
    -            exf->unextended_filename);
    -        switch (exf->file_ownership) {
    -            case OWNED_BY_THIS_PROJECT: WRITE("this project"); break;
    -            case OWNED_BY_ANOTHER_PROJECT: WRITE("another project"); break;
    -            case OWNED_BY_SPECIFIC_PROJECT:
    -                WRITE("project with IFID number <b>%S</b>",
    -                    exf->IFID_of_owner);
    -                break;
    -        }
    -        HTML::end_html_row(OUT);
    -    }
    -    HTML::end_html_table(OUT);
    -    HTML_OPEN("p");
    +    return FALSE;
     }
     
    diff --git a/docs/multimedia-module/2-fgr.html b/docs/multimedia-module/2-fgr.html index 4ddfbf88e..7cfc46606 100644 --- a/docs/multimedia-module/2-fgr.html +++ b/docs/multimedia-module/2-fgr.html @@ -79,7 +79,7 @@ function togglePopup(material_id) {

    -void Figures::start(void) {
    +void Figures::start(void) {
         PluginManager::plug(MAKE_SPECIAL_MEANINGS_PLUG, Figures::make_special_meanings);
         PluginManager::plug(NEW_BASE_KIND_NOTIFY_PLUG, Figures::figures_new_base_kind_notify);
         PluginManager::plug(NEW_INSTANCE_NOTIFY_PLUG, Figures::figures_new_named_instance_notify);
    @@ -124,10 +124,10 @@ function togglePopup(material_id) {
         <new-figure-sentence-object-unarticled>                       ==> { pass 1 }
     
     <new-figure-sentence-object-unarticled> ::=
    -    file <np-unparsed>                                       ==> { TRUE, RP[1] }
    +    file <np-unparsed>                                            ==> { TRUE, RP[1] }
     
     <nounphrase-figure> ::=
    -    figure ...                         ==> { 0, Diagrams::new_UNPARSED_NOUN(W) }
    +    figure ...                           ==> { 0, Diagrams::new_UNPARSED_NOUN(W) }
     
     <figure-sentence-object> ::=
         <figure-source> ( <quoted-text> ) |  ==> { R[1], -, <<alttext>> = R[2] }
    @@ -181,7 +181,7 @@ has been found to create a figure:
             filename *figure_file = NULL;
             if (wn >= 0) Filenames::in(Task::figures_path(), leaf);
             Figures::figures_create(W, id, figure_file, <<alttext>>);
    -        LOGIF(FIGURE_CREATIONS, "Created figure <%W> = filename '%f' = resource ID %d\n",
    +        LOGIF(MULTIMEDIA_CREATIONS, "Created figure <%W> = filename '%f' = resource ID %d\n",
                 W, figure_file, id);
         }
     }
    @@ -358,7 +358,7 @@ the cover art, which is handled by Bibliographic Data.
     }
     
    diff --git a/docs/multimedia-module/2-se.html b/docs/multimedia-module/2-se.html index 526b878fe..42799f958 100644 --- a/docs/multimedia-module/2-se.html +++ b/docs/multimedia-module/2-se.html @@ -79,7 +79,7 @@ function togglePopup(material_id) {

    -void Sounds::start(void) {
    +void Sounds::start(void) {
         PluginManager::plug(MAKE_SPECIAL_MEANINGS_PLUG, Sounds::make_special_meanings);
         PluginManager::plug(NEW_BASE_KIND_NOTIFY_PLUG, Sounds::new_base_kind_notify);
         PluginManager::plug(NEW_INSTANCE_NOTIFY_PLUG, Sounds::new_named_instance_notify);
    @@ -173,7 +173,7 @@ has been found to create a sound:
             DISCARD_TEXT(leaf)
             filename *sound_file = Filenames::in(Task::sounds_path(), leaf);
             Sounds::sounds_create(W, id, sound_file, <<alttext>>);
    -        LOGIF(FIGURE_CREATIONS,
    +        LOGIF(MULTIMEDIA_CREATIONS,
                 "Created sound effect <%W> = filename '%N' = resource ID %d\n", W, wn, id);
         }
     }
    @@ -316,7 +316,7 @@ created from Figures.w
     }
     
    diff --git a/docs/multimedia-module/P-wtmd.html b/docs/multimedia-module/P-wtmd.html new file mode 100644 index 000000000..6476015ca --- /dev/null +++ b/docs/multimedia-module/P-wtmd.html @@ -0,0 +1,98 @@ + + + + What This Module Does + + + + + + + + + + + + + + + +
    + + +

    An overview of the multimedia module's role and abilities.

    + +
    + +

    §1. Prerequisites. The knowledge module is a part of the Inform compiler toolset. It is +presented as a literate program or "web". Before diving in: +

    + +
    • (a) It helps to have some experience of reading webs: see inweb for more. +
    • (b) The module is written in C, in fact ANSI C99, but this is disguised by the +fact that it uses some extension syntaxes provided by the inweb literate +programming tool, making it a dialect of C called InC. See inweb for +full details, but essentially: it's C without predeclarations or header files, +and where functions have names like Tags::add_by_name rather than just add_by_name. +
    • (c) This module uses other modules drawn from the compiler, and also +uses a module of utility functions called foundation. +For more, see A Brief Guide to Foundation (in foundation). +
    +

    §2. Now in glorious Technicolor. This module consists only of three independent plugins, and even those are +very similar to each other: +

    + + + + +
    + + + diff --git a/docs/multimedia-module/index.html b/docs/multimedia-module/index.html index 694bf3149..55cc70cde 100644 --- a/docs/multimedia-module/index.html +++ b/docs/multimedia-module/index.html @@ -62,6 +62,17 @@
      +
    • +

      + Preliminaries

      + +
    • Chapter 1: Starting Up

      @@ -76,7 +87,6 @@
    • Chapter 2: Multimedia Features

      -

      Three plugins enabling Inform-written works of IF to make use of multimedia features of the Glulx virtual machine.

      • diff --git a/docs/runtime-module/2-emt.html b/docs/runtime-module/2-emt.html index 2cdf8e93c..75fab6ed2 100644 --- a/docs/runtime-module/2-emt.html +++ b/docs/runtime-module/2-emt.html @@ -84,7 +84,7 @@ function togglePopup(material_id) { inter_tree *I7_generation_tree = NULL; -inter_tree *Emit::tree(void) { +inter_tree *Emit::tree(void) { return I7_generation_tree; } @@ -349,7 +349,7 @@ insert them into the Inter stream close to the top. Packaging::exit(Emit::tree(), save); } -inter_name *Emit::named_numeric_constant(inter_name *name, inter_ti val) { +inter_name *Emit::named_numeric_constant(inter_name *name, inter_ti val) { packaging_state save = Packaging::enter_home_of(name); inter_symbol *con_name = Produce::define_symbol(name); Produce::guard(Inter::Constant::new_numerical(Packaging::at(Emit::tree()), Inter::SymbolsTables::id_from_IRS_and_symbol(Packaging::at(Emit::tree()), con_name), Inter::SymbolsTables::id_from_IRS_and_symbol(Packaging::at(Emit::tree()), int_interk), LITERAL_IVAL, val, Produce::baseline(Packaging::at(Emit::tree())), NULL)); @@ -405,7 +405,7 @@ insert them into the Inter stream close to the top. return save; } -packaging_state Emit::named_string_array_begin(inter_name *name, kind *K) { +packaging_state Emit::named_string_array_begin(inter_name *name, kind *K) { packaging_state save = Emit::named_array_begin(name, K); Produce::annotate_iname_i(name, STRINGARRAY_IANN, 1); return save; @@ -496,13 +496,13 @@ insert them into the Inter stream close to the top. current_A->no_entries++; } -packaging_state Emit::sum_constant_begin(inter_name *name, kind *K) { +packaging_state Emit::sum_constant_begin(inter_name *name, kind *K) { packaging_state save = Emit::named_array_begin(name, K); current_A->array_form = CONSTANT_SUM_LIST; return save; } -packaging_state Emit::named_array_begin(inter_name *N, kind *K) { +packaging_state Emit::named_array_begin(inter_name *N, kind *K) { packaging_state save = Packaging::enter_home_of(N); inter_symbol *symb = Produce::define_symbol(N); Emit::push_array(); @@ -512,7 +512,7 @@ insert them into the Inter stream close to the top. return save; } -void Emit::array_iname_entry(inter_name *iname) { +void Emit::array_iname_entry(inter_name *iname) { if (current_A == NULL) internal_error("entry outside of inter array"); inter_symbol *alias; if (iname == NULL) alias = Site::veneer_symbol(Emit::tree(), NOTHING_VSYMB); @@ -523,15 +523,15 @@ insert them into the Inter stream close to the top. Emit::add_entry(val1, val2); } -void Emit::array_null_entry(void) { +void Emit::array_null_entry(void) { Emit::array_iname_entry(Hierarchy::find(NULL_HL)); } -void Emit::array_MPN_entry(void) { +void Emit::array_MPN_entry(void) { Emit::array_iname_entry(Hierarchy::find(MAX_POSITIVE_NUMBER_HL)); } -void Emit::array_generic_entry(inter_ti val1, inter_ti val2) { +void Emit::array_generic_entry(inter_ti val1, inter_ti val2) { if (current_A == NULL) internal_error("entry outside of inter array"); Emit::add_entry(val1, val2); } @@ -547,7 +547,7 @@ insert them into the Inter stream close to the top. } #endif -void Emit::array_text_entry(text_stream *content) { +void Emit::array_text_entry(text_stream *content) { if (current_A == NULL) internal_error("entry outside of inter array"); inter_ti v1 = 0, v2 = 0; Produce::text_value(Emit::tree(), &v1, &v2, content); @@ -568,7 +568,7 @@ insert them into the Inter stream close to the top. Emit::add_entry(v1, v2); } -void Emit::array_numeric_entry(inter_ti N) { +void Emit::array_numeric_entry(inter_ti N) { if (current_A == NULL) internal_error("entry outside of inter array"); Emit::add_entry(LITERAL_IVAL, N); } @@ -586,7 +586,7 @@ insert them into the Inter stream close to the top. return IBM; } -void Emit::array_end(packaging_state save) { +void Emit::array_end(packaging_state save) { if (current_A == NULL) internal_error("inter array not opened"); inter_symbol *con_name = current_A->array_name_symbol; inter_bookmark *IBM = Packaging::at(Emit::tree()); @@ -617,7 +617,7 @@ insert them into the Inter stream close to the top. Packaging::exit(Emit::tree(), save); } -inter_name *Emit::named_iname_constant(inter_name *name, kind *K, inter_name *iname) { +inter_name *Emit::named_iname_constant(inter_name *name, kind *K, inter_name *iname) { packaging_state save = Packaging::enter_home_of(name); inter_symbol *con_name = Produce::define_symbol(name); inter_symbol *val_kind = Produce::kind_to_symbol(K); @@ -633,7 +633,7 @@ insert them into the Inter stream close to the top. return name; } -inter_name *Emit::named_numeric_constant_hex(inter_name *name, inter_ti val) { +inter_name *Emit::named_numeric_constant_hex(inter_name *name, inter_ti val) { packaging_state save = Packaging::enter_home_of(name); inter_symbol *con_name = Produce::define_symbol(name); Produce::annotate_symbol_i(con_name, HEX_IANN, 0); @@ -642,7 +642,7 @@ insert them into the Inter stream close to the top. return name; } -inter_name *Emit::named_unchecked_constant_hex(inter_name *name, inter_ti val) { +inter_name *Emit::named_unchecked_constant_hex(inter_name *name, inter_ti val) { packaging_state save = Packaging::enter_home_of(name); inter_symbol *con_name = Produce::define_symbol(name); Produce::annotate_symbol_i(con_name, HEX_IANN, 0); @@ -651,7 +651,7 @@ insert them into the Inter stream close to the top. return name; } -inter_name *Emit::named_numeric_constant_signed(inter_name *name, int val) { +inter_name *Emit::named_numeric_constant_signed(inter_name *name, int val) { packaging_state save = Packaging::enter_home_of(name); inter_symbol *con_name = Produce::define_symbol(name); Produce::annotate_symbol_i(con_name, SIGNED_IANN, 0); @@ -667,7 +667,7 @@ insert them into the Inter stream close to the top. */ } -void Emit::code_comment(text_stream *text) { +void Emit::code_comment(text_stream *text) { inter_ti ID = Inter::Warehouse::create_text(Inter::Tree::warehouse(Emit::tree()), Inter::Bookmarks::package(Packaging::at(Emit::tree()))); Str::copy(Inter::Warehouse::get_text(Inter::Tree::warehouse(Emit::tree()), ID), text); Produce::guard(Inter::Comment::new(Produce::at(Emit::tree()), (inter_ti) Produce::level(Emit::tree()), NULL, ID)); @@ -675,7 +675,7 @@ insert them into the Inter stream close to the top. } -void Emit::routine(inter_name *rname, kind *rkind, inter_package *block) { +void Emit::routine(inter_name *rname, kind *rkind, inter_package *block) { if (Packaging::at(Emit::tree()) == NULL) internal_error("no inter repository"); inter_symbol *AB_symbol = Produce::kind_to_symbol(rkind); inter_symbol *rsymb = Produce::define_symbol(rname); @@ -686,7 +686,7 @@ insert them into the Inter stream close to the top. Produce::baseline(Packaging::at(Emit::tree())), NULL)); } -inter_symbol *Emit::local(kind *K, text_stream *lname, inter_ti annot, text_stream *comm) { +inter_symbol *Emit::local(kind *K, text_stream *lname, inter_ti annot, text_stream *comm) { if (Site::get_cir(Emit::tree()) == NULL) internal_error("not in an inter routine"); if (K == NULL) K = K_number; inter_symbol *loc_name = Produce::new_local_symbol(Site::get_cir(Emit::tree()), lname); @@ -702,13 +702,13 @@ insert them into the Inter stream close to the top. return loc_name; } -void Emit::cast(kind *F, kind *T) { +void Emit::cast(kind *F, kind *T) { inter_symbol *from_kind = Produce::kind_to_symbol(F); inter_symbol *to_kind = Produce::kind_to_symbol(T); Produce::guard(Inter::Cast::new(Produce::at(Emit::tree()), from_kind, to_kind, (inter_ti) Produce::level(Emit::tree()), NULL)); } -void Emit::intervention(int stage, text_stream *segment, text_stream *part, text_stream *i6, text_stream *seg) { +void Emit::intervention(int stage, text_stream *segment, text_stream *part, text_stream *i6, text_stream *seg) { inter_warehouse *warehouse = Inter::Tree::warehouse(Emit::tree()); inter_ti ID1 = Inter::Warehouse::create_text(warehouse, Inter::Bookmarks::package(Packaging::at(Emit::tree()))); Str::copy(Inter::Warehouse::get_text(Inter::Tree::warehouse(Emit::tree()), ID1), segment); @@ -736,12 +736,12 @@ insert them into the Inter stream close to the top.

         
         
        -text_stream *Emit::to_text(inter_name *iname) {
        +text_stream *Emit::to_text(inter_name *iname) {
             if (iname == NULL) return NULL;
             return InterNames::to_symbol(iname)->symbol_name;
         }
         
        -void Emit::holster(value_holster *VH, inter_name *iname) {
        +void Emit::holster(value_holster *VH, inter_name *iname) {
             if (Holsters::data_acceptable(VH)) {
                 inter_ti v1 = 0, v2 = 0;
                 Emit::to_ival(&v1, &v2, iname);
        @@ -749,20 +749,20 @@ insert them into the Inter stream close to the top.
             }
         }
         
        -void Emit::symbol_to_ival(inter_ti *val1, inter_ti *val2, inter_symbol *S) {
        +void Emit::symbol_to_ival(inter_ti *val1, inter_ti *val2, inter_symbol *S) {
             inter_bookmark *IBM = Packaging::at(Emit::tree());
             if (S) { Inter::Symbols::to_data(Inter::Bookmarks::tree(IBM), Inter::Bookmarks::package(IBM), S, val1, val2); return; }
             *val1 = LITERAL_IVAL; *val2 = 0;
         }
         
        -void Emit::to_ival(inter_ti *val1, inter_ti *val2, inter_name *iname) {
        +void Emit::to_ival(inter_ti *val1, inter_ti *val2, inter_name *iname) {
             inter_bookmark *IBM = Packaging::at(Emit::tree());
             inter_symbol *S = InterNames::to_symbol(iname);
             if (S) { Inter::Symbols::to_data(Inter::Bookmarks::tree(IBM), Inter::Bookmarks::package(IBM), S, val1, val2); return; }
             *val1 = LITERAL_IVAL; *val2 = 0;
         }
         
        -void Emit::to_ival_in_context(inter_name *context, inter_ti *val1, inter_ti *val2, inter_name *iname) {
        +void Emit::to_ival_in_context(inter_name *context, inter_ti *val1, inter_ti *val2, inter_name *iname) {
             package_request *PR = InterNames::location(context);
             inter_package *pack = Packaging::incarnate(PR);
             inter_symbol *S = InterNames::to_symbol(iname);
        @@ -770,7 +770,7 @@ insert them into the Inter stream close to the top.
             *val1 = LITERAL_IVAL; *val2 = 0;
         }
         
        -int Emit::defined(inter_name *iname) {
        +int Emit::defined(inter_name *iname) {
             if (iname == NULL) return FALSE;
             inter_symbol *S = InterNames::to_symbol(iname);
             if (Inter::Symbols::is_defined(S)) return TRUE;
        @@ -782,27 +782,27 @@ insert them into the Inter stream close to the top.
             struct packaging_state saved_PS;
         } ival_emission;
         
        -ival_emission Emit::begin_ival_emission(inter_name *iname) {
        +ival_emission Emit::begin_ival_emission(inter_name *iname) {
             ival_emission IE;
             IE.emission_VH = Holsters::new(INTER_DATA_VHMODE);
             IE.saved_PS = Packaging::enter_home_of(iname);
             return IE;
         }
         
        -value_holster *Emit::ival_holster(ival_emission *IE) {
        +value_holster *Emit::ival_holster(ival_emission *IE) {
             return &(IE->emission_VH);
         }
         
        -void Emit::end_ival_emission(ival_emission *IE, inter_ti *v1, inter_ti *v2) {
        +void Emit::end_ival_emission(ival_emission *IE, inter_ti *v1, inter_ti *v2) {
             Holsters::unholster_pair(&(IE->emission_VH), v1, v2);
             Packaging::exit(Emit::tree(), IE->saved_PS);
         }
         
        -package_request *Emit::current_enclosure(void) {
        +package_request *Emit::current_enclosure(void) {
             return Packaging::enclosure(Emit::tree());
         }
         
        -packaging_state Emit::unused_packaging_state(void) {
        +packaging_state Emit::unused_packaging_state(void) {
             return Packaging::stateless();
         }
         
        diff --git a/docs/runtime-module/2-hrr.html b/docs/runtime-module/2-hrr.html index b1d65e296..7d2cc5e08 100644 --- a/docs/runtime-module/2-hrr.html +++ b/docs/runtime-module/2-hrr.html @@ -1723,11 +1723,11 @@ function togglePopup(material_id) {

        §4.

        -inter_name *Hierarchy::find(int id) {
        +inter_name *Hierarchy::find(int id) {
             return HierarchyLocations::find(Emit::tree(), id);
         }
         
        -void Hierarchy::make_available(inter_tree *I, inter_name *iname) {
        +void Hierarchy::make_available(inter_tree *I, inter_name *iname) {
             text_stream *ma_as = Produce::get_translation(iname);
             if (Str::len(ma_as) == 0) ma_as = Emit::to_text(iname);
             PackageTypes::get(I, I"_linkage");
        @@ -1743,7 +1743,7 @@ function togglePopup(material_id) {
             return HierarchyLocations::attach_new_package(Emit::tree(), NULL, NULL, hap_id);
         }
         
        -package_request *Hierarchy::local_package(int hap_id) {
        +package_request *Hierarchy::local_package(int hap_id) {
             return HierarchyLocations::attach_new_package(Emit::tree(), CompilationUnits::find(current_sentence), NULL, hap_id);
         }
         
        @@ -1771,7 +1771,7 @@ function togglePopup(material_id) {
             return HierarchyLocations::find_in_package(Emit::tree(), id, P, EMPTY_WORDING, NULL, -1, NULL);
         }
         
        -inter_name *Hierarchy::make_iname_with_memo(int id, package_request *P, wording W) {
        +inter_name *Hierarchy::make_iname_with_memo(int id, package_request *P, wording W) {
             return HierarchyLocations::find_in_package(Emit::tree(), id, P, W, NULL, -1, NULL);
         }
         
        diff --git a/docs/runtime-module/5-ef.html b/docs/runtime-module/5-ef.html
        new file mode 100644
        index 000000000..b9a1aa1a2
        --- /dev/null
        +++ b/docs/runtime-module/5-ef.html
        @@ -0,0 +1,139 @@
        +
        +
        +	
        +		External Files
        +
        +		
        +		
        +		
        +
        +
        +
        +
        +
        +
        +
        +		
        +	
        +	
        +		
        +		
        + + +

        §1. External files are written in Inter as their array names: +

        + +
        +typedef struct external_file_compilation_data {
        +    struct inter_name *exf_iname;
        +    struct inter_name *IFID_array_iname;
        +} external_file_compilation_data;
        +
        +external_file_compilation_data RTExternalFiles::new_data(wording W) {
        +    external_file_compilation_data efcd;
        +    package_request *P = Hierarchy::local_package(EXTERNAL_FILES_HAP);
        +    efcd.exf_iname = Hierarchy::make_iname_with_memo(FILE_HL, P, W);
        +    efcd.IFID_array_iname = Hierarchy::make_iname_with_memo(IFID_HL, P, W);
        +    return efcd;
        +}
        +
        +void RTExternalFiles::arrays(void) {
        +    if (PluginManager::active(files_plugin) == FALSE) return;
        +
        +    inter_name *iname = Hierarchy::find(NO_EXTERNAL_FILES_HL);
        +    Emit::named_numeric_constant(iname, (inter_ti) (NUMBER_CREATED(files_data)));
        +    Hierarchy::make_available(Emit::tree(), iname);
        +
        +    files_data *exf;
        +    LOOP_OVER(exf, files_data) {
        +        if (exf->file_ownership == OWNED_BY_SPECIFIC_PROJECT) {
        +            packaging_state save = Emit::named_string_array_begin(exf->compilation_data.IFID_array_iname, K_value);
        +            TEMPORARY_TEXT(II)
        +            WRITE_TO(II, "//%S", exf->IFID_of_owner);
        +            Emit::array_text_entry(II);
        +            DISCARD_TEXT(II)
        +            Emit::array_end(save);
        +        }
        +    }
        +
        +    LOOP_OVER(exf, files_data) {
        +        packaging_state save = Emit::named_array_begin(exf->compilation_data.exf_iname, K_value);
        +        Emit::array_iname_entry(Hierarchy::find(AUXF_MAGIC_VALUE_HL));
        +        Emit::array_iname_entry(Hierarchy::find(AUXF_STATUS_IS_CLOSED_HL));
        +        if (exf->file_is_binary) Emit::array_numeric_entry(1);
        +        else Emit::array_numeric_entry(0);
        +        Emit::array_numeric_entry(0);
        +        TEMPORARY_TEXT(WW)
        +        WRITE_TO(WW, "%w", Lexer::word_raw_text(exf->unextended_filename));
        +        Str::delete_first_character(WW);
        +        Str::delete_last_character(WW);
        +        Emit::array_text_entry(WW);
        +        DISCARD_TEXT(WW)
        +        switch (exf->file_ownership) {
        +            case OWNED_BY_THIS_PROJECT: Emit::array_iname_entry(PL::Bibliographic::IFID::UUID()); break;
        +            case OWNED_BY_ANOTHER_PROJECT: Emit::array_null_entry(); break;
        +            case OWNED_BY_SPECIFIC_PROJECT: Emit::array_iname_entry(exf->compilation_data.IFID_array_iname); break;
        +        }
        +        Emit::array_end(save);
        +    }
        +
        +    iname = Hierarchy::find(TABLEOFEXTERNALFILES_HL);
        +    packaging_state save = Emit::named_array_begin(iname, K_value);
        +    Emit::array_numeric_entry(0);
        +    LOOP_OVER(exf, files_data) Emit::array_iname_entry(exf->compilation_data.exf_iname);
        +    Emit::array_numeric_entry(0);
        +    Emit::array_end(save);
        +    Hierarchy::make_available(Emit::tree(), iname);
        +}
        +
        +
        • The structure external_file_compilation_data is private to this section.
        + + +
        + + + diff --git a/docs/runtime-module/5-fgr.html b/docs/runtime-module/5-fgr.html index 32d79c1d3..0272d3625 100644 --- a/docs/runtime-module/5-fgr.html +++ b/docs/runtime-module/5-fgr.html @@ -78,7 +78,7 @@ }
    diff --git a/docs/runtime-module/5-se.html b/docs/runtime-module/5-se.html index 44c3bbca0..d84437193 100644 --- a/docs/runtime-module/5-se.html +++ b/docs/runtime-module/5-se.html @@ -78,7 +78,7 @@ }
    diff --git a/docs/runtime-module/index.html b/docs/runtime-module/index.html index 97345989d..07416ab1a 100644 --- a/docs/runtime-module/index.html +++ b/docs/runtime-module/index.html @@ -309,6 +309,11 @@ Sound Effects -

    +
  • +

    + External Files - +

    +
  • diff --git a/inform7/Figures/memory-diagnostics.txt b/inform7/Figures/memory-diagnostics.txt index 04d907a55..3e8fef548 100644 --- a/inform7/Figures/memory-diagnostics.txt +++ b/inform7/Figures/memory-diagnostics.txt @@ -1,4 +1,4 @@ -Total memory consumption was 260176K = 254 MB +Total memory consumption was 260177K = 254 MB 62.7% was used for 1338084 objects, in 278606 frames in 204 x 800K = 163200K = 159 MB: @@ -89,8 +89,8 @@ Total memory consumption was 260176K = 254 MB ---- action_name 90 objects, 18720 bytes ---- property 146 objects, 18688 bytes ---- parse_node_tree 20 objects, 17280 bytes - ---- match_avinue_array 1 x 1000 objects, 16032 bytes ---- linked_list_item_array 1 x 1000 objects, 16032 bytes + ---- match_avinue_array 1 x 1000 objects, 16032 bytes ---- method 327 objects, 15696 bytes ---- to_phrase_request 59 objects, 15576 bytes ---- adjective 137 objects, 14248 bytes @@ -113,8 +113,8 @@ Total memory consumption was 260176K = 254 MB ---- parsing_pp_data 96 objects, 4608 bytes ---- build_vertex 40 objects, 4480 bytes ---- hierarchy_attachment_point 48 objects, 4224 bytes - ---- placement_affecting_array 1 x 100 objects, 4032 bytes ---- stacked_variable_list_array 1 x 100 objects, 4032 bytes + ---- placement_affecting_array 1 x 100 objects, 4032 bytes ---- activity 35 objects, 3920 bytes ---- inbuild_edition 54 objects, 3888 bytes ---- parse_node_annotation_type 118 objects, 3776 bytes @@ -127,8 +127,8 @@ Total memory consumption was 260176K = 254 MB ---- definition 44 objects, 3168 bytes ---- compatibility_specification 66 objects, 3168 bytes ---- inform_extension 19 objects, 3040 bytes - ---- property_of_value_storage 93 objects, 2976 bytes ---- either_or_property_data 62 objects, 2976 bytes + ---- property_of_value_storage 93 objects, 2976 bytes ---- submodule_request 72 objects, 2880 bytes ---- inter_construct 32 objects, 2560 bytes ---- part_of_inference_data 79 objects, 2528 bytes @@ -151,13 +151,13 @@ Total memory consumption was 260176K = 254 MB ---- constant_phrase 20 objects, 1280 bytes ---- build_script 40 objects, 1280 bytes ---- invocation_options_array 1 x 100 objects, 1224 bytes - ---- direction_inference_data 30 objects, 1200 bytes ---- hierarchy_metadatum 15 objects, 1200 bytes + ---- direction_inference_data 30 objects, 1200 bytes ---- quantifier 16 objects, 1024 bytes ---- table_column 16 objects, 896 bytes ---- inbuild_requirement 22 objects, 880 bytes - ---- code_generation 1 object, 864 bytes ---- control_structure_phrase 12 objects, 864 bytes + ---- code_generation 1 object, 864 bytes ---- cached_understanding 21 objects, 840 bytes ---- runtime_kind_structure 13 objects, 832 bytes ---- phrase_option_array 1 x 100 objects, 824 bytes @@ -168,19 +168,19 @@ Total memory consumption was 260176K = 254 MB ---- submodule_identity 23 objects, 736 bytes ---- rulebook_outcome 17 objects, 680 bytes ---- inform_language 6 objects, 672 bytes + ---- I6T_intervention 8 objects, 640 bytes ---- relation_guard 5 objects, 640 bytes ---- inter_warehouse_room 10 objects, 640 bytes - ---- I6T_intervention 8 objects, 640 bytes ---- nascent_array 7 objects, 616 bytes ---- inbuild_search_result 15 objects, 600 bytes ---- named_rulebook_outcome 15 objects, 600 bytes ---- label_namespace 10 objects, 560 bytes ---- small_word_set 11 objects, 528 bytes - ---- implication 13 objects, 520 bytes ---- inform_kit 5 objects, 520 bytes + ---- implication 13 objects, 520 bytes ---- inference_family 11 objects, 440 bytes - ---- i6_memory_setting 13 objects, 416 bytes ---- equation 4 objects, 416 bytes + ---- i6_memory_setting 13 objects, 416 bytes ---- module_package 10 objects, 400 bytes ---- dval_written 10 objects, 400 bytes ---- bp_family 12 objects, 384 bytes @@ -188,8 +188,8 @@ Total memory consumption was 260176K = 254 MB ---- source_file 5 objects, 360 bytes ---- inbuild_genre 7 objects, 336 bytes ---- pronoun 8 objects, 320 bytes - ---- grammatical_category 8 objects, 320 bytes ---- door_dir_notice 5 objects, 320 bytes + ---- grammatical_category 8 objects, 320 bytes ---- up_family 9 objects, 288 bytes ---- build_step 4 objects, 288 bytes ---- explicit_bp_data 5 objects, 280 bytes @@ -203,23 +203,23 @@ Total memory consumption was 260176K = 254 MB ---- kit_dependency 4 objects, 192 bytes ---- plural_dictionary_entry 4 objects, 192 bytes ---- inform_project 1 object, 176 bytes - ---- link_instruction 4 objects, 160 bytes - ---- code_generation_target 4 objects, 160 bytes ---- inference_subject_family 5 objects, 160 bytes ---- inter_architecture 4 objects, 160 bytes ---- pointer_allocation 2 objects, 160 bytes + ---- code_generation_target 4 objects, 160 bytes + ---- link_instruction 4 objects, 160 bytes ---- element_activation 4 objects, 128 bytes ---- codegen_pipeline 1 object, 128 bytes ---- inbuild_nest 3 objects, 120 bytes ---- inform_kit_ittt 2 objects, 96 bytes - ---- compile_task_data 1 object, 80 bytes ---- article 2 objects, 80 bytes ---- list_together_routine 2 objects, 80 bytes - ---- inter_warehouse 1 object, 56 bytes + ---- compile_task_data 1 object, 80 bytes ---- build_methodology 1 object, 56 bytes - ---- star_invention 1 object, 48 bytes - ---- figures_data 1 object, 48 bytes + ---- inter_warehouse 1 object, 56 bytes ---- HTML_file_state 1 object, 48 bytes + ---- figures_data 1 object, 48 bytes + ---- star_invention 1 object, 48 bytes ---- parse_name_notice 1 object, 40 bytes ---- by_routine_bp_data 1 object, 40 bytes ---- kind_template_definition 1 object, 40 bytes @@ -227,7 +227,7 @@ Total memory consumption was 260176K = 254 MB 37.2% was used for memory not allocated for objects: - 15.8% text stream storage 42246904 bytes in 265809 claims + 15.8% text stream storage 42246912 bytes in 265809 claims 3.4% dictionary storage 9278976 bytes in 16372 claims ---- sorting 1064 bytes in 3 claims 2.7% source text 7200000 bytes in 3 claims diff --git a/inform7/Figures/timings-diagnostics.txt b/inform7/Figures/timings-diagnostics.txt index e8902acac..6804c9559 100644 --- a/inform7/Figures/timings-diagnostics.txt +++ b/inform7/Figures/timings-diagnostics.txt @@ -1,15 +1,15 @@ 100.0% in inform7 run - 66.4% in compilation to Inter - 25.6% in //Phrases::Manager::compile_first_block// - 8.0% in //Phrases::Manager::compile_as_needed// - 6.9% in //Strings::compile_responses// - 6.0% in //InferenceSubjects::emit_all// + 66.9% in compilation to Inter + 26.3% in //Phrases::Manager::compile_first_block// + 7.8% in //Phrases::Manager::compile_as_needed// + 6.7% in //Strings::compile_responses// + 6.3% in //InferenceSubjects::emit_all// 4.1% in //MajorNodes::pre_pass// 3.4% in //MajorNodes::pass_1// - 2.0% in //Phrases::Manager::RulePrintingRule_routine// - 2.0% in //Phrases::Manager::rulebooks_array// + 1.9% in //Phrases::Manager::RulePrintingRule_routine// + 1.8% in //Phrases::Manager::rulebooks_array// 1.0% in //RTVerbs::ConjugateVerb// - 0.7% in //Phrases::Manager::traverse// + 0.9% in //Phrases::Manager::traverse// 0.5% in //Phrases::Manager::parse_rule_parameters// 0.5% in //World::stage_V// 0.3% in //MajorNodes::pass_2// @@ -20,17 +20,18 @@ 0.1% in //Task::make_built_in_kind_constructors// 0.1% in //World::stages_II_and_III// 3.4% not specifically accounted for - 31.1% in running Inter pipeline - 9.8% in step preparation - 9.6% in inter step 2/12: link - 7.2% in inter step 12/12: generate inform6 -> auto.inf + 30.6% in running Inter pipeline + 10.8% in step preparation + 9.8% in inter step 2/12: link + 6.8% in inter step 12/12: generate inform6 -> auto.inf 0.3% in inter step 9/12: make-identifiers-unique 0.1% in inter step 10/12: reconcile-verbs 0.1% in inter step 11/12: eliminate-redundant-labels + 0.1% in inter step 4/12: parse-linked-matter 0.1% in inter step 5/12: resolve-conditional-compilation 0.1% in inter step 6/12: assimilate 0.1% in inter step 7/12: resolve-external-symbols 0.1% in inter step 8/12: inspect-plugs - 2.9% not specifically accounted for - 2.0% in supervisor + 1.4% not specifically accounted for + 1.9% in supervisor 0.4% not specifically accounted for diff --git a/inform7/core-module/Chapter 1/Class Predeclarations.w b/inform7/core-module/Chapter 1/Class Predeclarations.w index e9724f3b4..a273227c9 100644 --- a/inform7/core-module/Chapter 1/Class Predeclarations.w +++ b/inform7/core-module/Chapter 1/Class Predeclarations.w @@ -207,7 +207,7 @@ DECLARE_CLASS(property_of_value_storage) DECLARE_CLASS(runtime_kind_structure) DECLARE_CLASS(test_scenario) -@ And finally //index// -- +@ //index// -- @e contents_entry_CLASS @e documentation_ref_CLASS @@ -221,3 +221,14 @@ DECLARE_CLASS(documentation_ref) DECLARE_CLASS(index_element) DECLARE_CLASS(index_page) DECLARE_CLASS(index_lexicon_entry) + +@ //multimedia// -- + +@e figures_data_CLASS +@e sounds_data_CLASS +@e files_data_CLASS + += +DECLARE_CLASS(figures_data) +DECLARE_CLASS(sounds_data) +DECLARE_CLASS(files_data) diff --git a/inform7/core-module/Chapter 1/How To Compile.w b/inform7/core-module/Chapter 1/How To Compile.w index d864331fa..3b763e24b 100644 --- a/inform7/core-module/Chapter 1/How To Compile.w +++ b/inform7/core-module/Chapter 1/How To Compile.w @@ -221,7 +221,7 @@ so on. Those absolute basics are made here. BENCH(Phrases::Manager::rulebooks_array) BENCH_IF(scenes_plugin, PL::Scenes::DetectSceneChange_routine) BENCH_IF(scenes_plugin, PL::Scenes::ShowSceneStatus_routine) - BENCH(ExternalFiles::arrays) + BENCH(RTExternalFiles::arrays) BENCH(Rulebooks::rulebook_var_creators) BENCH(Activities::activity_var_creators) BENCH(RTRelations::IterateRelations) diff --git a/inform7/index-module/Chapter 2/Index File Services.w b/inform7/index-module/Chapter 2/Index File Services.w index 44a2e96f6..be239a31d 100644 --- a/inform7/index-module/Chapter 2/Index File Services.w +++ b/inform7/index-module/Chapter 2/Index File Services.w @@ -589,7 +589,7 @@ void Index::index_actual_element(OUTPUT_STREAM, text_stream *elt) { #ifdef MULTIMEDIA_MODULE IXFigures::index_all(OUT); IXSounds::index_all(OUT); - ExternalFiles::index_all(OUT); + IXExternalFiles::index_all(OUT); #endif return; } diff --git a/inform7/index-module/Chapter 3/External Files.w b/inform7/index-module/Chapter 3/External Files.w new file mode 100644 index 000000000..7f51d9438 --- /dev/null +++ b/inform7/index-module/Chapter 3/External Files.w @@ -0,0 +1,48 @@ +[IXExternalFiles::] External Files. + +To produce the index of external files. + +@ This is more or less perfunctory, but still of some use, if only as a list. + += +void IXExternalFiles::index_all(OUTPUT_STREAM) { + if (PluginManager::active(files_plugin) == FALSE) return; + files_data *exf; + if (NUMBER_CREATED(files_data) == 0) { + HTML_OPEN("p"); + WRITE("This project doesn't read or write external files."); + HTML_CLOSE("p"); + return; + } + HTML_OPEN("p"); + WRITE("List of External Files"); + HTML_CLOSE("p"); + HTML::begin_html_table(OUT, "#ffffff", TRUE, 0, 0, 0, 0, 0); + LOOP_OVER(exf, files_data) { + HTML::first_html_column(OUT, THUMBNAIL_WIDTH+10); + if (exf->file_is_binary) { + HTML_TAG_WITH("img", "border=\"0\" src=\"inform:/doc_images/exf_binary.png\""); + } else { + HTML_TAG_WITH("img", "border=\"0\" src=\"inform:/doc_images/exf_text.png\""); + } + WRITE(" "); + HTML::next_html_column(OUT, 0); + WRITE("%+W", exf->name); + Index::link(OUT, Wordings::first_wn(exf->name)); + HTML_TAG("br"); + WRITE("Filename: %s %N- owned by ", + (exf->file_is_binary)?"- binary ":"", + exf->unextended_filename); + switch (exf->file_ownership) { + case OWNED_BY_THIS_PROJECT: WRITE("this project"); break; + case OWNED_BY_ANOTHER_PROJECT: WRITE("another project"); break; + case OWNED_BY_SPECIFIC_PROJECT: + WRITE("project with IFID number %S", + exf->IFID_of_owner); + break; + } + HTML::end_html_row(OUT); + } + HTML::end_html_table(OUT); + HTML_OPEN("p"); +} diff --git a/inform7/index-module/Contents.w b/inform7/index-module/Contents.w index 7db35e2cb..d52a54f89 100644 --- a/inform7/index-module/Contents.w +++ b/inform7/index-module/Contents.w @@ -25,3 +25,4 @@ Chapter 2: Indexing Chapter 3: Indexing for Plugins Figures Sound Effects + External Files diff --git a/inform7/multimedia-module/Chapter 1/Multimedia Module.w b/inform7/multimedia-module/Chapter 1/Multimedia Module.w index 27ef3238e..2fdcf8d03 100644 --- a/inform7/multimedia-module/Chapter 1/Multimedia Module.w +++ b/inform7/multimedia-module/Chapter 1/Multimedia Module.w @@ -8,34 +8,27 @@ which use this module: @d MULTIMEDIA_MODULE TRUE -@ This module defines the following classes: - -@e figures_data_CLASS -@e sounds_data_CLASS -@e external_file_CLASS - -= -DECLARE_CLASS(figures_data) -DECLARE_CLASS(sounds_data) -DECLARE_CLASS(external_file) - -@ - -= (early code) -plugin *multimedia_plugin, *figures_plugin, *sounds_plugin, *files_plugin; - @ Like all modules, this one must define a |start| and |end| function: -@e FIGURE_CREATIONS_DA +@e MULTIMEDIA_CREATIONS_DA = void MultimediaModule::start(void) { multimedia_plugin = PluginManager::new(NULL, I"multimedia", NULL); - figures_plugin = PluginManager::new(&Figures::start, I"figures", multimedia_plugin); - sounds_plugin = PluginManager::new(&Sounds::start, I"sounds", multimedia_plugin); - files_plugin = PluginManager::new(&ExternalFiles::start, I"glulx external files", multimedia_plugin); + figures_plugin = PluginManager::new(&Figures::start, I"figures", + multimedia_plugin); + sounds_plugin = PluginManager::new(&Sounds::start, I"sounds", + multimedia_plugin); + files_plugin = PluginManager::new(&ExternalFiles::start, I"glulx external files", + multimedia_plugin); - Log::declare_aspect(FIGURE_CREATIONS_DA, L"figure creations", FALSE, FALSE); + Log::declare_aspect(MULTIMEDIA_CREATIONS_DA, L"figure creations", FALSE, FALSE); } void MultimediaModule::end(void) { } + +@ Note that the "multimedia" plugin itself does nothihg except to be a parent +to the other three; it doesn't even have an activation function. + += (early code) +plugin *multimedia_plugin, *figures_plugin, *sounds_plugin, *files_plugin; diff --git a/inform7/multimedia-module/Chapter 2/External Files.w b/inform7/multimedia-module/Chapter 2/External Files.w index d2d8c0b3e..a4e193f3a 100644 --- a/inform7/multimedia-module/Chapter 2/External Files.w +++ b/inform7/multimedia-module/Chapter 2/External Files.w @@ -3,83 +3,49 @@ To register the names associated with external files, and build the small I6 arrays associated with each. -@ The test group |:files| exercises the features below. +@ The test group |:files| exercises the features in this plugin. -@ Each file can be text or binary, has a name, and can be owned by a this -project, by an unspecified other project, or by a project named by IFID. - -@d OWNED_BY_THIS_PROJECT 1 -@d OWNED_BY_ANOTHER_PROJECT 2 -@d OWNED_BY_SPECIFIC_PROJECT 3 - -@d files_data external_file +The following is called to activate the plugin: = -typedef struct external_file { - struct wording name; /* text of name */ - int unextended_filename; /* word number of text like |"bones"| */ - struct text_stream *exf_I6_identifier; /* an I6 identifier */ - int file_is_binary; /* true or false */ - int file_ownership; /* one of the above */ - struct text_stream *IFID_of_owner; /* an I6 identifier */ - struct inter_name *exf_iname; - struct inter_name *IFID_array_iname; - CLASS_DEFINITION -} external_file; - -@ A |-->| array to a run-time data structure associated -with an external file, read or written by the story file during play. - -= (early code) -kind *K_external_file = NULL; - -@ = void ExternalFiles::start(void) { PluginManager::plug(MAKE_SPECIAL_MEANINGS_PLUG, ExternalFiles::make_special_meanings); PluginManager::plug(NEW_BASE_KIND_NOTIFY_PLUG, ExternalFiles::files_new_base_kind_notify); PluginManager::plug(NEW_INSTANCE_NOTIFY_PLUG, ExternalFiles::files_new_named_instance_notify); } -@ = +@h One special meaning. +We add one special meaning for assertions, to catch sentences with the shape: + +>> The File of Wisdom (owned by another project) is called "wisdom". + += int ExternalFiles::make_special_meanings(void) { SpecialMeanings::declare(ExternalFiles::new_file_SMF, I"new-file", 2); return FALSE; } - -int ExternalFiles::files_new_base_kind_notify(kind *new_base, text_stream *name, wording W) { - if (Str::eq_wide_string(name, L"EXTERNAL_FILE_TY")) { - K_external_file = new_base; return TRUE; +int ExternalFiles::new_file_SMF(int task, parse_node *V, wording *NPs) { + wording SW = (NPs)?(NPs[0]):EMPTY_WORDING; + wording OW = (NPs)?(NPs[1]):EMPTY_WORDING; + switch (task) { /* "File... is the file..." */ + case ACCEPT_SMFT: + if (((SW)) && ((OW))) { + parse_node *O = <>; + (SW); + V->next = <>; + V->next->next = O; + return TRUE; + } + break; + case PASS_1_SMFT: + ExternalFiles::register_file(Node::get_text(V->next), + Node::get_text(V->next->next)); + break; } return FALSE; } -int allow_exf_creations = FALSE; -int ExternalFiles::files_new_named_instance_notify(instance *nc) { - if (K_external_file == NULL) return FALSE; - kind *K = Instances::to_kind(nc); - if (Kinds::eq(K, K_external_file)) { - if (allow_exf_creations == FALSE) - StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_BackdoorFileCreation), - "this is not the way to create a new external file", - "which should be done with a special 'The File ... is called ...' " - "sentence."); - ATTACH_PLUGIN_DATA_TO_SUBJECT(files, nc->as_subject, ExternalFiles::new_external_file(nc)); - return TRUE; - } - return FALSE; -} - -@ = -external_file *ExternalFiles::new_external_file(instance *nc) { - external_file *exf = CREATE(external_file); - return exf; -} - -@ External files are created with a special sentence: - ->> The File of Wisdom (owned by another project) is called "wisdom". - -Here is the subject: +@ And this is the Preform grammar needed for the subject phrase: = ::= @@ -111,7 +77,7 @@ Here is the subject: "is called \"wisdom\".'"); ==> { NOT_APPLICABLE, - }; -@ The object NP is simply quoted text. Although the Preform grammar doesn't +@ The object phrase is simply quoted text. Although the Preform grammar doesn't go into this level of detail, it's actually required to have 3 to 23 English letters or digits, with the first being a letter. @@ -120,15 +86,6 @@ letters or digits, with the first being a letter. | ==> { pass 1 } ... ==> @ -@ = - StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_FilenameNotTextual), - "a file can only be called with a single quoted piece of text", - "as in: 'The File of Wisdom is called \"wisdom\".'"); - ==> { -1, - }; - -@ This handles the special meaning "File... is the file...". - -= ::= | ==> { pass 2 } ==> { pass 1 } @@ -139,36 +96,37 @@ letters or digits, with the first being a letter. ::= ==> { 0, Diagrams::new_UNPARSED_NOUN(W) } -@ = -int ExternalFiles::new_file_SMF(int task, parse_node *V, wording *NPs) { - wording SW = (NPs)?(NPs[0]):EMPTY_WORDING; - wording OW = (NPs)?(NPs[1]):EMPTY_WORDING; - switch (task) { /* "File... is the file..." */ - case ACCEPT_SMFT: - if (((SW)) && ((OW))) { - parse_node *O = <>; - (SW); - V->next = <>; - V->next->next = O; - return TRUE; - } - break; - case PASS_1_SMFT: - if (PluginManager::active(files_plugin) == FALSE) - internal_error("Files plugin inactive"); - ExternalFiles::register_file(Node::get_text(V->next), - Node::get_text(V->next->next)); - break; - } - return FALSE; -} +@ = + StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_FilenameNotTextual), + "a file can only be called with a single quoted piece of text", + "as in: 'The File of Wisdom is called \"wisdom\".'"); + ==> { -1, - }; -void ExternalFiles::register_file(wording F, wording FN) { - int bad_filename = FALSE; +@ In assertion pass 1, then, the following is called on any sentence which +has been found to create a file: + += +void ExternalFiles::register_file(wording W, wording FN) { (FN); FN = Wordings::from(FN, <>); if (Wordings::empty(FN)) return; wchar_t *p = Lexer::word_text(Wordings::first_wn(FN)); + @; + int binary = FALSE; + int ownership = OWNED_BY_THIS_PROJECT; + TEMPORARY_TEXT(ifid_of_file) + @; + + ExternalFiles::files_create(W, binary, ownership, ifid_of_file, FN); + + LOGIF(MULTIMEDIA_CREATIONS, "Created external file <%W> = filename '%N'\n", W, FN); + DISCARD_TEXT(ifid_of_file) +} + +@ The restrictions here are really very conservative. + +@ = + int bad_filename = FALSE; if (Wide::len(p) < 5) bad_filename = TRUE; if (Characters::isalpha(p[1]) == FALSE) bad_filename = TRUE; for (int i=0; p[i]; i++) { @@ -192,12 +150,18 @@ void ExternalFiles::register_file(wording F, wording FN) { return; } - int ownership = OWNED_BY_THIS_PROJECT; - TEMPORARY_TEXT(ifid_of_file) +@ Each file can be text or binary, has a name, and can be owned by this project, +by an unspecified other project, or by a project identified by its IFID. - if ((F) == FALSE) internal_error("bad ef grammar"); - F = GET_RW(, 1); - int binary = <>; +@d OWNED_BY_THIS_PROJECT 1 +@d OWNED_BY_ANOTHER_PROJECT 2 +@d OWNED_BY_SPECIFIC_PROJECT 3 + +@ = + if ((W) == FALSE) internal_error("bad ef grammar"); + binary = <>; + W = GET_RW(, 1); + @; if (<> == TRUE) { wording OW = GET_RW(, 1); int j, invalid = FALSE; @@ -210,23 +174,21 @@ void ExternalFiles::register_file(wording F, wording FN) { invalid = TRUE; LOG("Objected to character %c\n", p[j]); } - if ((invalid) || (j==47)) { + if ((invalid) || (j==47)) StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_BadFileIFID), "the owner of the file should be specified " "using a valid double-quoted IFID", "as in: 'The File of Wisdom (owned by project " "\"4122DDA8-A153-46BC-8F57-42220F9D8795\") " "is called \"wisdom\".'"); - } else + else ownership = OWNED_BY_SPECIFIC_PROJECT; } - if (<> == FALSE) { - ownership = OWNED_BY_ANOTHER_PROJECT; - } + if (<> == FALSE) ownership = OWNED_BY_ANOTHER_PROJECT; - Assertions::Creator::vet_name_for_noun(F); - - if (((F)) && +@ = + Assertions::Creator::vet_name_for_noun(W); + if (((W)) && (Rvalues::is_CONSTANT_of_kind(<>, K_external_file))) { StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_FilenameDuplicate), "this is already the name of a file", @@ -234,122 +196,69 @@ void ExternalFiles::register_file(wording F, wording FN) { return; } +@h One significant kind. + += (early code) +kind *K_external_file = NULL; + +@ = +int ExternalFiles::files_new_base_kind_notify(kind *new_base, text_stream *name, wording W) { + if (Str::eq_wide_string(name, L"EXTERNAL_FILE_TY")) { + K_external_file = new_base; return TRUE; + } + return FALSE; +} + +@h Significant new instances. +This structure of additional data is attached to each figure instance. + += +typedef struct files_data { + struct wording name; /* text of name */ + int unextended_filename; /* word number of text like |"bones"| */ + struct text_stream *exf_identifier; /* an Inter identifier */ + int file_is_binary; /* true or false */ + int file_ownership; /* one of the |OWNED_BY_*| values above */ + struct text_stream *IFID_of_owner; /* if we know that */ + struct external_file_compilation_data compilation_data; + CLASS_DEFINITION +} files_data; + +@ We allow instances of "external file" to be created only through the above +code calling //Figures::figures_create//. If any other proposition somehow +manages to make a figure, a problem message is thrown. + += +int allow_exf_creations = FALSE; + +instance *ExternalFiles::files_create(wording W, int binary, int ownership, + text_stream *ifid_of_file, wording FN) { allow_exf_creations = TRUE; - pcalc_prop *prop = Propositions::Abstract::to_create_something( - K_external_file, F); - Assert::true(prop, CERTAIN_CE); + Assert::true(Propositions::Abstract::to_create_something(K_external_file, W), CERTAIN_CE); allow_exf_creations = FALSE; - external_file *exf = PLUGIN_DATA_ON_INSTANCE(files, Instances::latest()); - exf->name = F; - exf->unextended_filename = Wordings::first_wn(FN); - exf->file_is_binary = binary; - exf->file_ownership = ownership; - exf->IFID_of_owner = Str::duplicate(ifid_of_file); - - package_request *P = Hierarchy::local_package(EXTERNAL_FILES_HAP); - exf->exf_iname = Hierarchy::make_iname_with_memo(FILE_HL, P, exf->name); - exf->IFID_array_iname = Hierarchy::make_iname_with_memo(IFID_HL, P, exf->name); - - LOGIF(FIGURE_CREATIONS, "Created external file <%W> = filename '%N'\n", - F, exf->unextended_filename); - DISCARD_TEXT(ifid_of_file) + instance *I = Instances::latest(); + files_data *fd = PLUGIN_DATA_ON_INSTANCE(files, I); + fd->name = W; + fd->unextended_filename = Wordings::first_wn(FN); + fd->file_is_binary = binary; + fd->file_ownership = ownership; + fd->IFID_of_owner = Str::duplicate(ifid_of_file); + fd->compilation_data = RTExternalFiles::new_data(W); + return I; } -@h I6 arrays of file structures. -External files are written in I6 as their array names: - -= -void ExternalFiles::arrays(void) { - if (PluginManager::active(files_plugin) == FALSE) return; - - inter_name *iname = Hierarchy::find(NO_EXTERNAL_FILES_HL); - Emit::named_numeric_constant(iname, (inter_ti) (NUMBER_CREATED(external_file))); - Hierarchy::make_available(Emit::tree(), iname); - - external_file *exf; - LOOP_OVER(exf, external_file) { - if (exf->file_ownership == OWNED_BY_SPECIFIC_PROJECT) { - packaging_state save = Emit::named_string_array_begin(exf->IFID_array_iname, K_value); - TEMPORARY_TEXT(II) - WRITE_TO(II, "//%S//", exf->IFID_of_owner); - Emit::array_text_entry(II); - DISCARD_TEXT(II) - Emit::array_end(save); - } +int ExternalFiles::files_new_named_instance_notify(instance *I) { + if (K_external_file == NULL) return FALSE; + kind *K = Instances::to_kind(I); + if (Kinds::eq(K, K_external_file)) { + if (allow_exf_creations == FALSE) + StandardProblems::sentence_problem(Task::syntax_tree(), + _p_(PM_BackdoorFileCreation), + "this is not the way to create a new external file", + "which should be done with a special 'The File ... is called ...' " + "sentence."); + ATTACH_PLUGIN_DATA_TO_SUBJECT(files, I->as_subject, CREATE(files_data)); + return TRUE; } - - LOOP_OVER(exf, external_file) { - packaging_state save = Emit::named_array_begin(exf->exf_iname, K_value); - Emit::array_iname_entry(Hierarchy::find(AUXF_MAGIC_VALUE_HL)); - Emit::array_iname_entry(Hierarchy::find(AUXF_STATUS_IS_CLOSED_HL)); - if (exf->file_is_binary) Emit::array_numeric_entry(1); - else Emit::array_numeric_entry(0); - Emit::array_numeric_entry(0); - TEMPORARY_TEXT(WW) - WRITE_TO(WW, "%w", Lexer::word_raw_text(exf->unextended_filename)); - Str::delete_first_character(WW); - Str::delete_last_character(WW); - Emit::array_text_entry(WW); - DISCARD_TEXT(WW) - switch (exf->file_ownership) { - case OWNED_BY_THIS_PROJECT: Emit::array_iname_entry(PL::Bibliographic::IFID::UUID()); break; - case OWNED_BY_ANOTHER_PROJECT: Emit::array_null_entry(); break; - case OWNED_BY_SPECIFIC_PROJECT: Emit::array_iname_entry(exf->IFID_array_iname); break; - } - Emit::array_end(save); - } - - iname = Hierarchy::find(TABLEOFEXTERNALFILES_HL); - packaging_state save = Emit::named_array_begin(iname, K_value); - Emit::array_numeric_entry(0); - LOOP_OVER(exf, external_file) Emit::array_iname_entry(exf->exf_iname); - Emit::array_numeric_entry(0); - Emit::array_end(save); - Hierarchy::make_available(Emit::tree(), iname); -} - -@h External Files Index. -More or less perfunctory, but still of some use, if only as a list. - -= -void ExternalFiles::index_all(OUTPUT_STREAM) { - if (PluginManager::active(files_plugin) == FALSE) return; - external_file *exf; - if (NUMBER_CREATED(external_file) == 0) { - HTML_OPEN("p"); - WRITE("This project doesn't read or write external files."); - HTML_CLOSE("p"); - return; - } - HTML_OPEN("p"); - WRITE("List of External Files"); - HTML_CLOSE("p"); - HTML::begin_html_table(OUT, "#ffffff", TRUE, 0, 0, 0, 0, 0); - LOOP_OVER(exf, external_file) { - HTML::first_html_column(OUT, THUMBNAIL_WIDTH+10); - if (exf->file_is_binary) { - HTML_TAG_WITH("img", "border=\"0\" src=\"inform:/doc_images/exf_binary.png\""); - } else { - HTML_TAG_WITH("img", "border=\"0\" src=\"inform:/doc_images/exf_text.png\""); - } - WRITE(" "); - HTML::next_html_column(OUT, 0); - WRITE("%+W", exf->name); - Index::link(OUT, Wordings::first_wn(exf->name)); - HTML_TAG("br"); - WRITE("Filename: %s %N- owned by ", - (exf->file_is_binary)?"- binary ":"", - exf->unextended_filename); - switch (exf->file_ownership) { - case OWNED_BY_THIS_PROJECT: WRITE("this project"); break; - case OWNED_BY_ANOTHER_PROJECT: WRITE("another project"); break; - case OWNED_BY_SPECIFIC_PROJECT: - WRITE("project with IFID number %S", - exf->IFID_of_owner); - break; - } - HTML::end_html_row(OUT); - } - HTML::end_html_table(OUT); - HTML_OPEN("p"); + return FALSE; } diff --git a/inform7/multimedia-module/Chapter 2/Figures.w b/inform7/multimedia-module/Chapter 2/Figures.w index 770a806ce..f8fe59e68 100644 --- a/inform7/multimedia-module/Chapter 2/Figures.w +++ b/inform7/multimedia-module/Chapter 2/Figures.w @@ -50,10 +50,10 @@ int Figures::new_figure_SMF(int task, parse_node *V, wording *NPs) { ==> { pass 1 } ::= - file ==> { TRUE, RP[1] } + file ==> { TRUE, RP[1] } ::= - figure ... ==> { 0, Diagrams::new_UNPARSED_NOUN(W) } + figure ... ==> { 0, Diagrams::new_UNPARSED_NOUN(W) } ::= ( ) | ==> { R[1], -, <> = R[2] } @@ -99,7 +99,7 @@ void Figures::register_figure(wording W, wording FN) { filename *figure_file = NULL; if (wn >= 0) Filenames::in(Task::figures_path(), leaf); Figures::figures_create(W, id, figure_file, <>); - LOGIF(FIGURE_CREATIONS, "Created figure <%W> = filename '%f' = resource ID %d\n", + LOGIF(MULTIMEDIA_CREATIONS, "Created figure <%W> = filename '%f' = resource ID %d\n", W, figure_file, id); } } diff --git a/inform7/multimedia-module/Chapter 2/Sound Effects.w b/inform7/multimedia-module/Chapter 2/Sound Effects.w index 30838e969..10956b2f9 100644 --- a/inform7/multimedia-module/Chapter 2/Sound Effects.w +++ b/inform7/multimedia-module/Chapter 2/Sound Effects.w @@ -91,7 +91,7 @@ void Sounds::register_sound(wording W, wording FN) { DISCARD_TEXT(leaf) filename *sound_file = Filenames::in(Task::sounds_path(), leaf); Sounds::sounds_create(W, id, sound_file, <>); - LOGIF(FIGURE_CREATIONS, + LOGIF(MULTIMEDIA_CREATIONS, "Created sound effect <%W> = filename '%N' = resource ID %d\n", W, wn, id); } } diff --git a/inform7/multimedia-module/Contents.w b/inform7/multimedia-module/Contents.w index 26a234ea8..1d88f3f34 100644 --- a/inform7/multimedia-module/Contents.w +++ b/inform7/multimedia-module/Contents.w @@ -4,12 +4,13 @@ Purpose: A multimedia extension module for Inform. Language: InC Licence: Artistic License 2.0 +Preliminaries + What This Module Does + Chapter 1: Starting Up Multimedia Module Chapter 2: Multimedia Features -"Three plugins enabling Inform-written works of IF to make use of multimedia -features of the Glulx virtual machine." Figures Sound Effects External Files diff --git a/inform7/runtime-module/Chapter 5/External Files.w b/inform7/runtime-module/Chapter 5/External Files.w new file mode 100644 index 000000000..86334ff88 --- /dev/null +++ b/inform7/runtime-module/Chapter 5/External Files.w @@ -0,0 +1,66 @@ +[RTExternalFiles::] External Files. + +@ External files are written in Inter as their array names: + += +typedef struct external_file_compilation_data { + struct inter_name *exf_iname; + struct inter_name *IFID_array_iname; +} external_file_compilation_data; + +external_file_compilation_data RTExternalFiles::new_data(wording W) { + external_file_compilation_data efcd; + package_request *P = Hierarchy::local_package(EXTERNAL_FILES_HAP); + efcd.exf_iname = Hierarchy::make_iname_with_memo(FILE_HL, P, W); + efcd.IFID_array_iname = Hierarchy::make_iname_with_memo(IFID_HL, P, W); + return efcd; +} + +void RTExternalFiles::arrays(void) { + if (PluginManager::active(files_plugin) == FALSE) return; + + inter_name *iname = Hierarchy::find(NO_EXTERNAL_FILES_HL); + Emit::named_numeric_constant(iname, (inter_ti) (NUMBER_CREATED(files_data))); + Hierarchy::make_available(Emit::tree(), iname); + + files_data *exf; + LOOP_OVER(exf, files_data) { + if (exf->file_ownership == OWNED_BY_SPECIFIC_PROJECT) { + packaging_state save = Emit::named_string_array_begin(exf->compilation_data.IFID_array_iname, K_value); + TEMPORARY_TEXT(II) + WRITE_TO(II, "//%S//", exf->IFID_of_owner); + Emit::array_text_entry(II); + DISCARD_TEXT(II) + Emit::array_end(save); + } + } + + LOOP_OVER(exf, files_data) { + packaging_state save = Emit::named_array_begin(exf->compilation_data.exf_iname, K_value); + Emit::array_iname_entry(Hierarchy::find(AUXF_MAGIC_VALUE_HL)); + Emit::array_iname_entry(Hierarchy::find(AUXF_STATUS_IS_CLOSED_HL)); + if (exf->file_is_binary) Emit::array_numeric_entry(1); + else Emit::array_numeric_entry(0); + Emit::array_numeric_entry(0); + TEMPORARY_TEXT(WW) + WRITE_TO(WW, "%w", Lexer::word_raw_text(exf->unextended_filename)); + Str::delete_first_character(WW); + Str::delete_last_character(WW); + Emit::array_text_entry(WW); + DISCARD_TEXT(WW) + switch (exf->file_ownership) { + case OWNED_BY_THIS_PROJECT: Emit::array_iname_entry(PL::Bibliographic::IFID::UUID()); break; + case OWNED_BY_ANOTHER_PROJECT: Emit::array_null_entry(); break; + case OWNED_BY_SPECIFIC_PROJECT: Emit::array_iname_entry(exf->compilation_data.IFID_array_iname); break; + } + Emit::array_end(save); + } + + iname = Hierarchy::find(TABLEOFEXTERNALFILES_HL); + packaging_state save = Emit::named_array_begin(iname, K_value); + Emit::array_numeric_entry(0); + LOOP_OVER(exf, files_data) Emit::array_iname_entry(exf->compilation_data.exf_iname); + Emit::array_numeric_entry(0); + Emit::array_end(save); + Hierarchy::make_available(Emit::tree(), iname); +} diff --git a/inform7/runtime-module/Contents.w b/inform7/runtime-module/Contents.w index 84056a536..d5920990a 100644 --- a/inform7/runtime-module/Contents.w +++ b/inform7/runtime-module/Contents.w @@ -61,3 +61,4 @@ Chapter 4: Compilation Utilities Chapter 5: Plugin Support Figures Sound Effects + External Files