From 3271eae5f6b3960d35f22a7feff6b2c62fa44334 Mon Sep 17 00:00:00 2001 From: Graham Nelson Date: Wed, 27 Feb 2019 10:22:00 +0000 Subject: [PATCH] Tidied up inpolicy --- inpolicy/Chapter 1/Main.w | 19 ++- .../Problem Coverage.w | 145 ++++++++++-------- .../Version Numbering.w | 120 +++++++++------ inpolicy/Contents.w | 7 +- inpolicy/Preliminaries/Using Inpolicy.w | 66 ++++++++ makescript.txt | 1 + 6 files changed, 246 insertions(+), 112 deletions(-) rename inpolicy/{Chapter 1 => Chapter 2}/Problem Coverage.w (68%) rename inpolicy/{Chapter 1 => Chapter 2}/Version Numbering.w (75%) create mode 100755 inpolicy/Preliminaries/Using Inpolicy.w diff --git a/inpolicy/Chapter 1/Main.w b/inpolicy/Chapter 1/Main.w index c20ef9ae1..94fc94f54 100644 --- a/inpolicy/Chapter 1/Main.w +++ b/inpolicy/Chapter 1/Main.w @@ -6,11 +6,14 @@ this plan out. @h Main routine. @e SILENCE_CLSW +@e VERBOSE_CLSW @e PROBLEMS_CLSW @e ADVANCE_CLSW = -int return_happy = TRUE, silence_mode = FALSE; +pathname *path_to_inpolicy = NULL; /* where we are installed */ +pathname *path_to_inpolicy_materials = NULL; /* the materials pathname */ +int return_happy = TRUE, silence_mode = FALSE, verbose_mode = FALSE; int main(int argc, char **argv) { Foundation::start(); @@ -19,15 +22,22 @@ int main(int argc, char **argv) { L"[[Purpose]]\n\n" L"usage: inpolicy [options]\n"); - CommandLine::declare_boolean_switch(SILENCE_CLSW, L"silence", 1, - L"print nothing unless there's something wrong"); CommandLine::declare_switch(PROBLEMS_CLSW, L"check-problems", 1, L"check problem test case coverage"); CommandLine::declare_switch(ADVANCE_CLSW, L"advance-build", 2, L"increment daily build code for web X"); + CommandLine::declare_boolean_switch(SILENCE_CLSW, L"silence", 1, + L"print nothing unless there's something wrong"); + CommandLine::declare_boolean_switch(VERBOSE_CLSW, L"verbose", 1, + L"explain what inpolicy is doing"); + CommandLine::read(argc, argv, NULL, &Main::respond, &Main::disallow); + path_to_inpolicy = Pathnames::installation_path("INPOLICY_PATH", I"inpolicy"); + path_to_inpolicy_materials = Pathnames::subfolder(path_to_inpolicy, I"Materials"); + if (verbose_mode) PRINT("Installation path is %p\n", path_to_inpolicy); + Foundation::end(); if (return_happy) return 0; else return 1; } @@ -39,6 +49,8 @@ void Main::disallow(int id, text_stream *arg, void *state) { @ @d RUNTEST(Routine) + path_to_inpolicy = Pathnames::installation_path("INPOLICY_PATH", I"inpolicy"); + path_to_inpolicy_materials = Pathnames::subfolder(path_to_inpolicy, I"Materials"); if (silence_mode) { if (Routine(NULL) == FALSE) { return_happy = FALSE; Routine(STDERR); } } else { @@ -51,5 +63,6 @@ void Main::respond(int id, int val, text_stream *arg, void *state) { case ADVANCE_CLSW: Inversion::maintain(arg); break; case PROBLEMS_CLSW: RUNTEST(Coverage::check); break; case SILENCE_CLSW: silence_mode = val; break; + case VERBOSE_CLSW: verbose_mode = val; break; } } diff --git a/inpolicy/Chapter 1/Problem Coverage.w b/inpolicy/Chapter 2/Problem Coverage.w similarity index 68% rename from inpolicy/Chapter 1/Problem Coverage.w rename to inpolicy/Chapter 2/Problem Coverage.w index 529c37b07..83b10b409 100644 --- a/inpolicy/Chapter 1/Problem Coverage.w +++ b/inpolicy/Chapter 2/Problem Coverage.w @@ -4,21 +4,25 @@ To see which problem messages have test cases and which are linked to the documentation. @h Observation. +Problem messages are identified by their code-names, e.g., |PM_MisplacedFrom|; +those names should be unique, but any number of problems can instead be +marked with one of three special names. -@d CASE_EXISTS_PCON 0x00000001 -@d DOC_MENTIONS_PCON 0x00000002 -@d CODE_MENTIONS_PCON 0x00000004 -@d IMPOSSIBLE_PCON 0x00000008 -@d UNTESTABLE_PCON 0x00000010 -@d NAMELESS_PCON 0x00000020 +Problems can be mentioned in the code, in the documentation, or in the +set of Inform test cases. + +@d CASE_EXISTS_PCON 0x00000001 /* mentioned in test cases */ +@d DOC_MENTIONS_PCON 0x00000002 /* mentioned in documentation */ +@d CODE_MENTIONS_PCON 0x00000004 /* mentioned in source code */ +@d IMPOSSIBLE_PCON 0x00000008 /* this is |BelievedImpossible| */ +@d UNTESTABLE_PCON 0x00000010 /* this is |Untestable| */ +@d NAMELESS_PCON 0x00000020 /* this is |...| */ = -dictionary *problems_dictionary = NULL; - typedef struct known_problem { struct text_stream *name; - int contexts_observed; - int contexts_observed_multiple_times; + int contexts_observed; /* bitmap of the above bits */ + int contexts_observed_multiple_times; /* bitmap of the above bits */ MEMORY_MANAGEMENT } known_problem; @@ -26,6 +30,8 @@ typedef struct known_problem { and augment its bitmap of known contexts: = +dictionary *problems_dictionary = NULL; + void Coverage::observe_problem(text_stream *name, int context) { if (problems_dictionary == NULL) problems_dictionary = Dictionaries::new(1000, FALSE); @@ -92,23 +98,29 @@ void Coverage::xref_harvester(text_stream *text, text_file_position *tfp, void * } @h Problems generated in the I7 source. -Which is to say, actually existing problem messages. +Which is to say, actually existing problem messages. Ideally, this code +should find the modules included in Inform in some more sophisticated way. = -void Coverage::which_problems_exist(pathname *Workspace) { - Coverage::which_problems_exist_inner( - Pathnames::from_text(I"inform7"), Workspace); - Coverage::which_problems_exist_inner( - Pathnames::from_text(I"inform7/core-module"), Workspace); - Coverage::which_problems_exist_inner( - Pathnames::from_text(I"inform7/if-module"), Workspace); - Coverage::which_problems_exist_inner( - Pathnames::from_text(I"inform7/multimedia-module"), Workspace); - Coverage::which_problems_exist_inner( - Pathnames::from_text(I"inter/codegen-module"), Workspace); +void Coverage::which_problems_exist(void) { + Coverage::which_problems_exist_inner(Pathnames::from_text(I"inform7")); + Coverage::which_problems_exist_inner(Pathnames::from_text(I"inform7/core-module")); + Coverage::which_problems_exist_inner(Pathnames::from_text(I"inform7/if-module")); + Coverage::which_problems_exist_inner(Pathnames::from_text(I"inform7/multimedia-module")); + Coverage::which_problems_exist_inner(Pathnames::from_text(I"inter/codegen-module")); } -void Coverage::which_problems_exist_inner(pathname *D, pathname *Workspace) { +@ So now we have to read the contents page of a web, to see what section +files it contains: + += +typedef struct existence_state { + struct pathname *web_path; + struct pathname *chapter_path; + struct filename *section; +} existence_state; + +void Coverage::which_problems_exist_inner(pathname *D) { filename *C = Filenames::in_folder(D, I"Contents.w"); existence_state es; es.web_path = D; @@ -117,12 +129,6 @@ void Coverage::which_problems_exist_inner(pathname *D, pathname *Workspace) { &Coverage::section_harvester, NULL, &es); } -typedef struct existence_state { - struct pathname *web_path; - struct pathname *chapter_path; - struct filename *section; -} existence_state; - void Coverage::section_harvester(text_stream *text, text_file_position *tfp, void *state) { existence_state *es = (existence_state *) state; match_results mr = Regexp::create_mr(); @@ -143,6 +149,11 @@ void Coverage::section_harvester(text_stream *text, text_file_position *tfp, voi Regexp::dispose_of(&mr); } +@ So now we're working through individual section files. The exclusion of +the case called |sigil| throws out a macro definition in the source code, +not a specific problem case. + += void Coverage::existence_harvester(text_stream *text, text_file_position *tfp, void *state) { existence_state *es = (existence_state *) state; match_results mr = Regexp::create_mr(); @@ -151,64 +162,78 @@ void Coverage::existence_harvester(text_stream *text, text_file_position *tfp, v WRITE_TO(text, "%S%S", mr.exp[0], mr.exp[2]); TEMPORARY_TEXT(name); Str::copy(name, mr.exp[1]); - if (Str::eq_wide_string(name, L"sigil")) break; + if (Str::eq(name, I"sigil")) break; int context = CODE_MENTIONS_PCON; - if (Str::eq_wide_string(name, L"BelievedImpossible")) { context = IMPOSSIBLE_PCON; @ } - else if (Str::eq_wide_string(name, L"Untestable")) { context = UNTESTABLE_PCON; @ } - else if (Str::eq_wide_string(name, L"...")) { context = NAMELESS_PCON; @ } - if (Str::eq_wide_string(name, L"BelievedImpossible")) @ + if (Str::eq(name, I"BelievedImpossible")) { + context = IMPOSSIBLE_PCON; + WRITE_TO(name, "_%f_line%d", es->section, tfp->line_count); + } else if (Str::eq(name, I"Untestable")) { + context = UNTESTABLE_PCON; + WRITE_TO(name, "_%f_line%d", es->section, tfp->line_count); + } else if (Str::eq(name, I"...")) { + context = NAMELESS_PCON; + WRITE_TO(name, "_%f_line%d", es->section, tfp->line_count); + } Coverage::observe_problem(name, context); DISCARD_TEXT(name); } Regexp::dispose_of(&mr); } -@ = - WRITE_TO(name, "_%f_line%d", es->section, tfp->line_count); - @h Checking. +So the actual policy-enforcement routine is here: = int observations_made = FALSE; int Coverage::check(OUTPUT_STREAM) { if (observations_made == FALSE) { - pathname *P = - Pathnames::subfolder(Pathnames::from_text(I"inpolicy"), I"Workspace"); - Coverage::which_problems_have_test_cases(P); - Coverage::which_problems_are_referenced(P); - Coverage::which_problems_exist(P); + @; observations_made = TRUE; } int all_is_well = TRUE; + @; + if (all_is_well) WRITE("All is well.\n"); + else WRITE("This needs attention.\n"); + WRITE("\n"); + return all_is_well; +} +@ = + Coverage::which_problems_have_test_cases(path_to_inpolicy_materials); + Coverage::which_problems_are_referenced(path_to_inpolicy_materials); + Coverage::which_problems_exist(); + +@ Okay, so that's all of the scanning done; now to report on it. + +@ = WRITE("%d problem name(s) have been observed:\n", NUMBER_CREATED(known_problem)); INDENT; WRITE("Problems actually existing (the source code refers to them):\n"); INDENT; Coverage::cite(OUT, CODE_MENTIONS_PCON, 0, CODE_MENTIONS_PCON, - L"are named and in principle testable"); + I"are named and in principle testable"); if (Coverage::cite(OUT, 0, CODE_MENTIONS_PCON, CODE_MENTIONS_PCON, - L"are named more than once:") > 0) { + I"are named more than once:") > 0) { all_is_well = FALSE; Coverage::list(OUT, 0, CODE_MENTIONS_PCON, CODE_MENTIONS_PCON); } Coverage::cite(OUT, IMPOSSIBLE_PCON, 0, IMPOSSIBLE_PCON, - L"are 'BelievedImpossible', that is, no known source text causes them"); + I"are 'BelievedImpossible', that is, no known source text causes them"); Coverage::cite(OUT, UNTESTABLE_PCON, 0, UNTESTABLE_PCON, - L"are 'Untestable', that is, not mechanically testable"); + I"are 'Untestable', that is, not mechanically testable"); Coverage::cite(OUT, NAMELESS_PCON, 0, NAMELESS_PCON, - L"are '...', that is, they need to be give a name and a test case"); + I"are '...', that is, they need to be give a name and a test case"); OUTDENT; WRITE("Problems which should have test cases:\n"); INDENT; Coverage::cite(OUT, CASE_EXISTS_PCON+CODE_MENTIONS_PCON, 0, CASE_EXISTS_PCON+CODE_MENTIONS_PCON, - L"have test cases"); + I"have test cases"); if (Coverage::cite(OUT, CASE_EXISTS_PCON+CODE_MENTIONS_PCON, 0, CODE_MENTIONS_PCON, - L"have no test case yet:") > 0) { + I"have no test case yet:") > 0) { Coverage::list(OUT, CASE_EXISTS_PCON+CODE_MENTIONS_PCON, 0, CODE_MENTIONS_PCON); } if (Coverage::cite(OUT, CASE_EXISTS_PCON+CODE_MENTIONS_PCON, 0, CASE_EXISTS_PCON, - L"are spurious test cases, since no such problems exist:") > 0) { + I"are spurious test cases, since no such problems exist:") > 0) { all_is_well = FALSE; Coverage::list(OUT, CASE_EXISTS_PCON+CODE_MENTIONS_PCON, 0, CASE_EXISTS_PCON); } @@ -216,45 +241,39 @@ int Coverage::check(OUTPUT_STREAM) { WRITE("Problems which are cross-referenced in 'Writing with Inform':\n"); INDENT; Coverage::cite(OUT, CODE_MENTIONS_PCON+DOC_MENTIONS_PCON, 0, CODE_MENTIONS_PCON+DOC_MENTIONS_PCON, - L"are cross-referenced"); + I"are cross-referenced"); if (Coverage::cite(OUT, 0, DOC_MENTIONS_PCON, DOC_MENTIONS_PCON, - L"are cross-referenced more than once:") > 0) { + I"are cross-referenced more than once:") > 0) { all_is_well = FALSE; Coverage::list(OUT, 0, DOC_MENTIONS_PCON, DOC_MENTIONS_PCON); } if (Coverage::cite(OUT, CODE_MENTIONS_PCON+DOC_MENTIONS_PCON, 0, DOC_MENTIONS_PCON, - L"are spurious references, since no such problems exist:") > 0) { + I"are spurious references, since no such problems exist:") > 0) { all_is_well = FALSE; Coverage::list(OUT, CODE_MENTIONS_PCON+DOC_MENTIONS_PCON, 0, DOC_MENTIONS_PCON); } OUTDENT; - OUTDENT; - if (all_is_well) WRITE("All is well.\n"); - else WRITE("This needs attention.\n"); - WRITE("\n"); - return all_is_well; -} -int Coverage::cite(OUTPUT_STREAM, int mask, int mask2, int val, wchar_t *message) { +@ = +int Coverage::cite(OUTPUT_STREAM, int mask, int mask2, int val, text_stream *message) { int N = 0; known_problem *KP; LOOP_OVER(KP, known_problem) { if ((KP->contexts_observed & mask) == val) N++; if ((KP->contexts_observed_multiple_times & mask2) == val) N++; } - if ((N>0) && (message)) WRITE("%d problem(s) %w\n", N, message); + if ((N>0) && (message)) WRITE("%d problem(s) %S\n", N, message); return N; } void Coverage::list(OUTPUT_STREAM, int mask, int mask2, int val) { INDENT; known_problem *KP; - LOOP_OVER(KP, known_problem) { + LOOP_OVER(KP, known_problem) if (((KP->contexts_observed & mask) == val) || ((KP->contexts_observed_multiple_times & mask2) == val)) { WRITE("%S\n", KP->name); } - } OUTDENT; } diff --git a/inpolicy/Chapter 1/Version Numbering.w b/inpolicy/Chapter 2/Version Numbering.w similarity index 75% rename from inpolicy/Chapter 1/Version Numbering.w rename to inpolicy/Chapter 2/Version Numbering.w index e2806c23d..fcbfacf02 100644 --- a/inpolicy/Chapter 1/Version Numbering.w +++ b/inpolicy/Chapter 2/Version Numbering.w @@ -3,6 +3,10 @@ To update the build number(s) and versions for the intools. @h The build-numbers file. +The scheme here is that each project can optionally contain a UTF-8 encoded +text file called |versions.txt|, which lists all of its version history; +a line of that file corresponds to a "version". Out of these versions, one +must be marked as the current version. = typedef struct project { @@ -11,7 +15,7 @@ typedef struct project { int manual_updating; struct text_stream *web; struct filename *versions_file; - struct version *first_version; + struct linked_list *versions; /* of |version| */ struct version *current_version; struct text_stream *conts; MEMORY_MANAGEMENT @@ -23,42 +27,58 @@ typedef struct version { struct text_stream *build_code; struct text_stream *date; struct text_stream *notes; - int unstable; - struct version *next_version; MEMORY_MANAGEMENT } version; +@ And here we turn a named web into its |project| structure. We print its +current version number when we first load a project in: + += project *Inversion::read(text_stream *web) { project *P; - LOOP_OVER(P, project) - if (Str::eq(web, P->web)) - return P; + LOOP_OVER(P, project) if (Str::eq(web, P->web)) return P; P = CREATE(project); P->sync_line = Str::new(); P->sync_to = NULL; P->manual_updating = TRUE; P->web = Str::duplicate(web); - P->first_version = NULL; + P->versions = NEW_LINKED_LIST(version); P->current_version = NULL; - P->versions_file = Filenames::in_folder(Pathnames::from_text(web), I"versions.txt"); - TextFiles::read(P->versions_file, FALSE, "unable to read roster of version numbers", TRUE, - &Inversion::version_harvester, NULL, P); P->conts = Str::new(); + P->versions_file = Filenames::in_folder(Pathnames::from_text(web), I"versions.txt"); + @; + @; + return P; +} + +@ = if (P->current_version == NULL) { Errors::with_text("warning: no version marked as current", web); } else { PRINT("%S: %S %S (build %S)\n", web, P->current_version->name, P->current_version->number, P->current_version->build_code); } - return P; -} +@ = + TextFiles::read(P->versions_file, FALSE, "unable to read roster of version numbers", TRUE, + &Inversion::version_harvester, NULL, P); + +@ A version file contains lines which can either be a special command, or +give details of a version. The commands are |Automatic| or |Manual| (the +latter is the default), or |Sync to W|, where |W| is another project. +(All of this is infrastructure left over from when the Inform tools were +syncing version numbers to the main Inform 7 version number: with the +transition to Github, this scheme was dropped.) + += void Inversion::version_harvester(text_stream *text, text_file_position *tfp, void *state) { project *P = (project *) state; match_results mr = Regexp::create_mr(); if (Str::len(text) == 0) return; if (Regexp::match(&mr, text, L"Automatic")) { P->manual_updating = FALSE; + } else if (Regexp::match(&mr, text, L"Manual")) { + P->manual_updating = TRUE; } else if (Regexp::match(&mr, text, L"Sync to (%c*)")) { P->sync_to = Inversion::read(mr.exp[0]); P->manual_updating = FALSE; @@ -70,39 +90,39 @@ void Inversion::version_harvester(text_stream *text, text_file_position *tfp, vo V->date = Str::duplicate(mr.exp[3]); V->notes = Str::duplicate(mr.exp[4]); if (Str::get_first_char(V->build_code) == '*') { - V->unstable = TRUE; Str::delete_first_character(V->build_code); P->current_version = V; - } else V->unstable = FALSE; - if (P->first_version == NULL) P->first_version = V; - else { - version *W = P->first_version; - while ((W) && (W->next_version)) W = W->next_version; - W->next_version = V; } + ADD_TO_LINKED_LIST(V, version, P->versions); } else { Errors::in_text_file("can't parse version line", tfp); } Regexp::dispose_of(&mr); } +@ The following then writes back the versions file, following a version +increment: + += void Inversion::write(project *P) { text_stream vr_stream; text_stream *OUT = &vr_stream; if (Streams::open_to_file(OUT, P->versions_file, UTF8_ENC) == FALSE) Errors::fatal_with_file("can't write versions file", P->versions_file); if (P->sync_to) WRITE("Sync to %S\n", P->sync_to->web); - for (version *V = P->first_version; V; V = V->next_version) { - WRITE("%S\t%S\t", - V->name, V->number); - if (V->unstable) WRITE("*"); - WRITE("%S\t%S\t%S\n", - V->build_code, V->date, V->notes); + else if (P->manual_updating) WRITE("Manual\n"); + else WRITE("Automatic\n"); + version *V; + LOOP_OVER_LINKED_LIST(V, version, P->versions) { + WRITE("%S\t%S\t", V->name, V->number); + if (V == P->current_version) WRITE("*"); + WRITE("%S\t%S\t%S\n", V->build_code, V->date, V->notes); } Streams::close(OUT); } @h Updating. +The standard date format we use is "26 February 2018". = int Inversion::dated_today(project *P, text_stream *dateline) { @@ -116,6 +136,13 @@ int Inversion::dated_today(project *P, text_stream *dateline) { return rv; } +@ Here we read the Inform four-character code, e.g., |3Q27|, 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. + += void Inversion::increment(project *P) { if (P->current_version == NULL) return; text_stream *T = P->current_version->build_code; @@ -145,6 +172,8 @@ void Inversion::increment(project *P) { } @h Imposition. +When we impose a new version number on a web that has a contents page, we +update the metadata in that contents page. = void Inversion::impose(project *P) { @@ -179,6 +208,27 @@ void Inversion::impose_helper(text_stream *text, text_file_position *tfp, void * Regexp::dispose_of(&mr); } +@h Daily build maintenance. + += +void Inversion::maintain(text_stream *web) { + project *P = Inversion::read(web); + if (Inversion::needs_update(P)) { + Inversion::write(P); + Inversion::impose(P); + if ((Str::eq(web, I"inform7")) && (P->current_version)) { + filename *F = Filenames::from_text(I"build-code.mk"); + text_stream as_stream; + text_stream *OUT = &as_stream; + if (Streams::open_to_file(OUT, F, UTF8_ENC) == FALSE) + Errors::fatal_with_file("unable to write archive settings", F); + WRITE("BUILDCODE = %S\n", P->current_version->build_code); + Streams::close(OUT); + } + } +} + +@ = int Inversion::needs_update(project *P) { int rv = FALSE; if ((P->manual_updating == FALSE) && (P->current_version)) { @@ -204,23 +254,3 @@ int Inversion::needs_update(project *P) { } return rv; } - -@h Daily build maintenance. - -= -void Inversion::maintain(text_stream *web) { - project *P = Inversion::read(web); - if (Inversion::needs_update(P)) { - Inversion::write(P); - Inversion::impose(P); - if ((Str::eq(web, I"inform7")) && (P->current_version)) { - filename *F = Filenames::from_text(I"build-code.mk"); - text_stream as_stream; - text_stream *OUT = &as_stream; - if (Streams::open_to_file(OUT, F, UTF8_ENC) == FALSE) - Errors::fatal_with_file("unable to write archive settings", F); - WRITE("BUILDCODE = %S\n", P->current_version->build_code); - Streams::close(OUT); - } - } -} diff --git a/inpolicy/Contents.w b/inpolicy/Contents.w index 4c87270be..6a7e03763 100644 --- a/inpolicy/Contents.w +++ b/inpolicy/Contents.w @@ -12,8 +12,13 @@ Build Date: 10 February 2019 Import: foundation -Chapter 1: What It Does +Preliminaries + Using Inpolicy + +Chapter 1: Setting Up Basics Main + +Chapter 2: Policies Problem Coverage Version Numbering diff --git a/inpolicy/Preliminaries/Using Inpolicy.w b/inpolicy/Preliminaries/Using Inpolicy.w new file mode 100755 index 000000000..edcc2b6dc --- /dev/null +++ b/inpolicy/Preliminaries/Using Inpolicy.w @@ -0,0 +1,66 @@ +Using Inpolicy. + +A very short guide to a very small program. + +@h What Inpolicy is. +Inpolicy is a command-line tool whose sole purpose is to help keep the +Inform 7 source code tidy. Unlike Inweb, Intest and Indoc, this tool +can't sensibly be used for any project other than Inform. + +If you have compiled the standard distribution of the command-line tools +for Inform then the Inpolicy executable will be at |inpolicy/Tangled/inpolicy|. +Usage is very simple: + + |$ inpolicy/Tangled/inpolicy POLICY| + +where |POLICY| is whatever we want to check. There are very few at present; +in some ways this program is a placeholder for future tightening-up of the +style rules. + +@ When it runs, Inpolicy needs to know where it is installed in the file +system. There is no completely foolproof, cross-platform way to know this +(on some Unixes, a program cannot determine its own location), so Inpolicy +decides by the following set of rules: + +(a) If the user, at the command line, specified |-at P|, for some path +|P|, then we use that. +(b) Otherwise, if the host operating system can indeed tell us where the +executable is, we use that. This is currently implemented only on MacOS, +Windows and Linux. +(c) Otherwise, if the environment variable |$INPOLICY_PATH| exists and is +non-empty, we use that. +(d) And if all else fails, we assume that the location is |inpolicy|, with +respect to the current working directory. + +If you're not sure what Inpolicy has decided and suspect it may be wrong, +running Inpolicy with the |-verbose| switch will cause it to print its belief +about its location as it starts up. + +@h Policies. +|-check-problems| makes a survey of (a) all of the Problem messages issued +within the Inform 7 compiler, (b) all of the Problem test cases, and (c) all +of the advisory references to Problems in the Inform documentation, and +attempts to match these up. It prints out a report, and concludes with either +"All is well" or a recommendation for changes. For example: + + |1009 problem name(s) have been observed:| + | Problems actually existing (the source code refers to them):| + | 906 problem(s) are named and in principle testable| + | 81 problem(s) are 'BelievedImpossible', that is, no known source text causes them| + | 14 problem(s) are 'Untestable', that is, not mechanically testable| + | 8 problem(s) are '...', that is, they need to be give a name and a test case| + | Problems which should have test cases:| + | 904 problem(s) have test cases| + | 2 problem(s) have no test case yet:| + | PM_SuperfluousOf| + | PM_MisplacedFrom| + | Problems which are cross-referenced in 'Writing with Inform':| + | 483 problem(s) are cross-referenced| + |All is well.| + +As this example report shows, small sins are forgiven. + +@ |-advance-build W| tries to advance the build code for the web |W|. In +practice, this is used only when the web is |inform7|. The build code is +the familiar (to Inform users) four-character version number, such as +|3K27| or |6P98|. diff --git a/makescript.txt b/makescript.txt index 3c23212c5..8fb7bdd70 100644 --- a/makescript.txt +++ b/makescript.txt @@ -345,6 +345,7 @@ endef pages: $(INWEBX) inblorb -weave-docs -weave-into docs/inblorb $(INWEBX) indoc -weave-docs -weave-into docs/indoc + $(INWEBX) inpolicy -weave-docs -weave-into docs/inpolicy # ----------------------------------------------------------------------------- # Target "clean"