1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-06-26 04:00:43 +03:00

Brought the project itself into inbuild as a copy

This commit is contained in:
Graham Nelson 2020-02-11 00:15:49 +00:00
parent f432ac019f
commit e91d0e73f7
17 changed files with 460 additions and 270 deletions

View file

@ -123,6 +123,7 @@ int main(int argc, char **argv) {
if (LinkedLists::len(unsorted_nest_list) == 0)
SharedCLI::add_nest(
Pathnames::from_text(I"inform7/Internal"), INTERNAL_NEST_TAG);
SharedCLI::optioneering_complete();
inbuild_nest_list = SharedCLI::nest_list();
@ =

View file

@ -69,7 +69,8 @@ void InbuildModule::start(void) {
ExtensionManager::start();
TemplateManager::start();
LanguageManager::start();
ProjectManager::start();
ProjectBundleManager::start();
ProjectFileManager::start();
PipelineManager::start();
}

View file

@ -3,34 +3,30 @@
A subset of command-line options shared by the tools which incorporate this
module.
@ We add the following switches:
@h The nest list.
Nests used by the Inform and Inbuild tools are tagged with the following
comstamts, except that no nest is ever tagged |NOT_A_NEST_TAG|.
(There used to be quite a good joke here, but refactoring of the
code removed its premiss. Literate programming is like that sometimes.)
@e NEST_CLSW
@e INTERNAL_CLSW
@e EXTERNAL_CLSW
@e TRANSIENT_CLSW
@e NOT_A_NEST_TAG from 0
@e MATERIALS_NEST_TAG
@e EXTERNAL_NEST_TAG
@e GENERIC_NEST_TAG
@e INTERNAL_NEST_TAG
@ 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.
The following hold the nests in declaration order.
=
void SharedCLI::declare_options(void) {
CommandLine::declare_switch(NEST_CLSW, L"nest", 2,
L"add the nest at pathname X to the search list");
}
pathname *shared_transient_resources = NULL;
void SharedCLI::option(int id, int val, text_stream *arg, void *state) {
switch (id) {
case NEST_CLSW: SharedCLI::add_nest(Pathnames::from_text(arg), GENERIC_NEST_TAG); break;
case INTERNAL_CLSW: SharedCLI::add_nest(Pathnames::from_text(arg), INTERNAL_NEST_TAG); break;
case EXTERNAL_CLSW: SharedCLI::add_nest(Pathnames::from_text(arg), EXTERNAL_NEST_TAG); break;
case TRANSIENT_CLSW: shared_transient_resources = Pathnames::from_text(arg); break;
}
}
linked_list *unsorted_nest_list = NULL;
linked_list *shared_nest_list = NULL;
inbuild_nest *shared_internal_nest = NULL;
inbuild_nest *shared_external_nest = NULL;
inbuild_nest *shared_materials_nest = NULL;
inbuild_nest *SharedCLI::add_nest(pathname *P, int tag) {
if (unsorted_nest_list == NULL)
@ -46,6 +42,37 @@ inbuild_nest *SharedCLI::add_nest(pathname *P, int tag) {
return N;
}
@ 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;
void SharedCLI::sort_nest_list(void) {
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:
=
linked_list *SharedCLI::nest_list(void) {
if (shared_nest_list == NULL) internal_error("nest list never sorted");
return shared_nest_list;
}
inbuild_nest *SharedCLI::internal(void) {
return shared_internal_nest;
}
@ -54,6 +81,17 @@ inbuild_nest *SharedCLI::external(void) {
return shared_external_nest;
}
pathname *SharedCLI::materials(void) {
if (shared_materials_nest == NULL) return NULL;
return shared_materials_nest->location;
}
@ The transient area is used for ephemera such as dynamically written
documentation and telemetry files. |-transient| sets it, but otherwise
the external nest is used.
=
pathname *shared_transient_resources = NULL;
pathname *SharedCLI::transient(void) {
if (shared_transient_resources == NULL)
if (shared_external_nest)
@ -61,31 +99,150 @@ pathname *SharedCLI::transient(void) {
return shared_transient_resources;
}
@
@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).
@e NOT_A_NEST_TAG from 0
@e MATERIALS_NEST_TAG
@e EXTERNAL_NEST_TAG
@e GENERIC_NEST_TAG
@e INTERNAL_NEST_TAG
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.
=
linked_list *SharedCLI::nest_list(void) {
if (shared_nest_list == NULL) {
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);
}
return shared_nest_list;
text_stream *project_bundle_request = NULL;
text_stream *project_file_request = NULL;
int SharedCLI::set_I7_source(text_stream *loc) {
if (Str::len(project_file_request) > 0) return FALSE;
project_file_request = Str::duplicate(loc);
return TRUE;
}
int SharedCLI::set_I7_bundle(text_stream *loc) {
if (Str::len(project_bundle_request) > 0) return FALSE;
project_bundle_request = Str::duplicate(loc);
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;
void SharedCLI::create_shared_project(void) {
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);
filename_of_i7_source =
Filenames::in_folder(
Pathnames::subfolder(pathname_of_bundle, I"Source"),
I"story.ni");
if (Str::includes(project_bundle_request, I"#2oetMiq9bqxoxY"))
Kits::request(I"BasicInformKit");
}
if (Str::len(project_file_request) > 0) {
filename_of_i7_source = Filenames::from_text(project_file_request);
}
if (pathname_of_bundle) {
inbuild_copy *C = ProjectBundleManager::claim_folder_as_copy(pathname_of_bundle);
shared_project = ProjectBundleManager::from_copy(C);
} else if (filename_of_i7_source) {
inbuild_copy *C = ProjectFileManager::claim_file_as_copy(filename_of_i7_source);
shared_project = ProjectFileManager::from_copy(C);
}
@<Create the materials nest@>;
if (shared_project)
Projects::set_source_filename(shared_project, filename_of_i7_source);
}
@ The materials folder sits alongside the project folder and has the same name,
but ending |.materials| instead of |.inform|.
@<Create the materials nest@> =
pathname *materials = NULL;
if (pathname_of_bundle) {
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");
}
materials = Pathnames::subfolder(Pathnames::up(pathname_of_bundle), mf);
DISCARD_TEXT(mf);
Pathnames::create_in_file_system(materials);
} else if (filename_of_i7_source) {
materials = Pathnames::from_text(I"inform.materials");
}
if (materials) {
shared_materials_nest = SharedCLI::add_nest(materials, MATERIALS_NEST_TAG);
}
@ And the rest of Inform or Inbuild can now use:
=
inform_project *SharedCLI::project(void) {
return shared_project;
}
@h Command line.
We add the following switches:
@e NEST_CLSW
@e INTERNAL_CLSW
@e EXTERNAL_CLSW
@e TRANSIENT_CLSW
@e KIT_CLSW
@e PROJECT_CLSW
@e SOURCE_CLSW
=
void SharedCLI::declare_options(void) {
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::declare_switch(KIT_CLSW, L"kit", 2,
L"load the Inform kit called X");
CommandLine::declare_switch(PROJECT_CLSW, L"project", 2,
L"work within the Inform project X");
CommandLine::declare_switch(SOURCE_CLSW, L"source", 2,
L"use file X as the Inform source text");
}
void SharedCLI::option(int id, int val, text_stream *arg, void *state) {
switch (id) {
case NEST_CLSW: SharedCLI::add_nest(Pathnames::from_text(arg), GENERIC_NEST_TAG); break;
case INTERNAL_CLSW: SharedCLI::add_nest(Pathnames::from_text(arg), INTERNAL_NEST_TAG); break;
case EXTERNAL_CLSW: SharedCLI::add_nest(Pathnames::from_text(arg), EXTERNAL_NEST_TAG); break;
case TRANSIENT_CLSW: shared_transient_resources = Pathnames::from_text(arg); break;
case KIT_CLSW: Kits::request(arg); break;
case PROJECT_CLSW:
if (SharedCLI::set_I7_bundle(arg) == FALSE)
Errors::fatal_with_text("can't specify the project twice: '%S'", arg);
break;
case SOURCE_CLSW:
if (SharedCLI::set_I7_source(arg) == FALSE)
Errors::fatal_with_text("can't specify the source file twice: '%S'", arg);
break;
}
}
@ The client tool (i.e., Inform or Inbuild) should call this when no further
options remain to be processed.
=
void SharedCLI::optioneering_complete(void) {
SharedCLI::create_shared_project();
SharedCLI::sort_nest_list();
}

View file

@ -0,0 +1,92 @@
[ProjectBundleManager::] Project Bundle Manager.
A project bundle is a folder holding an Inform 7 work. The app creates these.
@h Genre definition.
=
inbuild_genre *project_bundle_genre = NULL;
void ProjectBundleManager::start(void) {
project_bundle_genre = Model::genre(I"projectbundle");
METHOD_ADD(project_bundle_genre, GENRE_WRITE_WORK_MTID, ProjectBundleManager::write_work);
METHOD_ADD(project_bundle_genre, GENRE_CLAIM_AS_COPY_MTID, ProjectBundleManager::claim_as_copy);
METHOD_ADD(project_bundle_genre, GENRE_SEARCH_NEST_FOR_MTID, ProjectBundleManager::search_nest_for);
METHOD_ADD(project_bundle_genre, GENRE_COPY_TO_NEST_MTID, ProjectBundleManager::copy_to_nest);
}
void ProjectBundleManager::write_work(inbuild_genre *gen, OUTPUT_STREAM, inbuild_work *work) {
WRITE("%S", work->title);
}
@ Project copies are annotated with a structure called an |inform_project|,
which stores data about extensions used by the Inform compiler.
=
inform_project *ProjectBundleManager::from_copy(inbuild_copy *C) {
if ((C) && (C->edition->work->genre == project_bundle_genre)) {
return RETRIEVE_POINTER_inform_project(C->content);
}
return NULL;
}
inbuild_copy *ProjectBundleManager::new_copy(text_stream *name, pathname *P) {
inform_project *K = Projects::new_ip(name, NULL, P);
inbuild_work *work = Works::new(project_bundle_genre, Str::duplicate(name), NULL);
inbuild_edition *edition = Model::edition(work, K->version);
K->as_copy = Model::copy_in_directory(edition, P, STORE_POINTER_inform_project(K));
return K->as_copy;
}
@h Claiming.
Here |arg| is a textual form of a filename or pathname, such as may have been
supplied at the command line; |ext| is a substring of it, and is its extension
(e.g., |jpg| if |arg| is |Geraniums.jpg|), or is empty if there isn't one;
|directory_status| is true if we know for some reason that this is a directory
not a file, false if we know the reverse, and otherwise not applicable.
A project needs to be a directory whose name ends in |.inform|.
=
void ProjectBundleManager::claim_as_copy(inbuild_genre *gen, inbuild_copy **C,
text_stream *arg, text_stream *ext, int directory_status) {
if (directory_status == FALSE) return;
if (Str::eq_insensitive(ext, I"inform")) {
pathname *P = Pathnames::from_text(arg);
*C = ProjectBundleManager::claim_folder_as_copy(P);
}
}
inbuild_copy *ProjectBundleManager::claim_folder_as_copy(pathname *P) {
inbuild_copy *C = ProjectBundleManager::new_copy(Pathnames::directory_name(P), P);
ProjectBundleManager::build_graph(C);
Works::add_to_database(C->edition->work, CLAIMED_WDBC);
return C;
}
@h Searching.
Here we look through a nest to find all projects matching the supplied
requirements; though in fact... projects are not nesting birds.
=
void ProjectBundleManager::search_nest_for(inbuild_genre *gen, inbuild_nest *N,
inbuild_requirement *req, linked_list *search_results) {
}
@h Copying.
Now the task is to copy a project into place in a nest; or would be, if only
projects lived there.
=
void ProjectBundleManager::copy_to_nest(inbuild_genre *gen, inbuild_copy *C, inbuild_nest *N,
int syncing, build_methodology *meth) {
Errors::with_text("projects (which is what '%S' is) cannot be copied to nests",
C->edition->work->title);
}
@h Build graph.
The build graph for a project will need further thought.
=
void ProjectBundleManager::build_graph(inbuild_copy *C) {
Graphs::copy_vertex(C);
}

View file

@ -0,0 +1,95 @@
[ProjectFileManager::] Project File Manager.
A project file is a plain text file of Inform 7 source text.
@h Genre definition.
=
inbuild_genre *project_file_genre = NULL;
void ProjectFileManager::start(void) {
project_file_genre = Model::genre(I"projectfile");
METHOD_ADD(project_file_genre, GENRE_WRITE_WORK_MTID, ProjectFileManager::write_work);
METHOD_ADD(project_file_genre, GENRE_CLAIM_AS_COPY_MTID, ProjectFileManager::claim_as_copy);
METHOD_ADD(project_file_genre, GENRE_SEARCH_NEST_FOR_MTID, ProjectFileManager::search_nest_for);
METHOD_ADD(project_file_genre, GENRE_COPY_TO_NEST_MTID, ProjectFileManager::copy_to_nest);
}
void ProjectFileManager::write_work(inbuild_genre *gen, OUTPUT_STREAM, inbuild_work *work) {
WRITE("%S", work->title);
}
@ Project copies are annotated with a structure called an |inform_project|,
which stores data about extensions used by the Inform compiler.
=
inform_project *ProjectFileManager::from_copy(inbuild_copy *C) {
if ((C) && (C->edition->work->genre == project_file_genre)) {
return RETRIEVE_POINTER_inform_project(C->content);
}
return NULL;
}
inbuild_copy *ProjectFileManager::new_copy(text_stream *name, filename *F) {
inform_project *K = Projects::new_ip(name, F, NULL);
inbuild_work *work = Works::new(project_file_genre, Str::duplicate(name), NULL);
inbuild_edition *edition = Model::edition(work, K->version);
K->as_copy = Model::copy_in_file(edition, F, STORE_POINTER_inform_project(K));
return K->as_copy;
}
@h Claiming.
Here |arg| is a textual form of a filename or pathname, such as may have been
supplied at the command line; |ext| is a substring of it, and is its extension
(e.g., |jpg| if |arg| is |Geraniums.jpg|), or is empty if there isn't one;
|directory_status| is true if we know for some reason that this is a directory
not a file, false if we know the reverse, and otherwise not applicable.
A project file needs to be a plain text file whose name ends in |.txt|, |.ni|
or |.i7|.
=
void ProjectFileManager::claim_as_copy(inbuild_genre *gen, inbuild_copy **C,
text_stream *arg, text_stream *ext, int directory_status) {
if (directory_status == TRUE) return;
if ((Str::eq_insensitive(ext, I"txt")) ||
(Str::eq_insensitive(ext, I"ni")) ||
(Str::eq_insensitive(ext, I"i7"))) {
filename *F = Filenames::from_text(arg);
*C = ProjectFileManager::claim_file_as_copy(F);
}
}
inbuild_copy *ProjectFileManager::claim_file_as_copy(filename *F) {
inbuild_copy *C = ProjectFileManager::new_copy(Filenames::get_leafname(F), F);
ProjectFileManager::build_graph(C);
Works::add_to_database(C->edition->work, CLAIMED_WDBC);
return C;
}
@h Searching.
Here we look through a nest to find all projects matching the supplied
requirements; though in fact... projects are not nesting birds.
=
void ProjectFileManager::search_nest_for(inbuild_genre *gen, inbuild_nest *N,
inbuild_requirement *req, linked_list *search_results) {
}
@h Copying.
Now the task is to copy a project into place in a nest; or would be, if only
projects lived there.
=
void ProjectFileManager::copy_to_nest(inbuild_genre *gen, inbuild_copy *C, inbuild_nest *N,
int syncing, build_methodology *meth) {
Errors::with_text("projects (which is what '%S' is) cannot be copied to nests",
C->edition->work->title);
}
@h Build graph.
The build graph for a project will need further thought.
=
void ProjectFileManager::build_graph(inbuild_copy *C) {
Graphs::copy_vertex(C);
}

View file

@ -1,100 +0,0 @@
[ProjectManager::] Project Manager.
A project is a folder holding an Inform 7 work.
@h Genre definition.
=
inbuild_genre *project_genre = NULL;
void ProjectManager::start(void) {
project_genre = Model::genre(I"project");
METHOD_ADD(project_genre, GENRE_WRITE_WORK_MTID, ProjectManager::write_work);
METHOD_ADD(project_genre, GENRE_CLAIM_AS_COPY_MTID, ProjectManager::claim_as_copy);
METHOD_ADD(project_genre, GENRE_SEARCH_NEST_FOR_MTID, ProjectManager::search_nest_for);
METHOD_ADD(project_genre, GENRE_COPY_TO_NEST_MTID, ProjectManager::copy_to_nest);
}
void ProjectManager::write_work(inbuild_genre *gen, OUTPUT_STREAM, inbuild_work *work) {
WRITE("%S", work->title);
}
@ Projects live in the |Inter| subdirectory of a nest:
=
pathname *ProjectManager::path_within_nest(inbuild_nest *N) {
if (N == NULL) internal_error("no nest");
return Pathnames::subfolder(N->location, I"Inter");
}
@ Project copies are annotated with a structure called an |inform_project|,
which stores data about extensions used by the Inform compiler.
=
inform_project *ProjectManager::from_copy(inbuild_copy *C) {
if ((C) && (C->edition->work->genre == project_genre)) {
return RETRIEVE_POINTER_inform_project(C->content);
}
return NULL;
}
inbuild_copy *ProjectManager::new_copy(text_stream *name, pathname *P) {
inform_project *K = Projects::new_ip(name, P);
inbuild_work *work = Works::new(project_genre, Str::duplicate(name), NULL);
inbuild_edition *edition = Model::edition(work, K->version);
K->as_copy = Model::copy_in_directory(edition, P, STORE_POINTER_inform_project(K));
return K->as_copy;
}
@h Claiming.
Here |arg| is a textual form of a filename or pathname, such as may have been
supplied at the command line; |ext| is a substring of it, and is its extension
(e.g., |jpg| if |arg| is |Geraniums.jpg|), or is empty if there isn't one;
|directory_status| is true if we know for some reason that this is a directory
not a file, false if we know the reverse, and otherwise not applicable.
A project needs to be a directory whose name ends in |,inform|.
=
void ProjectManager::claim_as_copy(inbuild_genre *gen, inbuild_copy **C,
text_stream *arg, text_stream *ext, int directory_status) {
if (directory_status == FALSE) return;
if (Str::eq_insensitive(ext, I"inform")) {
pathname *P = Pathnames::from_text(arg);
*C = ProjectManager::claim_folder_as_copy(P);
}
}
inbuild_copy *ProjectManager::claim_folder_as_copy(pathname *P) {
inbuild_copy *C = ProjectManager::new_copy(Pathnames::directory_name(P), P);
ProjectManager::build_graph(C);
Works::add_to_database(C->edition->work, CLAIMED_WDBC);
return C;
}
@h Searching.
Here we look through a nest to find all projects matching the supplied
requirements; though in fact... projects are not nesting birds.
=
void ProjectManager::search_nest_for(inbuild_genre *gen, inbuild_nest *N,
inbuild_requirement *req, linked_list *search_results) {
}
@h Copying.
Now the task is to copy a project into place in a nest; or would be, if only
projects lived there.
=
void ProjectManager::copy_to_nest(inbuild_genre *gen, inbuild_copy *C, inbuild_nest *N,
int syncing, build_methodology *meth) {
Errors::with_text("projects (which is what '%S' is) cannot be copied to nests",
C->edition->work->title);
}
@h Build graph.
The build graph for a project will need further thought.
=
void ProjectManager::build_graph(inbuild_copy *C) {
Graphs::copy_vertex(C);
}

View file

@ -6,12 +6,27 @@ An Inform 7 project.
typedef struct inform_project {
struct inbuild_copy *as_copy;
struct inbuild_version_number version;
struct filename *source_text;
MEMORY_MANAGEMENT
} inform_project;
inform_project *Projects::new_ip(text_stream *name, pathname *P) {
inform_project *Projects::new_ip(text_stream *name, filename *F, pathname *P) {
inform_project *T = CREATE(inform_project);
T->as_copy = NULL;
T->version = VersionNumbers::null();
return T;
}
void Projects::set_source_filename(inform_project *project, filename *F) {
project->source_text = F;
}
pathname *Projects::path(inform_project *project) {
if (project == NULL) return NULL;
return project->as_copy->location_if_path;
}
filename *Projects::source(inform_project *project) {
if (project == NULL) return NULL;
return project->source_text;
}

View file

@ -21,7 +21,8 @@ Chapter 3: Managing Genres of Work
Kit Manager
Extension Manager
Language Manager
Project Manager
Project Bundle Manager
Project File Manager
Template Manager
Pipeline Manager

View file

@ -117,10 +117,8 @@ list is not exhaustive.
@e DEBUG_CLSW
@e FORMAT_CLSW
@e CRASHALL_CLSW
@e KIT_CLSW
@e NOINDEX_CLSW
@e NOPROGRESS_CLSW
@e PROJECT_CLSW
@e RELEASE_CLSW
@e REQUIRE_PROBLEM_CLSW
@e RNG_CLSW
@ -160,27 +158,17 @@ list is not exhaustive.
L"return 0 unless exactly this Problem message is generated (for testing)");
CommandLine::declare_switch(PIPELINE_CLSW, L"pipeline", 2,
L"specify code-generation pipeline");
CommandLine::declare_switch(KIT_CLSW, L"kit", 2,
L"load the Inform kit called X");
CommandLine::declare_switch(PIPELINE_FILE_CLSW, L"pipeline-file", 2,
L"specify code-generation pipeline from file X");
CommandLine::declare_switch(PIPELINE_VARIABLE_CLSW, L"variable", 2,
L"set pipeline variable X (in form name=value)");
CommandLine::declare_switch(PROJECT_CLSW, L"project", 2,
L"work within the Inform project X");
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");
SharedCLI::declare_options();
@<Establish our location in the file system@> =
path_to_inform7 = Pathnames::installation_path("INFORM7_PATH", I"inform7");
@<With that done, configure all other settings@> =
SharedCLI::optioneering_complete();
VirtualMachines::set_identifier(story_filename_extension);
if (Locations::set_defaults(census_mode) == FALSE)
Problems::Fatal::issue("Unable to create folders in local file system");
@ -538,7 +526,6 @@ void CoreMain::switch(int id, int val, text_stream *arg, void *state) {
/* Other settings */
case FORMAT_CLSW: story_filename_extension = Str::duplicate(arg); break;
case CASE_CLSW: HTMLFiles::set_source_link_case(arg); break;
case KIT_CLSW: Kits::request(arg); break;
case REQUIRE_PROBLEM_CLSW: Problems::Fatal::require(arg); break;
case PIPELINE_CLSW: inter_processing_pipeline = Str::duplicate(arg); break;
case PIPELINE_FILE_CLSW: inter_processing_file = Str::duplicate(arg); break;
@ -557,17 +544,12 @@ void CoreMain::switch(int id, int val, text_stream *arg, void *state) {
Regexp::dispose_of(&mr);
break;
}
/* Useful pathnames */
case PROJECT_CLSW:
if (Str::includes(arg, I"#2oetMiq9bqxoxY")) Kits::request(I"BasicInformKit");
Locations::set_project(arg); break;
}
SharedCLI::option(id, val, arg, state);
}
void CoreMain::bareword(int id, text_stream *opt, void *state) {
if (Locations::set_I7_source(opt) == FALSE)
if (SharedCLI::set_I7_source(opt) == FALSE)
Errors::fatal_with_text("unknown command line argument: %S (see -help)", opt);
}

