175 lines
6.9 KiB
OpenEdge ABL
175 lines
6.9 KiB
OpenEdge ABL
|
[Swarm::] The Swarm.
|
||
|
|
||
|
To feed multiple output requests to the weaver, and to present
|
||
|
weaver results, and update indexes or contents pages.
|
||
|
|
||
|
@h Swarming.
|
||
|
A "weave" occurs when Inweb takes a portion of the web -- one section, one
|
||
|
chapter, or the whole thing -- and writes it out in a human-readable form (or
|
||
|
in some intermediate state which can be made into one, like a TeX file).
|
||
|
There can be many weaves in a single run of Inweb, in which case we call the
|
||
|
resulting flurry a "swarm", like the glittering cloud of locusts in the title
|
||
|
of Chapter 25 of "On the Banks of Plum Creek".
|
||
|
|
||
|
This routine is called with mode |SWARM_SECTIONS_SWM|, |SWARM_CHAPTERS_SWM| or
|
||
|
|SWARM_INDEX_SWM|, so in a non-swarming run it isn't called at all.
|
||
|
|
||
|
=
|
||
|
weave_target *swarm_leader = NULL; /* the most inclusive one we weave */
|
||
|
|
||
|
void Swarm::weave(web *W, text_stream *range, int swarm_mode, theme_tag *tag,
|
||
|
weave_pattern *pattern, filename *to, pathname *into, int docs_mode) {
|
||
|
swarm_leader = NULL;
|
||
|
chapter *C;
|
||
|
section *S;
|
||
|
LOOP_OVER_LINKED_LIST(C, chapter, W->chapters)
|
||
|
if (C->imported == FALSE) {
|
||
|
if (swarm_mode == SWARM_CHAPTERS_SWM)
|
||
|
if ((W->chaptered == TRUE) && (Reader::range_within(C->ch_range, range))) {
|
||
|
C->ch_weave = Swarm::weave_subset(W,
|
||
|
C->ch_range, FALSE, tag, pattern, to, into, docs_mode);
|
||
|
if (Str::len(range) > 0) swarm_leader = C->ch_weave;
|
||
|
}
|
||
|
if (swarm_mode == SWARM_SECTIONS_SWM)
|
||
|
LOOP_OVER_LINKED_LIST(S, section, C->sections)
|
||
|
if (Reader::range_within(S->range, range))
|
||
|
S->sect_weave = Swarm::weave_subset(W,
|
||
|
S->range, FALSE, tag, pattern, to, into, docs_mode);
|
||
|
}
|
||
|
|
||
|
Swarm::weave_index_templates(W, range, pattern, (to)?TRUE:FALSE);
|
||
|
}
|
||
|
|
||
|
@ The following is where an individual weave task begins, whether it comes
|
||
|
from the swarm, or has been specified at the command line (in which case
|
||
|
the call comes from Program Control).
|
||
|
|
||
|
=
|
||
|
weave_target *Swarm::weave_subset(web *W, text_stream *range, int open_afterwards,
|
||
|
theme_tag *tag, weave_pattern *pattern, filename *to, pathname *into, int docs_mode) {
|
||
|
weave_target *wt = NULL;
|
||
|
if (no_inweb_errors == 0) {
|
||
|
Analyser::analyse_code(W);
|
||
|
@<Compile a set of instructions for the weaver@>;
|
||
|
if (Weaver::weave_source(W, wt) == 0) /* i.e., the number of lines woven was zero */
|
||
|
Errors::fatal("empty weave request");
|
||
|
Formats::post_process_weave(wt, open_afterwards); /* e.g., run through TeX */
|
||
|
@<Report on the outcome of the weave to the console@>;
|
||
|
}
|
||
|
return wt;
|
||
|
}
|
||
|
|
||
|
@ Each individual weave generates one of the following sets of instructions:
|
||
|
|
||
|
=
|
||
|
typedef struct weave_target {
|
||
|
struct web *weave_web; /* which web we weave */
|
||
|
struct text_stream *weave_range; /* which parts of the web in this weave */
|
||
|
struct theme_tag *theme_match; /* pick out only paragraphs with this theme */
|
||
|
struct text_stream *booklet_title;
|
||
|
struct weave_pattern *pattern; /* which pattern is to be followed */
|
||
|
struct filename *weave_to; /* where to put it */
|
||
|
struct weave_format *format; /* plain text, say, or HTML */
|
||
|
struct text_stream *cover_sheet_to_use; /* leafname of the copy, or |NULL| for no cover */
|
||
|
void *post_processing_results; /* optional typesetting diagnostics after running through */
|
||
|
int self_contained; /* make a self-contained file if possible */
|
||
|
int docs_mode; /* make as part of a |-weave-docs| run */
|
||
|
MEMORY_MANAGEMENT
|
||
|
} weave_target;
|
||
|
|
||
|
@<Compile a set of instructions for the weaver@> =
|
||
|
wt = CREATE(weave_target);
|
||
|
wt->weave_web = W;
|
||
|
wt->weave_range = Str::duplicate(range);
|
||
|
wt->pattern = pattern;
|
||
|
wt->theme_match = tag;
|
||
|
wt->booklet_title = Str::new();
|
||
|
wt->format = pattern->pattern_format;
|
||
|
wt->post_processing_results = NULL;
|
||
|
wt->cover_sheet_to_use = Str::new();
|
||
|
wt->self_contained = FALSE;
|
||
|
wt->docs_mode = docs_mode;
|
||
|
if (W->no_sections <= 1) wt->self_contained = TRUE;
|
||
|
Str::copy(wt->cover_sheet_to_use, I"cover-sheet");
|
||
|
|
||
|
TEMPORARY_TEXT(leafname);
|
||
|
@<Translate the subweb range into details of what to weave@>;
|
||
|
pathname *H = W->redirect_weaves_to;
|
||
|
if (H == NULL) H = into;
|
||
|
if (H == NULL) {
|
||
|
if (W->single_file == NULL)
|
||
|
H = Reader::woven_folder(W);
|
||
|
else
|
||
|
H = Filenames::get_path_to(W->single_file);
|
||
|
}
|
||
|
if (to) {
|
||
|
wt->weave_to = to;
|
||
|
wt->self_contained = TRUE;
|
||
|
} else wt->weave_to = Filenames::in_folder(H, leafname);
|
||
|
DISCARD_TEXT(leafname);
|
||
|
|
||
|
@ From the range and the theme, we work out the weave title, the leafname,
|
||
|
and details of any cover-sheet to use.
|
||
|
|
||
|
@<Translate the subweb range into details of what to weave@> =
|
||
|
match_results mr = Regexp::create_mr();
|
||
|
if (Str::eq_wide_string(range, L"0")) {
|
||
|
wt->booklet_title = Str::new_from_wide_string(L"Complete Program");
|
||
|
if (W->single_file) {
|
||
|
Filenames::write_unextended_leafname(leafname, W->single_file);
|
||
|
} else {
|
||
|
WRITE_TO(leafname, "Complete");
|
||
|
}
|
||
|
if (wt->theme_match) @<Change the titling and leafname to match the tagged theme@>;
|
||
|
} else if (Regexp::match(&mr, range, L"%d+")) {
|
||
|
Str::clear(wt->booklet_title);
|
||
|
WRITE_TO(wt->booklet_title, "Chapter %S", range);
|
||
|
Str::copy(leafname, wt->booklet_title);
|
||
|
} else if (Regexp::match(&mr, range, L"%[A-O]")) {
|
||
|
Str::clear(wt->booklet_title);
|
||
|
WRITE_TO(wt->booklet_title, "Appendix %S", range);
|
||
|
Str::copy(leafname, wt->booklet_title);
|
||
|
} else if (Str::eq_wide_string(range, L"P")) {
|
||
|
wt->booklet_title = Str::new_from_wide_string(L"Preliminaries");
|
||
|
Str::copy(leafname, wt->booklet_title);
|
||
|
} else {
|
||
|
Str::copy(wt->booklet_title, range);
|
||
|
Str::copy(leafname, wt->booklet_title);
|
||
|
Str::clear(wt->cover_sheet_to_use);
|
||
|
}
|
||
|
LOOP_THROUGH_TEXT(P, leafname)
|
||
|
if ((Str::get(P) == '/') || (Str::get(P) == ' '))
|
||
|
Str::put(P, '-');
|
||
|
WRITE_TO(leafname, "%S", Formats::file_extension(wt->format));
|
||
|
Regexp::dispose_of(&mr);
|
||
|
|
||
|
@<Change the titling and leafname to match the tagged theme@> =
|
||
|
Str::clear(wt->booklet_title);
|
||
|
WRITE_TO(wt->booklet_title, "Extracts: %S", wt->theme_match->tag_name);
|
||
|
Str::copy(leafname, wt->theme_match->tag_name);
|
||
|
|
||
|
@ Each weave results in a compressed one-line printed report:
|
||
|
|
||
|
@<Report on the outcome of the weave to the console@> =
|
||
|
PRINT("[%S: %S -> %f", wt->booklet_title, wt->format->format_name, wt->weave_to);
|
||
|
Formats::report_on_post_processing(wt);
|
||
|
PRINT("]\n");
|
||
|
|
||
|
@ After every swarm, we rebuild the index. We first try for a template called
|
||
|
|chaptered-index.html| or |unchaptered-index.html|, then fall back on a
|
||
|
generic |index.html| if those aren't available in the current pattern.
|
||
|
|
||
|
=
|
||
|
void Swarm::weave_index_templates(web *W, text_stream *range, weave_pattern *pattern,
|
||
|
int self_contained) {
|
||
|
if (!(Bibliographic::data_exists(W, I"Version Number")))
|
||
|
Bibliographic::set_datum(W, I"Version Number", I" ");
|
||
|
text_stream *index_leaf = NULL;
|
||
|
if (W->chaptered) index_leaf = I"chaptered-index.html";
|
||
|
else index_leaf = I"unchaptered-index.html";
|
||
|
filename *OUT = Patterns::obtain_filename(pattern, index_leaf);
|
||
|
if (OUT == NULL) OUT = Patterns::obtain_filename(pattern, I"index.html");
|
||
|
if (OUT) Indexer::run(W, range, OUT, I"index.html", NULL, pattern);
|
||
|
if (self_contained == FALSE) Patterns::copy_payloads_into_weave(W, pattern);
|
||
|
}
|