[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 //html: Localisation//. 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(text_stream *structure, index_session *session) { localisation_dictionary *D = Indexing::get_localisation(session); Indexing::empty_list_of_pages(session); filename *index_structure = InstalledFiles::index_structure_file(structure); @; @; } @ = TextFiles::read(index_structure, FALSE, "unable to read index structure file", TRUE, &InterpretIndex::read_structure, NULL, (void *) session); @ |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_session *session = (index_session *) state; localisation_dictionary *D = Indexing::get_localisation(session); match_results mr = Regexp::create_mr(); if (Regexp::match(&mr, text, L"page (%C+) (%C+)")) { @; } else if (Regexp::match(&mr, text, L"contents (%C+) (%C+)")) { @; } else if (Regexp::match(&mr, text, L"element (%C+)")) { @; } 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. @ = text_stream *col = mr.exp[1]; text_stream *key = mr.exp[0]; TEMPORARY_TEXT(path) WRITE_TO(path, "Index.Pages.%S.Title", key); text_stream *heading = Localisation::read(D, path); Str::clear(path); WRITE_TO(path, "Index.Pages.%S.Caption", key); text_stream *explanation = Localisation::read(D, path); DISCARD_TEXT(path) InterpretIndex::register_page(col, heading, explanation, key, session); @ = index_page *latest = Indexing::latest_page(session); if (latest == NULL) internal_error("element without page"); text_stream *elt = mr.exp[0]; TEMPORARY_TEXT(tkey) TEMPORARY_TEXT(hkey) WRITE_TO(tkey, "Index.Elements.%S.Title", elt); WRITE_TO(hkey, "Index.Elements.%S.Heading", elt); InterpretIndex::register_element(elt, latest, Localisation::read(D, tkey), hkey); DISCARD_TEXT(tkey) DISCARD_TEXT(hkey) @ = index_page *page; linked_list *L = Indexing::get_list_of_pages(session); LOOP_OVER_LINKED_LIST(page, index_page, L) { TEMPORARY_TEXT(leafname) WRITE_TO(leafname, "%S.html", page->page_leafname); TEMPORARY_TEXT(key) WRITE_TO(key, "Index.Pages.%S.Title", page->page_leafname); text_stream index_file_struct; text_stream *OUT = &index_file_struct; InterpretIndex::open_file(OUT, page, leafname, Localisation::read(D, key), -1, session); Elements::periodic_table(OUT, page, leafname, session); InterpretIndex::close_index_file(OUT); DISCARD_TEXT(key) DISCARD_TEXT(leafname) } GroupedElement::detail_pages(session); @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; struct linked_list *elements; /* of |index_element| */ struct index_session *for_session; CLASS_DEFINITION } index_page; index_page *InterpretIndex::register_page(text_stream *col, text_stream *title, text_stream *exp, text_stream *leaf, index_session *session) { 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); new_page->elements = NEW_LINKED_LIST(index_element); new_page->for_session = session; Indexing::add_page(session, new_page); 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 *explanation_key; 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->explanation_key = Str::duplicate(explanation); ADD_TO_LINKED_LIST(ie, index_element, owner->elements); return ie; } @h Opening and closing HTML files. = text_stream *InterpretIndex::open_file(text_stream *IF, index_page *page, text_stream *index_leaf, text_stream *title, int sub, index_session *session) { filename *F = IndexLocations::filename(index_leaf, sub); if (STREAM_OPEN_TO_FILE(IF, 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 } HTML::header(IF, title, InstalledFiles::filename(CSS_FOR_STANDARD_PAGES_IRES), InstalledFiles::filename(JAVASCRIPT_FOR_STANDARD_PAGES_IRES), (void *) page); IndexUtilities::clear_page_data(session); return IF; } @ = void InterpretIndex::close_index_file(text_stream *ifl) { HTML::footer(ifl); STREAM_CLOSE(ifl); }