View file

@ -11,14 +11,12 @@ these are stored in the following globals. Explanations are given below,
not here.
= (early code)
pathname *pathname_of_materials = NULL;
pathname *pathname_of_extension_docs = NULL;
pathname *pathname_of_extension_docs_inner = NULL;
pathname *pathname_of_HTML_models = NULL;
pathname *pathname_of_materials_figures = NULL;
pathname *pathname_of_materials_release = NULL;
pathname *pathname_of_materials_sounds = NULL;
pathname *pathname_of_project = NULL;
pathname *pathname_of_project_index_details_folder = NULL;
pathname *pathname_of_project_index_folder = NULL;
pathname *pathname_of_released_figures = NULL;
@ -39,7 +37,6 @@ filename *filename_of_epsfile = NULL;
filename *filename_of_existing_story_file = NULL;
filename *filename_of_extensions_dictionary = NULL;
filename *filename_of_headings = NULL;
filename *filename_of_i7_source = NULL;
filename *filename_of_ifiction_record = NULL;
filename *filename_of_intro_booklet = NULL;
filename *filename_of_intro_postcard = NULL;
@ -53,32 +50,11 @@ filename *filename_of_report = NULL;
filename *filename_of_small_cover_art_jpeg = NULL;
filename *filename_of_small_cover_art_png = NULL;
filename *filename_of_small_default_cover_art = NULL;
filename *filename_of_SR_module = NULL;
filename *filename_of_story_file = NULL;
filename *filename_of_telemetry = NULL;
filename *filename_of_uuid = NULL;
filename *filename_of_xrefs = NULL;
@h Command line settings.
The following are called when the command line is parsed.
=
void Locations::set_project(text_stream *loc) {
pathname_of_project = Pathnames::from_text(loc);
}
int Locations::set_I7_source(text_stream *loc) {
if (filename_of_i7_source) return FALSE;
filename_of_i7_source = Filenames::from_text(loc);
return TRUE;
}
int Locations::set_SR_module(text_stream *loc) {
if (filename_of_SR_module) return FALSE;
filename_of_SR_module = Filenames::from_text(loc);
return TRUE;
}
@h Establishing the defaults.
Inform's file access happens inside four different areas: the internal
resources area, usually inside the Inform application; the external resources
@ -91,16 +67,14 @@ and census mode, when it's scanning the file system for extensions.
=
int Locations::set_defaults(int census_mode) {
@<Materials folder@>;
if (pathname_of_materials)
SharedCLI::add_nest(pathname_of_materials, MATERIALS_NEST_TAG);
@<Internal resources@>;
@<External resources@>;
@<Project resources@>;
@<Materials resources@>;
if ((census_mode == FALSE) && (filename_of_i7_source == NULL))
inform_project *project = SharedCLI::project();
if ((census_mode == FALSE) && (project == NULL))
Problems::Fatal::issue("Except in census mode, source text must be supplied");
if ((census_mode) && (filename_of_i7_source))
if ((census_mode) && (project))
Problems::Fatal::issue("In census mode, no source text may be supplied");
return TRUE;
}
@ -266,27 +240,15 @@ have no purpose unless Inform is in a release run (with |-release| set on
the command line), but they take no time to generate so we make them anyway.
@<Project resources@> =
@<The Source folder within the project@>;
pathname *proj = Projects::path(SharedCLI::project());
@<The Build folder within the project@>;
@<The Index folder within the project@>;
filename_of_uuid = Filenames::in_folder(pathname_of_project, I"uuid.txt");
filename_of_uuid = Filenames::in_folder(proj, I"uuid.txt");
filename_of_ifiction_record = Filenames::in_folder(pathname_of_project, I"Metadata.iFiction");
filename_of_manifest = Filenames::in_folder(pathname_of_project, I"manifest.plist");
filename_of_blurb = Filenames::in_folder(pathname_of_project, I"Release.blurb");
@ This contains just the main source text for the project. Anachronistically,
this has the filename extension |.ni| for "natural Inform", which was the
working title for Inform 7 back in the early 2000s.
@<The Source folder within the project@> =
if (filename_of_i7_source == NULL)
if (pathname_of_project)
filename_of_i7_source =
Filenames::in_folder(
Pathnames::subfolder(pathname_of_project, I"Source"),
I"story.ni");
filename_of_ifiction_record = Filenames::in_folder(proj, I"Metadata.iFiction");
filename_of_manifest = Filenames::in_folder(proj, I"manifest.plist");
filename_of_blurb = Filenames::in_folder(proj, I"Release.blurb");
@ The build folder for a project contains all of the working files created
during the compilation process. The opening part here may be a surprise:
@ -307,7 +269,7 @@ will produce if this is a Release run.
pathname *build_folder = pathname_of_transient_census_data;
if (census_mode == FALSE) {
build_folder = Pathnames::subfolder(pathname_of_project, I"Build");
build_folder = Pathnames::subfolder(proj, I"Build");
if (Pathnames::create_in_file_system(build_folder) == 0) return FALSE;
}
@ -335,7 +297,7 @@ the index as seen by the user.
@<The Index folder within the project@> =
pathname_of_project_index_folder =
Pathnames::subfolder(pathname_of_project, I"Index");
Pathnames::subfolder(proj, I"Index");
pathname_of_project_index_details_folder =
Pathnames::subfolder(pathname_of_project_index_folder, I"Details");
@ -347,28 +309,6 @@ the index as seen by the user.
filename_of_headings =
Filenames::in_folder(pathname_of_project_index_folder, I"Headings.xml");
@h Materials folder.
The materials folder sits alongside the project folder and has the same name,
but ending |.materials| instead of |.inform|.
@<Materials folder@> =
if (pathname_of_project) {
TEMPORARY_TEXT(mf);
WRITE_TO(mf, "%S", Pathnames::directory_name(pathname_of_project));
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_of_materials =
Pathnames::subfolder(pathname_of_project->pathname_of_parent, mf);
DISCARD_TEXT(mf);
if (Pathnames::create_in_file_system(pathname_of_materials) == 0) return FALSE;
} else {
pathname_of_materials = Pathnames::from_text(I"inform.materials");
}
@h Materials resources.
@<Materials resources@> =
@ -386,15 +326,17 @@ This is also where the originals (not the released copies) of the Figures
and Sounds, if any, live: in their own subfolders.
@<Figures and sounds@> =
pathname_of_materials_figures = Pathnames::subfolder(pathname_of_materials, I"Figures");
pathname_of_materials_sounds = Pathnames::subfolder(pathname_of_materials, I"Sounds");
pathname *M = SharedCLI::materials();
filename_of_large_cover_art_jpeg = Filenames::in_folder(pathname_of_materials, I"Cover.jpg");
filename_of_large_cover_art_png = Filenames::in_folder(pathname_of_materials, I"Cover.png");
filename_of_small_cover_art_jpeg = Filenames::in_folder(pathname_of_materials, I"Small Cover.jpg");
filename_of_small_cover_art_png = Filenames::in_folder(pathname_of_materials, I"Small Cover.png");
pathname_of_materials_figures = Pathnames::subfolder(M, I"Figures");
pathname_of_materials_sounds = Pathnames::subfolder(M, I"Sounds");
filename_of_epsfile = Filenames::in_folder(pathname_of_materials, I"Inform Map.eps");
filename_of_large_cover_art_jpeg = Filenames::in_folder(M, I"Cover.jpg");
filename_of_large_cover_art_png = Filenames::in_folder(M, I"Cover.png");
filename_of_small_cover_art_jpeg = Filenames::in_folder(M, I"Small Cover.jpg");
filename_of_small_cover_art_png = Filenames::in_folder(M, I"Small Cover.png");
filename_of_epsfile = Filenames::in_folder(M, I"Inform Map.eps");
@ On a release run, Inblorb will populate the Release subfolder of Materials;
figures and sounds will be copied into the relevant subfolders. The principle
@ -402,7 +344,10 @@ is that everything in Release can always be thrown away without loss, because
it can all be generated again.
@<The Release folder@> =
pathname_of_materials_release = Pathnames::subfolder(pathname_of_materials, I"Release");
pathname *M = SharedCLI::materials();
pathname_of_materials_release = Pathnames::subfolder(M, I"Release");
pathname_of_released_interpreter = Pathnames::subfolder(pathname_of_materials_release, I"interpreter");
pathname_of_released_figures = Pathnames::subfolder(pathname_of_materials_release, I"Figures");
pathname_of_released_sounds = Pathnames::subfolder(pathname_of_materials_release, I"Sounds");
@ -416,7 +361,7 @@ have by default, if so.
TEMPORARY_TEXT(leaf);
WRITE_TO(leaf, "story.%S", story_filename_extension);
filename_of_existing_story_file =
Filenames::in_folder(pathname_of_materials, leaf);
Filenames::in_folder(SharedCLI::materials(), leaf);
DISCARD_TEXT(leaf);
@h Location of extensions.
@ -465,7 +410,8 @@ leafname |A.html|.
=
filename *Locations::in_index(text_stream *leafname, int sub) {
if (pathname_of_project == NULL) return Filenames::in_folder(NULL, leafname);
pathname *proj = Projects::path(SharedCLI::project());
if (proj == NULL) return Filenames::in_folder(NULL, leafname);
if (sub >= 0) {
TEMPORARY_TEXT(full_leafname);
WRITE_TO(full_leafname, "%d_%S", sub, leafname);

View file

@ -4,7 +4,6 @@ Interface to the Problems module.
@
@d REDIRECT_PROBLEM_SOURCE_TO pathname_of_project
@d PROBLEMS_HTML_EMITTER HTMLFiles::char_out
@ Inform tops and tails its output of problem messages, and it also prints

View file

@ -34,7 +34,7 @@ void SourceFiles::read_primary_source_text(void) {
if (Str::len(early) > 0) Feeds::feed_stream(early);
DISCARD_TEXT(early);
SourceFiles::read_further_mandatory_text();
SourceFiles::read_file(filename_of_i7_source, I"your source text", NULL, FALSE);
SourceFiles::read_file(Projects::source(SharedCLI::project()), I"your source text", NULL, FALSE);
}
@ The following reads in the text of the optional file of use options, if

View file

@ -209,7 +209,7 @@ void PL::Bibliographic::Release::handle_release_declaration_inner(parse_node *p)
TEMPORARY_TEXT(leaf);
WRITE_TO(leaf, "%N", Wordings::first_wn(SW));
filename_of_existing_story_file =
Filenames::in_folder(pathname_of_materials, leaf);
Filenames::in_folder(SharedCLI::materials(), leaf);
DISCARD_TEXT(leaf);
}
existing_story_file = TRUE;
@ -221,7 +221,7 @@ void PL::Bibliographic::Release::handle_release_declaration_inner(parse_node *p)
Word::dequote(Wordings::first_wn(DW));
TEMPORARY_TEXT(leaf);
WRITE_TO(leaf, "%N", Wordings::first_wn(LW));
filename *A = Filenames::in_folder(pathname_of_materials, leaf);
filename *A = Filenames::in_folder(SharedCLI::materials(), leaf);
DISCARD_TEXT(leaf);
PL::Bibliographic::Release::create_aux_file(A,
pathname_of_materials_release,
@ -234,7 +234,7 @@ void PL::Bibliographic::Release::handle_release_declaration_inner(parse_node *p)
Word::dequote(Wordings::first_wn(LW));
TEMPORARY_TEXT(leaf);
WRITE_TO(leaf, "%N", Wordings::first_wn(LW));
filename *A = Filenames::in_folder(pathname_of_materials, leaf);
filename *A = Filenames::in_folder(SharedCLI::materials(), leaf);
DISCARD_TEXT(leaf);
PL::Bibliographic::Release::create_aux_file(A,
pathname_of_materials_release,
@ -249,7 +249,7 @@ void PL::Bibliographic::Release::handle_release_declaration_inner(parse_node *p)
Word::dequote(Wordings::first_wn(FW));
TEMPORARY_TEXT(leaf);
WRITE_TO(leaf, "%N", Wordings::first_wn(LW));
filename *A = Filenames::in_folder(pathname_of_materials, leaf);
filename *A = Filenames::in_folder(SharedCLI::materials(), leaf);
DISCARD_TEXT(leaf);
TEMPORARY_TEXT(folder);
WRITE_TO(folder, "%N", Wordings::first_wn(FW));
@ -352,13 +352,13 @@ application sandboxing in Mac OS X in 2012 may force us to revisit this.
}
@<Create the Materials folder if not already present@> =
if (Pathnames::create_in_file_system(pathname_of_materials) == FALSE) {
if (Pathnames::create_in_file_system(SharedCLI::materials()) == FALSE) {
Problems::Issue::release_problem_path(_p_(Untestable),
"In order to release the story file along with other "
"resources, I tried to create a folder alongside this "
"Inform project, but was unable to do so. The folder "
"was to have been called",
pathname_of_materials);
SharedCLI::materials());
return;
}
@ -614,7 +614,7 @@ void PL::Bibliographic::Release::write_ifiction_record(OUTPUT_STREAM, zbyte *hea
WRITE("<auxiliary>\n"); INDENT;
WRITE("<leafname>");
TEMPORARY_TEXT(rel);
Filenames::to_text_relative(rel, af->name_of_original_file, pathname_of_materials);
Filenames::to_text_relative(rel, af->name_of_original_file, SharedCLI::materials());
HTMLFiles::write_xml_safe_text(OUT, rel);
DISCARD_TEXT(rel);
WRITE("</leafname>\n");
@ -867,7 +867,7 @@ the Blorb-file's filename won't be too long for the file system.
filename_of_cblorb_report);
@<Tell Inblorb where the project and release folders are@> =
WRITE("project folder \"%p\"\n", pathname_of_project);
WRITE("project folder \"%p\"\n", Projects::path(SharedCLI::project()));
if (create_Materials)
WRITE("release to \"%p\"\n", pathname_of_materials_release);
@ -1001,14 +1001,14 @@ file online.
LOOP_OVER(af, auxiliary_file)
if (af->from_payload == JAVASCRIPT_PAYLOAD) {
TEMPORARY_TEXT(rel);
Filenames::to_text_relative(rel, af->name_of_original_file, pathname_of_materials);
Filenames::to_text_relative(rel, af->name_of_original_file, SharedCLI::materials());
WRITE("<script src='%S'></script>", rel);
DISCARD_TEXT(rel);
}
LOOP_OVER(af, auxiliary_file)
if (af->from_payload == CSS_PAYLOAD) {
TEMPORARY_TEXT(rel);
Filenames::to_text_relative(rel, af->name_of_original_file, pathname_of_materials);
Filenames::to_text_relative(rel, af->name_of_original_file, SharedCLI::materials());
WRITE("<link rel='stylesheet' href='%S' type='text/css' media='all'></link>", rel);
DISCARD_TEXT(rel);
}

View file

@ -100,9 +100,9 @@ void HTMLFiles::html_source_link(OUTPUT_STREAM, source_location sl, int nonbreak
if (sl.file_of_origin) {
TEMPORARY_TEXT(fn);
WRITE_TO(fn, "%f", TextFromFiles::get_filename(sl.file_of_origin));
if (pathname_of_project) {
if (Projects::path(SharedCLI::project())) {
TEMPORARY_TEXT(pp);
WRITE_TO(pp, "%p", pathname_of_project);
WRITE_TO(pp, "%p", Projects::path(SharedCLI::project()));
int N = Str::len(pp);
if (Str::prefix_eq(fn, pp, N))
Str::delete_n_characters(fn, N+1);

View file

@ -211,7 +211,7 @@ void PL::Figures::write_picture_manifest(OUTPUT_STREAM, int include_cover,
if (bf->figure_number > 1) {
WRITE("<key>%d</key>\n", bf->figure_number);
TEMPORARY_TEXT(rel);
Filenames::to_text_relative(rel, bf->filename_of_image_file, pathname_of_materials);
Filenames::to_text_relative(rel, bf->filename_of_image_file, SharedCLI::materials());
WRITE("<string>%S</string>\n", rel);
DISCARD_TEXT(rel);
}
@ -335,7 +335,7 @@ void PL::Figures::index_all(OUTPUT_STREAM) {
Index::link(OUT, Wordings::first_wn(bf->name));
TEMPORARY_TEXT(rel);
Filenames::to_text_relative(rel, bf->filename_of_image_file, pathname_of_materials);
Filenames::to_text_relative(rel, bf->filename_of_image_file, SharedCLI::materials());
HTML_TAG("br");
WRITE("%SFilename: \"%S\" - resource number %d", line2, rel, bf->figure_number);
DISCARD_TEXT(rel);

View file

@ -175,7 +175,7 @@ void PL::Sounds::write_sounds_manifest(OUTPUT_STREAM) {
LOOP_OVER(bs, blorb_sound) {
WRITE("<key>%d</key>\n", bs->sound_number);
TEMPORARY_TEXT(rel);
Filenames::to_text_relative(rel, bs->filename_of_sound_file, pathname_of_materials);
Filenames::to_text_relative(rel, bs->filename_of_sound_file, SharedCLI::materials());
WRITE("<string>%S</string>\n", rel);
DISCARD_TEXT(rel);
}
@ -331,7 +331,7 @@ void PL::Sounds::index_all(OUTPUT_STREAM) {
WRITE("%+W", bs->name);
Index::link(OUT, Wordings::first_wn(bs->name));
TEMPORARY_TEXT(rel);
Filenames::to_text_relative(rel, bs->filename_of_sound_file, pathname_of_materials);
Filenames::to_text_relative(rel, bs->filename_of_sound_file, SharedCLI::materials());
HTML_TAG("br");
WRITE("%SFilename: \"%S\" - resource number %d", line2, rel, bs->sound_number);
DISCARD_TEXT(rel);

View file

@ -69,10 +69,11 @@ void Problems::Buffer::copy_source_reference_into_problem_buffer(wording W) {
TEMPORARY_TEXT(file);
if (referred) {
WRITE_TO(file, "%f", TextFromFiles::get_filename(referred));
#ifdef REDIRECT_PROBLEM_SOURCE_TO
if (REDIRECT_PROBLEM_SOURCE_TO) {
#ifdef INBUILD_MODULE
pathname *proj = Projects::path(SharedCLI::project());
if (proj) {
TEMPORARY_TEXT(project_prefix);
WRITE_TO(project_prefix, "%p", pathname_of_project);
WRITE_TO(project_prefix, "%p", proj);
if (Str::prefix_eq(file, project_prefix, Str::len(project_prefix)))
Str::delete_n_characters(file, Str::len(project_prefix));
}