2020-02-13 21:43:24 +02:00
|
|
|
[Inbuild::] Inbuild Control.
|
2020-02-10 12:27:24 +02:00
|
|
|
|
2020-02-13 21:43:24 +02:00
|
|
|
The top-level controller through which client tools use this module.
|
2020-02-10 12:27:24 +02:00
|
|
|
|
2020-02-13 21:43:24 +02:00
|
|
|
@h Phases.
|
2020-03-28 15:00:08 +02:00
|
|
|
The |inbuild| module provides services to whichever program is using it:
|
|
|
|
recall that the module is included both in |inform7| and in |inbuild| (the
|
|
|
|
command line tool), so either of those might be what we call "the client".
|
|
|
|
|
|
|
|
This section defines how the client communicates with us to get everything
|
|
|
|
set up correctly. Although nothing at all clever happens in this code, it
|
|
|
|
requires careful sequencing to avoid invisible errors coming in because
|
|
|
|
function X assumes that function Y has already been called, or perhaos that
|
|
|
|
it never will be again. The |inbuild| module therefore runs through a
|
|
|
|
number of named "phases" on its way to reaching fully-operational status,
|
|
|
|
at which time the client can freely use its facilities.
|
|
|
|
|
|
|
|
@e STARTUP_INBUILD_PHASE from 1
|
|
|
|
@e CONFIGURATION_INBUILD_PHASE
|
2020-02-13 21:43:24 +02:00
|
|
|
@e PRETINKERING_INBUILD_PHASE
|
2020-02-13 01:48:37 +02:00
|
|
|
@e TINKERING_INBUILD_PHASE
|
2020-02-13 21:43:24 +02:00
|
|
|
@e NESTED_INBUILD_PHASE
|
|
|
|
@e PROJECTED_INBUILD_PHASE
|
2020-03-28 15:00:08 +02:00
|
|
|
@e TARGETED_INBUILD_PHASE
|
2020-02-13 21:43:24 +02:00
|
|
|
@e GOING_OPERATIONAL_INBUILD_PHASE
|
|
|
|
@e OPERATIONAL_INBUILD_PHASE
|
|
|
|
|
2020-03-28 15:00:08 +02:00
|
|
|
@ We're going to use the following assertions to make sure we don't slip up.
|
|
|
|
Some functions run only in some phases. Phases can be skipped, but not taken
|
|
|
|
out of turn.
|
|
|
|
|
2020-02-13 21:43:24 +02:00
|
|
|
@d RUN_ONLY_IN_PHASE(P)
|
|
|
|
if (inbuild_phase < P) internal_error("too soon");
|
|
|
|
if (inbuild_phase > P) internal_error("too late");
|
|
|
|
@d RUN_ONLY_FROM_PHASE(P)
|
|
|
|
if (inbuild_phase < P) internal_error("too soon");
|
|
|
|
@d RUN_ONLY_BEFORE_PHASE(P)
|
|
|
|
if (inbuild_phase >= P) internal_error("too late");
|
2020-02-13 01:48:37 +02:00
|
|
|
|
|
|
|
=
|
2020-03-28 15:00:08 +02:00
|
|
|
int inbuild_phase = STARTUP_INBUILD_PHASE;
|
|
|
|
void Inbuild::enter_phase(int p) {
|
|
|
|
if (p <= inbuild_phase) internal_error("phases out of sequence");
|
|
|
|
inbuild_phase = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
@h Startup phase.
|
|
|
|
The following is called when the |inbuild| module starts up.
|
|
|
|
|
|
|
|
=
|
|
|
|
void Inbuild::startup(void) {
|
|
|
|
KitManager::start();
|
|
|
|
ExtensionManager::start();
|
|
|
|
TemplateManager::start();
|
|
|
|
LanguageManager::start();
|
|
|
|
ProjectBundleManager::start();
|
|
|
|
ProjectFileManager::start();
|
|
|
|
PipelineManager::start();
|
|
|
|
|
|
|
|
InterSkill::create();
|
|
|
|
Inform7Skill::create();
|
|
|
|
Inform6Skill::create();
|
|
|
|
InblorbSkill::create();
|
|
|
|
|
|
|
|
ControlStructures::create_standard();
|
|
|
|
|
|
|
|
inbuild_phase = CONFIGURATION_INBUILD_PHASE;
|
|
|
|
Inbuild::set_defaults();
|
|
|
|
}
|
|
|
|
|
|
|
|
@h Configuration phase.
|
|
|
|
Initially, then, we are in the configuration phase. When the client defines
|
|
|
|
its command-line options, we expect it to call |Inbuild::declare_options|
|
|
|
|
so that we can define further options -- this provides the large set of
|
|
|
|
common options found in both |inform7| and |inbuild|, our two possible clients.
|
|
|
|
|
|
|
|
=
|
|
|
|
void Inbuild::declare_options(void) {
|
|
|
|
RUN_ONLY_IN_PHASE(CONFIGURATION_INBUILD_PHASE)
|
|
|
|
@<Declare Inform-related options@>;
|
|
|
|
@<Declare resource-related options@>;
|
|
|
|
@<Declare Inter-related options@>;
|
|
|
|
}
|
2020-02-13 01:48:37 +02:00
|
|
|
|
2020-03-28 15:00:08 +02:00
|
|
|
@ These options all predate the 2015-20 reworking of the compiler, and their
|
|
|
|
names are a series of historical accidents. |-format| in particular works in
|
|
|
|
a clunky sort of way and should perhaps be deprecated in favour of some
|
|
|
|
better way to choose a virtual machine to compile to.
|
2020-02-13 21:43:24 +02:00
|
|
|
|
2020-02-27 02:35:17 +02:00
|
|
|
@e INBUILD_INFORM_CLSG
|
2020-02-13 21:43:24 +02:00
|
|
|
|
|
|
|
@e PROJECT_CLSW
|
2020-02-21 00:20:04 +02:00
|
|
|
@e DEBUG_CLSW
|
|
|
|
@e RELEASE_CLSW
|
2020-03-28 15:00:08 +02:00
|
|
|
@e FORMAT_CLSW
|
|
|
|
@e SOURCE_CLSW
|
2020-02-23 14:36:39 +02:00
|
|
|
@e CENSUS_CLSW
|
2020-02-26 21:58:32 +02:00
|
|
|
@e RNG_CLSW
|
|
|
|
@e CASE_CLSW
|
2020-02-13 21:43:24 +02:00
|
|
|
|
2020-03-28 15:00:08 +02:00
|
|
|
@<Declare Inform-related options@> =
|
2020-02-27 02:35:17 +02:00
|
|
|
CommandLine::begin_group(INBUILD_INFORM_CLSG, I"for translating Inform source text to Inter");
|
2020-02-13 21:43:24 +02:00
|
|
|
CommandLine::declare_switch(PROJECT_CLSW, L"project", 2,
|
|
|
|
L"work within the Inform project X");
|
2020-02-21 00:20:04 +02:00
|
|
|
CommandLine::declare_boolean_switch(DEBUG_CLSW, L"debug", 1,
|
2020-02-27 02:35:17 +02:00
|
|
|
L"compile with debugging features even on a Release", FALSE);
|
2020-02-21 00:20:04 +02:00
|
|
|
CommandLine::declare_boolean_switch(RELEASE_CLSW, L"release", 1,
|
2020-02-27 02:35:17 +02:00
|
|
|
L"compile a version suitable for a Release build", FALSE);
|
2020-02-21 00:20:04 +02:00
|
|
|
CommandLine::declare_textual_switch(FORMAT_CLSW, L"format", 1,
|
|
|
|
L"compile I6 code suitable for the virtual machine X");
|
2020-02-13 21:43:24 +02:00
|
|
|
CommandLine::declare_switch(SOURCE_CLSW, L"source", 2,
|
|
|
|
L"use file X as the Inform source text");
|
2020-02-23 14:36:39 +02:00
|
|
|
CommandLine::declare_boolean_switch(CENSUS_CLSW, L"census", 1,
|
2020-02-27 02:35:17 +02:00
|
|
|
L"perform an extensions census", FALSE);
|
|
|
|
CommandLine::declare_boolean_switch(RNG_CLSW, L"rng", 1,
|
|
|
|
L"fix the random number generator of the story file (for testing)", FALSE);
|
|
|
|
CommandLine::declare_switch(CASE_CLSW, L"case", 2,
|
|
|
|
L"make any source links refer to the source in extension example X");
|
|
|
|
CommandLine::end_group();
|
|
|
|
|
2020-03-28 15:00:08 +02:00
|
|
|
@ Again, except for |-nest|, these go back to the mid-2010s.
|
|
|
|
|
|
|
|
@e INBUILD_RESOURCES_CLSG
|
|
|
|
|
|
|
|
@e NEST_CLSW
|
|
|
|
@e INTERNAL_CLSW
|
|
|
|
@e EXTERNAL_CLSW
|
|
|
|
@e TRANSIENT_CLSW
|
|
|
|
|
|
|
|
@<Declare resource-related options@> =
|
2020-02-27 02:35:17 +02:00
|
|
|
CommandLine::begin_group(INBUILD_RESOURCES_CLSG, I"for locating resources in the file system");
|
|
|
|
CommandLine::declare_switch(NEST_CLSW, L"nest", 2,
|
|
|
|
L"add the nest at pathname X to the search list");
|
|
|
|
CommandLine::declare_switch(INTERNAL_CLSW, L"internal", 2,
|
|
|
|
L"use X as the location of built-in material such as the Standard Rules");
|
|
|
|
CommandLine::declare_switch(EXTERNAL_CLSW, L"external", 2,
|
|
|
|
L"use X as the user's home for installed material such as extensions");
|
|
|
|
CommandLine::declare_switch(TRANSIENT_CLSW, L"transient", 2,
|
|
|
|
L"use X for transient data such as the extensions census");
|
|
|
|
CommandLine::end_group();
|
|
|
|
|
2020-03-28 15:00:08 +02:00
|
|
|
@ These are all new in 2020. They are not formally shared with the |inter| tool,
|
|
|
|
but |-pipeline-file| and |-variable| have the same effect as they would there.
|
|
|
|
|
|
|
|
@e INBUILD_INTER_CLSG
|
|
|
|
|
|
|
|
@e KIT_CLSW
|
|
|
|
@e PIPELINE_CLSW
|
|
|
|
@e PIPELINE_FILE_CLSW
|
|
|
|
@e PIPELINE_VARIABLE_CLSW
|
|
|
|
|
|
|
|
@<Declare Inter-related options@> =
|
2020-02-27 02:35:17 +02:00
|
|
|
CommandLine::begin_group(INBUILD_INTER_CLSG, I"for tweaking code generation from Inter");
|
|
|
|
CommandLine::declare_switch(KIT_CLSW, L"kit", 2,
|
|
|
|
L"include Inter code from the kit called X");
|
2020-02-25 01:16:59 +02:00
|
|
|
CommandLine::declare_switch(PIPELINE_CLSW, L"pipeline", 2,
|
2020-03-28 01:17:16 +02:00
|
|
|
L"specify code-generation pipeline by name (default is \"compile\")");
|
2020-02-25 01:16:59 +02:00
|
|
|
CommandLine::declare_switch(PIPELINE_FILE_CLSW, L"pipeline-file", 2,
|
2020-03-28 01:17:16 +02:00
|
|
|
L"specify code-generation pipeline as file X");
|
2020-02-25 01:16:59 +02:00
|
|
|
CommandLine::declare_switch(PIPELINE_VARIABLE_CLSW, L"variable", 2,
|
|
|
|
L"set pipeline variable X (in form name=value)");
|
2020-02-13 21:43:24 +02:00
|
|
|
CommandLine::end_group();
|
|
|
|
|
2020-03-28 15:00:08 +02:00
|
|
|
@ Use of the above options will cause the following global variables to be
|
|
|
|
set appropriately.
|
|
|
|
|
|
|
|
=
|
2020-03-28 01:17:16 +02:00
|
|
|
filename *inter_pipeline_file = NULL;
|
2020-02-25 01:16:59 +02:00
|
|
|
dictionary *pipeline_vars = NULL;
|
2020-02-13 21:43:24 +02:00
|
|
|
pathname *shared_transient_resources = NULL;
|
2020-02-21 00:20:04 +02:00
|
|
|
int this_is_a_debug_compile = FALSE; /* Destined to be compiled with debug features */
|
|
|
|
int this_is_a_release_compile = FALSE; /* Omit sections of source text marked not for release */
|
|
|
|
text_stream *story_filename_extension = NULL; /* What story file we will eventually have */
|
2020-02-23 14:36:39 +02:00
|
|
|
int census_mode = FALSE; /* Running only to update extension documentation */
|
2020-02-26 21:58:32 +02:00
|
|
|
int rng_seed_at_start_of_play = 0; /* The seed value, or 0 if not seeded */
|
2020-02-13 21:43:24 +02:00
|
|
|
|
2020-02-25 01:16:59 +02:00
|
|
|
void Inbuild::set_defaults(void) {
|
2020-03-28 15:00:08 +02:00
|
|
|
RUN_ONLY_IN_PHASE(CONFIGURATION_INBUILD_PHASE)
|
|
|
|
#ifdef CODEGEN_MODULE
|
|
|
|
pipeline_vars = CodeGen::Pipeline::basic_dictionary(I"output.ulx");
|
|
|
|
#endif
|
|
|
|
Inbuild::set_inter_pipeline(I"compile");
|
2020-02-25 01:16:59 +02:00
|
|
|
}
|
|
|
|
|
2020-03-28 15:00:08 +02:00
|
|
|
@ The pipeline name can be set not only here but also by |inform7| much
|
|
|
|
later on (way past the configuration stage), if it reads a sentence like:
|
|
|
|
|
|
|
|
>> Use inter pipeline "special".
|
|
|
|
|
|
|
|
=
|
|
|
|
text_stream *inter_pipeline_name = NULL;
|
|
|
|
|
|
|
|
void Inbuild::set_inter_pipeline(text_stream *name) {
|
|
|
|
if (inter_pipeline_name == NULL) inter_pipeline_name = Str::new();
|
|
|
|
else Str::clear(inter_pipeline_name);
|
|
|
|
WRITE_TO(inter_pipeline_name, "%S", name);
|
2020-02-27 02:35:17 +02:00
|
|
|
}
|
|
|
|
|
2020-03-28 15:00:08 +02:00
|
|
|
@ |inform7| needs to know this:
|
|
|
|
|
|
|
|
=
|
|
|
|
int Inbuild::currently_releasing(void) {
|
|
|
|
return this_is_a_release_compile;
|
|
|
|
}
|
|
|
|
|
|
|
|
@ The |inbuild| module itself doesn't parse command-line options: that's for
|
|
|
|
the client to do, using code from Foundation. When the client finds an option
|
|
|
|
it doesn't know about, that will be one of ourse, so it should call the following:
|
|
|
|
|
|
|
|
=
|
2020-02-13 21:43:24 +02:00
|
|
|
void Inbuild::option(int id, int val, text_stream *arg, void *state) {
|
|
|
|
RUN_ONLY_IN_PHASE(CONFIGURATION_INBUILD_PHASE)
|
|
|
|
switch (id) {
|
2020-02-21 00:20:04 +02:00
|
|
|
case DEBUG_CLSW: this_is_a_debug_compile = val; break;
|
|
|
|
case FORMAT_CLSW: story_filename_extension = Str::duplicate(arg); break;
|
|
|
|
case RELEASE_CLSW: this_is_a_release_compile = val; break;
|
2020-03-28 15:00:08 +02:00
|
|
|
case NEST_CLSW:
|
|
|
|
Inbuild::add_nest(Pathnames::from_text(arg), GENERIC_NEST_TAG); break;
|
|
|
|
case INTERNAL_CLSW:
|
|
|
|
Inbuild::add_nest(Pathnames::from_text(arg), INTERNAL_NEST_TAG); break;
|
|
|
|
case EXTERNAL_CLSW:
|
|
|
|
Inbuild::add_nest(Pathnames::from_text(arg), EXTERNAL_NEST_TAG); break;
|
|
|
|
case TRANSIENT_CLSW:
|
|
|
|
shared_transient_resources = Pathnames::from_text(arg); break;
|
2020-02-13 21:43:24 +02:00
|
|
|
case KIT_CLSW: Inbuild::request_kit(arg); break;
|
|
|
|
case PROJECT_CLSW:
|
|
|
|
if (Inbuild::set_I7_bundle(arg) == FALSE)
|
|
|
|
Errors::fatal_with_text("can't specify the project twice: '%S'", arg);
|
|
|
|
break;
|
|
|
|
case SOURCE_CLSW:
|
|
|
|
if (Inbuild::set_I7_source(arg) == FALSE)
|
|
|
|
Errors::fatal_with_text("can't specify the source file twice: '%S'", arg);
|
|
|
|
break;
|
2020-02-23 14:36:39 +02:00
|
|
|
case CENSUS_CLSW: census_mode = val; break;
|
2020-03-28 01:17:16 +02:00
|
|
|
case PIPELINE_CLSW: inter_pipeline_name = Str::duplicate(arg); break;
|
|
|
|
case PIPELINE_FILE_CLSW: inter_pipeline_file = Filenames::from_text(arg); break;
|
2020-03-28 15:00:08 +02:00
|
|
|
case PIPELINE_VARIABLE_CLSW: @<Set a pipeline variable@>; break;
|
|
|
|
case RNG_CLSW: @<Seed the random number generator@>; break;
|
2020-02-26 21:58:32 +02:00
|
|
|
case CASE_CLSW: HTMLFiles::set_source_link_case(arg); break;
|
2020-02-13 21:43:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-28 15:00:08 +02:00
|
|
|
@ Note that the following has no effect unless the |codegen| module is part
|
|
|
|
of the client. In practice, that will be true for |inform7| but not |inbuild|.
|
|
|
|
|
|
|
|
@<Set a pipeline variable@> =
|
|
|
|
match_results mr = Regexp::create_mr();
|
|
|
|
if (Regexp::match(&mr, arg, L"(%c+)=(%c+)")) {
|
|
|
|
if (Str::get_first_char(arg) != '*') {
|
|
|
|
Errors::fatal("-variable names must begin with '*'");
|
|
|
|
} else {
|
|
|
|
#ifdef CODEGEN_MODULE
|
|
|
|
Str::copy(Dictionaries::create_text(pipeline_vars, mr.exp[0]), mr.exp[1]);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Errors::fatal("-variable should take the form 'name=value'");
|
|
|
|
}
|
|
|
|
Regexp::dispose_of(&mr);
|
|
|
|
|
|
|
|
@ 16339 is a well-known prime number for use in 16-bit random number algorithms,
|
|
|
|
such as the one used in the Z-machine VM. It works fine in 32-bit cases too.
|
|
|
|
|
|
|
|
@<Seed the random number generator@> =
|
|
|
|
if (val) rng_seed_at_start_of_play = -16339;
|
|
|
|
else rng_seed_at_start_of_play = 0;
|
|
|
|
|
|
|
|
@h The Pretinkering, Tinkering, Nested and Projected phases.
|
|
|
|
Once the tool has finished with the command line, it should call this
|
2020-02-21 00:20:04 +02:00
|
|
|
function. Inbuild rapidly runs through the next few phases as it does so.
|
2020-02-13 21:43:24 +02:00
|
|
|
From the "nested" phase, the final list of nests in the search path for
|
|
|
|
finding kits, extensions and so on exists; from the "projected" phase,
|
2020-03-28 15:00:08 +02:00
|
|
|
the main Inform project (if there is one) exists.
|
2020-02-13 21:43:24 +02:00
|
|
|
|
2020-03-28 15:00:08 +02:00
|
|
|
Recall that Inbuild does not need to be dealing with an Inform 7 project
|
|
|
|
as a target, but that if it is, then it is the only such. We call this
|
|
|
|
the "shared project". There will be lots of other copies known to Inbuild --
|
|
|
|
all the kits and extensions needed to build the shared project -- but only
|
|
|
|
one project.
|
2020-03-07 10:46:43 +02:00
|
|
|
|
2020-03-28 15:00:08 +02:00
|
|
|
The client should set |compile_only| if it just wants to make a basic,
|
|
|
|
non-incremental compilation of the project. In practice, |inform7| wants
|
|
|
|
that but |inbuild| does not.
|
2020-02-22 01:16:23 +02:00
|
|
|
|
2020-03-28 15:00:08 +02:00
|
|
|
When this call returns to the client, |inbuild| is in the Targeted phase,
|
|
|
|
which continues until the client calls |Inbuild::go_operational| (see below).
|
2020-02-22 01:16:23 +02:00
|
|
|
|
2020-03-28 15:00:08 +02:00
|
|
|
=
|
|
|
|
inbuild_copy *Inbuild::optioneering_complete(inbuild_copy *C, int compile_only,
|
|
|
|
void (*preform_callback)(inform_language *)) {
|
|
|
|
RUN_ONLY_IN_PHASE(CONFIGURATION_INBUILD_PHASE)
|
2020-02-13 21:43:24 +02:00
|
|
|
inbuild_phase = PRETINKERING_INBUILD_PHASE;
|
2020-03-28 15:00:08 +02:00
|
|
|
|
|
|
|
@<Find the virtual machine@>;
|
2020-02-22 01:16:23 +02:00
|
|
|
inform_project *project = Inbuild::create_shared_project(C);
|
|
|
|
|
2020-02-13 21:43:24 +02:00
|
|
|
inbuild_phase = TINKERING_INBUILD_PHASE;
|
|
|
|
Inbuild::sort_nest_list();
|
2020-03-28 15:00:08 +02:00
|
|
|
|
2020-02-13 21:43:24 +02:00
|
|
|
inbuild_phase = NESTED_INBUILD_PHASE;
|
2020-03-28 15:00:08 +02:00
|
|
|
@<Read the definition of the natural language of syntax@>;
|
|
|
|
|
|
|
|
if (project) {
|
|
|
|
Inbuild::pass_kit_requests();
|
2020-03-29 19:39:17 +03:00
|
|
|
Copies::get_source_text(project->as_copy);
|
2020-03-28 15:00:08 +02:00
|
|
|
}
|
|
|
|
|
2020-02-13 21:43:24 +02:00
|
|
|
inbuild_phase = PROJECTED_INBUILD_PHASE;
|
2020-03-28 15:00:08 +02:00
|
|
|
if (project)
|
|
|
|
Projects::construct_build_target(project,
|
|
|
|
Inbuild::current_vm(), this_is_a_release_compile, compile_only);
|
|
|
|
|
|
|
|
inbuild_phase = TARGETED_INBUILD_PHASE;
|
|
|
|
if (project) return project->as_copy;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
@ The VM to be used depends on the settings of all three of |-format|,
|
|
|
|
|-release| and |-debug|, and those can be given in any order at the command
|
|
|
|
line, which is why we couldn't work this out earlier:
|
|
|
|
|
|
|
|
@<Find the virtual machine@> =
|
|
|
|
text_stream *ext = story_filename_extension;
|
|
|
|
if (Str::len(ext) == 0) ext = I"ulx";
|
|
|
|
int with_debugging = FALSE;
|
|
|
|
if ((this_is_a_release_compile == FALSE) || (this_is_a_debug_compile))
|
|
|
|
with_debugging = TRUE;
|
|
|
|
Inbuild::set_current_vm(TargetVMs::find(ext, with_debugging));
|
|
|
|
|
|
|
|
@ The "language of syntax" of a project is the natural language, by default
|
|
|
|
English, in which its source text is written.
|
2020-02-22 01:16:23 +02:00
|
|
|
|
2020-03-28 15:00:08 +02:00
|
|
|
We scan the available natural languages first. To do that it's sufficient to
|
|
|
|
generate a list of search results for all possible languages: each as it
|
|
|
|
comes to light will have been recorded as a possibility. We can then simply
|
|
|
|
ignore the search results. Note that this can only be done in the Nested
|
|
|
|
phase or after, because we need the nests in order to perform a search.
|
|
|
|
|
|
|
|
Once that's done, we ask the client to load the Preform grammar for the
|
|
|
|
language of the project. For now that's always English, but here is where
|
|
|
|
we would attempt to detect the language of syntax if we could.
|
|
|
|
|
|
|
|
@<Read the definition of the natural language of syntax@> =
|
|
|
|
inbuild_requirement *req = Requirements::anything_of_genre(language_genre);
|
|
|
|
linked_list *L = NEW_LINKED_LIST(inbuild_search_result);
|
|
|
|
Nests::search_for(req, Inbuild::nest_list(), L);
|
2020-02-22 01:16:23 +02:00
|
|
|
if (project) {
|
2020-03-28 15:00:08 +02:00
|
|
|
Projects::set_to_English(project);
|
|
|
|
(*preform_callback)(Projects::get_language_of_syntax(project));
|
2020-02-22 01:16:23 +02:00
|
|
|
} else {
|
2020-03-28 15:00:08 +02:00
|
|
|
(*preform_callback)(Languages::internal_English());
|
2020-02-22 01:16:23 +02:00
|
|
|
}
|
2020-02-13 21:43:24 +02:00
|
|
|
|
2020-03-28 15:00:08 +02:00
|
|
|
@ =
|
|
|
|
target_vm *current_target_VM = NULL;
|
2020-02-21 00:20:04 +02:00
|
|
|
target_vm *Inbuild::current_vm(void) {
|
2020-03-28 15:00:08 +02:00
|
|
|
RUN_ONLY_FROM_PHASE(TINKERING_INBUILD_PHASE)
|
2020-02-21 00:20:04 +02:00
|
|
|
return current_target_VM;
|
|
|
|
}
|
2020-03-28 15:00:08 +02:00
|
|
|
void Inbuild::set_current_vm(target_vm *VM) {
|
|
|
|
RUN_ONLY_IN_PHASE(PRETINKERING_INBUILD_PHASE)
|
|
|
|
current_target_VM = VM;
|
2020-02-21 00:20:04 +02:00
|
|
|
}
|
|
|
|
|
2020-03-28 15:00:08 +02:00
|
|
|
@h The Going Operational and Operational phases.
|
|
|
|
|inbuild| is now in the Targeted phase, then, meaning that the client has
|
|
|
|
called |Inbuild::optioneering_complete| and has been making further
|
|
|
|
preparations of its own. (For example, it could attach further kit
|
|
|
|
dependencies to the shared project.) The client has one further duty to
|
|
|
|
perform: to call |Inbuild::go_operational|. After that, everything is ready
|
|
|
|
for use.
|
2020-02-13 21:43:24 +02:00
|
|
|
|
|
|
|
The brief "going operational" phase is used, for example, to build out
|
2020-03-28 15:00:08 +02:00
|
|
|
dependency graphs. We do that copy by copy. The shared project, if there is
|
|
|
|
one, goes first; then everything else known to us.
|
2020-02-13 21:43:24 +02:00
|
|
|
|
|
|
|
=
|
2020-02-25 01:16:59 +02:00
|
|
|
inform_project *Inbuild::go_operational(void) {
|
2020-03-28 15:00:08 +02:00
|
|
|
RUN_ONLY_IN_PHASE(TARGETED_INBUILD_PHASE)
|
2020-02-13 21:43:24 +02:00
|
|
|
inbuild_phase = GOING_OPERATIONAL_INBUILD_PHASE;
|
2020-03-26 21:22:26 +02:00
|
|
|
inform_project *P = Inbuild::project();
|
|
|
|
if (P) Copies::go_operational(P->as_copy);
|
2020-02-13 21:43:24 +02:00
|
|
|
inbuild_copy *C;
|
|
|
|
LOOP_OVER(C, inbuild_copy)
|
2020-03-26 21:22:26 +02:00
|
|
|
if ((P == NULL) || (C != P->as_copy))
|
|
|
|
Copies::go_operational(C);
|
2020-02-13 21:43:24 +02:00
|
|
|
inbuild_phase = OPERATIONAL_INBUILD_PHASE;
|
2020-02-23 14:36:39 +02:00
|
|
|
if (census_mode) Extensions::Census::handle_census_mode();
|
2020-02-25 01:16:59 +02:00
|
|
|
return Inbuild::project();
|
2020-02-13 21:43:24 +02:00
|
|
|
}
|
|
|
|
|
2020-02-11 02:15:49 +02:00
|
|
|
@h The nest list.
|
2020-02-26 21:58:32 +02:00
|
|
|
Nests are directories which hold resources to be used by the Intools, and
|
|
|
|
one of Inbuild's main roles is to search and manage nests. All nests can
|
|
|
|
hold extensions, kits, language definitions, and so on.
|
|
|
|
|
|
|
|
But among nests three are special, and can hold other things as well.
|
|
|
|
|
|
|
|
(a) The "internal" nest is part of the installation of Inform as software.
|
|
|
|
It contains, for example, the build-in extensions. But it also contains
|
|
|
|
miscellaneous other files needed by Infomr (see below).
|
|
|
|
|
|
|
|
(b) The "external" nest is the one to which the user installs her own
|
|
|
|
selection of extensions, and so on. On most platforms, the external nest
|
|
|
|
is also the default home of "transient" storage, for more ephemeral content,
|
|
|
|
such as the mechanically generated extension documentation. Some mobile
|
|
|
|
operating systems are aggressive about wanting to delete ephemeral files
|
|
|
|
used by applications, so |-transient| can be used to divert these.
|
|
|
|
|
|
|
|
(c) Every project has its own private nest, in the form of its associated
|
|
|
|
Materials folder. For example, in |Jane Eyre.inform| is a project, then
|
|
|
|
alongside it is |Jane Eyre.materials| and this is a nest.
|
|
|
|
|
2020-02-11 02:15:49 +02:00
|
|
|
@ Inform customarily has exactly one |-internal| and one |-external| nest,
|
|
|
|
but in fact any number of each are allowed, including none. However, the
|
|
|
|
first to be declared are used by the compiler as "the" internal and external
|
|
|
|
nests, respectively.
|
2020-02-10 12:27:24 +02:00
|
|
|
|
2020-02-11 02:15:49 +02:00
|
|
|
The following hold the nests in declaration order.
|
2020-02-10 12:27:24 +02:00
|
|
|
|
2020-02-11 02:15:49 +02:00
|
|
|
=
|
2020-02-10 12:27:24 +02:00
|
|
|
linked_list *unsorted_nest_list = NULL;
|
|
|
|
inbuild_nest *shared_internal_nest = NULL;
|
|
|
|
inbuild_nest *shared_external_nest = NULL;
|
2020-02-11 02:15:49 +02:00
|
|
|
inbuild_nest *shared_materials_nest = NULL;
|
2020-02-10 12:27:24 +02:00
|
|
|
|
2020-02-13 21:43:24 +02:00
|
|
|
inbuild_nest *Inbuild::add_nest(pathname *P, int tag) {
|
|
|
|
RUN_ONLY_BEFORE_PHASE(TINKERING_INBUILD_PHASE)
|
2020-02-10 12:27:24 +02:00
|
|
|
if (unsorted_nest_list == NULL)
|
|
|
|
unsorted_nest_list = NEW_LINKED_LIST(inbuild_nest);
|
|
|
|
inbuild_nest *N = Nests::new(P);
|
|
|
|
Nests::set_tag(N, tag);
|
|
|
|
ADD_TO_LINKED_LIST(N, inbuild_nest, unsorted_nest_list);
|
|
|
|
if ((tag == EXTERNAL_NEST_TAG) && (shared_external_nest == NULL))
|
|
|
|
shared_external_nest = N;
|
|
|
|
if ((tag == INTERNAL_NEST_TAG) && (shared_internal_nest == NULL))
|
|
|
|
shared_internal_nest = N;
|
|
|
|
if (tag == INTERNAL_NEST_TAG) Nests::protect(N);
|
|
|
|
return N;
|
|
|
|
}
|
|
|
|
|
2020-02-11 02:15:49 +02:00
|
|
|
@ It is then sorted in tag order. This is so that if we look for, say, an
|
|
|
|
extension with a given name, then results in a project's materials folder
|
|
|
|
are given precedence over those in the external folder, and so on.
|
|
|
|
|
|
|
|
=
|
|
|
|
linked_list *shared_nest_list = NULL;
|
2020-02-13 21:43:24 +02:00
|
|
|
void Inbuild::sort_nest_list(void) {
|
|
|
|
RUN_ONLY_IN_PHASE(TINKERING_INBUILD_PHASE)
|
2020-02-11 02:15:49 +02:00
|
|
|
shared_nest_list = NEW_LINKED_LIST(inbuild_nest);
|
|
|
|
inbuild_nest *N;
|
|
|
|
LOOP_OVER_LINKED_LIST(N, inbuild_nest, unsorted_nest_list)
|
|
|
|
if (Nests::get_tag(N) == MATERIALS_NEST_TAG)
|
|
|
|
ADD_TO_LINKED_LIST(N, inbuild_nest, shared_nest_list);
|
|
|
|
LOOP_OVER_LINKED_LIST(N, inbuild_nest, unsorted_nest_list)
|
|
|
|
if (Nests::get_tag(N) == EXTERNAL_NEST_TAG)
|
|
|
|
ADD_TO_LINKED_LIST(N, inbuild_nest, shared_nest_list);
|
|
|
|
LOOP_OVER_LINKED_LIST(N, inbuild_nest, unsorted_nest_list)
|
|
|
|
if (Nests::get_tag(N) == GENERIC_NEST_TAG)
|
|
|
|
ADD_TO_LINKED_LIST(N, inbuild_nest, shared_nest_list);
|
|
|
|
LOOP_OVER_LINKED_LIST(N, inbuild_nest, unsorted_nest_list)
|
|
|
|
if (Nests::get_tag(N) == INTERNAL_NEST_TAG)
|
|
|
|
ADD_TO_LINKED_LIST(N, inbuild_nest, shared_nest_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
@ And the rest of Inform or Inbuild can now use:
|
|
|
|
|
|
|
|
=
|
2020-02-13 21:43:24 +02:00
|
|
|
linked_list *Inbuild::nest_list(void) {
|
|
|
|
RUN_ONLY_FROM_PHASE(NESTED_INBUILD_PHASE)
|
2020-02-11 02:15:49 +02:00
|
|
|
if (shared_nest_list == NULL) internal_error("nest list never sorted");
|
|
|
|
return shared_nest_list;
|
|
|
|
}
|
|
|
|
|
2020-02-13 21:43:24 +02:00
|
|
|
inbuild_nest *Inbuild::internal(void) {
|
|
|
|
RUN_ONLY_FROM_PHASE(NESTED_INBUILD_PHASE)
|
2020-02-10 12:27:24 +02:00
|
|
|
return shared_internal_nest;
|
|
|
|
}
|
|
|
|
|
2020-02-13 21:43:24 +02:00
|
|
|
inbuild_nest *Inbuild::external(void) {
|
|
|
|
RUN_ONLY_FROM_PHASE(NESTED_INBUILD_PHASE)
|
2020-02-10 12:27:24 +02:00
|
|
|
return shared_external_nest;
|
|
|
|
}
|
|
|
|
|
2020-02-13 21:43:24 +02:00
|
|
|
pathname *Inbuild::materials(void) {
|
|
|
|
RUN_ONLY_FROM_PHASE(NESTED_INBUILD_PHASE)
|
2020-02-11 02:15:49 +02:00
|
|
|
if (shared_materials_nest == NULL) return NULL;
|
|
|
|
return shared_materials_nest->location;
|
|
|
|
}
|
|
|
|
|
2020-03-10 22:21:55 +02:00
|
|
|
inbuild_nest *Inbuild::materials_nest(void) {
|
|
|
|
RUN_ONLY_FROM_PHASE(NESTED_INBUILD_PHASE)
|
|
|
|
return shared_materials_nest;
|
|
|
|
}
|
|
|
|
|
2020-02-26 21:58:32 +02:00
|
|
|
@ As noted above, the transient area is used for ephemera such as dynamically
|
|
|
|
written documentation and telemetry files. |-transient| sets it, but otherwise
|
2020-02-11 02:15:49 +02:00
|
|
|
the external nest is used.
|
|
|
|
|
|
|
|
=
|
2020-02-13 21:43:24 +02:00
|
|
|
pathname *Inbuild::transient(void) {
|
|
|
|
RUN_ONLY_FROM_PHASE(PROJECTED_INBUILD_PHASE)
|
2020-02-10 12:27:24 +02:00
|
|
|
if (shared_transient_resources == NULL)
|
|
|
|
if (shared_external_nest)
|
|
|
|
return shared_external_nest->location;
|
|
|
|
return shared_transient_resources;
|
|
|
|
}
|
|
|
|
|
2020-02-11 02:15:49 +02:00
|
|
|
@h The shared project.
|
|
|
|
In any single run, each of the Inform tools concerns itself with a single
|
|
|
|
Inform 7 program. This can be presented to it either in a project bundle
|
|
|
|
(a directory which contains source, settings, space for an index and for
|
|
|
|
temporary build files), or as a single file (just a text file containing
|
|
|
|
source text).
|
2020-02-10 12:27:24 +02:00
|
|
|
|
2020-02-11 02:15:49 +02:00
|
|
|
It is also possible o set a folder to be the project bundle, and nevertheless
|
|
|
|
specify a file somewhere else to be the source text. What you can't do is
|
|
|
|
specify the bundle twice, or specify the file twice.
|
2020-02-10 12:27:24 +02:00
|
|
|
|
|
|
|
=
|
2020-02-11 02:15:49 +02:00
|
|
|
text_stream *project_bundle_request = NULL;
|
|
|
|
text_stream *project_file_request = NULL;
|
|
|
|
|
2020-02-13 21:43:24 +02:00
|
|
|
int Inbuild::set_I7_source(text_stream *loc) {
|
|
|
|
RUN_ONLY_FROM_PHASE(CONFIGURATION_INBUILD_PHASE)
|
2020-02-11 02:15:49 +02:00
|
|
|
if (Str::len(project_file_request) > 0) return FALSE;
|
|
|
|
project_file_request = Str::duplicate(loc);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2020-03-28 15:00:08 +02:00
|
|
|
@ If we are given a |-project| on the command line, we can then work out
|
|
|
|
where its Materials folder is, and therefore where any expert settings files
|
|
|
|
would be. Note that the name of the expert settings file depends on the name
|
|
|
|
of the client, i.e., it will be |inform7-settings.txt| or |inbuild-settings.txt|
|
|
|
|
depending on who's asking.
|
|
|
|
|
|
|
|
=
|
2020-02-13 21:43:24 +02:00
|
|
|
int Inbuild::set_I7_bundle(text_stream *loc) {
|
|
|
|
RUN_ONLY_FROM_PHASE(CONFIGURATION_INBUILD_PHASE)
|
2020-02-11 02:15:49 +02:00
|
|
|
if (Str::len(project_bundle_request) > 0) return FALSE;
|
|
|
|
project_bundle_request = Str::duplicate(loc);
|
2020-02-11 12:29:10 +02:00
|
|
|
pathname *pathname_of_bundle = Pathnames::from_text(project_bundle_request);
|
2020-02-13 21:43:24 +02:00
|
|
|
pathname *materials = Inbuild::pathname_of_materials(pathname_of_bundle);
|
2020-02-11 12:29:10 +02:00
|
|
|
TEMPORARY_TEXT(leaf);
|
|
|
|
WRITE_TO(leaf, "%s-settings.txt", INTOOL_NAME);
|
|
|
|
filename *expert_settings = Filenames::in_folder(materials, leaf);
|
|
|
|
if (TextFiles::exists(expert_settings))
|
|
|
|
CommandLine::also_read_file(expert_settings);
|
|
|
|
DISCARD_TEXT(leaf);
|
2020-02-11 02:15:49 +02:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
@ If a bundle is found, then by default the source text within it is called
|
|
|
|
|story.ni|. The |.ni| is an anachronism now, but at one time stood for
|
|
|
|
"natural Inform", the working title for Inform 7 in the early 2000s.
|
|
|
|
|
|
|
|
=
|
|
|
|
inform_project *shared_project = NULL;
|
|
|
|
|
2020-02-22 01:16:23 +02:00
|
|
|
inform_project *Inbuild::create_shared_project(inbuild_copy *C) {
|
2020-02-13 21:43:24 +02:00
|
|
|
RUN_ONLY_IN_PHASE(PRETINKERING_INBUILD_PHASE)
|
2020-02-11 02:15:49 +02:00
|
|
|
filename *filename_of_i7_source = NULL;
|
|
|
|
pathname *pathname_of_bundle = NULL;
|
|
|
|
if (Str::len(project_bundle_request) > 0) {
|
|
|
|
pathname_of_bundle = Pathnames::from_text(project_bundle_request);
|
2020-02-10 12:27:24 +02:00
|
|
|
}
|
2020-02-11 02:15:49 +02:00
|
|
|
if (Str::len(project_file_request) > 0) {
|
|
|
|
filename_of_i7_source = Filenames::from_text(project_file_request);
|
|
|
|
}
|
2020-02-13 01:48:37 +02:00
|
|
|
if (C) {
|
|
|
|
pathname_of_bundle = C->location_if_path;
|
|
|
|
filename_of_i7_source = C->location_if_file;
|
|
|
|
}
|
|
|
|
if ((pathname_of_bundle) && (filename_of_i7_source == NULL))
|
|
|
|
filename_of_i7_source =
|
|
|
|
Filenames::in_folder(
|
|
|
|
Pathnames::subfolder(pathname_of_bundle, I"Source"),
|
|
|
|
I"story.ni");
|
2020-02-11 02:15:49 +02:00
|
|
|
if (pathname_of_bundle) {
|
2020-02-13 01:48:37 +02:00
|
|
|
if (C == NULL) C = ProjectBundleManager::claim_folder_as_copy(pathname_of_bundle);
|
2020-02-11 02:15:49 +02:00
|
|
|
shared_project = ProjectBundleManager::from_copy(C);
|
|
|
|
} else if (filename_of_i7_source) {
|
2020-02-13 01:48:37 +02:00
|
|
|
if (C == NULL) C = ProjectFileManager::claim_file_as_copy(filename_of_i7_source);
|
2020-02-11 02:15:49 +02:00
|
|
|
shared_project = ProjectFileManager::from_copy(C);
|
|
|
|
}
|
2020-02-22 16:09:13 +02:00
|
|
|
@<Create the default externals nest@>;
|
2020-02-11 02:15:49 +02:00
|
|
|
@<Create the materials nest@>;
|
2020-02-12 01:20:14 +02:00
|
|
|
if (shared_project) {
|
|
|
|
pathname *P = (shared_materials_nest)?(shared_materials_nest->location):NULL;
|
|
|
|
if (P) P = Pathnames::subfolder(P, I"Source");
|
|
|
|
if (Str::len(project_file_request) > 0) P = NULL;
|
|
|
|
Projects::set_source_filename(shared_project, P, filename_of_i7_source);
|
2020-02-26 21:58:32 +02:00
|
|
|
if (rng_seed_at_start_of_play != 0)
|
|
|
|
Projects::fix_rng(shared_project, rng_seed_at_start_of_play);
|
2020-02-12 01:20:14 +02:00
|
|
|
}
|
2020-02-22 01:16:23 +02:00
|
|
|
return shared_project;
|
2020-02-11 02:15:49 +02:00
|
|
|
}
|
|
|
|
|
2020-02-22 16:09:13 +02:00
|
|
|
@<Create the default externals nest@> =
|
|
|
|
inbuild_nest *E = shared_external_nest;
|
|
|
|
if (E == NULL) {
|
|
|
|
pathname *P = home_path;
|
|
|
|
char *subfolder_within = INFORM_FOLDER_RELATIVE_TO_HOME;
|
|
|
|
if (subfolder_within[0]) {
|
|
|
|
TEMPORARY_TEXT(SF);
|
|
|
|
WRITE_TO(SF, "%s", subfolder_within);
|
|
|
|
P = Pathnames::subfolder(home_path, SF);
|
|
|
|
DISCARD_TEXT(SF);
|
|
|
|
}
|
|
|
|
P = Pathnames::subfolder(P, I"Inform");
|
|
|
|
E = Inbuild::add_nest(P, EXTERNAL_NEST_TAG);
|
|
|
|
}
|
|
|
|
|
2020-02-11 02:15:49 +02:00
|
|
|
@<Create the materials nest@> =
|
|
|
|
pathname *materials = NULL;
|
|
|
|
if (pathname_of_bundle) {
|
2020-02-13 21:43:24 +02:00
|
|
|
materials = Inbuild::pathname_of_materials(pathname_of_bundle);
|
2020-02-11 02:15:49 +02:00
|
|
|
Pathnames::create_in_file_system(materials);
|
|
|
|
} else if (filename_of_i7_source) {
|
|
|
|
materials = Pathnames::from_text(I"inform.materials");
|
|
|
|
}
|
|
|
|
if (materials) {
|
2020-02-13 21:43:24 +02:00
|
|
|
shared_materials_nest = Inbuild::add_nest(materials, MATERIALS_NEST_TAG);
|
2020-02-11 02:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@ And the rest of Inform or Inbuild can now use:
|
|
|
|
|
|
|
|
=
|
2020-02-13 21:43:24 +02:00
|
|
|
inform_project *Inbuild::project(void) {
|
2020-03-04 21:34:23 +02:00
|
|
|
RUN_ONLY_FROM_PHASE(TINKERING_INBUILD_PHASE)
|
2020-02-11 02:15:49 +02:00
|
|
|
return shared_project;
|
|
|
|
}
|
|
|
|
|
2020-02-11 12:29:10 +02:00
|
|
|
@ The materials folder sits alongside the project folder and has the same name,
|
|
|
|
but ending |.materials| instead of |.inform|.
|
|
|
|
|
|
|
|
=
|
2020-02-13 21:43:24 +02:00
|
|
|
pathname *Inbuild::pathname_of_materials(pathname *pathname_of_bundle) {
|
2020-02-11 12:29:10 +02:00
|
|
|
TEMPORARY_TEXT(mf);
|
|
|
|
WRITE_TO(mf, "%S", Pathnames::directory_name(pathname_of_bundle));
|
|
|
|
int i = Str::len(mf)-1;
|
|
|
|
while ((i>0) && (Str::get_at(mf, i) != '.')) i--;
|
|
|
|
if (i>0) {
|
|
|
|
Str::truncate(mf, i);
|
|
|
|
WRITE_TO(mf, ".materials");
|
|
|
|
}
|
|
|
|
pathname *materials = Pathnames::subfolder(Pathnames::up(pathname_of_bundle), mf);
|
|
|
|
DISCARD_TEXT(mf);
|
|
|
|
return materials;
|
|
|
|
}
|
|
|
|
|
2020-02-12 01:20:14 +02:00
|
|
|
@h Kit requests.
|
2020-02-13 21:43:24 +02:00
|
|
|
These are triggered by, for example, |-kit MyFancyKit| at the command line.
|
|
|
|
For timing reasons, we store those up in the configuration phase and then
|
|
|
|
add them as dependencies only when a project exists.
|
2020-02-12 01:20:14 +02:00
|
|
|
|
|
|
|
=
|
|
|
|
linked_list *kits_requested_at_command_line = NULL;
|
2020-02-13 21:43:24 +02:00
|
|
|
void Inbuild::request_kit(text_stream *name) {
|
|
|
|
RUN_ONLY_IN_PHASE(CONFIGURATION_INBUILD_PHASE)
|
2020-02-12 01:20:14 +02:00
|
|
|
if (kits_requested_at_command_line == NULL)
|
|
|
|
kits_requested_at_command_line = NEW_LINKED_LIST(text_stream);
|
|
|
|
text_stream *kit_name;
|
|
|
|
LOOP_OVER_LINKED_LIST(kit_name, text_stream, kits_requested_at_command_line)
|
|
|
|
if (Str::eq(kit_name, name))
|
|
|
|
return;
|
|
|
|
ADD_TO_LINKED_LIST(Str::duplicate(name), text_stream, kits_requested_at_command_line);
|
|
|
|
}
|
|
|
|
|
2020-02-13 21:43:24 +02:00
|
|
|
void Inbuild::pass_kit_requests(void) {
|
|
|
|
RUN_ONLY_IN_PHASE(NESTED_INBUILD_PHASE)
|
2020-02-12 01:20:14 +02:00
|
|
|
if ((shared_project) && (kits_requested_at_command_line)) {
|
|
|
|
text_stream *kit_name;
|
|
|
|
LOOP_OVER_LINKED_LIST(kit_name, text_stream, kits_requested_at_command_line) {
|
2020-03-09 14:44:59 +02:00
|
|
|
Projects::add_kit_dependency(shared_project, kit_name, NULL, NULL);
|
2020-02-12 01:20:14 +02:00
|
|
|
Projects::not_necessarily_parser_IF(shared_project);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-28 15:00:08 +02:00
|
|
|
@h Access to unmanaged Inform resources.
|
2020-02-26 21:58:32 +02:00
|
|
|
Inform needs a whole pile of files to have been installed on the host computer
|
|
|
|
before it can run: everything from the Standard Rules to a PDF file explaining
|
|
|
|
what interactive fiction is. They're never written to, only read. They are
|
2020-03-28 15:00:08 +02:00
|
|
|
stored in subdirectories called |Miscellany| or |HTML| of the internal nest;
|
|
|
|
but they're just plain old files, and are not managed by Inbuild as "copies".
|
2020-02-26 21:58:32 +02:00
|
|
|
|
2020-03-28 15:00:08 +02:00
|
|
|
Our client can access these files using the following function:
|
2020-02-26 12:02:06 +02:00
|
|
|
|
|
|
|
@e CBLORB_REPORT_MODEL_IRES from 1
|
|
|
|
@e DOCUMENTATION_SNIPPETS_IRES
|
|
|
|
@e INTRO_BOOKLET_IRES
|
|
|
|
@e INTRO_POSTCARD_IRES
|
|
|
|
@e LARGE_DEFAULT_COVER_ART_IRES
|
|
|
|
@e SMALL_DEFAULT_COVER_ART_IRES
|
|
|
|
@e DOCUMENTATION_XREFS_IRES
|
|
|
|
@e JAVASCRIPT_FOR_STANDARD_PAGES_IRES
|
|
|
|
@e JAVASCRIPT_FOR_EXTENSIONS_IRES
|
|
|
|
@e JAVASCRIPT_FOR_ONE_EXTENSION_IRES
|
|
|
|
@e CSS_FOR_STANDARD_PAGES_IRES
|
|
|
|
@e EXTENSION_DOCUMENTATION_MODEL_IRES
|
2020-02-11 12:29:10 +02:00
|
|
|
|
2020-02-26 12:02:06 +02:00
|
|
|
=
|
|
|
|
filename *Inbuild::file_from_installation(int ires) {
|
|
|
|
inbuild_nest *I = Inbuild::internal();
|
|
|
|
if (I == NULL) Errors::fatal("Did not set -internal when calling");
|
|
|
|
pathname *misc = Pathnames::subfolder(I->location, I"Miscellany");
|
|
|
|
pathname *models = Pathnames::subfolder(I->location, I"HTML");
|
|
|
|
switch (ires) {
|
2020-03-28 15:00:08 +02:00
|
|
|
case DOCUMENTATION_SNIPPETS_IRES:
|
|
|
|
return Filenames::in_folder(misc, I"definitions.html");
|
|
|
|
case INTRO_BOOKLET_IRES:
|
|
|
|
return Filenames::in_folder(misc, I"IntroductionToIF.pdf");
|
|
|
|
case INTRO_POSTCARD_IRES:
|
|
|
|
return Filenames::in_folder(misc, I"Postcard.pdf");
|
|
|
|
case LARGE_DEFAULT_COVER_ART_IRES:
|
|
|
|
return Filenames::in_folder(misc, I"Cover.jpg");
|
|
|
|
case SMALL_DEFAULT_COVER_ART_IRES:
|
|
|
|
return Filenames::in_folder(misc, I"Small Cover.jpg");
|
|
|
|
|
|
|
|
case CBLORB_REPORT_MODEL_IRES:
|
|
|
|
return Filenames::in_folder(models, I"CblorbModel.html");
|
|
|
|
case DOCUMENTATION_XREFS_IRES:
|
|
|
|
return Filenames::in_folder(models, I"xrefs.txt");
|
|
|
|
case JAVASCRIPT_FOR_STANDARD_PAGES_IRES:
|
|
|
|
return Filenames::in_folder(models, I"main.js");
|
|
|
|
case JAVASCRIPT_FOR_EXTENSIONS_IRES:
|
|
|
|
return Filenames::in_folder(models, I"extensions.js");
|
|
|
|
case JAVASCRIPT_FOR_ONE_EXTENSION_IRES:
|
|
|
|
return Filenames::in_folder(models, I"extensionfile.js");
|
|
|
|
case CSS_FOR_STANDARD_PAGES_IRES:
|
|
|
|
return Filenames::in_folder(models, I"main.css");
|
|
|
|
case EXTENSION_DOCUMENTATION_MODEL_IRES:
|
|
|
|
return Filenames::in_folder(models, I"extensionfile.html");
|
2020-02-26 21:58:32 +02:00
|
|
|
}
|
2020-02-26 12:02:06 +02:00
|
|
|
internal_error("unknown installation resource file");
|
|
|
|
return NULL;
|
|
|
|
}
|
2020-03-28 15:00:08 +02:00
|
|
|
|