diff --git a/foundation-module/Chapter_7/Version Number Ranges.w b/foundation-module/Chapter_7/Version_Number_Ranges.nw similarity index 84% rename from foundation-module/Chapter_7/Version Number Ranges.w rename to foundation-module/Chapter_7/Version_Number_Ranges.nw index 4ea13e4..a8b33f2 100644 --- a/foundation-module/Chapter_7/Version Number Ranges.w +++ b/foundation-module/Chapter_7/Version_Number_Ranges.nw @@ -2,25 +2,26 @@ Ranges of acceptable version numbers. -@h Ranges. +@ \section{Ranges.} We often want to check if a semver lies in a given precedence range, which we -store as an "interval" in the mathematical sense. For example, the range |[2,6)| +store as an "interval" in the mathematical sense. For example, the range [[[2,6)]] means all versions from 2.0.0 (inclusve) up to, but not equal to, 6.0.0. The lower end is called "closed" because it includes the end-value 2.0.0, and the upper end "open" because it does not. An infinite end means that there os no restriction in that direction; an empty end means that, in fact, the interval is the empty set, that is, that no version number can ever satisfy it. -The |end_value| element is meaningful only for |CLOSED_RANGE_END| and |OPEN_RANGE_END| -ends. If one end is marked |EMPTY_RANGE_END|, so must the other be: it makes +The [[end_value]] element is meaningful only for [[CLOSED_RANGE_END]] and [[OPEN_RANGE_END]] +ends. If one end is marked [[EMPTY_RANGE_END]], so must the other be: it makes no sense for an interval to be empty seen from one end but not the other. -@e CLOSED_RANGE_END from 1 -@e OPEN_RANGE_END -@e INFINITE_RANGE_END -@e EMPTY_RANGE_END +<<*>>= +enum CLOSED_RANGE_END from 1 +enum OPEN_RANGE_END +enum INFINITE_RANGE_END +enum EMPTY_RANGE_END -= +<<*>>= typedef struct range_end { int end_type; struct semantic_version_number end_value; @@ -32,10 +33,10 @@ typedef struct semver_range { CLASS_DEFINITION } semver_range; -@ As hinted above, the notation |[| and |]| is used for closed ends, and |(| -and |)| for open ones. +@ As hinted above, the notation [[[]] and [[]]] is used for closed ends, and [[(]] +and [[)]] for open ones. -= +<<*>>= void VersionNumberRanges::write_range(OUTPUT_STREAM, semver_range *R) { if (R == NULL) internal_error("no range"); switch(R->lower.end_type) { @@ -54,7 +55,7 @@ void VersionNumberRanges::write_range(OUTPUT_STREAM, semver_range *R) { @ The "allow anything" range runs from minus to plus infinity. Every version number lies in this range. -= +<<*>>= semver_range *VersionNumberRanges::any_range(void) { semver_range *R = CREATE(semver_range); R->lower.end_type = INFINITE_RANGE_END; @@ -72,18 +73,18 @@ int VersionNumberRanges::is_any_range(semver_range *R) { } @ The "compatibility" range for a given version lies at the heart of semver: -to be compatible with version |V|, version |W| must be of equal or greater +to be compatible with version [[V]], version [[W]] must be of equal or greater precedence, and must have the same major version number. For example, -for |2.1.7| the range will be |[2.1.7, 3-A)|, all versions at least 2.1.7 but +for [[2.1.7]] the range will be [[[2.1.7, 3-A)]], all versions at least 2.1.7 but not as high as 3.0.0-A. -Note that |3.0.0-A| is the least precendent version allowed by semver with -major version 3. The |-| gives it lower precedence than all release versions of -3.0.0; the fact that upper case |A| is alphabetically the earliest non-empty +Note that [[3.0.0-A]] is the least precendent version allowed by semver with +major version 3. The [[-]] gives it lower precedence than all release versions of +3.0.0; the fact that upper case [[A]] is alphabetically the earliest non-empty alphanumeric string gives it lower precendence than all other prerelease versions. -= +<<*>>= semver_range *VersionNumberRanges::compatibility_range(semantic_version_number V) { semver_range *R = VersionNumberRanges::any_range(); if (VersionNumbers::is_null(V) == FALSE) { @@ -102,7 +103,7 @@ semver_range *VersionNumberRanges::compatibility_range(semantic_version_number V @ More straightforwardly, these ranges are for anything from V, or up to V, inclusive: -= +<<*>>= semver_range *VersionNumberRanges::at_least_range(semantic_version_number V) { semver_range *R = VersionNumberRanges::any_range(); R->lower.end_type = CLOSED_RANGE_END; @@ -119,7 +120,7 @@ semver_range *VersionNumberRanges::at_most_range(semantic_version_number V) { @ Here we test whether V is at least a given end, and then at most: -= +<<*>>= int VersionNumberRanges::version_ge_end(semantic_version_number V, range_end E) { switch (E.end_type) { case CLOSED_RANGE_END: @@ -154,7 +155,7 @@ int VersionNumberRanges::version_le_end(semantic_version_number V, range_end E) @ This allows a simple way to write: -= +<<*>>= int VersionNumberRanges::in_range(semantic_version_number V, semver_range *R) { if (R == NULL) return TRUE; if ((VersionNumberRanges::version_ge_end(V, R->lower)) && @@ -163,18 +164,18 @@ int VersionNumberRanges::in_range(semantic_version_number V, semver_range *R) { } @ The following decides which end restriction is stricter: it returns 1 -of |E1| is, -1 if |E2| is, and 0 if they are equally onerous. +of [[E1]] is, -1 if [[E2]] is, and 0 if they are equally onerous. The empty set is as strict as it gets: nothing qualifies. Similarly, infinite ends are as relaxed as can be: everything qualifies. And otherwise, we need to know which end we're looking at in order to decide: -a lower end of |[4, ...]| is stricter than a lower end of |[3, ...]|, but an -upper end of |[..., 4]| is not as strict as an upper end of |[..., 3]|. Where +a lower end of [[[4, ...]]] is stricter than a lower end of [[[3, ...]]], but an +upper end of [[[..., 4]]] is not as strict as an upper end of [[[..., 3]]]. Where the boundary value is the same, open ends are stricter than closed ends. -= +<<*>>= int VersionNumberRanges::stricter(range_end E1, range_end E2, int lower) { if ((E1.end_type == EMPTY_RANGE_END) && (E2.end_type == EMPTY_RANGE_END)) return 0; if (E1.end_type == EMPTY_RANGE_END) return 1; @@ -192,13 +193,13 @@ int VersionNumberRanges::stricter(range_end E1, range_end E2, int lower) { } @ And so we finally arrive at the following, which intersects two ranges: -that is, it changes |R1| to the range of versions which lie inside both the -original |R1| and also |R2|. (This is used by Inbuild when an extension is +that is, it changes [[R1]] to the range of versions which lie inside both the +original [[R1]] and also [[R2]]. (This is used by Inbuild when an extension is included in two different places in the source text, but with possibly different version needs.) The return value is true if an actual change took place, and false otherwise. -= +<<*>>= int VersionNumberRanges::intersect_range(semver_range *R1, semver_range *R2) { int lc = VersionNumberRanges::stricter(R1->lower, R2->lower, TRUE); int uc = VersionNumberRanges::stricter(R1->upper, R2->upper, FALSE); diff --git a/foundation-module/Chapter_7/Version Numbers.w b/foundation-module/Chapter_7/Version_Numbers.nw similarity index 79% rename from foundation-module/Chapter_7/Version Numbers.w rename to foundation-module/Chapter_7/Version_Numbers.nw index 19ff087..e3419b0 100644 --- a/foundation-module/Chapter_7/Version Numbers.w +++ b/foundation-module/Chapter_7/Version_Numbers.nw @@ -2,9 +2,9 @@ Semantic version numbers such as 3.7.1. -@h Standard adoption. +@ \section{Standard adoption.} The Semantic Version Number standard, semver 2.0.0, provides a strict set -of rules for the format and meaning of version numbers: see |https://semver.org|. +of rules for the format and meaning of version numbers: see [[https://semver.org]]. Prior to the standard most version numbers in computing usage looked like dot-divided runs of non-negative integers: for example, 4, 7.1, and 0.2.3. @@ -13,53 +13,54 @@ therefore formally incorrect to have a version 2, or a version 2.3. We will not be so strict on the textual form, which we will allow to be abbreviated. Thus: -(a) The text |6.4.7| is understood to mean 6.4.7 and printed back as |6.4.7| -(b) The text |6| is understood to mean 6.0.0 and printed back as |6| -(c) The text |6.1| is understood to mean 6.1.0 and printed back as |6.1| -(d) The text |6.1.0| is understood to mean 6.1.0 and printed back as |6.1.0| +(a) The text [[6.4.7]] is understood to mean 6.4.7 and printed back as [[6.4.7]] +(b) The text [[6]] is understood to mean 6.0.0 and printed back as [[6]] +(c) The text [[6.1]] is understood to mean 6.1.0 and printed back as [[6.1]] +(d) The text [[6.1.0]] is understood to mean 6.1.0 and printed back as [[6.1.0]] Similarly, the absence of a version number (called "null" below) will be understood to mean 0.0.0, but will be distinguished from the explicit choice to number something as 0.0.0. @ A complication is that Inform 7 extensions have for many years allowed two -forms of version number: either just |N|, which fits the scheme above, or -|N/DDDDDD|, which does not. This is a format which was chosen for sentimental +forms of version number: either just [[N]], which fits the scheme above, or +[[N/DDDDDD]], which does not. This is a format which was chosen for sentimental reasons: IF enthusiasts know it well from the banner text of the Infocom titles of the 1980s. This story file, for instance, was compiled at the time of the Reykjavik summit between Presidents Gorbachev and Reagan: -= (text) + Moonmist Infocom interactive fiction - a mystery story Copyright (c) 1986 by Infocom, Inc. All rights reserved. Moonmist is a trademark of Infocom, Inc. Release number 9 / Serial number 861022 -= -Story file collectors customarily abbreviate this in catalogues to |9/861022|. -So we will allow this notation, but will convert |N/DDDDDD| to |N.0.DDDDDD|, +Story file collectors customarily abbreviate this in catalogues to [[9/861022]]. + +So we will allow this notation, but will convert [[N/DDDDDD| to |N.0.DDDDDD]], pushing the six date digits into the minor patch. (See the discussion of the bug report I7-2130, where users curating old extensions recommended this as -easier to deal with than |N.DDDDDD|.) So, then, |9/861022| means 9.0.861022 in +easier to deal with than [[N.DDDDDD]].) So, then, [[9/861022]] means 9.0.861022 in semver precedence order. In all non-textual respects, and in particular on precedence rules, we follow the standard exactly. -@ In the array below, unspecified numbers are stored as |-1|. The three +@ In the array below, unspecified numbers are stored as [[-1]]. The three components are otherwise required to be non-negative integers. -Semver allows for more elaborate forms: for example |3.1.41-alpha.72.zeta+6Q45| -would mean 3.1.41 but with prerelease versioning |alpha.72.zeta| and build -metadata |6Q45|. The |prerelease_segments| list for this would be a list of -three texts: |alpha|, |72|, |zeta|. +Semver allows for more elaborate forms: for example [[3.1.41-alpha.72.zeta+6Q45]] +would mean 3.1.41 but with prerelease versioning [[alpha.72.zeta]] and build +metadata [[6Q45]]. The [[prerelease_segments]] list for this would be a list of +three texts: [[alpha]], [[72]], [[zeta]]. -@d SEMVER_NUMBER_DEPTH 3 /* major, minor, patch */ +<<*>>= +#define SEMVER_NUMBER_DEPTH 3 /* major, minor, patch */ -= +<<*>>= typedef struct semantic_version_number { int version_numbers[SEMVER_NUMBER_DEPTH]; - struct linked_list *prerelease_segments; /* of |text_stream| */ + struct linked_list *prerelease_segments; /* of [[text_stream]] */ struct text_stream *build_metadata; } semantic_version_number; @@ -71,9 +72,9 @@ typedef struct semantic_version_number_holder { @ All invalid strings of numbers -- i.e., breaking the above rules -- are called "null" versions, and can never be valid as the version of anything. Instead they are used to represent the absence of a version number. -(In particular, a string of |-1|s is null.) +(In particular, a string of [[-1]]s is null.) -= +<<*>>= semantic_version_number VersionNumbers::null(void) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconditional-uninitialized" @@ -95,10 +96,10 @@ int VersionNumbers::is_null(semantic_version_number V) { return FALSE; } -@h Printing and parsing. +@ \section{Printing and parsing.} Printing is simple enough: -= +<<*>>= void VersionNumbers::to_text(OUTPUT_STREAM, semantic_version_number V) { if (VersionNumbers::is_null(V)) { WRITE("null"); return; } for (int i=0; (i= 0); i++) { @@ -116,30 +117,31 @@ void VersionNumbers::to_text(OUTPUT_STREAM, semantic_version_number V) { if (V.build_metadata) WRITE("+%S", V.build_metadata); } -@ And this provides for the |%v| escape, though we must be careful when +@ And this provides for the [[%v]] escape, though we must be careful when using this to pass a pointer to the version, not the version itself; -variadic macros are not carefully enough type-checked by |clang| or |gcc| +variadic macros are not carefully enough type-checked by [[clang]] or [[gcc]] to catch this sort of slip. -= +<<*>>= void VersionNumbers::writer(OUTPUT_STREAM, char *format_string, void *vE) { semantic_version_number *V = (semantic_version_number *) vE; VersionNumbers::to_text(OUT, *V); } @ Parsing is much more of a slog. The following returns a null version if -the text |T| is in any respect malformed, i.e., if it deviates from the +the text [[T]] is in any respect malformed, i.e., if it deviates from the above specification in even the most trivial way. We parse the three parts -of a semver version in order: e.g. |3.1.41-alpha.72.zeta+6Q45| the first +of a semver version in order: e.g. [[3.1.41-alpha.72.zeta+6Q45]] the first part is up to the hyphen, the second part between the hyphen and the plus sign, and the third part runs to the end. The second and third parts are optional, but if both are given, they must be in that order. -@e MMP_SEMVERPART from 1 -@e PRE_SEMVERPART -@e BM_SEMVERPART +<<*>>= +enum MMP_SEMVERPART from 1 +enum PRE_SEMVERPART +enum BM_SEMVERPART -= +<<*>>= semantic_version_number VersionNumbers::from_text(text_stream *T) { semantic_version_number V = VersionNumbers::null(); int component = 0, val = -1, dots_used = 0, slashes_used = 0, count = 0; @@ -151,7 +153,7 @@ semantic_version_number VersionNumbers::from_text(text_stream *T) { case MMP_SEMVERPART: if (c == '.') dots_used++; if (c == '/') slashes_used++; - if ((c == '.') || (c == '/') || (c == '-') || (c == '+')) { + if ((c == '.') [[| (c == '/') || (c == '-') |]] (c == '+')) { if (val == -1) return VersionNumbers::null(); if (component >= SEMVER_NUMBER_DEPTH) return VersionNumbers::null(); V.version_numbers[component] = val; @@ -168,9 +170,9 @@ semantic_version_number VersionNumbers::from_text(text_stream *T) { break; case PRE_SEMVERPART: if (c == '.') { - @; + <>; } else if (c == '+') { - @; part = BM_SEMVERPART; + <>; part = BM_SEMVERPART; } else { PUT_TO(prerelease, c); } @@ -181,7 +183,7 @@ semantic_version_number VersionNumbers::from_text(text_stream *T) { break; } } - if ((part == PRE_SEMVERPART) && (Str::len(prerelease) > 0)) @; + if ((part == PRE_SEMVERPART) && (Str::len(prerelease) > 0)) <>; DISCARD_TEXT(prerelease) if ((dots_used > 0) && (slashes_used > 0)) return VersionNumbers::null(); if (slashes_used > 0) { @@ -198,13 +200,13 @@ semantic_version_number VersionNumbers::from_text(text_stream *T) { return V; } -@ = +<>= if (Str::len(prerelease) == 0) return VersionNumbers::null(); if (V.prerelease_segments == NULL) V.prerelease_segments = NEW_LINKED_LIST(text_stream); ADD_TO_LINKED_LIST(Str::duplicate(prerelease), text_stream, V.prerelease_segments); Str::clear(prerelease); -@h Precedence. +@ \section{Precedence.} The most important part of the semver standard is the rule on which versions take precedence over which others, and we follow it exactly. The following criteria are used in turn: major version; minor version; patch version; @@ -214,7 +216,7 @@ compared numerically if consisting of digits only, and alphabetically otherwise; and finally the number of prerelease elements. Build metadata is disregarded entirely. -= +<<*>>= int VersionNumbers::le(semantic_version_number V1, semantic_version_number V2) { for (int i=0; i>= int VersionNumbers::floor(int N) { if (N < 0) return 0; return N; } -@ This returns a non-negative integer if |T| contains only digits, and |-1| +@ This returns a non-negative integer if [[T]] contains only digits, and [[-1]] otherwise. If the value has more than about 10 digits, then the result will not be meaningful, which I think is a technical violation of the standard. -= +<<*>>= int VersionNumbers::strict_atoi(text_stream *T) { LOOP_THROUGH_TEXT(pos, T) if (Characters::isdigit(Str::get(pos)) == FALSE) @@ -272,13 +274,13 @@ int VersionNumbers::strict_atoi(text_stream *T) { return Str::atoi(T, 0); } -@h Trichotomy. +@ \section{Trichotomy.} We now use the above function to construct ordering relations on semvers. -These are trichotomous, that is, for each pair |V1, V2|, exactly one of the -|VersionNumbers::eq(V1, V2)|, |VersionNumbers::gt(V1, V2)|, |VersionNumbers::lt(V1, V2)| +These are trichotomous, that is, for each pair [[V1, V2]], exactly one of the +[[VersionNumbers::eq(V1, V2)]], [[VersionNumbers::gt(V1, V2)]], [[VersionNumbers::lt(V1, V2)]] is true. -= +<<*>>= int VersionNumbers::eq(semantic_version_number V1, semantic_version_number V2) { if ((VersionNumbers::le(V1, V2)) && (VersionNumbers::le(V2, V1))) return TRUE; @@ -301,9 +303,9 @@ int VersionNumbers::lt(semantic_version_number V1, semantic_version_number V2) { return (VersionNumbers::ge(V1, V2))?FALSE:TRUE; } -@ And the following can be used for sorting, following the |strcmp| convention. +@ And the following can be used for sorting, following the [[strcmp]] convention. -= +<<*>>= int VersionNumbers::cmp(semantic_version_number V1, semantic_version_number V2) { if (VersionNumbers::eq(V1, V2)) return 0; if (VersionNumbers::gt(V1, V2)) return 1;