[HTMLFormat::] HTML Formats. To provide for weaving into HTML and into EPUB books. @ = void HTMLFormat::create(void) { @; @; } @ = weave_format *wf = Formats::create_weave_format(I"HTML", I".html"); METHOD_ADD(wf, TOP_FOR_MTID, HTMLFormat::top); @; @ = weave_format *wf = Formats::create_weave_format(I"ePub", I".html"); METHOD_ADD(wf, TOP_FOR_MTID, HTMLFormat::top_EPUB); @; METHOD_ADD(wf, BEGIN_WEAVING_FOR_MTID, HTMLFormat::begin_weaving_EPUB); METHOD_ADD(wf, END_WEAVING_FOR_MTID, HTMLFormat::end_weaving_EPUB); @ = METHOD_ADD(wf, SUBHEADING_FOR_MTID, HTMLFormat::subheading); METHOD_ADD(wf, TOC_FOR_MTID, HTMLFormat::toc); METHOD_ADD(wf, PARAGRAPH_HEADING_FOR_MTID, HTMLFormat::paragraph_heading); METHOD_ADD(wf, SOURCE_CODE_FOR_MTID, HTMLFormat::source_code); METHOD_ADD(wf, INLINE_CODE_FOR_MTID, HTMLFormat::inline_code); METHOD_ADD(wf, DISPLAY_LINE_FOR_MTID, HTMLFormat::display_line); METHOD_ADD(wf, ITEM_FOR_MTID, HTMLFormat::item); METHOD_ADD(wf, BAR_FOR_MTID, HTMLFormat::bar); METHOD_ADD(wf, FIGURE_FOR_MTID, HTMLFormat::figure); METHOD_ADD(wf, PARA_MACRO_FOR_MTID, HTMLFormat::para_macro); METHOD_ADD(wf, PAGEBREAK_FOR_MTID, HTMLFormat::pagebreak); METHOD_ADD(wf, BLANK_LINE_FOR_MTID, HTMLFormat::blank_line); METHOD_ADD(wf, CHANGE_MATERIAL_FOR_MTID, HTMLFormat::change_material); METHOD_ADD(wf, CHANGE_COLOUR_FOR_MTID, HTMLFormat::change_colour); METHOD_ADD(wf, ENDNOTE_FOR_MTID, HTMLFormat::endnote); METHOD_ADD(wf, COMMENTARY_TEXT_FOR_MTID, HTMLFormat::commentary_text); METHOD_ADD(wf, LOCALE_FOR_MTID, HTMLFormat::locale); METHOD_ADD(wf, TAIL_FOR_MTID, HTMLFormat::tail); @h Current state. To keep track of what we're writing, across many intermittent calls to the routines below, we store a crude sort of state in two global variables. (This isn't thread-safe and means we can only write one file at a time, but in fact that's fine here.) @d HTML_OUT 0 /* write position in HTML file is currently outside of p, pre, li */ @d HTML_IN_P 1 /* write position in HTML file is currently outside p */ @d HTML_IN_PRE 2 /* write position in HTML file is currently outside pre */ @d HTML_IN_LI 3 /* write position in HTML file is currently outside li */ = int html_in_para = HTML_OUT; /* one of the above */ int item_depth = 0; /* for |HTML_IN_LI| only: how many lists we're nested inside */ void HTMLFormat::p(OUTPUT_STREAM, char *class) { if (class) HTML_OPEN_WITH("p", "class=\"%s\"", class) else HTML_OPEN("p"); html_in_para = HTML_IN_P; } void HTMLFormat::cp(OUTPUT_STREAM) { HTML_CLOSE("p"); WRITE("\n"); html_in_para = HTML_OUT; } void HTMLFormat::pre(OUTPUT_STREAM, char *class) { if (class) HTML_OPEN_WITH("pre", "class=\"%s\"", class) else HTML_OPEN("pre"); WRITE("\n"); INDENT; html_in_para = HTML_IN_PRE; } void HTMLFormat::cpre(OUTPUT_STREAM) { OUTDENT; HTML_CLOSE("pre"); WRITE("\n"); html_in_para = HTML_OUT; } @ Depth 1 means "inside a list entry"; depth 2, "inside an entry of a list which is itself inside a list entry"; and so on. = void HTMLFormat::go_to_depth(OUTPUT_STREAM, int depth) { if (html_in_para != HTML_IN_LI) HTMLFormat::exit_current_paragraph(OUT); if (item_depth == depth) { HTML_CLOSE("li"); } else { while (item_depth < depth) { HTML_OPEN_WITH("ul", "class=\"items\""); item_depth++; } while (item_depth > depth) { HTML_CLOSE("li"); HTML_CLOSE("ul"); WRITE("\n"); item_depth--; } } if (depth > 0) { HTML_OPEN("li"); html_in_para = HTML_IN_LI; } else { html_in_para = HTML_OUT; } } @ The following generically gets us out of whatever we're currently into: = void HTMLFormat::exit_current_paragraph(OUTPUT_STREAM) { switch (html_in_para) { case HTML_IN_P: HTMLFormat::cp(OUT); break; case HTML_IN_PRE: HTMLFormat::cpre(OUT); break; case HTML_IN_LI: HTMLFormat::go_to_depth(OUT, 0); break; } } @ "Breadcrumbs" are the chain of links in a horizontal list at the top of the page, and this drops one. = void HTMLFormat::breadcrumb(OUTPUT_STREAM, text_stream *text, text_stream *link) { if (link) { HTML_OPEN("li"); HTML::begin_link(OUT, link); WRITE("%S", text); HTML::end_link(OUT); HTML_CLOSE("li"); } else { HTML_OPEN("li"); HTML_OPEN("b"); WRITE("%S", text); HTML_CLOSE("b"); HTML_CLOSE("li"); } } @h Methods. For documentation, see "Weave Fornats". = void HTMLFormat::top(weave_format *self, text_stream *OUT, weave_target *wv, text_stream *comment) { HTML::declare_as_HTML(OUT, FALSE); Indexer::cover_sheet_maker(OUT, wv->weave_web, I"template", wv, WEAVE_FIRST_HALF); if (wv->self_contained == FALSE) { filename *CSS = Patterns::obtain_filename(wv->pattern, I"inweb.css"); if (wv->pattern->hierarchical) Patterns::copy_up_file_into_weave(wv->weave_web, CSS); else Patterns::copy_file_into_weave(wv->weave_web, CSS); } HTML::comment(OUT, comment); html_in_para = HTML_OUT; } void HTMLFormat::top_EPUB(weave_format *self, text_stream *OUT, weave_target *wv, text_stream *comment) { HTML::declare_as_HTML(OUT, TRUE); Epub::note_page(wv->weave_web->as_ebook, wv->weave_to, wv->booklet_title, I""); Indexer::cover_sheet_maker(OUT, wv->weave_web, I"template", wv, WEAVE_FIRST_HALF); HTML::comment(OUT, comment); html_in_para = HTML_OUT; } @ = void HTMLFormat::subheading(weave_format *self, text_stream *OUT, weave_target *wv, int level, text_stream *comment, text_stream *head) { HTMLFormat::exit_current_paragraph(OUT); switch (level) { case 1: HTML::heading(OUT, "h3", comment); break; case 2: HTMLFormat::p(OUT, "purpose"); WRITE("%S", comment); if (head) { WRITE(": "); Formats::text(OUT, wv, head); } HTMLFormat::cp(OUT); break; } } @ = void HTMLFormat::toc(weave_format *self, text_stream *OUT, weave_target *wv, int stage, text_stream *text1, text_stream *text2, paragraph *P) { HTMLFormat::exit_current_paragraph(OUT); switch (stage) { case 1: HTML_OPEN_WITH("ul", "class=\"toc\""); HTML_OPEN("li"); break; case 2: HTML_CLOSE("li"); HTML_OPEN("li"); break; case 3: { TEMPORARY_TEXT(TEMP) HTMLFormat::xref(TEMP, wv, P, NULL, TRUE); HTML::begin_link(OUT, TEMP); DISCARD_TEXT(TEMP) WRITE("%s%S", (Str::get_first_char(P->ornament) == 'S')?"§":"¶", P->paragraph_number); WRITE(". %S", text2); HTML::end_link(OUT); break; } case 4: HTML_CLOSE("li"); HTML_CLOSE("ul"); HTML::hr(OUT, "tocbar"); WRITE("\n"); break; } } @ = section *page_section = NULL; int crumbs_dropped = FALSE; void HTMLFormat::paragraph_heading(weave_format *self, text_stream *OUT, weave_target *wv, text_stream *TeX_macro, section *S, paragraph *P, text_stream *heading_text, text_stream *chaptermark, text_stream *sectionmark, int weight) { page_section = S; if (weight == 3) return; /* Skip chapter headings */ HTMLFormat::exit_current_paragraph(OUT); if (P) { HTMLFormat::p(OUT, "inwebparagraph"); TEMPORARY_TEXT(TEMP) HTMLFormat::xref(TEMP, wv, P, NULL, FALSE); HTML::anchor(OUT, TEMP); DISCARD_TEXT(TEMP) HTML_OPEN("b"); WRITE("%s%S", (Str::get_first_char(P->ornament) == 'S')?"§":"¶", P->paragraph_number); WRITE(". %S%s ", heading_text, (Str::len(heading_text) > 0)?".":""); HTML_CLOSE("b"); } else { if (wv->self_contained == FALSE) { if (crumbs_dropped == FALSE) { filename *C = Patterns::obtain_filename(wv->pattern, I"crumbs.gif"); if (wv->pattern->hierarchical) Patterns::copy_up_file_into_weave(wv->weave_web, C); else Patterns::copy_file_into_weave(wv->weave_web, C); crumbs_dropped = TRUE; } HTML_OPEN_WITH("ul", "class=\"crumbs\""); HTMLFormat::drop_initial_breadcrumbs(OUT, wv->breadcrumbs, wv->docs_mode); text_stream *bct = Bibliographic::get_datum(wv->weave_web->md, I"Title"); if (Str::len(Bibliographic::get_datum(wv->weave_web->md, I"Short Title")) > 0) { bct = Bibliographic::get_datum(wv->weave_web->md, I"Short Title"); } HTMLFormat::breadcrumb(OUT, bct, I"index.html"); if (wv->weave_web->md->chaptered) { TEMPORARY_TEXT(chapter_link); WRITE_TO(chapter_link, "index.html#%s%S", (wv->weave_web->as_ebook)?"C":"", S->owning_chapter->md->ch_range); HTMLFormat::breadcrumb(OUT, S->owning_chapter->md->ch_title, chapter_link); DISCARD_TEXT(chapter_link); } HTMLFormat::breadcrumb(OUT, heading_text, NULL); HTML_CLOSE("ul"); } else { HTML_OPEN_WITH("ul", "class=\"crumbs\""); HTMLFormat::breadcrumb(OUT, heading_text, NULL); HTML_CLOSE("ul"); } } } void HTMLFormat::drop_initial_breadcrumbs(OUTPUT_STREAM, linked_list *crumbs, int docs_mode) { if (LinkedLists::len(crumbs) > 0) { breadcrumb_request *BR; LOOP_OVER_LINKED_LIST(BR, breadcrumb_request, crumbs) { HTMLFormat::breadcrumb(OUT, BR->breadcrumb_text, BR->breadcrumb_link); } } else if (docs_mode) HTMLFormat::breadcrumb(OUT, I"★", I"../webs.html"); } @ = void HTMLFormat::source_code(weave_format *self, text_stream *OUT, weave_target *wv, int tab_stops_of_indentation, text_stream *prefatory, text_stream *matter, text_stream *colouring, text_stream *concluding_comment, int starts, int finishes, int code_mode) { if (starts) { if (Str::len(prefatory) > 0) { HTML_OPEN_WITH("span", "class=\"definitionkeyword\""); WRITE("%S", prefatory); HTML_CLOSE("span"); WRITE(" "); if (Str::eq(prefatory, I"enum")) { match_results mr = Regexp::create_mr(); if (Regexp::match(&mr, matter, L"(%c*) from (%C+) *")) { HTMLFormat::source_code(self, OUT, wv, 0, NULL, mr.exp[0], colouring, concluding_comment, starts, FALSE, code_mode); HTML_OPEN_WITH("span", "class=\"definitionkeyword\""); WRITE(" from "); HTML_CLOSE("span"); HTMLFormat::source_code(self, OUT, wv, 0, NULL, mr.exp[1], colouring, concluding_comment, FALSE, finishes, code_mode); Regexp::dispose_of(&mr); return; } Regexp::dispose_of(&mr); } } else for (int i=0; i; if (Str::get_at(matter, i) == '<') WRITE("<"); else if (Str::get_at(matter, i) == '>') WRITE(">"); else if (Str::get_at(matter, i) == '&') WRITE("&"); else WRITE("%c", Str::get_at(matter, i)); } if (current_colour >= 0) HTML_CLOSE("span"); current_colour = -1; if (finishes) { if (Str::len(concluding_comment) > 0) { if (!starts) WRITE(" "); HTML_OPEN_WITH("span", "class=\"comment\""); Formats::text(OUT, wv, concluding_comment); HTML_CLOSE("span"); } WRITE("\n"); } } @ = if (colour_wanted != current_colour) { if (current_colour >= 0) HTML_CLOSE("span"); Formats::change_colour(OUT, wv, colour_wanted, TRUE); current_colour = colour_wanted; } @ = void HTMLFormat::inline_code(weave_format *self, text_stream *OUT, weave_target *wv, int enter) { if (enter) { if (html_in_para == HTML_OUT) HTMLFormat::p(OUT, "inwebparagraph"); HTML_OPEN_WITH("code", "class=\"display\""); } else { HTML_CLOSE("code"); } } @ = void HTMLFormat::display_line(weave_format *self, text_stream *OUT, weave_target *wv, text_stream *from) { HTMLFormat::exit_current_paragraph(OUT); HTML_OPEN("blockquote"); WRITE("\n"); INDENT; HTMLFormat::p(OUT, NULL); WRITE("%S", from); HTMLFormat::cp(OUT); OUTDENT; HTML_CLOSE("blockquote"); WRITE("\n"); } @ = void HTMLFormat::item(weave_format *self, text_stream *OUT, weave_target *wv, int depth, text_stream *label) { HTMLFormat::go_to_depth(OUT, depth); if (Str::len(label) > 0) WRITE("(%S) ", label); else WRITE(" "); } @ = void HTMLFormat::bar(weave_format *self, text_stream *OUT, weave_target *wv) { HTMLFormat::exit_current_paragraph(OUT); HTML::hr(OUT, NULL); } @ = void HTMLFormat::figure(weave_format *self, text_stream *OUT, weave_target *wv, text_stream *figname, int w, int h) { HTMLFormat::exit_current_paragraph(OUT); filename *F = Filenames::in_folder( Pathnames::subfolder(wv->weave_web->md->path_to_web, I"Figures"), figname); filename *RF = Filenames::from_text(figname); TEMPORARY_TEXT(ext); Filenames::write_extension(ext, RF); if (Str::eq_insensitive(ext, I".txt")) { HTMLFormat::pre(OUT, NULL); TextFiles::read(F, FALSE, "unable to read file of test cases", TRUE, &HTMLFormat::text_file_helper, NULL, OUT); HTMLFormat::cpre(OUT); } else { HTML_OPEN("center"); HTML::image(OUT, RF); Patterns::copy_file_into_weave(wv->weave_web, F); HTML_CLOSE("center"); } DISCARD_TEXT(ext); WRITE("\n"); } void HTMLFormat::text_file_helper(text_stream *text, text_file_position *tfp, void *state) { text_stream *OUT = (text_stream *) state; WRITE("%S\n", text); } @ = void HTMLFormat::para_macro(weave_format *self, text_stream *OUT, weave_target *wv, para_macro *pmac, int defn) { paragraph *P = pmac->defining_paragraph; WRITE("<"); HTML_OPEN_WITH("span", "class=\"%s\"", (defn)?"cwebmacrodefn":"cwebmacro"); WRITE("%S", pmac->macro_name); HTML_CLOSE("span"); WRITE(" "); HTML_OPEN_WITH("span", "class=\"cwebmacronumber\""); WRITE("%S", P->paragraph_number); HTML_CLOSE("span"); WRITE(">%s", (defn)?" =":""); } @ = void HTMLFormat::pagebreak(weave_format *self, text_stream *OUT, weave_target *wv) { HTMLFormat::exit_current_paragraph(OUT); } @ = void HTMLFormat::blank_line(weave_format *self, text_stream *OUT, weave_target *wv, int in_comment) { if (html_in_para == HTML_IN_PRE) { WRITE("\n"); } else { int old_state = html_in_para, old_depth = item_depth; HTMLFormat::exit_current_paragraph(OUT); if ((old_state == HTML_IN_P) || ((old_state == HTML_IN_LI) && (old_depth > 1))) HTMLFormat::p(OUT,"inwebparagraph"); } } @ = void HTMLFormat::change_material(weave_format *self, text_stream *OUT, weave_target *wv, int old_material, int new_material, int content) { if (old_material != new_material) { if (old_material == MACRO_MATERIAL) HTML_CLOSE("code"); if ((content) || (new_material != MACRO_MATERIAL)) HTMLFormat::exit_current_paragraph(OUT); switch (old_material) { case CODE_MATERIAL: case REGULAR_MATERIAL: switch (new_material) { case CODE_MATERIAL: WRITE("\n"); HTMLFormat::pre(OUT, "display"); break; case DEFINITION_MATERIAL: WRITE("\n"); HTMLFormat::pre(OUT, "definitions"); break; case MACRO_MATERIAL: if (content) { WRITE("\n"); HTMLFormat::p(OUT,"macrodefinition"); } HTML_OPEN_WITH("code", "class=\"display\""); WRITE("\n"); break; case REGULAR_MATERIAL: if (content) { WRITE("\n"); HTMLFormat::p(OUT,"inwebparagraph"); } break; } break; case MACRO_MATERIAL: switch (new_material) { case CODE_MATERIAL: WRITE("\n"); HTMLFormat::pre(OUT, "displaydefn"); break; case DEFINITION_MATERIAL: WRITE("\n"); HTMLFormat::pre(OUT, "definitions"); break; } break; case DEFINITION_MATERIAL: switch (new_material) { case CODE_MATERIAL: WRITE("\n"); HTMLFormat::pre(OUT, "display"); break; case MACRO_MATERIAL: WRITE("\n"); HTMLFormat::p(OUT, "macrodefinition"); HTML_OPEN_WITH("code", "class=\"display\""); WRITE("\n"); break; } break; default: HTMLFormat::cpre(OUT); break; } } } @ = void HTMLFormat::change_colour(weave_format *self, text_stream *OUT, weave_target *wv, int col, int in_code) { char *cl = "plain"; switch (col) { case MACRO_COLOUR: cl = "cwebmacrotext"; break; case FUNCTION_COLOUR: cl = "functiontext"; break; case IDENTIFIER_COLOUR: cl = "identifier"; break; case ELEMENT_COLOUR: cl = "element"; break; case RESERVED_COLOUR: cl = "reserved"; break; case STRING_COLOUR: cl = "string"; break; case CHAR_LITERAL_COLOUR: cl = "character"; break; case CONSTANT_COLOUR: cl = "constant"; break; case PLAIN_COLOUR: cl = "plain"; break; case EXTRACT_COLOUR: cl = "extract"; break; case COMMENT_COLOUR: cl = "comment"; break; default: PRINT("col: %d\n", col); internal_error("bad colour"); break; } HTML_OPEN_WITH("span", "class=\"%s\"", cl); } @ = void HTMLFormat::endnote(weave_format *self, text_stream *OUT, weave_target *wv, int end) { if (end == 1) { HTMLFormat::exit_current_paragraph(OUT); HTMLFormat::p(OUT, "endnote"); } else { HTMLFormat::cp(OUT); } } @ = void HTMLFormat::commentary_text(weave_format *self, text_stream *OUT, weave_target *wv, text_stream *id) { for (int i=0; i < Str::len(id); i++) { if (html_in_para == HTML_OUT) HTMLFormat::p(OUT, "inwebparagraph"); if (Str::get_at(id, i) == '&') WRITE("&"); else if (Str::get_at(id, i) == '<') WRITE("<"); else if (Str::get_at(id, i) == '>') WRITE(">"); else if ((i == 0) && (Str::get_at(id, i) == '-') && (Str::get_at(id, i+1) == '-') && ((Str::get_at(id, i+2) == ' ') || (Str::get_at(id, i+2) == 0))) { WRITE("—"); i++; } else if ((Str::get_at(id, i) == ' ') && (Str::get_at(id, i+1) == '-') && (Str::get_at(id, i+2) == '-') && ((Str::get_at(id, i+3) == ' ') || (Str::get_at(id, i+3) == '\n') || (Str::get_at(id, i+3) == 0))) { WRITE(" —"); i+=2; } else PUT(Str::get_at(id, i)); } } @ = void HTMLFormat::locale(weave_format *self, text_stream *OUT, weave_target *wv, paragraph *par1, paragraph *par2) { TEMPORARY_TEXT(TEMP) HTMLFormat::xref(TEMP, wv, par1, page_section, TRUE); HTML::begin_link(OUT, TEMP); DISCARD_TEXT(TEMP) WRITE("%s%S", (Str::get_first_char(par1->ornament) == 'S')?"§":"¶", par1->paragraph_number); if (par2) WRITE("-%S", par2->paragraph_number); HTML::end_link(OUT); } @ = void HTMLFormat::xref(OUTPUT_STREAM, weave_target *wv, paragraph *P, section *from, int a_link) { TEMPORARY_TEXT(linkto); if ((from) && (P->under_section != from)) { Str::copy(linkto, P->under_section->sect_range); LOOP_THROUGH_TEXT(pos, linkto) if ((Str::get(pos) == '/') || (Str::get(pos) == ' ')) Str::put(pos, '-'); WRITE_TO(linkto, ".html"); } WRITE("%S%s%S", linkto, (a_link)?"#":"", P->ornament); DISCARD_TEXT(linkto); WRITE("P"); text_stream *N = P->paragraph_number; LOOP_THROUGH_TEXT(pos, N) if (Str::get(pos) == '.') WRITE("_"); else PUT(Str::get(pos)); } @ = void HTMLFormat::tail(weave_format *self, text_stream *OUT, weave_target *wv, text_stream *comment, section *this_S) { HTMLFormat::exit_current_paragraph(OUT); if (wv->docs_mode) { chapter *C = this_S->owning_chapter; section *S, *last_S = NULL, *prev_S = NULL, *next_S = NULL; LOOP_OVER_LINKED_LIST(S, section, C->sections) { if (S == this_S) prev_S = last_S; if (last_S == this_S) next_S = S; last_S = S; } if ((prev_S) || (next_S)) { HTML::hr(OUT, "tocbar"); HTML_OPEN_WITH("ul", "class=\"toc\""); HTML_OPEN("li"); if (prev_S == NULL) WRITE("(This section begins %S.)", C->md->ch_title); else { TEMPORARY_TEXT(TEMP); HTMLFormat::sref(TEMP, wv, prev_S); HTML::begin_link(OUT, TEMP); WRITE("Back to '%S'", prev_S->md->sect_title); HTML::end_link(OUT); DISCARD_TEXT(TEMP); } HTML_CLOSE("li"); HTML_OPEN("li"); if (next_S == NULL) WRITE("(This section ends %S.)", C->md->ch_title); else { TEMPORARY_TEXT(TEMP); HTMLFormat::sref(TEMP, wv, next_S); HTML::begin_link(OUT, TEMP); WRITE("Continue with '%S'", next_S->md->sect_title); HTML::end_link(OUT); DISCARD_TEXT(TEMP); } HTML_CLOSE("li"); HTML_CLOSE("ul"); } HTML::hr(OUT, "tocbar"); } HTML::comment(OUT, comment); HTML::completed(OUT); Bibliographic::set_datum(wv->weave_web->md, I"Booklet Title", wv->booklet_title); Indexer::cover_sheet_maker(OUT, wv->weave_web, I"template", wv, WEAVE_SECOND_HALF); } @ = void HTMLFormat::sref(OUTPUT_STREAM, weave_target *wv, section *S) { if (S == NULL) internal_error("unwoven section"); LOOP_THROUGH_TEXT(pos, S->sect_range) if (Str::get(pos) == '/') PUT('-'); else PUT(Str::get(pos)); WRITE(".html"); } @h EPUB-only methods. = int HTMLFormat::begin_weaving_EPUB(weave_format *wf, web *W, weave_pattern *pattern) { TEMPORARY_TEXT(T) WRITE_TO(T, "%S", Bibliographic::get_datum(W->md, I"Title")); W->as_ebook = Epub::new(T, "P"); filename *CSS = Patterns::obtain_filename(pattern, I"inweb.css"); Epub::use_CSS_throughout(W->as_ebook, CSS); Epub::attach_metadata(W->as_ebook, L"identifier", T); DISCARD_TEXT(T) pathname *P = Reader::woven_folder(W); W->redirect_weaves_to = Epub::begin_construction(W->as_ebook, P, NULL); Shell::copy(CSS, W->redirect_weaves_to, ""); return SWARM_SECTIONS_SWM; } void HTMLFormat::end_weaving_EPUB(weave_format *wf, web *W, weave_pattern *pattern) { Epub::end_construction(W->as_ebook); }