From dea875195b826bd320869adb49e2cb5d1b657a1e Mon Sep 17 00:00:00 2001 From: AwesomeAdam54321 Date: Sat, 9 Mar 2024 11:58:05 +0800 Subject: [PATCH] foundation-module: Chapter_8: Nowebify. --- ... Webs.w => Bibliographic_Data_for_Webs.nw} | 31 ++-- .../{Build Files.w => Build_Files.nw} | 44 ++--- .../{Simple Tangler.w => Simple_Tangler.nw} | 107 +++++------ .../{Web Modules.w => Web_Modules.nw} | 95 +++++----- .../{Web Structure.w => Web_Structure.nw} | 173 +++++++++--------- 5 files changed, 227 insertions(+), 223 deletions(-) rename foundation-module/Chapter_8/{Bibliographic Data for Webs.w => Bibliographic_Data_for_Webs.nw} (93%) rename foundation-module/Chapter_8/{Build Files.w => Build_Files.nw} (87%) rename foundation-module/Chapter_8/{Simple Tangler.w => Simple_Tangler.nw} (78%) rename foundation-module/Chapter_8/{Web Modules.w => Web_Modules.nw} (72%) rename foundation-module/Chapter_8/{Web Structure.w => Web_Structure.nw} (83%) diff --git a/foundation-module/Chapter_8/Bibliographic Data for Webs.w b/foundation-module/Chapter_8/Bibliographic_Data_for_Webs.nw similarity index 93% rename from foundation-module/Chapter_8/Bibliographic Data for Webs.w rename to foundation-module/Chapter_8/Bibliographic_Data_for_Webs.nw index c1b6dd9..91e7556 100755 --- a/foundation-module/Chapter_8/Bibliographic Data for Webs.w +++ b/foundation-module/Chapter_8/Bibliographic_Data_for_Webs.nw @@ -3,11 +3,11 @@ To manage key-value pairs of bibliographic data, metadata if you like, associated with a given web. -@h Storing data. +@ \section{Storing data.} There are never more than a dozen or so key-value pairs, and it's more convenient to store them directly here than to use a dictionary. -= +<<*>>= typedef struct web_bibliographic_datum { struct text_stream *key; struct text_stream *value; @@ -20,12 +20,13 @@ typedef struct web_bibliographic_datum { @ We keep these in linked lists, and here's a convenient way to scan them: -@d LOOP_OVER_BIBLIOGRAPHIC_DATA(bd, Wm) +<<*>>= +#define LOOP_OVER_BIBLIOGRAPHIC_DATA(bd, Wm) LOOP_OVER_LINKED_LIST(bd, web_bibliographic_datum, Wm->bibliographic_data) @ The following check the rules: -= +<<*>>= int Bibliographic::datum_can_be_declared(web_md *Wm, text_stream *key) { web_bibliographic_datum *bd = Bibliographic::look_up_datum(Wm, key); if (bd == NULL) return FALSE; @@ -38,10 +39,10 @@ int Bibliographic::datum_on_or_off(web_md *Wm, text_stream *key) { return bd->on_or_off; } -@h Initialising a web. +@ \section{Initialising a web.} Each web has the following slate of data: -= +<<*>>= void Bibliographic::initialise_data(web_md *Wm) { web_bibliographic_datum *bd; @@ -82,7 +83,7 @@ void Bibliographic::initialise_data(web_md *Wm) { @ Once the declarations for a web have been processed, the following is called to check that all the mandatory declarations have indeed been made: -= +<<*>>= void Bibliographic::check_required_data(web_md *Wm) { web_bibliographic_datum *bd; LOOP_OVER_BIBLIOGRAPHIC_DATA(bd, Wm) @@ -92,10 +93,10 @@ void Bibliographic::check_required_data(web_md *Wm) { "The web does not specify '%S: ...'", bd->key); } -@h Reading bibliographic data. +@ \section{Reading bibliographic data.} Key names are case-sensitive. -= +<<*>>= text_stream *Bibliographic::get_datum(web_md *Wm, text_stream *key) { web_bibliographic_datum *bd = Bibliographic::look_up_datum(Wm, key); if (bd) return bd->value; @@ -118,20 +119,20 @@ web_bibliographic_datum *Bibliographic::look_up_datum(web_md *Wm, text_stream *k return NULL; } -@h Writing bibliographic data. +@ \section{Writing bibliographic data.} Note that a key-value pair is created if the key doesn't exist at present, so this routine never fails. -= +<<*>>= web_bibliographic_datum *Bibliographic::set_datum(web_md *Wm, text_stream *key, text_stream *val) { web_bibliographic_datum *bd = Bibliographic::look_up_datum(Wm, key); - if (bd == NULL) @ + if (bd == NULL) <> else Str::copy(bd->value, val); - if (Str::eq_wide_string(key, L"Title")) @; + if (Str::eq_wide_string(key, L"Title")) <>; return bd; } -@ = +<>= bd = CREATE(web_bibliographic_datum); bd->key = Str::duplicate(key); bd->value = Str::duplicate(val); @@ -146,7 +147,7 @@ written to the "Title" key, then a full-caps "WUTHERING HEIGHTS" is written to a "Capitalized Title" key. (This enables cover sheets which want to typeset the title in full caps to do so.) -@ = +<>= TEMPORARY_TEXT(recapped) Str::copy(recapped, val); LOOP_THROUGH_TEXT(P, recapped) diff --git a/foundation-module/Chapter_8/Build Files.w b/foundation-module/Chapter_8/Build_Files.nw similarity index 87% rename from foundation-module/Chapter_8/Build Files.w rename to foundation-module/Chapter_8/Build_Files.nw index af0e163..c8e8b8a 100644 --- a/foundation-module/Chapter_8/Build Files.w +++ b/foundation-module/Chapter_8/Build_Files.nw @@ -2,11 +2,11 @@ Manages the build metadata for an inweb project. -@h About build files. -When we read a web, we look for a file in it called |build.txt|. If no such +@ \section{About build files.} +When we read a web, we look for a file in it called [[build.txt]]. If no such file exists, we look for the same thing in the current working directory. -= +<<*>>= filename *BuildFiles::build_file_for_web(web_md *WS) { filename *F = Filenames::in(WS->path_to_web, I"build.txt"); if (TextFiles::exists(F)) return F; @@ -17,7 +17,7 @@ filename *BuildFiles::build_file_for_web(web_md *WS) { @ The format of such a file is very simple: up to three text fields: -= +<<*>>= typedef struct build_file_data { struct text_stream *prerelease_text; struct text_stream *build_code; @@ -26,7 +26,7 @@ typedef struct build_file_data { @ Here's how to read in a build file: -= +<<*>>= build_file_data BuildFiles::read(filename *F) { build_file_data bfd; bfd.prerelease_text = Str::new(); @@ -55,7 +55,7 @@ void BuildFiles::build_file_helper(text_stream *text, text_file_position *tfp, v @ And here is how to write one: -= +<<*>>= void BuildFiles::write(build_file_data bfd, filename *F) { text_stream vr_stream; text_stream *OUT = &vr_stream; @@ -69,11 +69,11 @@ void BuildFiles::write(build_file_data bfd, filename *F) { Streams::close(OUT); } -@h Bibliographic implications. +@ \section{Bibliographic implications.} Whenever a web is read in by Inweb, its build file is looked at in order to set some bibliographic data. -= +<<*>>= void BuildFiles::set_bibliographic_data_for(web_md *WS) { filename *F = BuildFiles::build_file_for_web(WS); if (F) { @@ -92,10 +92,10 @@ synthesize the semantic version number for the project. Note that this is called even if no build file had ever been found, so it's quite legal for the Contents page to specify all of this. -If no error occurs, then the expansion |[[Semantic Version Number]]| is +If no error occurs, then the expansion [[[[Semantic Version Number]]]] is guaranteed to produce a semver-legal version number. -= +<<*>>= void BuildFiles::deduce_semver(web_md *WS) { TEMPORARY_TEXT(combined) text_stream *s = Bibliographic::get_datum(WS, I"Semantic Version Number"); @@ -121,11 +121,11 @@ void BuildFiles::deduce_semver(web_md *WS) { DISCARD_TEXT(combined) } -@h Advancing. +@ \section{Advancing.} We update the build date to today and, if supplied, also increment the build number if we find that the date has changed. -= +<<*>>= void BuildFiles::advance_for_web(web_md *WS) { filename *F = BuildFiles::build_file_for_web(WS); if (F) BuildFiles::advance(F); @@ -141,10 +141,10 @@ void BuildFiles::advance(filename *F) { } @ The standard date format we use is "26 February 2018". If the contents of -|dateline| match today's date in this format, we return |TRUE|; otherwise we -rewrite |dateline| to today and return |FALSE|. +[[dateline]] match today's date in this format, we return [[TRUE]]; otherwise we +rewrite [[dateline]] to today and return [[FALSE]]. -= +<<*>>= int BuildFiles::dated_today(text_stream *dateline) { char *monthname[12] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; @@ -161,16 +161,16 @@ int BuildFiles::dated_today(text_stream *dateline) { return rv; } -@ Traditional Inform build codes are four-character, e.g., |3Q27|. Here, we +@ Traditional Inform build codes are four-character, e.g., [[3Q27]]. Here, we read such a code and increase it by one. The two-digit code at the back is -incremented, but rolls around from |99| to |01|, in which case the letter is -advanced, except that |I| and |O| are skipped, and if the letter passes |Z| -then it rolls back around to |A| and the initial digit is incremented. +incremented, but rolls around from [[99]] to [[01]], in which case the letter is +advanced, except that [[I]] and [[O]] are skipped, and if the letter passes [[Z]] +then it rolls back around to [[A]] and the initial digit is incremented. This allows for 21384 distinct build codes, enough to use one each day for some 58 years. -= +<<*>>= void BuildFiles::increment(text_stream *T) { if (Str::len(T) != 4) Errors::with_text("build code malformed: %S", T); else { @@ -178,8 +178,8 @@ void BuildFiles::increment(text_stream *T) { int L = Str::get_at(T, 1); int M1 = Str::get_at(T, 2) - '0'; int M2 = Str::get_at(T, 3) - '0'; - if ((N < 0) || (N > 9) || (L < 'A') || (L > 'Z') || - (M1 < 0) || (M1 > 9) || (M2 < 0) || (M2 > 9)) { + if ((N < 0) [[| (N > 9) || (L < 'A') || (L > 'Z') |]] + (M1 < 0) [[| (M1 > 9) || (M2 < 0) |]] (M2 > 9)) { Errors::with_text("build code malformed: %S", T); } else { M2++; diff --git a/foundation-module/Chapter_8/Simple Tangler.w b/foundation-module/Chapter_8/Simple_Tangler.nw similarity index 78% rename from foundation-module/Chapter_8/Simple Tangler.w rename to foundation-module/Chapter_8/Simple_Tangler.nw index d7274cb..155a145 100644 --- a/foundation-module/Chapter_8/Simple Tangler.w +++ b/foundation-module/Chapter_8/Simple_Tangler.nw @@ -13,10 +13,10 @@ a program: something much simpler would surely be sufficient. And here it is. [1] Why might we have this? Because kits of Inter code take this form. @ The simple tangler is controlled using a parcel of settings. Note also the -|state|, which is not used by the reader itself, but instead allows the callback +[[state]], which is not used by the reader itself, but instead allows the callback functions to have a shared state of their own. -= +<<*>>= typedef struct simple_tangle_docket { void (*raw_callback)(struct text_stream *, struct simple_tangle_docket *); void (*command_callback)(struct text_stream *, struct text_stream *, @@ -27,7 +27,7 @@ typedef struct simple_tangle_docket { struct pathname *web_path; } simple_tangle_docket; -@ = +<<*>>= simple_tangle_docket SimpleTangler::new_docket( void (*A)(struct text_stream *, struct simple_tangle_docket *), void (*B)(struct text_stream *, struct text_stream *, @@ -49,7 +49,7 @@ simple_tangle_docket SimpleTangler::new_docket( should open), or a section (which the tangler should find and open), or a whole web of section files (ditto): -= +<<*>>= void SimpleTangler::tangle_text(simple_tangle_docket *docket, text_stream *text) { SimpleTangler::tangle_L1(docket, text, NULL, NULL, FALSE); } @@ -66,7 +66,7 @@ void SimpleTangler::tangle_web(simple_tangle_docket *docket) { SimpleTangler::tangle_L1(docket, NULL, NULL, NULL, TRUE); } -@ = +<<*>>= void SimpleTangler::tangle_L1(simple_tangle_docket *docket, text_stream *text, filename *F, text_stream *leafname, int whole_web) { TEMPORARY_TEXT(T) @@ -77,7 +77,7 @@ void SimpleTangler::tangle_L1(simple_tangle_docket *docket, text_stream *text, @ First, dispose of the "whole web" possibility. -= +<<*>>= void SimpleTangler::tangle_L2(OUTPUT_STREAM, text_stream *text, filename *F, text_stream *leafname, simple_tangle_docket *docket, int whole_web) { if (whole_web) { @@ -95,26 +95,26 @@ void SimpleTangler::tangle_L2(OUTPUT_STREAM, text_stream *text, filename *F, } } -@ When tangling a file, we begin in |comment| mode; when tangling other matter, +@ When tangling a file, we begin in [[comment]] mode; when tangling other matter, not so much. -= +<<*>>= void SimpleTangler::tangle_L3(OUTPUT_STREAM, text_stream *text, text_stream *leafname, simple_tangle_docket *docket, filename *F) { int comment = FALSE; FILE *Input_File = NULL; if ((Str::len(leafname) > 0) || (F)) { - @; + <>; comment = TRUE; } - @; + <>; if (Input_File) fclose(Input_File); } -@ Note that if we are looking for an explicit section -- say, |Juggling.i6t| -- -from a web |W|, we translate that into the path |W/Sections/Juggling.i6t|. +@ Note that if we are looking for an explicit section -- say, [[Juggling.i6t]] -- +from a web [[W]], we translate that into the path [[W/Sections/Juggling.i6t]]. -@ = +<>= if (F) { Input_File = Filenames::fopen(F, "r"); } else if (Str::len(leafname) > 0) { @@ -124,7 +124,7 @@ from a web |W|, we translate that into the path |W/Sections/Juggling.i6t|. if (Input_File == NULL) (*(docket->error_callback))("unable to open the file '%S'", leafname); -@ = +<>= TEMPORARY_TEXT(command) TEMPORARY_TEXT(argument) int skip_part = FALSE, extract = FALSE; @@ -132,50 +132,51 @@ from a web |W|, we translate that into the path |W/Sections/Juggling.i6t|. do { Str::clear(command); Str::clear(argument); - @; + <>; NewCharacter: if (cr == EOF) break; if (((cr == '@') || (cr == '=')) && (col == 1)) { int inweb_syntax = -1; - if (cr == '=') @ - else @; - @; + if (cr == '=') <> + else <>; + <>; continue; } - if (comment == FALSE) @; + if (comment == FALSE) <>; } while (cr != EOF); DISCARD_TEXT(command) DISCARD_TEXT(argument) @ Our text files are encoded as ISO Latin-1, not as Unicode UTF-8, so ordinary -|fgetc| is used, and no BOM marker is parsed. Lines are assumed to be terminated -with either |0x0a| or |0x0d|. (Since blank lines are harmless, we take no -trouble over |0a0d| or |0d0a| combinations.) The built-in template files, almost -always the only ones used, are line terminated |0x0a| in Unix fashion. +[[fgetc]] is used, and no BOM marker is parsed. Lines are assumed to be terminated +with either [[0x0a]] or [[0x0d]]. (Since blank lines are harmless, we take no +trouble over [[0a0d]] or [[0d0a]] combinations.) The built-in template files, almost +always the only ones used, are line terminated [[0x0a]] in Unix fashion. -@ = +<>= if (Input_File) cr = fgetc(Input_File); else if (text) { cr = Str::get_at(text, sfp); if (cr == 0) cr = EOF; else sfp++; } else cr = EOF; col++; if ((cr == 10) || (cr == 13)) col = 0; -@ Here we see the limited range of Inweb syntaxes allowed; but some |@| and |=| +@ Here we see the limited range of Inweb syntaxes allowed; but some [[@]] and [[=]] commands can be used, at least. -@d INWEB_PARAGRAPH_SYNTAX 1 -@d INWEB_CODE_SYNTAX 2 -@d INWEB_DASH_SYNTAX 3 -@d INWEB_PURPOSE_SYNTAX 4 -@d INWEB_FIGURE_SYNTAX 5 -@d INWEB_EQUALS_SYNTAX 6 -@d INWEB_EXTRACT_SYNTAX 7 +<<*>>= +#define INWEB_PARAGRAPH_SYNTAX 1 +#define INWEB_CODE_SYNTAX 2 +#define INWEB_DASH_SYNTAX 3 +#define INWEB_PURPOSE_SYNTAX 4 +#define INWEB_FIGURE_SYNTAX 5 +#define INWEB_EQUALS_SYNTAX 6 +#define INWEB_EXTRACT_SYNTAX 7 -@ = +<>= TEMPORARY_TEXT(at_cmd) int committed = FALSE, unacceptable_character = FALSE; while (TRUE) { - @; - if ((committed == FALSE) && ((cr == 10) || (cr == 13) || (cr == ' '))) { + <>; + if ((committed == FALSE) && ((cr == 10) [[| (cr == 13) |]] (cr == ' '))) { if (Str::eq_wide_string(at_cmd, L"p")) inweb_syntax = INWEB_PARAGRAPH_SYNTAX; else if (Str::eq_wide_string(at_cmd, L"h")) @@ -202,7 +203,7 @@ commands can be used, at least. } if (!(((cr >= 'A') && (cr <= 'Z')) || ((cr >= 'a') && (cr <= 'z')) || ((cr >= '0') && (cr <= '9')) - || (cr == '-') || (cr == '>') || (cr == ':') || (cr == '_'))) + [[| (cr == '-') || (cr == '>') || (cr == ':') |]] (cr == '_'))) unacceptable_character = TRUE; if ((cr == 10) || (cr == 13)) break; PUT_TO(at_cmd, cr); @@ -210,10 +211,10 @@ commands can be used, at least. Str::copy(command, at_cmd); DISCARD_TEXT(at_cmd) -@ = +<>= TEMPORARY_TEXT(equals_cmd) while (TRUE) { - @; + <>; if ((cr == 10) || (cr == 13)) break; PUT_TO(equals_cmd, cr); } @@ -231,14 +232,14 @@ commands can be used, at least. Regexp::dispose_of(&mr); DISCARD_TEXT(equals_cmd) -@ = +<>= switch (inweb_syntax) { case INWEB_PARAGRAPH_SYNTAX: { TEMPORARY_TEXT(heading_name) Str::copy_tail(heading_name, command, 2); int c; while (((c = Str::get_last_char(heading_name)) != 0) && - ((c == ' ') || (c == '\t') || (c == '.'))) + ((c == ' ') [[| (c == '\t') |]] (c == '.'))) Str::delete_last_character(heading_name); if (Str::len(heading_name) == 0) (*(docket->error_callback))("Empty heading name", NULL); @@ -266,11 +267,11 @@ commands can be used, at least. case INWEB_FIGURE_SYNTAX: break; } -@ = +<>= if (cr == '{') { - @; + <>; if ((cr == '-') && (docket->command_callback)) { - @; + <>; if (Str::get_first_char(command) == '!') continue; (*(docket->command_callback))(OUT, command, argument, docket); continue; @@ -280,9 +281,9 @@ commands can be used, at least. } } if ((cr == '(') && (docket->bplus_callback)) { - @; + <>; if (cr == '+') { - @; + <>; continue; } else { /* otherwise the open bracket was a literal */ PUT_TO(OUT, '('); @@ -291,29 +292,29 @@ commands can be used, at least. } PUT_TO(OUT, cr); -@ And here we read a normal command. The command name must not include |}| -or |:|. If there is no |:| then the argument is left unset (so that it will -be the empty string: see above). The argument must not include |}|. +@ And here we read a normal command. The command name must not include [[}]] +or [[:]]. If there is no [[:]] then the argument is left unset (so that it will +be the empty string: see above). The argument must not include [[}]]. -@ = +<>= Str::clear(command); Str::clear(argument); int com_mode = TRUE; while (TRUE) { - @; + <>; if ((cr == '}') || (cr == EOF)) break; if ((cr == ':') && (com_mode)) { com_mode = FALSE; continue; } if (com_mode) PUT_TO(command, cr); else PUT_TO(argument, cr); } -@ And similarly, for the |(+| ... |+)| notation which was once used to mark +@ And similarly, for the [[(+| ... |+)]] notation which was once used to mark I7 material within I6: -@ = +<>= TEMPORARY_TEXT(material) while (TRUE) { - @; + <>; if (cr == EOF) break; if ((cr == ')') && (Str::get_last_char(material) == '+')) { Str::delete_last_character(material); break; } diff --git a/foundation-module/Chapter_8/Web Modules.w b/foundation-module/Chapter_8/Web_Modules.nw similarity index 72% rename from foundation-module/Chapter_8/Web Modules.w rename to foundation-module/Chapter_8/Web_Modules.nw index bfc1aa8..a6bc79e 100644 --- a/foundation-module/Chapter_8/Web Modules.w +++ b/foundation-module/Chapter_8/Web_Modules.nw @@ -2,32 +2,33 @@ To search for included modules, and track dependencies between them. -@h Creation. +@ \section{Creation.} Each web of source material discovered by Inweb is given one of the following. Ordinarily these are found only when reading in a web for weaving, tangling and so on: in the vast majority of Inweb runs, all modules will have the -"module origin marker" |READING_WEB_MOM|. But when Inweb is constructing a +"module origin marker" [[READING_WEB_MOM]]. But when Inweb is constructing a makefile for a suite of tools, it can also discover multiple webs by other means. -@e READING_WEB_MOM from 0 -@e MAKEFILE_TOOL_MOM -@e MAKEFILE_WEB_MOM -@e MAKEFILE_MODULE_MOM +<<*>>= +enum READING_WEB_MOM from 0 +enum MAKEFILE_TOOL_MOM +enum MAKEFILE_WEB_MOM +enum MAKEFILE_MODULE_MOM -= +<<*>>= typedef struct module { struct pathname *module_location; struct text_stream *module_name; - struct linked_list *dependencies; /* of |module|: which other modules does this need? */ + struct linked_list *dependencies; /* of [[module]]: which other modules does this need? */ struct text_stream *module_tag; - int origin_marker; /* one of the |*_MOM| values above */ - struct linked_list *chapters_md; /* of |chapter_md|: just the ones in this module */ - struct linked_list *sections_md; /* of |section_md|: just the ones in this module */ + int origin_marker; /* one of the [[*_MOM]] values above */ + struct linked_list *chapters_md; /* of [[chapter_md]]: just the ones in this module */ + struct linked_list *sections_md; /* of [[section_md]]: just the ones in this module */ CLASS_DEFINITION } module; -@ = +<<*>>= module *WebModules::new(text_stream *name, pathname *at, int m) { module *M = CREATE(module); M->module_location = at; @@ -44,48 +45,48 @@ module *WebModules::new(text_stream *name, pathname *at, int m) { contains a suite of utility routines, or a major component of a program, but which is not a program in its own right. -Internally, though, every web produces a |module| structure. The one for the +Internally, though, every web produces a [[module]] structure. The one for the main web -- which can be tangled, and results in an actual program -- is -internally named |"(main)"|, a name which the user will never see. +internally named [["(main)"]], a name which the user will never see. -= +<<*>>= module *WebModules::create_main_module(web_md *WS) { return WebModules::new(I"(main)", WS->path_to_web, READING_WEB_MOM); } -@h Dependencies. +@ \section{Dependencies.} When web A imports module B, we will say that A is dependent on B. A web can import multiple modules, so there can a list of dependencies. These are needed when constructing makefiles, since the source code in B affects the program generated by A. -= +<<*>>= void WebModules::dependency(module *A, module *B) { if ((A == NULL) || (B == NULL)) internal_error("no module"); ADD_TO_LINKED_LIST(B, module, A->dependencies); } -@h Searching. +@ \section{Searching.} The following abstracts the idea of a place where modules might be found. (At one time there was going to be a more elaborate search hierarchy.) -= +<<*>>= typedef struct module_search { struct pathname *path_to_search; CLASS_DEFINITION } module_search; -@ = +<<*>>= module_search *WebModules::make_search_path(pathname *ext_path) { module_search *ms = CREATE(module_search); ms->path_to_search = ext_path; return ms; } -@ When a web's contents page says to |import Blah|, how do we find the module -called |Blah| on disc? We try four possibilities in sequence: +@ When a web's contents page says to [[import Blah]], how do we find the module +called [[Blah]] on disc? We try four possibilities in sequence: -= +<<*>>= module *WebModules::find(web_md *WS, module_search *ms, text_stream *name, pathname *X) { TEMPORARY_TEXT(T) WRITE_TO(T, "%S-module", name); @@ -97,16 +98,16 @@ module *WebModules::find(web_md *WS, module_search *ms, text_stream *name, pathn int N = 4; for (int i=0; i; + if ((P) && (WebModules::exists(P))) <>; } DISCARD_TEXT(T) return NULL; } @ When the module is found (if it is), a suitable module structure is made, -and a dependency created from the web's |(main)| module to this one. +and a dependency created from the web's [[(main)]] module to this one. -@ = +<>= pathname *Q = Pathnames::from_text(name); module *M = WebModules::new(Pathnames::directory_name(Q), P, READING_WEB_MOM); WebModules::dependency(WS->as_module, M); @@ -115,30 +116,30 @@ and a dependency created from the web's |(main)| module to this one. @ We accept that a plausibly-named directory is indeed the module being sought if it looks like a web. -= +<<*>>= int WebModules::exists(pathname *P) { return WebMetadata::directory_looks_like_a_web(P); } -@h Resolving cross-reference names. -Suppose we are in module |from_M| and want to understand which section of -a relevant web |text| might refer to. It could be the name of a module, +@ \section{Resolving cross-reference names.} +Suppose we are in module [[from_M]] and want to understand which section of +a relevant web [[text]] might refer to. It could be the name of a module, either this one or one dependent on it; or the name of a chapter in one of those, or the shortened forms of those; or the name of a section. It may match multiple possibilities: we return how many, and if this is -positive, we write the module in which the first find was made in |*return M|, -the section in |*return_Sm|, and set the flag |*named_as_module| according +positive, we write the module in which the first find was made in [[*return M]], +the section in [[*return_Sm]], and set the flag [[*named_as_module]] according to whether the reference was a bare module name (say, "foundation") or not. -Note that we consider first the possibilities within |from_M|: we only +Note that we consider first the possibilities within [[from_M]]: we only look at other modules if there are none. Thus, an unambiguous result in -|from_M| is good enough, even if there are other possibilities elsewhere. +[[from_M]] is good enough, even if there are other possibilities elsewhere. -A reference in the form |module: reference| is taken to be in the module -of that name: for example, |"foundation: Web Modules"| would find the +A reference in the form [[module: reference]] is taken to be in the module +of that name: for example, [["foundation: Web Modules"]] would find the section of code you are now reading. -= +<<*>>= int WebModules::named_reference(module **return_M, section_md **return_Sm, int *named_as_module, text_stream *title, module *from_M, text_stream *text, int list, int sections_only) { @@ -156,7 +157,7 @@ int WebModules::named_reference(module **return_M, section_md **return_Sm, } LOOP_OVER_LINKED_LIST(M, module, from_M->dependencies) { if (Str::eq_insensitive(M->module_name, seek_module)) { - @; + <>; } } Regexp::dispose_of(&mr); @@ -164,20 +165,20 @@ int WebModules::named_reference(module **return_M, section_md **return_Sm, for (int stage = 1; ((finds == 0) && (stage <= 2)); stage++) { if (stage == 1) { M = from_M; - @; + <>; } if (stage == 2) { LOOP_OVER_LINKED_LIST(M, module, from_M->dependencies) - @; + <>; } } return finds; } -@ = +<>= if (M == NULL) internal_error("no module"); if (Str::eq_insensitive(M->module_name, seek)) - @; + <>; chapter_md *Cm; section_md *Sm; LOOP_OVER_LINKED_LIST(Cm, chapter_md, M->chapters_md) { @@ -185,13 +186,13 @@ int WebModules::named_reference(module **return_M, section_md **return_Sm, ((Str::eq_insensitive(Cm->ch_title, seek)) || (Str::eq_insensitive(Cm->ch_basic_title, seek)) || (Str::eq_insensitive(Cm->ch_decorated_title, seek)))) - @; + <>; LOOP_OVER_LINKED_LIST(Sm, section_md, Cm->sections_md) if (Str::eq_insensitive(Sm->sect_title, seek)) - @; + <>; } -@ = +<>= finds++; if (finds == 1) { *return_M = M; *return_Sm = FIRST_IN_LINKED_LIST(section_md, M->sections_md); @@ -200,7 +201,7 @@ int WebModules::named_reference(module **return_M, section_md **return_Sm, } if (list) WRITE_TO(STDERR, "(%d) Module '%S'\n", finds, M->module_name); -@ = +<>= finds++; if (finds == 1) { *return_M = M; *return_Sm = FIRST_IN_LINKED_LIST(section_md, Cm->sections_md); @@ -209,7 +210,7 @@ int WebModules::named_reference(module **return_M, section_md **return_Sm, if (list) WRITE_TO(STDERR, "(%d) Chapter '%S' of module '%S'\n", finds, Cm->ch_title, M->module_name); -@ = +<>= finds++; if (finds == 1) { *return_M = M; *return_Sm = Sm; diff --git a/foundation-module/Chapter_8/Web Structure.w b/foundation-module/Chapter_8/Web_Structure.nw similarity index 83% rename from foundation-module/Chapter_8/Web Structure.w rename to foundation-module/Chapter_8/Web_Structure.nw index 4181fe6..3ff0ac7 100755 --- a/foundation-module/Chapter_8/Web Structure.w +++ b/foundation-module/Chapter_8/Web_Structure.nw @@ -3,7 +3,7 @@ To read the structure of a literate programming web from a path in the file system. -@h Introduction. +@ \section{Introduction.} Webs are literate programs for the Inweb LP system. A single web consists of a number of chapters (though sometimes just one, called "Sections"), each of which consists of a number of sections. A web can represent a stand-alone @@ -13,21 +13,22 @@ called a "module". 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. -@e V1_SYNTAX from 1 -@e V2_SYNTAX +<<*>>= +enum V1_SYNTAX from 1 +enum V2_SYNTAX -@h Web MD. +@ \section{Web MD.} No relation to the website of the same name: MD here stands for metadata. Our task in this section will be to read a web from the filing system and produce the following metadata structure. -Each web produces a single instance of |web_md|: +Each web produces a single instance of [[web_md]]: -= +<<*>>= typedef struct web_md { struct pathname *path_to_web; /* relative to the current working directory */ struct filename *single_file; /* relative to the current working directory */ - struct linked_list *bibliographic_data; /* of |web_bibliographic_datum| */ + struct linked_list *bibliographic_data; /* of [[web_bibliographic_datum]] */ struct semantic_version_number version_number; /* as deduced from bibliographic data */ int default_syntax; /* which version syntax the sections will have */ int chaptered; /* has the author explicitly divided it into named chapters? */ @@ -35,20 +36,20 @@ typedef struct web_md { struct module *as_module; /* the root of a small dependency graph */ - struct filename *contents_filename; /* or |NULL| for a single-file web */ - struct linked_list *tangle_target_names; /* of |text_stream| */ - struct linked_list *header_filenames; /* of |filename| */ + struct filename *contents_filename; /* or [[NULL]] for a single-file web */ + struct linked_list *tangle_target_names; /* of [[text_stream]] */ + struct linked_list *header_filenames; /* of [[filename]] */ - struct linked_list *chapters_md; /* of |chapter_md| */ - struct linked_list *sections_md; /* of |section_md| */ + struct linked_list *chapters_md; /* of [[chapter_md]] */ + struct linked_list *sections_md; /* of [[section_md]] */ CLASS_DEFINITION } web_md; -@ The |chapters_md| list in a |web_md| contains these as its entries: +@ The [[chapters_md]] list in a [[web_md]] contains these as its entries: -= +<<*>>= typedef struct chapter_md { - struct text_stream *ch_range; /* e.g., |P| for Preliminaries, |7| for Chapter 7, |C| for Appendix C */ + struct text_stream *ch_range; /* e.g., [[P| for Preliminaries, |7| for Chapter 7, |C]] for Appendix C */ struct text_stream *ch_title; /* e.g., "Chapter 3: Fresh Water Fish" */ struct text_stream *ch_basic_title; /* e.g., "Chapter 3" */ struct text_stream *ch_decorated_title; /* e.g., "Fresh Water Fish" */ @@ -58,13 +59,13 @@ typedef struct chapter_md { int imported; /* from a different web? */ - struct linked_list *sections_md; /* of |section_md| */ + struct linked_list *sections_md; /* of [[section_md]] */ CLASS_DEFINITION } chapter_md; -@ And the |sections_md| list in a |chapter_md| contains these as its entries: +@ And the [[sections_md]] list in a [[chapter_md]] contains these as its entries: -= +<<*>>= typedef struct section_md { struct text_stream *sect_title; /* e.g., "Program Control" */ struct text_stream *sect_range; /* e.g., "2/ct" */ @@ -82,13 +83,13 @@ typedef struct section_md { CLASS_DEFINITION } section_md; -@h Reading from the file system. +@ \section{Reading from the file system.} Webs can be stored in two ways: as a directory containing a multitude of files, -in which case the pathname |P| is supplied; or as a single file with everything +in which case the pathname [[P]] is supplied; or as a single file with everything in one (and thus, implicitly, a single chapter and a single section), in which -case a filename |alt_F| is supplied. +case a filename [[alt_F]] is supplied. -= +<<*>>= web_md *WebMetadata::get_without_modules(pathname *P, filename *alt_F) { return WebMetadata::get(P, alt_F, V2_SYNTAX, NULL, FALSE, FALSE, NULL); } @@ -97,20 +98,20 @@ web_md *WebMetadata::get(pathname *P, filename *alt_F, int syntax_version, module_search *I, int verbosely, int including_modules, pathname *path_to_inweb) { if ((including_modules) && (I == NULL)) I = WebModules::make_search_path(NULL); web_md *Wm = CREATE(web_md); - @; - @; + <>; + <>; WebMetadata::read_contents_page(Wm, Wm->as_module, I, verbosely, including_modules, NULL, path_to_inweb); - @; - @; + <>; + <>; return Wm; } -@ = +<>= Wm->bibliographic_data = NEW_LINKED_LIST(web_bibliographic_datum); Bibliographic::initialise_data(Wm); -@ = +<>= if (P) { Wm->path_to_web = P; Wm->single_file = NULL; @@ -130,14 +131,14 @@ web_md *WebMetadata::get(pathname *P, filename *alt_F, int syntax_version, Wm->header_filenames = NEW_LINKED_LIST(filename); Wm->as_module = WebModules::create_main_module(Wm); -@ = +<>= Bibliographic::check_required_data(Wm); BuildFiles::set_bibliographic_data_for(Wm); BuildFiles::deduce_semver(Wm); @ If no range is supplied, we make one ourselves. -@ = +<>= int sequential = FALSE; /* are we numbering sections sequentially? */ if (Str::eq(Bibliographic::get_datum(Wm, I"Sequential Section Ranges"), I"On")) sequential = TRUE; @@ -147,12 +148,12 @@ web_md *WebMetadata::get(pathname *P, filename *alt_F, int syntax_version, int section_counter = 1; LOOP_OVER_LINKED_LIST(Sm, section_md, Cm->sections_md) { if (Str::len(Sm->sect_range) == 0) - @; + <>; section_counter++; } } -@ = +<>= if (sequential) { WRITE_TO(Sm->sect_range, "%S/", Cm->ch_range); WRITE_TO(Sm->sect_range, "s%d", section_counter); @@ -162,17 +163,17 @@ web_md *WebMetadata::get(pathname *P, filename *alt_F, int syntax_version, do { Str::clear(Sm->sect_range); WRITE_TO(Sm->sect_range, "%S/", Cm->ch_range); - @; + <>; if (--letters_from_each_word == 0) break; } while (Str::len(Sm->sect_range) > 5); - @; + <>; } @ We collapse words to an initial letter plus consonants: thus "electricity" would be "elctrcty", since we don't count "y" as a vowel here. -@ = +<>= int sn = 0, sw = Str::len(Sm->sect_range); if (Platform::is_folder_separator(Str::get_at(from, sn))) sn++; int letters_from_current_word = 0; @@ -197,7 +198,7 @@ would be "elctrcty", since we don't count "y" as a vowel here. @ We never want two sections to have the same range. -@ = +<>= TEMPORARY_TEXT(original_range) Str::copy(original_range, Sm->sect_range); int disnum = 0, collision = FALSE; @@ -224,10 +225,10 @@ would be "elctrcty", since we don't count "y" as a vowel here. } while (collision); DISCARD_TEXT(original_range) -@h Reading the contents page. +@ \section{Reading the contents page.} Making the web begins by reading the contents section, which really isn't a section at all (and perhaps we shouldn't pretend that it is by the use of the -|.w| file extension, but we probably want it to have the same file extension, +[[.w]] file extension, but we probably want it to have the same file extension, and its syntax is chosen so that syntax-colouring for regular sections doesn't make it look odd). When the word "section" is used in the Inweb code, it almost always means "section other than the contents". @@ -242,7 +243,7 @@ With a single-file web, the "contents section" doesn't exist as a file in its own right: instead, it's the top few lines of the single file. We handle that by halting at the junction point. -= +<<*>>= typedef struct reader_state { struct web_md *Wm; struct filename *contents_filename; @@ -268,7 +269,7 @@ void WebMetadata::read_contents_page(web_md *Wm, module *of_module, module_search *import_path, int verbosely, int including_modules, pathname *path, pathname *X) { reader_state RS; - @; + <>; int cl = TextFiles::read(RS.contents_filename, FALSE, "can't open contents file", TRUE, WebMetadata::read_contents_line, NULL, &RS); @@ -282,7 +283,7 @@ void WebMetadata::read_contents_page(web_md *Wm, module *of_module, if (RS.section_count == 1) RS.last_section->is_a_singleton = TRUE; } -@ = +<>= RS.Wm = Wm; RS.reading_from = of_module; RS.in_biblio = TRUE; @@ -318,7 +319,7 @@ void WebMetadata::read_contents_page(web_md *Wm, module *of_module, and sets out bibliographic information about the web, the sections and their organisation, and so on. -= +<<*>>= void WebMetadata::read_contents_line(text_stream *line, text_file_position *tfp, void *X) { reader_state *RS = (reader_state *) X; if (RS->halted) return; @@ -328,40 +329,40 @@ void WebMetadata::read_contents_line(text_stream *line, text_file_position *tfp, begins_with_white_space = TRUE; Str::trim_white_space(line); - @; + <>; int syntax = RS->Wm->default_syntax; filename *filename_of_single_file_web = NULL; if ((RS->halt_at_at) && (Str::get_at(line, 0) == '@')) - @; + <>; - @; + <>; } @ Since the web syntax version affects how the rest of the file is read, it's no good simply to store this up for later: we have to change the web structure immediately. -@ = +<>= if (Str::eq(line, I"Web Syntax Version: 1")) RS->Wm->default_syntax = V1_SYNTAX; else if (Str::eq(line, I"Web Syntax Version: 2")) RS->Wm->default_syntax = V2_SYNTAX; -@ Suppose we're reading a single-file web, and we hit the first |@| marker. +@ Suppose we're reading a single-file web, and we hit the first [[@]] marker. The contents part has now ended, so we should halt scanning. But we also need to give the web a single chapter ("Sections", range "S"), which contains a single section ("All") consisting of the remainder of the single file. -@ = +<>= RS->halted = TRUE; text_stream *new_chapter_range = I"S"; text_stream *language_name = NULL; line = I"Sections"; - @; + <>; line = I"All"; filename_of_single_file_web = tfp->text_file_filename; - @; + <>; return; @ With those two complications out of the way, we now know that we're reading @@ -369,21 +370,21 @@ a line of contents material. At the start of the contents, this will be a series of bibliographic data values; then there's a blank line, and then we're into the section listing. -@ = - if (Str::len(line) == 0) @ - else if (RS->in_biblio) @ - else @; +<>= + if (Str::len(line) == 0) <> + else if (RS->in_biblio) <> + else <>; @ At this point we've gone through the bibliographic lines at the top of the contents page, and are soon going to read in the sections. -@ = +<>= RS->in_biblio = FALSE; @ The bibliographic data gives lines in any order specifying values of variables with fixed names; a blank line ends the block. -@ = +<>= if (RS->main_web_not_module) { match_results mr = Regexp::create_mr(); if (Regexp::match(&mr, line, L"(%c+?): (%c+?) *")) { @@ -391,7 +392,7 @@ variables with fixed names; a blank line ends the block. Str::copy(key, mr.exp[0]); TEMPORARY_TEXT(value) Str::copy(value, mr.exp[1]); - @; + <>; DISCARD_TEXT(key) DISCARD_TEXT(value) } else { @@ -403,7 +404,7 @@ variables with fixed names; a blank line ends the block. Regexp::dispose_of(&mr); } -@ = +<>= if (Bibliographic::datum_can_be_declared(RS->Wm, key)) { if (Bibliographic::datum_on_or_off(RS->Wm, key)) { if ((Str::ne_wide_string(value, L"On")) && (Str::ne_wide_string(value, L"Off"))) { @@ -426,20 +427,20 @@ variables with fixed names; a blank line ends the block. @ In the bulk of the contents, we find indented lines for sections and unindented ones for chapters. -@ = +<>= if (begins_with_white_space == FALSE) { if (Str::get_first_char(line) == '"') { RS->in_purpose = TRUE; Str::delete_first_character(line); } - if (RS->in_purpose == TRUE) @ - else @; - } else @; + if (RS->in_purpose == TRUE) <> + else <>; + } else <>; @ After a declared chapter heading, subsequent lines form its purpose, until we reach a closed quote: we then stop, but remove the quotation marks. Because we like a spoonful of syntactic sugar on our porridge, that's why. -@ = +<>= if ((Str::len(line) > 0) && (Str::get_last_char(line) == '"')) { Str::truncate(line, Str::len(line)-1); RS->in_purpose = FALSE; } @@ -451,7 +452,7 @@ we like a spoonful of syntactic sugar on our porridge, that's why. @ The title tells us everything we need to know about a chapter: -@ = +<>= TEMPORARY_TEXT(new_chapter_range) /* e.g., S, P, 1, 2, 3, A, B, ... */ TEMPORARY_TEXT(pdf_leafname) text_stream *language_name = NULL; @@ -460,7 +461,7 @@ we like a spoonful of syntactic sugar on our porridge, that's why. if (Regexp::match(&mr, line, L"(%c*%C) %(Independent(%c*)%)")) { text_stream *title_alone = mr.exp[0]; language_name = mr.exp[1]; - @; + <>; Str::copy(line, title_alone); } int this_is_a_chapter = TRUE; @@ -540,7 +541,7 @@ we like a spoonful of syntactic sugar on our porridge, that's why. DISCARD_TEXT(err) } - if (this_is_a_chapter) @; + if (this_is_a_chapter) <>; DISCARD_TEXT(new_chapter_range) DISCARD_TEXT(pdf_leafname) Regexp::dispose_of(&mr); @@ -548,7 +549,7 @@ we like a spoonful of syntactic sugar on our porridge, that's why. @ A chapter whose title marks it as Independent becomes a new tangle target, with the same language as the main web unless stated otherwise. -@ = +<>= match_results mr = Regexp::create_mr(); if (Regexp::match(&mr, language_name, L" *")) language_name = Bibliographic::get_datum(RS->Wm, I"Language"); @@ -556,7 +557,7 @@ with the same language as the main web unless stated otherwise. language_name = mr.exp[0]; Regexp::dispose_of(&mr); -@ = +<>= chapter_md *Cm = CREATE(chapter_md); Cm->ch_range = Str::duplicate(new_chapter_range); if (line == NULL) PRINT("Nullity!\n"); @@ -584,16 +585,16 @@ with the same language as the main web unless stated otherwise. of registering a new section within a chapter -- more interesting because we also read in and process its file. -@ = +<>= section_md *Sm = CREATE(section_md); - @; - @; - @; + <>; + <>; + <>; if (Sm->source_file_for_section == NULL) - @; + <>; -@ = +<>= Sm->source_file_for_section = filename_of_single_file_web; Sm->using_syntax = syntax; Sm->is_a_singleton = FALSE; @@ -612,7 +613,7 @@ we also read in and process its file. Regexp::dispose_of(&mr); Sm->owning_module = RS->reading_from; -@ = +<>= chapter_md *Cm = RS->chapter_being_scanned; RS->section_count++; RS->last_section = Sm; @@ -620,28 +621,28 @@ we also read in and process its file. ADD_TO_LINKED_LIST(Sm, section_md, RS->Wm->sections_md); ADD_TO_LINKED_LIST(Sm, section_md, RS->reading_from->sections_md); -@ = +<>= Sm->sect_language_name = RS->chapter_being_scanned->ch_language_name; /* by default */ match_results mr = Regexp::create_mr(); if (Regexp::match(&mr, line, L"(%c*%C) %(Independent (%c*) *%)")) { text_stream *title_alone = mr.exp[0]; text_stream *language_name = mr.exp[1]; - @; + <>; Str::copy(Sm->sect_title, title_alone); } Regexp::dispose_of(&mr); -@ = +<>= text_stream *p = language_name; if (Str::len(p) == 0) p = Bibliographic::get_datum(RS->Wm, I"Language"); Sm->sect_independent_language = Str::duplicate(p); @ If we're told that a section is called "Bells and Whistles", what filename -is it stored in? Firstly, the leafname is normally |Bells and Whistles.w|, -but the extension used doesn't have to be |.w|: for Inform 6 template files, -the extension needs to be |.i6t|. We allow either. +is it stored in? Firstly, the leafname is normally [[Bells and Whistles.w]], +but the extension used doesn't have to be [[.w]]: for Inform 6 template files, +the extension needs to be [[.i6t]]. We allow either. -@ = +<>= TEMPORARY_TEXT(leafname_to_use) WRITE_TO(leafname_to_use, "%S.i6t", Sm->sect_title); pathname *P = RS->path_to; @@ -656,9 +657,9 @@ the extension needs to be |.i6t|. We allow either. } DISCARD_TEXT(leafname_to_use) -@h Relative pathnames or filenames. +@ \section{Relative pathnames or filenames.} -= +<<*>>= int WebMetadata::directory_looks_like_a_web(pathname *P) { return TextFiles::exists(WebMetadata::contents_filename(P)); } @@ -667,9 +668,9 @@ filename *WebMetadata::contents_filename(pathname *P) { return Filenames::in(P, I"Contents.w"); } -@h Statistics. +@ \section{Statistics.} -= +<<*>>= int WebMetadata::chapter_count(web_md *Wm) { int n = 0; chapter_md *Cm;