Chapter 1: Nowebify.

This commit is contained in:
AwesomeAdam54321 2024-03-09 12:30:16 +08:00
parent eec9a49d8c
commit 5cdfe7a60b
6 changed files with 328 additions and 322 deletions

View file

@ -3,19 +3,19 @@
Mainly for HTML, to add the necessary JavaScript for unusual requirements
such as equations or footnotes.
@h Creation.
@ \section{Creation.}
At present, plugins are simply their names: Inweb knows as little as possible
about what they do. The model is just that a file being woven either does or
does not need a plugin of a given name.
=
<<*>>=
typedef struct weave_plugin {
struct text_stream *plugin_name;
int last_included_in_round;
CLASS_DEFINITION
} weave_plugin;
@ =
<<*>>=
weave_plugin *Assets::new(text_stream *name) {
weave_plugin *wp;
LOOP_OVER(wp, weave_plugin)
@ -30,7 +30,7 @@ weave_plugin *Assets::new(text_stream *name) {
@ And almost the same can be said about colour schemes, except that these we
actually look for: they will be available to some patterns and not others.
=
<<*>>=
typedef struct colour_scheme {
struct text_stream *scheme_name;
struct text_stream *prefix;
@ -39,7 +39,7 @@ typedef struct colour_scheme {
CLASS_DEFINITION
} colour_scheme;
@ =
<<*>>=
colour_scheme *Assets::find_colour_scheme(weave_pattern *pattern,
text_stream *name, text_stream *pre) {
colour_scheme *cs;
@ -61,12 +61,12 @@ colour_scheme *Assets::find_colour_scheme(weave_pattern *pattern,
return cs;
}
@h Plugin inclusion.
@ \section{Plugin inclusion.}
Plugins are included both by the pattern, if they are needed for anything
woven to that pattern, and by the individual weave order, if a particular
need has arisen on a particular file.
=
<<*>>=
int current_inclusion_round = 0;
void Assets::include_relevant_plugins(text_stream *OUT, weave_pattern *pattern,
web *W, weave_order *wv, filename *from) {
@ -86,11 +86,11 @@ no matter how many times this is called.
To include a plugin is by definition to include its assets. These may be held
either in the current pattern, or in the one it is based on, or the one
that in turn is based on, and so forth. The first-discovered asset wins:
i.e., if the current pattern's copy of the asset contains |MyAsset.png| then
this prevails over any |MyAsset.png| held by patterns further down. To do
i.e., if the current pattern's copy of the asset contains [[MyAsset.png]] then
this prevails over any [[MyAsset.png]] held by patterns further down. To do
this, we store the leafnames in a dictionary.
=
<<*>>=
void Assets::include_plugin(OUTPUT_STREAM, web *W, weave_plugin *wp,
weave_pattern *pattern, filename *from) {
if (wp->last_included_in_round == current_inclusion_round) return;
@ -125,13 +125,13 @@ void Assets::include_plugin(OUTPUT_STREAM, web *W, weave_plugin *wp,
}
}
@ Colour schemes are CSS files held slightly differently, in the |Colouring|
@ Colour schemes are CSS files held slightly differently, in the [[Colouring]]
subdirectory of (presumably) an HTML-based pattern.
A colour scheme can only be included once in each round, i.e., for each woven
file, no matter how many times this is called.
=
<<*>>=
void Assets::include_colour_scheme(OUTPUT_STREAM, web *W, colour_scheme *cs,
weave_pattern *pattern, filename *from) {
if (cs->last_included_in_round == current_inclusion_round) return;
@ -153,21 +153,22 @@ void Assets::include_colour_scheme(OUTPUT_STREAM, web *W, colour_scheme *cs,
DISCARD_TEXT(css)
}
@h Asset rules lists.
@ \section{Asset rules lists.}
The practical effect of the two function above, then, is to call
//Assets::include_asset// on each asset needed. What that function does
is highly configurable by the pattern, so we now have to show how. Each
different filename extension, such as |.jpg|, has its own rule for what to do:
different filename extension, such as [[.jpg]], has its own rule for what to do:
@e EMBED_ASSET_METHOD from 1
@e COPY_ASSET_METHOD
@e PRIVATE_COPY_ASSET_METHOD
@e COLLATE_ASSET_METHOD
<<*>>=
enum EMBED_ASSET_METHOD from 1
enum COPY_ASSET_METHOD
enum PRIVATE_COPY_ASSET_METHOD
enum COLLATE_ASSET_METHOD
=
<<*>>=
typedef struct asset_rule {
struct text_stream *applies_to;
int method; /* one of the |*_ASSET_METHOD| values above */
int method; /* one of the [[*_ASSET_METHOD]] values above */
struct text_stream *pre;
struct text_stream *post;
int transform_names;
@ -175,22 +176,22 @@ typedef struct asset_rule {
} asset_rule;
@ A pattern has a list of such rules, as follows. In each list, exactly one
rule has the empty text as its |applies_to|: that one is the default, for any
rule has the empty text as its [[applies_to]]: that one is the default, for any
file whose extension does not appear in the rules list.
(The default rule is to copy the file as a binary object, doing nothing fancy.)
=
<<*>>=
linked_list *Assets::new_asset_rules_list(void) {
linked_list *L = NEW_LINKED_LIST(asset_rule);
Assets::add_asset_rule(L, I"", I"copy", NULL);
return L;
}
@ This is called by //Patterns// in response to |assets: EXT CMD| commands. The
|CMD| part is in |line|.
@ This is called by //Patterns// in response to [[assets: EXT CMD]] commands. The
[[CMD]] part is in [[line]].
=
<<*>>=
void Assets::add_asset_rule(linked_list *L, text_stream *ext, text_stream *line,
text_file_position *tfp) {
asset_rule *R = Assets::new_rule(L, ext, line, tfp);
@ -203,23 +204,23 @@ asset_rule *Assets::new_rule(linked_list *L, text_stream *ext, text_stream *line
if (L)
LOOP_OVER_LINKED_LIST(R, asset_rule, L)
if (Str::eq_insensitive(R->applies_to, ext)) {
@<Use this R@>;
<<Use this R>>;
return R;
}
R = CREATE(asset_rule);
R->applies_to = Str::duplicate(ext);
@<Set R to defaults@>;
@<Use this R@>;
<<Set R to defaults>>;
<<Use this R>>;
return R;
}
@<Set R to defaults@> =
<<Set R to defaults>>=
R->method = COPY_ASSET_METHOD;
R->pre = Str::new();
R->post = Str::new();
R->transform_names = FALSE;
@<Use this R@> =
<<Use this R>>=
text_stream *cmd = line;
text_stream *detail = NULL;
match_results mr = Regexp::create_mr();
@ -228,13 +229,13 @@ asset_rule *Assets::new_rule(linked_list *L, text_stream *ext, text_stream *line
detail = mr.exp[1];
}
if (Str::eq(cmd, I"copy")) {
@<Set R to defaults@>; R->method = COPY_ASSET_METHOD;
<<Set R to defaults>>; R->method = COPY_ASSET_METHOD;
} else if (Str::eq(cmd, I"private copy")) {
@<Set R to defaults@>; R->method = PRIVATE_COPY_ASSET_METHOD;
<<Set R to defaults>>; R->method = PRIVATE_COPY_ASSET_METHOD;
} else if (Str::eq(cmd, I"embed")) {
@<Set R to defaults@>; R->method = EMBED_ASSET_METHOD;
<<Set R to defaults>>; R->method = EMBED_ASSET_METHOD;
} else if (Str::eq(cmd, I"collate")) {
@<Set R to defaults@>; R->method = COLLATE_ASSET_METHOD;
<<Set R to defaults>>; R->method = COLLATE_ASSET_METHOD;
} else if (Str::eq(cmd, I"prefix")) {
R->pre = Str::duplicate(detail);
} else if (Str::eq(cmd, I"suffix")) {
@ -244,11 +245,11 @@ asset_rule *Assets::new_rule(linked_list *L, text_stream *ext, text_stream *line
} else Errors::in_text_file("no such asset command", tfp);
Regexp::dispose_of(&mr);
@ Given a filename |F| for some asset, which rule applies to it? The answer
@ Given a filename [[F]] for some asset, which rule applies to it? The answer
is that if the current pattern, or any pattern it is based on, defines a rule,
then the topmost one applies; and otherwise the default rule applies.
=
<<*>>=
asset_rule *Assets::applicable_rule(weave_pattern *pattern, filename *F) {
TEMPORARY_TEXT(ext)
Filenames::write_extension(ext, F);
@ -266,11 +267,11 @@ asset_rule *Assets::applicable_rule(weave_pattern *pattern, filename *F) {
return NULL;
}
@h Inclusion of assets.
@ \section{Inclusion of assets.}
Finally, then, we can include a single asset. This has already been located,
at filename |F|, and we now know how to find the applicable rule.
at filename [[F]], and we now know how to find the applicable rule.
=
<<*>>=
pathname *Assets::include_asset(OUTPUT_STREAM, asset_rule *R, web *W, filename *F,
text_stream *trans, weave_pattern *pattern, filename *from) {
if (R == NULL) R = Assets::applicable_rule(pattern, F);
@ -280,19 +281,19 @@ pathname *Assets::include_asset(OUTPUT_STREAM, asset_rule *R, web *W, filename *
WRITE_TO(url, "%S", Filenames::get_leafname(F));
if (R->transform_names == FALSE) trans = NULL;
pathname *result = NULL;
if (Str::len(R->pre) > 0) @<Embed the prefix, if any@>;
if (Str::len(R->pre) > 0) <<Embed the prefix, if any>>;
switch (R->method) {
case EMBED_ASSET_METHOD: @<Embed asset@>; break;
case COPY_ASSET_METHOD: @<Copy asset@>; break;
case PRIVATE_COPY_ASSET_METHOD: @<Copy asset@>; break;
case COLLATE_ASSET_METHOD: @<Collate asset@>; break;
case EMBED_ASSET_METHOD: <<Embed asset>>; break;
case COPY_ASSET_METHOD: <<Copy asset>>; break;
case PRIVATE_COPY_ASSET_METHOD: <<Copy asset>>; break;
case COLLATE_ASSET_METHOD: <<Collate asset>>; break;
}
if (Str::len(R->post) > 0) @<Embed the suffix, if any@>;
if (Str::len(R->post) > 0) <<Embed the suffix, if any>>;
DISCARD_TEXT(url)
return result;
}
@<Embed the prefix, if any@> =
<<Embed the prefix, if any>>=
for (int i=0; i<Str::len(R->pre); i++) {
if (Str::includes_at(R->pre, i, I"URL")) {
WRITE("%S", url);
@ -301,11 +302,11 @@ pathname *Assets::include_asset(OUTPUT_STREAM, asset_rule *R, web *W, filename *
}
WRITE("\n");
@<Embed asset@> =
<<Embed asset>>=
if (verbose_mode) PRINT("Embed asset %f\n", F);
Assets::transform(OUT, F, trans);
@<Copy asset@> =
<<Copy asset>>=
pathname *H = W->redirect_weaves_to;
if (H == NULL) H = Reader::woven_folder(W);
if ((AP) && (R->method != PRIVATE_COPY_ASSET_METHOD)) H = AP;
@ -326,11 +327,11 @@ pathname *Assets::include_asset(OUTPUT_STREAM, asset_rule *R, web *W, filename *
Epub::note_image(W->as_ebook, rel);
}
@<Collate asset@> =
<<Collate asset>>=
if (verbose_mode) PRINT("Collate asset %f\n", F);
Collater::for_web_and_pattern(OUT, W, pattern, F, from);
@<Embed the suffix, if any@> =
<<Embed the suffix, if any>>=
for (int i=0; i<Str::len(R->post); i++) {
if (Str::includes_at(R->post, i, I"URL")) {
WRITE("%S", url);
@ -340,11 +341,11 @@ pathname *Assets::include_asset(OUTPUT_STREAM, asset_rule *R, web *W, filename *
WRITE("\n");
@ "Transforming" is what happens to a CSS file to change the class names of
its |span| and |pre| styling rules, to add a prefix text. This is what changes
its [[span]] and [[pre]] styling rules, to add a prefix text. This is what changes
the style names for colouring, say, COBOL source code from, e.g.,
|span.identifier-syntax| to |span.ConsoleText-identifier-syntax|.
[[span.identifier-syntax]] to [[span.ConsoleText-identifier-syntax]].
=
<<*>>=
typedef struct css_file_transformation {
struct text_stream *OUT;
struct text_stream *trans;

View file

@ -5,99 +5,101 @@ module.
@ Every program using //foundation// must define this:
@d PROGRAM_NAME "inweb"
<<*>>=
#define PROGRAM_NAME "inweb"
@ We need to itemise the structures we'll want to allocate. For explanations,
see //foundation: A Brief Guide to Foundation//.
@e asset_rule_CLASS
@e breadcrumb_request_CLASS
@e chapter_CLASS
@e colony_CLASS
@e colony_member_CLASS
@e colour_scheme_CLASS
@e colouring_language_block_CLASS
@e colouring_rule_CLASS
@e defined_constant_CLASS
@e enumeration_set_CLASS
@e footnote_CLASS
@e hash_table_entry_CLASS
@e hash_table_entry_usage_CLASS
@e language_function_CLASS
@e language_type_CLASS
@e macro_usage_CLASS
@e makefile_specifics_CLASS
@e nonterminal_variable_CLASS
@e para_macro_CLASS
@e paragraph_CLASS
@e paragraph_tagging_CLASS
@e preform_nonterminal_CLASS
@e programming_language_CLASS
@e reserved_word_CLASS
@e section_CLASS
@e source_line_CLASS
@e structure_element_CLASS
@e tangle_target_CLASS
@e tex_results_CLASS
@e text_literal_CLASS
@e theme_tag_CLASS
@e weave_format_CLASS
@e weave_pattern_CLASS
@e weave_plugin_CLASS
@e weave_order_CLASS
@e web_CLASS
@e writeme_asset_CLASS
<<*>>=
enum asset_rule_CLASS
enum breadcrumb_request_CLASS
enum chapter_CLASS
enum colony_CLASS
enum colony_member_CLASS
enum colour_scheme_CLASS
enum colouring_language_block_CLASS
enum colouring_rule_CLASS
enum defined_constant_CLASS
enum enumeration_set_CLASS
enum footnote_CLASS
enum hash_table_entry_CLASS
enum hash_table_entry_usage_CLASS
enum language_function_CLASS
enum language_type_CLASS
enum macro_usage_CLASS
enum makefile_specifics_CLASS
enum nonterminal_variable_CLASS
enum para_macro_CLASS
enum paragraph_CLASS
enum paragraph_tagging_CLASS
enum preform_nonterminal_CLASS
enum programming_language_CLASS
enum reserved_word_CLASS
enum section_CLASS
enum source_line_CLASS
enum structure_element_CLASS
enum tangle_target_CLASS
enum tex_results_CLASS
enum text_literal_CLASS
enum theme_tag_CLASS
enum weave_format_CLASS
enum weave_pattern_CLASS
enum weave_plugin_CLASS
enum weave_order_CLASS
enum web_CLASS
enum writeme_asset_CLASS
@e weave_document_node_CLASS
@e weave_head_node_CLASS
@e weave_body_node_CLASS
@e weave_tail_node_CLASS
@e weave_section_header_node_CLASS
@e weave_section_footer_node_CLASS
@e weave_chapter_header_node_CLASS
@e weave_chapter_footer_node_CLASS
@e weave_verbatim_node_CLASS
@e weave_section_purpose_node_CLASS
@e weave_subheading_node_CLASS
@e weave_bar_node_CLASS
@e weave_linebreak_node_CLASS
@e weave_pagebreak_node_CLASS
@e weave_paragraph_heading_node_CLASS
@e weave_endnote_node_CLASS
@e weave_material_node_CLASS
@e weave_figure_node_CLASS
@e weave_extract_node_CLASS
@e weave_audio_node_CLASS
@e weave_download_node_CLASS
@e weave_video_node_CLASS
@e weave_embed_node_CLASS
@e weave_pmac_node_CLASS
@e weave_vskip_node_CLASS
@e weave_chapter_node_CLASS
@e weave_section_node_CLASS
@e weave_code_line_node_CLASS
@e weave_function_usage_node_CLASS
@e weave_commentary_node_CLASS
@e weave_carousel_slide_node_CLASS
@e weave_toc_node_CLASS
@e weave_toc_line_node_CLASS
@e weave_chapter_title_page_node_CLASS
@e weave_defn_node_CLASS
@e weave_source_code_node_CLASS
@e weave_url_node_CLASS
@e weave_footnote_cue_node_CLASS
@e weave_begin_footnote_text_node_CLASS
@e weave_display_line_node_CLASS
@e weave_function_defn_node_CLASS
@e weave_item_node_CLASS
@e weave_grammar_index_node_CLASS
@e weave_inline_node_CLASS
@e weave_locale_node_CLASS
@e weave_maths_node_CLASS
enum weave_document_node_CLASS
enum weave_head_node_CLASS
enum weave_body_node_CLASS
enum weave_tail_node_CLASS
enum weave_section_header_node_CLASS
enum weave_section_footer_node_CLASS
enum weave_chapter_header_node_CLASS
enum weave_chapter_footer_node_CLASS
enum weave_verbatim_node_CLASS
enum weave_section_purpose_node_CLASS
enum weave_subheading_node_CLASS
enum weave_bar_node_CLASS
enum weave_linebreak_node_CLASS
enum weave_pagebreak_node_CLASS
enum weave_paragraph_heading_node_CLASS
enum weave_endnote_node_CLASS
enum weave_material_node_CLASS
enum weave_figure_node_CLASS
enum weave_extract_node_CLASS
enum weave_audio_node_CLASS
enum weave_download_node_CLASS
enum weave_video_node_CLASS
enum weave_embed_node_CLASS
enum weave_pmac_node_CLASS
enum weave_vskip_node_CLASS
enum weave_chapter_node_CLASS
enum weave_section_node_CLASS
enum weave_code_line_node_CLASS
enum weave_function_usage_node_CLASS
enum weave_commentary_node_CLASS
enum weave_carousel_slide_node_CLASS
enum weave_toc_node_CLASS
enum weave_toc_line_node_CLASS
enum weave_chapter_title_page_node_CLASS
enum weave_defn_node_CLASS
enum weave_source_code_node_CLASS
enum weave_url_node_CLASS
enum weave_footnote_cue_node_CLASS
enum weave_begin_footnote_text_node_CLASS
enum weave_display_line_node_CLASS
enum weave_function_defn_node_CLASS
enum weave_item_node_CLASS
enum weave_grammar_index_node_CLASS
enum weave_inline_node_CLASS
enum weave_locale_node_CLASS
enum weave_maths_node_CLASS
@ And then expand the following macros, all defined in //Memory//.
=
<<*>>=
DECLARE_CLASS_ALLOCATED_IN_ARRAYS(source_line, 1000)
DECLARE_CLASS(asset_rule)
DECLARE_CLASS(breadcrumb_request)

View file

@ -3,63 +3,63 @@
To parse the command line arguments with which inweb was called,
and to handle any errors it needs to issue.
@h Instructions.
@ \section{Instructions.}
The following structure exists just to hold what the user specified on the
command line: there will only ever be one of these.
=
<<*>>=
typedef struct inweb_instructions {
int inweb_mode; /* our main mode of operation: one of the |*_MODE| constants */
int inweb_mode; /* our main mode of operation: one of the [[*_MODE]] constants */
struct pathname *chosen_web; /* project folder relative to cwd */
struct filename *chosen_file; /* or, single file relative to cwd */
struct text_stream *chosen_range; /* which subset of this web we apply to (often, all of it) */
int chosen_range_actually_chosen; /* rather than being a default choice */
int swarm_mode; /* relevant to weaving only: one of the |*_SWARM| constants */
struct text_stream *tag_setting; /* |-weave-tag X|: weave, but only the material tagged X */
struct text_stream *weave_pattern; /* |-weave-as X|: for example, |-weave-to HTML| */
int swarm_mode; /* relevant to weaving only: one of the [[*_SWARM]] constants */
struct text_stream *tag_setting; /* [[-weave-tag X]]: weave, but only the material tagged X */
struct text_stream *weave_pattern; /* [[-weave-as X|: for example, |-weave-to HTML]] */
int show_languages_switch; /* |-show-languages|: print list of available PLs */
int catalogue_switch; /* |-catalogue|: print catalogue of sections */
int functions_switch; /* |-functions|: print catalogue of functions within sections */
int structures_switch; /* |-structures|: print catalogue of structures within sections */
int advance_switch; /* |-advance-build|: advance build file for web */
int scan_switch; /* |-scan|: simply show the syntactic scan of the source */
int ctags_switch; /* |-ctags|: generate a set of Universal Ctags on each tangle */
struct filename *weave_to_setting; /* |-weave-to X|: the pathname X, if supplied */
struct pathname *weave_into_setting; /* |-weave-into X|: the pathname X, if supplied */
int show_languages_switch; /* [[-show-languages]]: print list of available PLs */
int catalogue_switch; /* [[-catalogue]]: print catalogue of sections */
int functions_switch; /* [[-functions]]: print catalogue of functions within sections */
int structures_switch; /* [[-structures]]: print catalogue of structures within sections */
int advance_switch; /* [[-advance-build]]: advance build file for web */
int scan_switch; /* [[-scan]]: simply show the syntactic scan of the source */
int ctags_switch; /* [[-ctags]]: generate a set of Universal Ctags on each tangle */
struct filename *weave_to_setting; /* [[-weave-to X]]: the pathname X, if supplied */
struct pathname *weave_into_setting; /* [[-weave-into X]]: the pathname X, if supplied */
int sequential; /* give the sections sequential sigils */
struct filename *tangle_setting; /* |-tangle-to X|: the pathname X, if supplied */
struct filename *ctags_setting; /* |-ctags-to X|: the pathname X, if supplied */
struct filename *makefile_setting; /* |-makefile X|: the filename X, if supplied */
struct filename *gitignore_setting; /* |-gitignore X|: the filename X, if supplied */
struct filename *advance_setting; /* |-advance-build-file X|: advance build file X */
struct filename *writeme_setting; /* |-write-me X|: advance build file X */
struct filename *prototype_setting; /* |-prototype X|: the pathname X, if supplied */
struct filename *navigation_setting; /* |-navigation X|: the filename X, if supplied */
struct filename *colony_setting; /* |-colony X|: the filename X, if supplied */
struct text_stream *member_setting; /* |-member X|: sets web to member X of colony */
struct linked_list *breadcrumb_setting; /* of |breadcrumb_request| */
struct text_stream *platform_setting; /* |-platform X|: sets prevailing platform to X */
int verbose_switch; /* |-verbose|: print names of files read to stdout */
struct filename *tangle_setting; /* [[-tangle-to X]]: the pathname X, if supplied */
struct filename *ctags_setting; /* [[-ctags-to X]]: the pathname X, if supplied */
struct filename *makefile_setting; /* [[-makefile X]]: the filename X, if supplied */
struct filename *gitignore_setting; /* [[-gitignore X]]: the filename X, if supplied */
struct filename *advance_setting; /* [[-advance-build-file X]]: advance build file X */
struct filename *writeme_setting; /* [[-write-me X]]: advance build file X */
struct filename *prototype_setting; /* [[-prototype X]]: the pathname X, if supplied */
struct filename *navigation_setting; /* [[-navigation X]]: the filename X, if supplied */
struct filename *colony_setting; /* [[-colony X]]: the filename X, if supplied */
struct text_stream *member_setting; /* [[-member X]]: sets web to member X of colony */
struct linked_list *breadcrumb_setting; /* of [[breadcrumb_request]] */
struct text_stream *platform_setting; /* [[-platform X]]: sets prevailing platform to X */
int verbose_switch; /* [[-verbose]]: print names of files read to stdout */
int targets; /* used only for parsing */
struct programming_language *test_language_setting; /* |-test-language X| */
struct filename *test_language_on_setting; /* |-test-language-on X| */
struct programming_language *test_language_setting; /* [[-test-language X]] */
struct filename *test_language_on_setting; /* [[-test-language-on X]] */
struct pathname *import_setting; /* |-import X|: where to find imported webs */
struct pathname *import_setting; /* [[-import X]]: where to find imported webs */
} inweb_instructions;
@h Reading the command line.
@ \section{Reading the command line.}
The dull work of this is done by the Foundation module: all we need to do is
to enumerate constants for the Inweb-specific command line switches, and
then declare them.
=
<<*>>=
inweb_instructions Configuration::read(int argc, char **argv) {
inweb_instructions args;
@<Initialise the args@>;
@<Declare the command-line switches specific to Inweb@>;
<<Initialise the args>>;
<<Declare the command-line switches specific to Inweb>>;
CommandLine::read(argc, argv, &args, &Configuration::switch, &Configuration::bareword);
Configuration::member_and_colony(&args);
if (Str::len(args.weave_pattern) == 0) WRITE_TO(args.weave_pattern, "HTML");
@ -75,7 +75,7 @@ inweb_instructions Configuration::read(int argc, char **argv) {
return args;
}
@<Initialise the args@> =
<<Initialise the args>>=
args.inweb_mode = NO_MODE;
args.swarm_mode = SWARM_OFF_SWM;
args.show_languages_switch = FALSE;
@ -112,58 +112,59 @@ inweb_instructions Configuration::read(int argc, char **argv) {
args.test_language_on_setting = NULL;
@ The CommandLine section of Foundation needs to be told what command-line
switches we want, other than the standard set (such as |-help|) which it
switches we want, other than the standard set (such as [[-help]]) which it
provides automatically.
@e VERBOSE_CLSW
@e IMPORT_FROM_CLSW
<<*>>=
enum VERBOSE_CLSW
enum IMPORT_FROM_CLSW
@e LANGUAGES_CLSG
enum LANGUAGES_CLSG
@e LANGUAGE_CLSW
@e LANGUAGES_CLSW
@e SHOW_LANGUAGES_CLSW
@e TEST_LANGUAGE_CLSW
@e TEST_LANGUAGE_ON_CLSW
enum LANGUAGE_CLSW
enum LANGUAGES_CLSW
enum SHOW_LANGUAGES_CLSW
enum TEST_LANGUAGE_CLSW
enum TEST_LANGUAGE_ON_CLSW
@e ANALYSIS_CLSG
enum ANALYSIS_CLSG
@e CATALOGUE_CLSW
@e FUNCTIONS_CLSW
@e STRUCTURES_CLSW
@e ADVANCE_CLSW
@e GITIGNORE_CLSW
@e MAKEFILE_CLSW
@e WRITEME_CLSW
@e PLATFORM_CLSW
@e ADVANCE_FILE_CLSW
@e PROTOTYPE_CLSW
@e SCAN_CLSW
enum CATALOGUE_CLSW
enum FUNCTIONS_CLSW
enum STRUCTURES_CLSW
enum ADVANCE_CLSW
enum GITIGNORE_CLSW
enum MAKEFILE_CLSW
enum WRITEME_CLSW
enum PLATFORM_CLSW
enum ADVANCE_FILE_CLSW
enum PROTOTYPE_CLSW
enum SCAN_CLSW
@e WEAVING_CLSG
enum WEAVING_CLSG
@e WEAVE_CLSW
@e WEAVE_INTO_CLSW
@e WEAVE_TO_CLSW
@e OPEN_CLSW
@e WEAVE_AS_CLSW
@e WEAVE_TAG_CLSW
@e BREADCRUMB_CLSW
@e NAVIGATION_CLSW
enum WEAVE_CLSW
enum WEAVE_INTO_CLSW
enum WEAVE_TO_CLSW
enum OPEN_CLSW
enum WEAVE_AS_CLSW
enum WEAVE_TAG_CLSW
enum BREADCRUMB_CLSW
enum NAVIGATION_CLSW
@e TANGLING_CLSG
enum TANGLING_CLSG
@e TANGLE_CLSW
@e TANGLE_TO_CLSW
@e CTAGS_TO_CLSW
@e CTAGS_CLSW
enum TANGLE_CLSW
enum TANGLE_TO_CLSW
enum CTAGS_TO_CLSW
enum CTAGS_CLSW
@e COLONIAL_CLSG
enum COLONIAL_CLSG
@e COLONY_CLSW
@e MEMBER_CLSW
enum COLONY_CLSW
enum MEMBER_CLSW
@<Declare the command-line switches specific to Inweb@> =
<<Declare the command-line switches specific to Inweb>>=
CommandLine::declare_heading(L"inweb: a tool for literate programming\n\n"
L"Usage: inweb WEB OPTIONS RANGE\n\n"
L"WEB must be a directory holding a literate program (a 'web')\n\n"
@ -265,9 +266,9 @@ provides automatically.
CommandLine::declare_switch(IMPORT_FROM_CLSW, L"import-from", 2,
L"specify that imported modules are at pathname X");
@ Foundation calls this on any |-switch| argument read:
@ Foundation calls this on any [[-switch]] argument read:
=
<<*>>=
void Configuration::switch(int id, int val, text_stream *arg, void *state) {
inweb_instructions *args = (inweb_instructions *) state;
switch (id) {
@ -379,7 +380,7 @@ void Configuration::switch(int id, int val, text_stream *arg, void *state) {
@ The colony file is, in one sense, a collection of presets for the web
location and its navigational aids.
=
<<*>>=
void Configuration::member_and_colony(inweb_instructions *args) {
if (args->colony_setting) Colonies::load(args->colony_setting);
if (Str::len(args->member_setting) > 0) {
@ -402,10 +403,10 @@ void Configuration::member_and_colony(inweb_instructions *args) {
}
@ Foundation calls this routine on any command-line argument which is
neither a switch (like |-weave|), nor an argument for a switch (like
the |X| in |-weave-as X|).
neither a switch (like [[-weave]]), nor an argument for a switch (like
the [[X]] in [[-weave-as X]]).
=
<<*>>=
void Configuration::bareword(int id, text_stream *opt, void *state) {
inweb_instructions *args = (inweb_instructions *) state;
if ((args->chosen_web == NULL) && (args->chosen_file == NULL)) {
@ -416,11 +417,11 @@ void Configuration::bareword(int id, text_stream *opt, void *state) {
} else Configuration::set_range(args, opt);
}
@ Here we read a range. The special ranges |index|, |chapters| and |sections|
are converted into swarm settings instead. |all| is simply an alias for |0|.
@ Here we read a range. The special ranges [[index]], [[chapters]] and [[sections]]
are converted into swarm settings instead. [[all]] is simply an alias for [[0]].
Otherwise, a range is a chapter number/letter, or a section range.
=
<<*>>=
void Configuration::set_range(inweb_instructions *args, text_stream *opt) {
match_results mr = Regexp::create_mr();
if (Str::eq_wide_string(opt, L"index")) {
@ -452,7 +453,7 @@ void Configuration::set_range(inweb_instructions *args, text_stream *opt) {
@ We can only be in a single mode at a time:
=
<<*>>=
void Configuration::set_fundamental_mode(inweb_instructions *args, int new_material) {
if ((args->inweb_mode != NO_MODE) && (args->inweb_mode != new_material))
Errors::fatal("can only do one at a time - weaving, tangling or analysing");

View file

@ -2,32 +2,32 @@
Managing weave patterns, which are bundled configuration settings for weaving.
@h Reading in.
@ \section{Reading in.}
Patterns are stored as directories in the file system, and are identified by
names such as |HTML|. On request, we need to find the directory corresponding
names such as [[HTML]]. On request, we need to find the directory corresponding
to such a name, and to read it in. This structure holds the result:
=
<<*>>=
typedef struct weave_pattern {
struct text_stream *pattern_name; /* such as |HTML| */
struct text_stream *pattern_name; /* such as [[HTML]] */
struct pathname *pattern_location; /* the directory */
struct weave_pattern *based_on; /* inherit from which other pattern? */
struct weave_format *pattern_format; /* such as |DVI|: the desired final format */
struct linked_list *plugins; /* of |weave_plugin|: any extras needed */
struct linked_list *colour_schemes; /* of |colour_scheme|: any extras needed */
struct weave_format *pattern_format; /* such as [[DVI]]: the desired final format */
struct linked_list *plugins; /* of [[weave_plugin]]: any extras needed */
struct linked_list *colour_schemes; /* of [[colour_scheme]]: any extras needed */
struct text_stream *mathematics_plugin; /* name only, not a |weave_pattern *| */
struct text_stream *footnotes_plugin; /* name only, not a |weave_pattern *| */
struct text_stream *mathematics_plugin; /* name only, not a [[weave_pattern *]] */
struct text_stream *footnotes_plugin; /* name only, not a [[weave_pattern *]] */
struct text_stream *initial_extension; /* filename extension, that is */
struct linked_list *post_commands; /* of |text_stream| */
struct linked_list *blocked_templates; /* of |text_stream| */
struct linked_list *post_commands; /* of [[text_stream]] */
struct linked_list *blocked_templates; /* of [[text_stream]] */
struct linked_list *asset_rules; /* of |asset_rule| */
struct linked_list *asset_rules; /* of [[asset_rule]] */
int show_abbrevs; /* show section range abbreviations in the weave? */
int number_sections; /* insert section numbers into the weave? */
struct text_stream *default_range; /* for example, |sections| */
struct text_stream *default_range; /* for example, [[sections]] */
struct web *patterned_for; /* the web which caused this to be read in */
@ -38,17 +38,17 @@ typedef struct weave_pattern {
@ When a given web needs a pattern with a given name, this is where it comes.
=
<<*>>=
weave_pattern *Patterns::find(web *W, text_stream *name) {
filename *pattern_file = NULL;
weave_pattern *wp = CREATE(weave_pattern);
@<Initialise the pattern structure@>;
@<Locate the pattern directory@>;
@<Read in the pattern.txt file@>;
<<Initialise the pattern structure>>;
<<Locate the pattern directory>>;
<<Read in the pattern.txt file>>;
return wp;
}
@<Initialise the pattern structure@> =
<<Initialise the pattern structure>>=
wp->pattern_name = Str::duplicate(name);
wp->pattern_location = NULL;
wp->plugins = NEW_LINKED_LIST(weave_plugin);
@ -66,7 +66,7 @@ weave_pattern *Patterns::find(web *W, text_stream *name) {
wp->commands = 0;
wp->name_command_given = FALSE;
@<Locate the pattern directory@> =
<<Locate the pattern directory>>=
wp->pattern_location = NULL;
pathname *CP = Colonies::patterns_path();
if (CP) {
@ -89,7 +89,7 @@ weave_pattern *Patterns::find(web *W, text_stream *name) {
if (wp->pattern_location == NULL)
Errors::fatal_with_text("no such weave pattern as '%S'", name);
@<Read in the pattern.txt file@> =
<<Read in the pattern.txt file>>=
if (pattern_file)
TextFiles::read(pattern_file, FALSE, "can't open pattern.txt file",
TRUE, Patterns::scan_pattern_line, NULL, wp);
@ -99,16 +99,16 @@ weave_pattern *Patterns::find(web *W, text_stream *name) {
Errors::fatal_with_text("pattern did not name itself at the top", name);
@ The Foundation module provides a standard way to scan text files line by
line, and this is used to send each line in the |pattern.txt| file to the
line, and this is used to send each line in the [[pattern.txt]] file to the
following routine:
=
<<*>>=
void Patterns::scan_pattern_line(text_stream *line, text_file_position *tfp, void *X) {
weave_pattern *wp = (weave_pattern *) X;
Str::trim_white_space(line); /* ignore trailing space */
if (Str::len(line) == 0) return; /* ignore blank lines */
if (Str::get_first_char(line) == '#') return; /* lines opening with |#| are comments */
if (Str::get_first_char(line) == '#') return; /* lines opening with [[#]] are comments */
wp->commands++;
match_results mr = Regexp::create_mr();
@ -180,7 +180,7 @@ void Patterns::scan_pattern_line(text_stream *line, text_file_position *tfp, voi
Regexp::dispose_of(&mr);
}
@ =
<<*>>=
int Patterns::yes_or_no(text_stream *arg, text_file_position *tfp) {
if (Str::eq(arg, I"yes")) return TRUE;
if (Str::eq(arg, I"no")) return FALSE;
@ -200,11 +200,11 @@ text_stream *Patterns::plugin_name(text_stream *arg, text_file_position *tfp) {
return Str::duplicate(arg);
}
@h Post-processing.
@ \section{Post-processing.}
In effect, a pattern can hold a shell script to run after each weave (subset)
completes.
=
<<*>>=
void Patterns::post_process(weave_pattern *pattern, weave_order *wv) {
text_stream *T;
LOOP_OVER_LINKED_LIST(T, text_stream, pattern->post_commands) {
@ -241,14 +241,14 @@ void Patterns::post_process(weave_pattern *pattern, weave_order *wv) {
}
}
@h Obtaining files.
Patterns provide place template files, such as |template-body.html|, in
@ \section{Obtaining files.}
Patterns provide place template files, such as [[template-body.html]], in
their root directories.
Note that if you're rash enough to set up a cycle of patterns inheriting
from each other then this routine will lock up into an infinite loop.
=
<<*>>=
filename *Patterns::find_template(weave_pattern *pattern, text_stream *leafname) {
for (weave_pattern *wp = pattern; wp; wp = wp->based_on) {
text_stream *T;
@ -263,7 +263,7 @@ filename *Patterns::find_template(weave_pattern *pattern, text_stream *leafname)
@ Similarly, but looking in an intermediate directory:
=
<<*>>=
filename *Patterns::find_file_in_subdirectory(weave_pattern *pattern,
text_stream *dirname, text_stream *leafname) {
for (weave_pattern *wp = pattern; wp; wp = wp->based_on) {
@ -274,7 +274,7 @@ filename *Patterns::find_file_in_subdirectory(weave_pattern *pattern,
return NULL;
}
@ =
<<*>>=
void Patterns::include_plugins(OUTPUT_STREAM, web *W, weave_pattern *pattern, filename *from) {
for (weave_pattern *p = pattern; p; p = p->based_on) {
weave_plugin *wp;

View file

@ -6,7 +6,7 @@ this plan out.
@ Inweb syntax has gradually shifted over the years, but there are two main
versions: the second was cleaned up and simplified from the first in 2019.
=
<<*>>=
int default_inweb_syntax = V2_SYNTAX;
@ Inweb has a single fundamental mode of operation: on any given run, it
@ -14,21 +14,22 @@ is either tangling, weaving or analysing. These processes use the same input
and parsing code, but then do very different things to produce their output,
so the fork in the road is not met until halfway through Inweb's execution.
@e NO_MODE from 0 /* a special mode for doing nothing except printing command-line syntax */
@e ANALYSE_MODE /* for -scan, -catalogue, -functions and so on */
@e TANGLE_MODE /* for any form of -tangle */
@e WEAVE_MODE /* for any form of -weave */
@e TRANSLATE_MODE /* a special mode for translating a multi-web makefile */
<<*>>=
enum NO_MODE from 0 /* a special mode for doing nothing except printing command-line syntax */
enum ANALYSE_MODE /* for -scan, -catalogue, -functions and so on */
enum TANGLE_MODE /* for any form of -tangle */
enum WEAVE_MODE /* for any form of -weave */
enum TRANSLATE_MODE /* a special mode for translating a multi-web makefile */
=
<<*>>=
int fundamental_mode = NO_MODE;
@ This operation will be applied to a single web, and will apply to the whole
of that web unless we specify otherwise. Subsets of the web are represented by
short pieces of text called "ranges". This can be a section range like
|2/pine|, a chapter number like |12|, an appendix letter |A| or the
preliminaries block |P|, the special chapter |S| for the "Sections" chapter
of an unchaptered web, or the special value |0| to mean the entire web (which
[[2/pine]], a chapter number like [[12]], an appendix letter [[A]] or the
preliminaries block [[P]], the special chapter [[S]] for the "Sections" chapter
of an unchaptered web, or the special value [[0]] to mean the entire web (which
is the default).
When weaving in "swarm mode", however, the user chooses a multiplicity of
@ -36,33 +37,34 @@ operations rather than just one. Now it's no longer a matter of weaving a
particular section or chapter: we can weave all of the sections or chapters,
one after another.
@e SWARM_OFF_SWM from 0
@e SWARM_INDEX_SWM /* make index(es) as if swarming, but don't actually swarm */
@e SWARM_CHAPTERS_SWM /* swarm the chapters */
@e SWARM_SECTIONS_SWM /* swarm the individual sections */
<<*>>=
enum SWARM_OFF_SWM from 0
enum SWARM_INDEX_SWM /* make index(es) as if swarming, but don't actually swarm */
enum SWARM_CHAPTERS_SWM /* swarm the chapters */
enum SWARM_SECTIONS_SWM /* swarm the individual sections */
@ In order to run, Inweb needs to know where it is installed -- this
enables it to find its configuration file, the macros file, and so on.
Unless told otherwise on the command line, we'll assume Inweb is present
in the current working directory. The "materials" will then be in a further
subfolder called |Materials|.
subfolder called [[Materials]].
=
<<*>>=
pathname *path_to_inweb = NULL; /* where we are installed */
pathname *path_to_inweb_materials = NULL; /* the materials pathname */
pathname *path_to_inweb_patterns = NULL; /* where built-in patterns are stored */
@ We count the errors in order to be able to exit with a suitable exit code.
=
<<*>>=
int no_inweb_errors = 0;
int verbose_mode = FALSE;
@h Main routine.
@ \section{Main routine.}
=
<<*>>=
int main(int argc, char **argv) {
@<Initialise inweb@>;
<<Initialise inweb>>;
inweb_instructions args = Configuration::read(argc, argv);
verbose_mode = args.verbose_switch;
fundamental_mode = args.inweb_mode;
@ -76,22 +78,22 @@ int main(int argc, char **argv) {
Main::follow_instructions(&args);
@<Shut inweb down@>;
<<Shut inweb down>>;
}
@<Initialise inweb@> =
<<Initialise inweb>>=
Foundation::start(argc, argv);
Formats::create_weave_formats();
@<Shut inweb down@> =
<<Shut inweb down>>=
Foundation::end();
return (no_inweb_errors == 0)?0:1;
@h Following instructions.
@ \section{Following instructions.}
This is the whole program in a nutshell, and it's a pretty old-school
program: some input, some thinking, a choice of three forms of output.
=
<<*>>=
void Main::follow_instructions(inweb_instructions *ins) {
web *W = NULL;
if ((ins->chosen_web) || (ins->chosen_file)) {
@ -102,16 +104,16 @@ void Main::follow_instructions(inweb_instructions *ins) {
Parser::parse_web(W, ins->inweb_mode);
}
if (no_inweb_errors == 0) {
if (ins->inweb_mode == TRANSLATE_MODE) @<Translate a makefile@>
else if (ins->show_languages_switch) @<List available programming languages@>
else if ((ins->test_language_setting) || (ins->test_language_on_setting)) @<Test a language@>
else if (ins->inweb_mode != NO_MODE) @<Analyse, tangle or weave an existing web@>;
if (ins->inweb_mode == TRANSLATE_MODE) <<Translate a makefile>>
else if (ins->show_languages_switch) <<List available programming languages>>
else if ((ins->test_language_setting) || (ins->test_language_on_setting)) <<Test a language>>
else if (ins->inweb_mode != NO_MODE) <<Analyse, tangle or weave an existing web>>;
}
}
@ This is a one-off featurette:
@<Translate a makefile@> =
<<Translate a makefile>>=
if ((ins->makefile_setting) && (ins->prototype_setting == NULL))
ins->prototype_setting = Filenames::from_text(I"script.mkscript");
if ((ins->gitignore_setting) && (ins->prototype_setting == NULL))
@ -130,13 +132,13 @@ void Main::follow_instructions(inweb_instructions *ins) {
@ As is this:
@<List available programming languages@> =
<<List available programming languages>>=
Languages::read_definitions(NULL);
Languages::show(STDOUT);
@ And this:
@<Test a language@> =
<<Test a language>>=
if ((ins->test_language_setting) && (ins->test_language_on_setting)) {
TEMPORARY_TEXT(matter)
TEMPORARY_TEXT(coloured)
@ -152,15 +154,15 @@ void Main::follow_instructions(inweb_instructions *ins) {
@ But otherwise we do something with the given web:
@<Analyse, tangle or weave an existing web@> =
<<Analyse, tangle or weave an existing web>>=
if (ins->inweb_mode != ANALYSE_MODE) Reader::print_web_statistics(W);
if (ins->inweb_mode == ANALYSE_MODE) @<Analyse the web@>;
if (ins->inweb_mode == TANGLE_MODE) @<Tangle the web@>;
if (ins->inweb_mode == WEAVE_MODE) @<Weave the web@>;
if (ins->inweb_mode == ANALYSE_MODE) <<Analyse the web>>;
if (ins->inweb_mode == TANGLE_MODE) <<Tangle the web>>;
if (ins->inweb_mode == WEAVE_MODE) <<Weave the web>>;
@ "Analysis" invokes any combination of the following diagnostic tools:
@<Analyse the web@> =
<<Analyse the web>>=
if (ins->swarm_mode != SWARM_OFF_SWM)
Errors::fatal("only specific parts of the web can be analysed");
if (ins->catalogue_switch)
@ -189,17 +191,17 @@ quite different language from the rest of the web, and tangles to a different
output, but needs to be part of the web since it's essential to an understanding
of the whole system.
In this section we determine |tn|, the target number wanted, and |tangle_to|,
In this section we determine [[tn]], the target number wanted, and [[tangle_to]],
the filename of the tangled code to write. This may have been set at the command
line , but otherwise we impose a sensible choice based on the target.
@<Tangle the web@> =
<<Tangle the web>>=
TEMPORARY_TEXT(tangle_leaf)
tangle_target *tn = NULL;
if (Str::eq_wide_string(ins->chosen_range, L"0")) {
@<Work out main tangle destination@>;
<<Work out main tangle destination>>;
} else if (Reader::get_section_for_range(W, ins->chosen_range)) {
@<Work out an independent tangle destination, from one section of the web@>;
<<Work out an independent tangle destination, from one section of the web>>;
}
if (Str::len(tangle_leaf) == 0) { Errors::fatal("no tangle destination known"); }
@ -217,7 +219,7 @@ line , but otherwise we impose a sensible choice based on the target.
@ Here the target number is 0, and the tangle is of the main part of the web,
which for many small webs will be the entire thing.
@<Work out main tangle destination@> =
<<Work out main tangle destination>>=
tn = NULL;
if (Bibliographic::data_exists(W->md, I"Short Title"))
Str::copy(tangle_leaf, Bibliographic::get_datum(W->md, I"Short Title"));
@ -225,9 +227,9 @@ which for many small webs will be the entire thing.
Str::copy(tangle_leaf, Bibliographic::get_datum(W->md, I"Title"));
Str::concatenate(tangle_leaf, W->main_language->file_extension);
@ If someone tangles, say, |2/eg| then the default filename is "Example Section".
@ If someone tangles, say, [[2/eg]] then the default filename is "Example Section".
@<Work out an independent tangle destination, from one section of the web@> =
<<Work out an independent tangle destination, from one section of the web>>=
section *S = Reader::get_section_for_range(W, ins->chosen_range);
tn = S->sect_target;
if (tn == NULL) Errors::fatal("section cannot be independently tangled");
@ -235,7 +237,7 @@ which for many small webs will be the entire thing.
@ Weaving is not actually easier, it's just more thoroughly delegated:
@<Weave the web@> =
<<Weave the web>>=
Numbering::number_web(W);
theme_tag *tag = Tags::find_by_name(ins->tag_setting, FALSE);
@ -248,7 +250,7 @@ which for many small webs will be the entire thing.
int r = Formats::begin_weaving(W, pattern);
if (r != SWARM_OFF_SWM) ins->swarm_mode = r;
@<Assign section numbers for printing purposes@>;
<<Assign section numbers for printing purposes>>;
if (ins->swarm_mode == SWARM_OFF_SWM) {
Swarm::weave_subset(W, ins->chosen_range, FALSE, tag, pattern,
ins->weave_to_setting, ins->weave_into_setting,
@ -260,18 +262,18 @@ which for many small webs will be the entire thing.
}
Formats::end_weaving(W, pattern);
@<Assign section numbers for printing purposes@> =
<<Assign section numbers for printing purposes>>=
section *S; int k = 1;
LOOP_OVER(S, section)
if (Reader::range_within(S->md->sect_range, ins->chosen_range))
S->printed_number = k++;
@h Error messages.
@ \section{Error messages.}
The Foundation module provides convenient functions to issue error messages,
but we'll use the following wrapper when issuing an error at a line of web
source:
=
<<*>>=
void Main::error_in_web(text_stream *message, source_line *sl) {
if (sl) {
Errors::in_text_file_S(message, &(sl->source));

View file

@ -3,7 +3,7 @@
To feed multiple output requests to the weaver, and to present
weaver results, and update indexes or contents pages.
@h Swarming.
@ \section{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).
@ -11,10 +11,10 @@ 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.
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_order *swarm_leader = NULL; /* the most inclusive one we weave */
void Swarm::weave(web *W, text_stream *range, int swarm_mode, theme_tag *tag,
@ -47,26 +47,26 @@ void Swarm::weave(web *W, text_stream *range, int swarm_mode, theme_tag *tag,
from the swarm, or has been specified at the command line (in which case
the call comes from Program Control).
=
<<*>>=
weave_order *Swarm::weave_subset(web *W, text_stream *range, int open_afterwards,
theme_tag *tag, weave_pattern *pattern, filename *to, pathname *into,
linked_list *breadcrumbs, filename *navigation) {
weave_order *wv = NULL;
if (no_inweb_errors == 0) {
Analyser::analyse_code(W);
@<Compile a set of instructions for the weaver@>;
<<Compile a set of instructions for the weaver>>;
if (Weaver::weave(wv) == 0) /* i.e., the number of lines woven was zero */
Errors::fatal("empty weave request");
Patterns::post_process(wv->pattern, wv);
Formats::post_process_weave(wv, open_afterwards);
@<Report on the outcome of the weave to the console@>;
<<Report on the outcome of the weave to the console>>;
}
return wv;
}
@ Each individual weave generates one of the following sets of instructions:
=
<<*>>=
typedef struct weave_order {
struct web *weave_web; /* which web we weave */
struct text_stream *weave_range; /* which parts of the web in this weave */
@ -78,16 +78,16 @@ typedef struct weave_order {
void *post_processing_results; /* optional typesetting diagnostics after running through */
int self_contained; /* make a self-contained file if possible */
struct linked_list *breadcrumbs; /* non-standard breadcrumb trail, if any */
struct filename *navigation; /* navigation links, or |NULL| if not supplied */
struct linked_list *plugins; /* of |weave_plugin|: these are for HTML extensions */
struct linked_list *colour_schemes; /* of |colour_scheme|: these are for HTML */
struct filename *navigation; /* navigation links, or [[NULL]] if not supplied */
struct linked_list *plugins; /* of [[weave_plugin]]: these are for HTML extensions */
struct linked_list *colour_schemes; /* of [[colour_scheme]]: these are for HTML */
/* used for workspace during an actual weave: */
struct source_line *current_weave_line;
CLASS_DEFINITION
} weave_order;
@<Compile a set of instructions for the weaver@> =
<<Compile a set of instructions for the weaver>>=
wv = CREATE(weave_order);
wv->weave_web = W;
wv->weave_range = Str::duplicate(range);
@ -116,7 +116,7 @@ typedef struct weave_order {
Errors::fatal("no sections match that range");
TEMPORARY_TEXT(leafname)
@<Translate the subweb range into details of what to weave@>;
<<Translate the subweb range into details of what to weave>>;
pathname *H = W->redirect_weaves_to;
if (H == NULL) H = into;
if (H == NULL) {
@ -136,7 +136,7 @@ typedef struct weave_order {
@ 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@> =
<<Translate the subweb range into details of what to weave>>=
match_results mr = Regexp::create_mr();
if (Str::eq_wide_string(range, L"0")) {
if (W->md->single_file) {
@ -146,7 +146,7 @@ and details of any cover-sheet to use.
wv->booklet_title = Str::new_from_wide_string(L"Complete Program");
WRITE_TO(leafname, "Complete");
}
if (wv->theme_match) @<Change the titling and leafname to match the tagged theme@>;
if (wv->theme_match) <<Change the titling and leafname to match the tagged theme>>;
} else if (Regexp::match(&mr, range, L"%d+")) {
Str::clear(wv->booklet_title);
WRITE_TO(wv->booklet_title, "Chapter %S", range);
@ -174,19 +174,19 @@ and details of any cover-sheet to use.
WRITE_TO(leafname, "%S", Formats::file_extension(wv->format));
Regexp::dispose_of(&mr);
@<Change the titling and leafname to match the tagged theme@> =
<<Change the titling and leafname to match the tagged theme>>=
Str::clear(wv->booklet_title);
WRITE_TO(wv->booklet_title, "Extracts: %S", wv->theme_match->tag_name);
Str::copy(leafname, wv->theme_match->tag_name);
@ Each weave results in a compressed one-line printed report:
@<Report on the outcome of the weave to the console@> =
<<Report on the outcome of the weave to the console>>=
PRINT("[%S: %S -> %f", wv->booklet_title, wv->format->format_name, wv->weave_to);
Formats::report_on_post_processing(wv);
PRINT("]\n");
@ =
<<*>>=
void Swarm::ensure_plugin(weave_order *wv, text_stream *name) {
weave_plugin *existing;
LOOP_OVER_LINKED_LIST(existing, weave_plugin, wv->plugins)
@ -227,7 +227,7 @@ void Swarm::include_plugins(OUTPUT_STREAM, web *W, weave_order *wv, filename *fr
@ After every swarm, we rebuild the index:
=
<<*>>=
void Swarm::weave_index_templates(web *W, text_stream *range, weave_pattern *pattern,
pathname *into, filename *nav, linked_list *crumbs) {
if (!(Bibliographic::data_exists(W->md, I"Version Number")))