Chapter 1: Nowebify.
This commit is contained in:
parent
eec9a49d8c
commit
5cdfe7a60b
6 changed files with 328 additions and 322 deletions
|
@ -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;
|
|
@ -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)
|
|
@ -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");
|
|
@ -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;
|
|
@ -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));
|
|
@ -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")))
|
Loading…
Reference in a new issue