HTML utility code.
§2. Keeping track of which images are referred to in the HTML we generate:
dictionary *image_usages = NULL; how many times, if at all, this image has been used typedef struct image_usage { struct text_stream *leafname; int usage_count; struct filename *resolved_to; MEMORY_MANAGEMENT } image_usage; typedef struct image_source { struct pathname *src; a location from which images can be taken MEMORY_MANAGEMENT } image_source;
The structure image_usage is accessed in 3/fln and here.
The structure image_source is private to this section.
§3. We can either generate entirely fresh HTML pages, or we can inject material into a division inside a copy of an existing page: this is called "top-and-tailing".
int first_request_for_tt = TRUE; will the next request be the first? text_stream *DSET_main_tail_matter = NULL; text_stream *DSET_main_top_matter = NULL; text_stream *DSET_section_tail_matter = NULL; text_stream *DSET_section_top_matter = NULL;
§4. Images. In the Inform application, a special http
transport called inform:
is used
for references to the in-app documentation, so an image called orange.png
will be found at the URL inform:/orange.png
.
Otherwise, of course, we need to make an images folder alongside the HTML
we produce. It will be called images
, so relative to the HTML, the URL
would then be images/orange.png
.
However, it"s also possible that the book"s instructions tell us to use images from an already-existing location instead.
Note that each time the URL of an image is looked up, we make a note of it, so that we can keep track of which images we actually need.
void HTMLUtilities::image_URL(OUTPUT_STREAM, text_stream *leafname) { if (image_usages == NULL) image_usages = Dictionaries::new(100, FALSE); image_usage *iu = NULL; if (Dictionaries::find(image_usages, leafname)) { iu = Dictionaries::read_value(image_usages, leafname); } else { Dictionaries::create(image_usages, leafname); iu = CREATE(image_usage); iu->usage_count = 0; iu->leafname = Str::duplicate(leafname); Dictionaries::write_value(image_usages, leafname, iu); } iu->usage_count++; filename *F = Filenames::in_folder(indoc_settings->images_path, leafname); if (indoc_settings->html_for_Inform_application == 1) WRITE("inform:/%/f", F); else { if (indoc_settings->images_copy) F = Filenames::in_folder(Pathnames::from_text(I"images"), leafname); WRITE("%/f", F); } iu->resolved_to = F; }
The function HTMLUtilities::image_URL is used in §13, §17, 1/mn (§1.1), 2/rr (§4.5), 2/css (§7).
void HTMLUtilities::note_images(void) { image_usage *iu; LOOP_OVER(iu, image_usage) Epub::note_image(indoc_settings->ebook, iu->resolved_to); }
The function HTMLUtilities::note_images is used in 1/mn (§1).
§6. Suppose we are indeed copying images into place: we have to get them from somewhere. The somewheres are folders called "image sources", and this routine adds one:
void HTMLUtilities::add_image_source(pathname *path) { image_source *is = CREATE(image_source); is->src = path; }
The function HTMLUtilities::add_image_source is used in 1/ins (§3, §5.1).
§7. During the copying process, we look for each image, say orange.png
, in
each of these image sources, starting from the most recently added and
working backwards. As soon as we find a file of that name, we copy it over.
void HTMLUtilities::copy_images(void) { if (indoc_settings->images_copy) { pathname *I = Pathnames::subfolder(indoc_settings->destination, I"images"); Pathnames::create_in_file_system(I); image_usage *iu; LOOP_OVER(iu, image_usage) { int found = FALSE; image_source *is; LOOP_BACKWARDS_OVER(is, image_source) { filename *F = Filenames::in_folder(is->src, iu->leafname); if (TextFiles::exists(F)) { found = TRUE; Shell::copy(F, I, "-f"); break; } } if (found == FALSE) { Errors::with_text("unable to find the image %S", iu->leafname); } } } }
The function HTMLUtilities::copy_images is used in 1/mn (§1).
void HTMLUtilities::begin_file(OUTPUT_STREAM, volume *V) { HTML::declare_as_HTML(OUT, indoc_settings->XHTML); filename *CSS = NULL; if ((V) && (Str::len(V->vol_CSS_leafname) > 0)) CSS = Filenames::from_text(V->vol_CSS_leafname); HTML::begin_head(OUT, CSS); TEMPORARY_TEXT(comment); char *monthname[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; WRITE_TO(comment, "Generated by indoc on %d %s %d", the_present->tm_mday, monthname[the_present->tm_mon], the_present->tm_year+1900); HTML::comment(OUT, comment); DISCARD_TEXT(comment); } void HTMLUtilities::write_title(OUTPUT_STREAM, text_stream *title) { WRITE("<title>%S</title>\n", title); }
The function HTMLUtilities::begin_file is used in 2/rnd (§16.2), 3/iu (§1), 4/cm (§9.1).
The function HTMLUtilities::write_title is used in 2/rnd (§16.2), 3/iu (§1), 4/cm (§9.1).
§9. Here's text within a link:
void HTMLUtilities::general_link(OUTPUT_STREAM, text_stream *cl, text_stream *to, text_stream *text) { HTML::begin_link_with_class(OUT, cl, to); WRITE("%S", text); HTML::end_link(OUT); }
The function HTMLUtilities::general_link is used in §11, 3/iu (§4), 3/cai (§9.2.3.4, §9.2.3.5), 3/ei (§3.5), 4/cm (§5, §6, §9.3.1, §9.3.2.1, §10), 4/ca (§5, §6), 4/ct (§3, §6).
§10. And a link with both text and a title (tooltip) tag:
void HTMLUtilities::titled_link(OUTPUT_STREAM, text_stream *cl, text_stream *to, text_stream *ti, text_stream *text) { HTML::begin_link_with_class_title(OUT, cl, to, ti); WRITE("%S", text); HTML::end_link(OUT); }
The function HTMLUtilities::titled_link appears nowhere else.
§11. And a standardised paragraph which is itself a link:
void HTMLUtilities::textual_link(OUTPUT_STREAM, text_stream *to, text_stream *text) { HTML_OPEN("p"); HTMLUtilities::general_link(OUT, I"standardlink", to, text); HTML_CLOSE("p"); }
The function HTMLUtilities::textual_link is used in 4/cm (§9.3.1).
§12. Miscellaneous HTML. Horizontal ruled lines.
void HTMLUtilities::ruled_line(OUTPUT_STREAM) { if (indoc_settings->format == HTML_FORMAT) HTML_TAG("hr") else WRITE("----------------------------------------------------------------------\n"); }
The function HTMLUtilities::ruled_line is used in 2/rnd (§9.1), 4/nd (§6), 4/cm (§4), 4/ca (§4), 4/ct (§5), 4/cr (§5, §6), 4/cu (§5, §6).
void HTMLUtilities::image_element(OUTPUT_STREAM, text_stream *name) { TEMPORARY_TEXT(details); WRITE_TO(details, "alt=\"%S\" src=\"", name); HTMLUtilities::image_URL(details, name); WRITE_TO(details, "\""); HTML::tag(OUT, "img", details); DISCARD_TEXT(details); } void HTMLUtilities::image_element_scaled(OUTPUT_STREAM, text_stream *name, int xsize, int ysize) { TEMPORARY_TEXT(details); WRITE_TO(details, "alt=\"%S\" src=\"", name); HTMLUtilities::image_URL(details, name); WRITE_TO(details, "\" width=\"%d\" height=\"%d\"", xsize, ysize); HTML::tag(OUT, "img", details); DISCARD_TEXT(details); } void HTMLUtilities::image_with_id(OUTPUT_STREAM, text_stream *name, text_stream *id) { TEMPORARY_TEXT(details); WRITE_TO(details, "alt=\"%S\" src=\"", name); HTMLUtilities::image_URL(details, name); WRITE_TO(details, "\" id=\"%S\"", id); HTML::tag(OUT, "img", details); DISCARD_TEXT(details); } void HTMLUtilities::asterisk_image(OUTPUT_STREAM, text_stream *name) { TEMPORARY_TEXT(details); WRITE_TO(details, "class=\"asterisk\" alt=\"*\" src=\""); HTMLUtilities::image_URL(details, name); WRITE_TO(details, "\""); HTML::tag_sc(OUT, "img", details); DISCARD_TEXT(details); }
The function HTMLUtilities::image_element is used in 2/rnd (§11.2.2.3), 4/ct (§3), 4/cr (§10).
The function HTMLUtilities::image_element_scaled is used in 2/rnd (§11.2.2.3).
The function HTMLUtilities::image_with_id is used in 4/cm (§6), 4/ca (§6).
The function HTMLUtilities::asterisk_image is used in 2/exm (§8.2.2), 2/rnd (§14), 4/cr (§6.2).
§14. The "extra" functions here are for revealing or concealing page content
when the user clicks a button. Each such piece of content is in its own
uniquely-ID'd <div>
, as follows:
void HTMLUtilities::extra_div_open(OUTPUT_STREAM, int id) { HTML_OPEN_WITH("div", "id=\"extra%d\" style=\"display: none;\"", id); }
The function HTMLUtilities::extra_div_open is used in 4/cm (§9.3.2.1).
§15. And the following links provide the wiring for the buttons:
void HTMLUtilities::extra_link(OUTPUT_STREAM, int id) { TEMPORARY_TEXT(onclick); WRITE_TO(onclick, "showExtra('extra%d', 'plus%d'); return false;", id, id); HTML::begin_link_with_class_onclick(OUT, NULL, I"#", onclick); DISCARD_TEXT(onclick); TEMPORARY_TEXT(details); WRITE_TO(details, "alt=\"show\" id=\"plus%d\" src=\"", id); HTMLUtilities::extra_icon(details, I"extra"); WRITE_TO(details, "\""); HTML::tag(OUT, "img", details); DISCARD_TEXT(details); HTML_CLOSE("a"); WRITE(" "); } void HTMLUtilities::all_extras_link(OUTPUT_STREAM, text_stream *from) { WRITE(" "); TEMPORARY_TEXT(onclick); WRITE_TO(onclick, "showExtra%S(); return false;", from); HTML::begin_link_with_class_onclick(OUT, NULL, I"#", onclick); DISCARD_TEXT(onclick); TEMPORARY_TEXT(details); WRITE_TO(details, "alt=\"show\" id=\"plus%S\" src=\"", from); HTMLUtilities::extra_icon(details, I"extrab"); WRITE_TO(details, "\""); HTML::tag(OUT, "img", details); DISCARD_TEXT(details); HTML_CLOSE("a"); }
The function HTMLUtilities::extra_link is used in 4/cm (§9.3.2.1).
The function HTMLUtilities::all_extras_link is used in 4/cm (§9.3.2).
§16. These links call some standard Javascript functions, thus:
void HTMLUtilities::write_javascript_for_buttons(OUTPUT_STREAM) { WRITE(" function showExtra(id, imid) {\n"); WRITE(" if (document.getElementById(id).style.display == 'block') {\n"); WRITE(" document.getElementById(id).style.display = 'none';\n"); WRITE(" document.getElementById(imid).src = '"); HTMLUtilities::extra_icon(OUT, I"extra"); WRITE("';\n"); WRITE(" } else {\n"); WRITE(" document.getElementById(id).style.display = 'block';\n"); WRITE(" document.getElementById(imid).src = '"); HTMLUtilities::extra_icon(OUT, I"extraclose"); WRITE("';\n"); WRITE(" }\n"); WRITE(" }\n"); WRITE(" function onLoaded() {\n"); WRITE(" if (window.location.hash) {\n"); WRITE(" var hash = window.location.hash.substring(2);\n"); WRITE(" if (hash.search(\"_\") >= 0) {\n"); WRITE(" var res = hash.split(\"_\");\n"); WRITE(" showExample(\"example\"+res[1]);\n"); WRITE(" } else {\n"); WRITE(" showExample(\"example\"+hash);\n"); WRITE(" }\n"); WRITE(" }\n"); WRITE(" }\n"); WRITE(" window.onload=onLoaded;\n"); WRITE(" function showExample(id) {\n"); WRITE(" if (document.getElementById(id).style.display == 'block') {\n"); WRITE(" document.getElementById(id).style.display = 'none';\n"); WRITE(" } else {\n"); WRITE(" document.getElementById(id).style.display = 'block';\n"); WRITE(" }\n"); WRITE(" }\n"); WRITE(" function openExtra(id, imid) {\n"); WRITE(" document.getElementById(id).style.display = 'block';\n"); WRITE(" document.getElementById(imid).src = '"); HTMLUtilities::extra_icon(OUT, I"extraclose"); WRITE("';\n"); WRITE(" }\n"); WRITE(" function closeExtra(id, imid) {\n"); WRITE(" document.getElementById(id).style.display = 'none';\n"); WRITE(" document.getElementById(imid).src = '"); HTMLUtilities::extra_icon(OUT, I"extra"); WRITE("';\n"); WRITE(" }\n"); }
The function HTMLUtilities::write_javascript_for_buttons is used in 2/rnd (§16.2), 4/cm (§9.1).
void HTMLUtilities::extra_icon(OUTPUT_STREAM, text_stream *name) { TEMPORARY_TEXT(img); WRITE_TO(img, "%S.png", name); HTMLUtilities::image_URL(OUT, img); DISCARD_TEXT(img); }
The function HTMLUtilities::extra_icon is used in §15, §16, §18.
§18. And the following compiles a set of specific functions for numbered buttons, used on the Contents page:
void HTMLUtilities::write_javascript_for_contents_buttons(OUTPUT_STREAM) { volume *V; LOOP_OVER(V, volume) { WRITE(" function showExtra%S() {\n", V->vol_abbrev); WRITE(" if (document.getElementById('plus%S').src.indexOf('", V->vol_abbrev); HTMLUtilities::extra_icon(OUT, I"extrab"); WRITE("') >= 0) {\n"); for (int i=0; i<V->vol_chapter_count; i++) { int bn = (V->allocation_id)*1000+i; WRITE(" openExtra('extra%d', 'plus%d');\n", bn, bn); } WRITE(" document.getElementById('plus%S').src = '", V->vol_abbrev); HTMLUtilities::extra_icon(OUT, I"extracloseb"); WRITE("';\n"); WRITE(" } else {\n"); for (int i=0; i<V->vol_chapter_count; i++) { int bn = (V->allocation_id)*1000+i; WRITE(" closeExtra('extra%d', 'plus%d');\n", bn, bn); } WRITE(" document.getElementById('plus%S').src = '", V->vol_abbrev); HTMLUtilities::extra_icon(OUT, I"extrab"); WRITE("';\n"); WRITE(" }\n"); WRITE(" }\n"); } }
The function HTMLUtilities::write_javascript_for_contents_buttons is used in 4/cm (§9.1).
§19. JavaScript to handle the paste icon works differently on different platforms.
void HTMLUtilities::paste_script(OUTPUT_STREAM, text_stream *content, int code_num) { HTML::open_javascript(OUT, FALSE); WRITE("function pasteCode"); if (Str::len(content) == 0) WRITE("(code"); else WRITE("%d(code", code_num); WRITE(") {\n"); if (indoc_settings->javascript_paste_method == PASTEMODE_Andrew) WRITE(" var myProject = window.Project;\n"); if (indoc_settings->javascript_paste_method == PASTEMODE_David) WRITE(" var myProject = external.Project;\n"); WRITE("\n"); WRITE(" myProject.selectView('source');\n"); WRITE(" myProject.pasteCode("); if (Str::len(content) == 0) { WRITE("code"); } else WRITE("'%S'", content); WRITE(");\n}\n"); HTML::close_javascript(OUT); } void HTMLUtilities::create_script(OUTPUT_STREAM, text_stream *content, int code_num, text_stream *titling) { HTML::open_javascript(OUT, FALSE); WRITE("function createNewProject"); if (Str::len(content) == 0) WRITE("(code"); else WRITE("%d(code", code_num); WRITE(", title) {\n"); if (indoc_settings->javascript_paste_method == PASTEMODE_Andrew) WRITE(" var myProject = window.Project;\n"); if (indoc_settings->javascript_paste_method == PASTEMODE_David) WRITE(" var myProject = external.Project;\n"); WRITE("\n"); WRITE(" myProject.createNewProject("); if (Str::len(content) == 0) WRITE("title"); else WRITE("'%S'", titling); WRITE(", "); if (Str::len(content) == 0) WRITE("code"); else WRITE("'%S'", content); WRITE(");\n}\n"); HTML::close_javascript(OUT); }
The function HTMLUtilities::paste_script is used in 2/rnd (§11.2.2.3, §16.2).
The function HTMLUtilities::create_script is used in 2/rnd (§11.2.2.3, §16.2).
§20. Definitions. Some nice little boxes for syntax definitions in computery manuals:
int no_definition_anchors = 0; void HTMLUtilities::definition_box(OUTPUT_STREAM, text_stream *defn, text_stream *sigil, volume *V, section *S) { if (indoc_settings->format == HTML_FORMAT) { TEMPORARY_TEXT(anchor); WRITE_TO(anchor, "defn%d", no_definition_anchors++); TEMPORARY_TEXT(comment); WRITE_TO(comment, "START PHRASE \"%S\"", anchor); HTML::comment(OUT, comment); DISCARD_TEXT(comment); HTML_OPEN_WITH("div", "class=\"definition\""); HTML::anchor(OUT, anchor); HTMLUtilities::defn_unpack(OUT, defn, V, S, anchor); WRITE("\n"); DISCARD_TEXT(anchor); HTML::comment(OUT, I"END PHRASE"); TEMPORARY_TEXT(defnhead); WRITE_TO(defnhead, "definition of %S", sigil); HTML::comment(OUT, defnhead); DISCARD_TEXT(defnhead); } else { WRITE("PHRASE: %S\n", defn); } } void HTMLUtilities::end_definition_box(OUTPUT_STREAM) { if (indoc_settings->format == HTML_FORMAT) { WRITE("\n"); HTML::comment(OUT, I"end definition"); HTML_CLOSE("div"); } else WRITE("\n"); }
The function HTMLUtilities::definition_box is used in 2/rr (§4.6.2).
The function HTMLUtilities::end_definition_box is used in 2/rr (§4.6.2).
§21. Though these are in fact quite a lot of trouble:
void HTMLUtilities::defn_unpack(OUTPUT_STREAM, text_stream *given_defn, volume *V, section *S, text_stream *anchor) { match_results mr = Regexp::create_mr(); <Given alternates divided by an ampersand, recurse to unpack each in turn 21.1>; TEMPORARY_TEXT(defn); Str::copy(defn, given_defn); TEMPORARY_TEXT(index_as); <Work out an index mark for this definition 21.2>; if (indoc_settings->inform_definitions_mode) { <Rewrite definition as an HTML paragraph of class defnprototype 21.3>; <Set the kind of the result of the phrase in italic, not bold 21.4>; <Specially set and specially index a phrase to decide a condition 21.5>; <Specially set and specially index a text substitution 21.6>; <Tidy up the definition paragraph 21.7>; WRITE("%S", defn); } else { HTML_OPEN_WITH("span", "class=\"definitionterm\""); WRITE("%S", defn); HTML_CLOSE("span"); } Regexp::dispose_of(&mr); }
The function HTMLUtilities::defn_unpack is used in §20, §21.1.
§21.1.
<Given alternates divided by an ampersand, recurse to unpack each in turn 21.1> =
if (Regexp::match(&mr, given_defn, L"(%c*?) & (%c*)")) { HTMLUtilities::defn_unpack(OUT, mr.exp[0], V, S, anchor); HTML_TAG("br"); WRITE("<i>or:</i>   "); HTMLUtilities::defn_unpack(OUT, mr.exp[1], V, S, anchor); Regexp::dispose_of(&mr); return; }
This code is used in §21.
§21.2.
<Work out an index mark for this definition 21.2> =
Str::copy(index_as, given_defn); if (indoc_settings->inform_definitions_mode) Regexp::replace(index_as, L" ...%c*", NULL, 0); Regexp::replace(index_as, L": *", NULL, 0); WRITE_TO(index_as, "=___=!definition"); Indexes::mark_index_term(index_as, V, S, anchor, NULL, NULL, NULL);
This code is used in §21.
§21.3.
<Rewrite definition as an HTML paragraph of class defnprototype 21.3> =
TEMPORARY_TEXT(proto); HTML::open(proto, "p", I"class='defnprototype'"); given alternative wordings, put only the first in boldface Regexp::replace(defn, L"(%i+?)/(%C+)", L"%0</b>/%1<b>", REP_REPEATING); WRITE_TO(proto, "<b>%S</b>", defn); HTML::close(proto, "p"); Str::copy(defn, proto);
This code is used in §21.
§21.4.
<Set the kind of the result of the phrase in italic, not bold 21.4> =
if (Regexp::match(&mr, defn, L"(%c*) ... (%c*?)</b>")) { WRITE_TO(defn, "%S</b> ... <i>", mr.exp[0]); Regexp::replace(mr.exp[1], L"<b>", NULL, REP_REPEATING); Regexp::replace(mr.exp[1], L"</b>", NULL, REP_REPEATING); WRITE_TO(defn, "%S</i>", mr.exp[1]); }
This code is used in §21.
§21.5.
<Specially set and specially index a phrase to decide a condition 21.5> =
if ((Regexp::match(&mr, defn, L"<b>if (%c*)")) && (Regexp::match(NULL, defn, L"%c*a condition%c*"))) { WRITE_TO(defn, "<i>if</i> <b>%S", mr.exp[0]); Regexp::replace(index_as, L"if ", NULL, REP_ATSTART); text_stream *index_alph = NULL; if (Regexp::match(&mr, index_as, L"%(%c*?%) (%c*)")) index_alph = mr.exp[0]; TEMPORARY_TEXT(term); WRITE_TO(term, "%S=___=!if-definition", index_as); Indexes::mark_index_term(term, V, S, anchor, NULL, NULL, index_alph); DISCARD_TEXT(term); }
This code is used in §21.
§21.6.
<Specially set and specially index a text substitution 21.6> =
if (Regexp::match(&mr, defn, L"<b>say \"%[(%c*)%]\"</b>")) { WRITE_TO(defn, "say \"[<b>%S</b>]\"", mr.exp[0]); Regexp::replace(index_as, L"say ", NULL, REP_ATSTART); text_stream *index_alph = NULL; if (Regexp::match(&mr, index_as, L"%[%(?:%(%c*?%) %)?(%c*)%]")) index_alph = mr.exp[0]; TEMPORARY_TEXT(term); WRITE_TO(term, "%S=___=!say-definition", index_as); Indexes::mark_index_term(term, V, S, anchor, NULL, NULL, index_alph); DISCARD_TEXT(term); }
This code is used in §21.
§21.7.
<Tidy up the definition paragraph 21.7> =
Regexp::replace(defn, L"<b></b>", NULL, REP_REPEATING); Regexp::replace(defn, L"</b><b>", NULL, REP_REPEATING); TEMPORARY_TEXT(star); Str::copy(star, defn); Str::clear(defn); int bl = 0; while (Regexp::match(&mr, star, L"(%c)(%c*)")) { text_stream *ch = mr.exp[0]; Str::copy(star, mr.exp[1]); if (Str::eq(ch, I"(")) { if (bl == 0) WRITE_TO(defn, "</b>"); bl++; } WRITE_TO(defn, "%S", ch); if (Str::eq(ch, I")")) { bl--; if (bl == 0) WRITE_TO(defn, "<b>"); } } DISCARD_TEXT(star);
This code is used in §21.
§22. Topping and tailing. If we're preparing HTML for use in a website, we probably want our
documentation content to be just one <div>
in a larger page whose
design indoc
knows nothing about. The following therefore lets us
use an external file as the prototype, cutting it up into a head before
the text [TEXT]
and a tail afterwards.
void HTMLUtilities::read_top_and_tail_matter(filename *F, int main_flag) { tt_helper_state tths; tths.pretext = TRUE; if (main_flag) { DSET_main_top_matter = Str::new(); DSET_main_tail_matter = Str::new(); tths.top_text = DSET_main_top_matter; tths.tail_text = DSET_main_tail_matter; } else { DSET_section_top_matter = Str::new(); DSET_section_tail_matter = Str::new(); tths.top_text = DSET_section_top_matter; tths.tail_text = DSET_section_tail_matter; } TextFiles::read(F, FALSE, "can't read top and tail file", TRUE, HTMLUtilities::tt_helper, NULL, &tths); }
The function HTMLUtilities::read_top_and_tail_matter is used in §24.
typedef struct tt_helper_state { int pretext; text_stream *top_text; text_stream *tail_text; } tt_helper_state; void HTMLUtilities::tt_helper(text_stream *line, text_file_position *tfp, void *v_tths) { tt_helper_state *tths = (tt_helper_state *) v_tths; Str::trim_white_space_at_end(line); match_results mr = Regexp::create_mr(); if (Regexp::match(&mr, line, L"(%c*?)%[TEXT%](%c*)")) { WRITE_TO(tths->top_text, "%S", mr.exp[0]); HTML::begin_div_with_id(tths->top_text, "bodytext"); HTML::end_div(tths->tail_text); WRITE_TO(tths->tail_text, "%S\n", mr.exp[1]); Regexp::dispose_of(&mr); tths->pretext = FALSE; } else { if (tths->pretext) WRITE_TO(tths->top_text, "%S\n", line); else WRITE_TO(tths->tail_text, "%S\n", line); } }
The function HTMLUtilities::tt_helper is used in §22.
The structure tt_helper_state is private to this section.
§24. And this routine caches requests for tops or tails.
void HTMLUtilities::get_tt_matter(OUTPUT_STREAM, int top, int main) { if (first_request_for_tt) { if (indoc_settings->top_and_tail_sections) HTMLUtilities::read_top_and_tail_matter(indoc_settings->top_and_tail_sections, FALSE); if (indoc_settings->top_and_tail) HTMLUtilities::read_top_and_tail_matter(indoc_settings->top_and_tail, TRUE); } first_request_for_tt = FALSE; if ((top == 1) && (main == 1)) WRITE("%S", DSET_main_top_matter); if ((top == 1) && (main == 0)) WRITE("%S", DSET_main_tail_matter); if ((top == 0) && (main == 1)) WRITE("%S", DSET_section_top_matter); if ((top == 0) && (main == 0)) WRITE("%S", DSET_section_tail_matter); }
The function HTMLUtilities::get_tt_matter is used in 2/rnd (§16.2, §16.1.1), 3/iu (§1, §2), 4/cm (§9.1, §9.2).