mirror of
https://github.com/ganelson/inform.git
synced 2024-07-05 16:44:21 +03:00
236 lines
8.2 KiB
OpenEdge ABL
236 lines
8.2 KiB
OpenEdge ABL
[InterpretIndex::] Index Interpreter.
|
|
|
|
An index is generated by interpreting an index structure file.
|
|
|
|
@ The index is generated by a bare-bones structure file. These are identified
|
|
by name: in particular |Basic| is the barer version, for Basic Inform projects,
|
|
while |Standard| is the index as generated to suit typical IF uses of the Standard
|
|
Rules -- so, in other words, that's the index which most Inform users know.
|
|
These names have to correspond to |.indext| structure files stored in the
|
|
Inform distribution.
|
|
|
|
The structure file really just shows which index elements to include on which
|
|
pages. For example:
|
|
= (text)
|
|
page Kinds e9cf08
|
|
element Ch
|
|
element Ar
|
|
element Vl
|
|
=
|
|
declares a new index page with leafname |Kinds.html|, and with the highlight
|
|
colour (in CSS hexadecimal style) |e9cf08|; and then declzres that it contains
|
|
the three elements |Ch|, |Ar| and |Vl|, in that order. Note that this file does
|
|
not contain any user-facing text: all of that comes from //Localisation//, with
|
|
|%%Kinds|, |%%Ch|, |%%Ar| and |%%Vl| being localisation contexts.
|
|
|
|
The file also doesn't contain instructions for what goes into those elements.
|
|
All of that is hardwired into this module's code: for example, |Ar| is generated
|
|
by the function //ArithmeticElement::render// in //Arithmetic Element//.
|
|
|
|
The method here is basically to read all the declarations, generating a set
|
|
of //index_page// and //index_element// objects to represent them, and only to
|
|
begin writing some HTML when this scanning is done, i.e., when the whole structure
|
|
file has been read.
|
|
|
|
=
|
|
void InterpretIndex::generate(inter_tree *I, text_stream *structure, localisation_dictionary *D) {
|
|
InterpretIndex::set_tree(I);
|
|
filename *index_structure = InstalledFiles::index_structure_file(structure);
|
|
index_generation_state igs;
|
|
@<Initialise IGS@>;
|
|
@<Read the structure file line by line@>;
|
|
@<Actually generate the index files@>;
|
|
InterpretIndex::set_tree(NULL);
|
|
}
|
|
|
|
@ This little structure is just some state being carried by the reader-function
|
|
which goes through the |.indext| file line by line.
|
|
|
|
=
|
|
typedef struct index_generation_state {
|
|
struct localisation_dictionary *dict;
|
|
struct linked_list *pages; /* of |index_page| */
|
|
} index_generation_state;
|
|
|
|
@<Initialise IGS@> =
|
|
igs.pages = NEW_LINKED_LIST(index_page);
|
|
igs.dict = D;
|
|
|
|
@<Read the structure file line by line@> =
|
|
TextFiles::read(index_structure, FALSE, "unable to read index structure file", TRUE,
|
|
&InterpretIndex::read_structure, NULL, (void *) &igs);
|
|
|
|
@ |contents| is currently implemented identically to |pages|, but it is supposed to
|
|
represent the home page of the index. The declaration for it should come
|
|
last in the structure file, like so:
|
|
= (text)
|
|
contents Welcome 111111
|
|
=
|
|
It has no elements, because its only content will be a menu of links to the other
|
|
pages.
|
|
|
|
=
|
|
void InterpretIndex::read_structure(text_stream *text, text_file_position *tfp, void *state) {
|
|
index_generation_state *igs = (index_generation_state *) state;
|
|
localisation_dictionary *D = igs->dict;
|
|
match_results mr = Regexp::create_mr();
|
|
if (Regexp::match(&mr, text, L"page (%C+) (%C+)")) {
|
|
@<Register a new index page@>;
|
|
} else if (Regexp::match(&mr, text, L"contents (%C+) (%C+)")) {
|
|
@<Register a new index page@>;
|
|
} else if (Regexp::match(&mr, text, L"element (%C+)")) {
|
|
@<Register a new index element@>;
|
|
}
|
|
Regexp::dispose_of(&mr);
|
|
}
|
|
|
|
@ Note that the heading written on |Kinds.html|, say, is drawn from the
|
|
localisation file under the key |%Title| in the context |%%Kinds|. In English,
|
|
that will be "Kinds", but if the index is being generated with a Dutch localisation
|
|
dictionary then perhaps it would be "Soorten". Under the hood, though, the filename
|
|
will be |Kinds.html| either way.
|
|
|
|
@<Register a new index page@> =
|
|
text_stream *col = mr.exp[1];
|
|
text_stream *key = mr.exp[0];
|
|
text_stream *heading = Localisation::read(D, key, I"Title");
|
|
text_stream *explanation = Localisation::read(D, key, I"Caption");
|
|
index_page *new_page = InterpretIndex::register_page(col, heading, explanation, key);
|
|
ADD_TO_LINKED_LIST(new_page, index_page, igs->pages);
|
|
|
|
@<Register a new index element@> =
|
|
if (LinkedLists::len(igs->pages) == 0) internal_error("element without page");
|
|
index_page *latest = LAST_IN_LINKED_LIST(index_page, igs->pages);
|
|
text_stream *elt = mr.exp[0];
|
|
InterpretIndex::register_element(elt, latest,
|
|
Localisation::read(D, elt, I"Title"),
|
|
Localisation::read(D, elt, I"Heading"));
|
|
|
|
@<Actually generate the index files@> =
|
|
index_page *page;
|
|
LOOP_OVER_LINKED_LIST(page, index_page, igs.pages) {
|
|
TEMPORARY_TEXT(leafname)
|
|
WRITE_TO(leafname, "%S.html", page->page_leafname);
|
|
text_stream *OUT =
|
|
InterpretIndex::open_file(page, leafname,
|
|
Localisation::read(D, page->page_leafname, I"Title"), -1, D);
|
|
Elements::periodic_table(OUT, page, leafname, D);
|
|
InterpretIndex::close_index_file(OUT);
|
|
DISCARD_TEXT(leafname)
|
|
}
|
|
GroupedElement::detail_pages(D);
|
|
|
|
@ This is a one-off function for generating the content of an index element
|
|
(without its heading, or any HTML surround): it's used for unit-testing those
|
|
elements.
|
|
|
|
=
|
|
void InterpretIndex::generate_one_element(OUTPUT_STREAM, inter_tree *I, wording elt,
|
|
localisation_dictionary *D) {
|
|
InterpretIndex::set_tree(I);
|
|
Elements::test_card(OUT, elt, D);
|
|
InterpretIndex::set_tree(NULL);
|
|
}
|
|
|
|
@h Registering.
|
|
So, then, here are the objects representing the index pages and their elements
|
|
of content:
|
|
|
|
=
|
|
typedef struct index_page {
|
|
int no_elements;
|
|
struct text_stream *key_colour;
|
|
struct text_stream *page_title;
|
|
struct text_stream *page_explanation;
|
|
struct text_stream *page_leafname;
|
|
CLASS_DEFINITION
|
|
} index_page;
|
|
|
|
index_page *InterpretIndex::register_page(text_stream *col, text_stream *title,
|
|
text_stream *exp, text_stream *leaf) {
|
|
index_page *new_page = CREATE(index_page);
|
|
new_page->no_elements = 0;
|
|
new_page->key_colour = Str::duplicate(col);
|
|
new_page->page_title = Str::duplicate(title);
|
|
new_page->page_explanation = Str::duplicate(exp);
|
|
new_page->page_leafname = Str::duplicate(leaf);
|
|
return new_page;
|
|
}
|
|
|
|
@ =
|
|
typedef struct index_element {
|
|
int atomic_number; /* 1, 2, 3, ..., within its page */
|
|
struct text_stream *chemical_symbol;
|
|
struct text_stream *element_name;
|
|
struct text_stream *explanatory_note;
|
|
struct index_page *owning_page;
|
|
CLASS_DEFINITION
|
|
} index_element;
|
|
|
|
index_element *InterpretIndex::register_element(text_stream *abb, index_page *owner,
|
|
text_stream *title, text_stream *explanation) {
|
|
if (owner == NULL)
|
|
internal_error("template creates index elements improperly");
|
|
if (Str::len(abb) > 2)
|
|
internal_error("abbreviation for index element too long");
|
|
index_element *ie = CREATE(index_element);
|
|
ie->owning_page = owner;
|
|
ie->atomic_number = ++(owner->no_elements);
|
|
ie->chemical_symbol = Str::duplicate(abb);
|
|
ie->element_name = Str::duplicate(title);
|
|
ie->explanatory_note = Str::duplicate(explanation);
|
|
return ie;
|
|
}
|
|
|
|
@h Current.
|
|
A clumsy convenience: keeping track of the page currently being written, and
|
|
of the Inter tree currently being indexed.
|
|
|
|
=
|
|
index_page *current_index_page = NULL;
|
|
void InterpretIndex::set_page(index_page *page) {
|
|
current_index_page = page;
|
|
}
|
|
index_page *InterpretIndex::get_page(void) {
|
|
return current_index_page;
|
|
}
|
|
|
|
inter_tree *indexing_tree = NULL;
|
|
void InterpretIndex::set_tree(inter_tree *I) {
|
|
indexing_tree = I;
|
|
}
|
|
inter_tree *InterpretIndex::get_tree(void) {
|
|
if (indexing_tree == NULL) internal_error("no indexing tree");
|
|
return indexing_tree;
|
|
}
|
|
|
|
@h Opening and closing HTML files.
|
|
|
|
=
|
|
text_stream index_file_struct; /* The current index file being written */
|
|
text_stream *InterpretIndex::open_file(index_page *page, text_stream *index_leaf,
|
|
text_stream *title, int sub, localisation_dictionary *D) {
|
|
filename *F = IndexLocations::filename(index_leaf, sub);
|
|
if (STREAM_OPEN_TO_FILE(&index_file_struct, F, UTF8_ENC) == FALSE) {
|
|
#ifdef CORE_MODULE
|
|
Problems::fatal_on_file("Can't open index file", F);
|
|
#endif
|
|
#ifndef CORE_MODULE
|
|
Errors::fatal_with_file("can't open index file", F);
|
|
#endif
|
|
}
|
|
text_stream *OUT = &index_file_struct;
|
|
InterpretIndex::set_page(page);
|
|
HTML::header(OUT, title,
|
|
InstalledFiles::filename(CSS_FOR_STANDARD_PAGES_IRES),
|
|
InstalledFiles::filename(JAVASCRIPT_FOR_STANDARD_PAGES_IRES));
|
|
return OUT;
|
|
}
|
|
|
|
@ =
|
|
void InterpretIndex::close_index_file(text_stream *ifl) {
|
|
HTML::footer(ifl);
|
|
STREAM_CLOSE(ifl);
|
|
InterpretIndex::set_page(NULL);
|
|
}
|