1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-18 06:54:26 +03:00
inform7/inbuild/inbuild-module/Chapter 2/Requirements.w
2020-02-08 10:34:58 +00:00

165 lines
5.1 KiB
OpenEdge ABL

[Requirements::] Requirements.
A requirement is a way to specify some subset of works: for example, those
with a given title, and/or version number.
@ A null minimum version means "no minimum", a null maximum means "no maximum".
=
typedef struct inbuild_requirement {
struct inbuild_work *work;
struct inbuild_version_number min_version;
struct inbuild_version_number max_version;
int allow_malformed;
MEMORY_MANAGEMENT
} inbuild_requirement;
inbuild_requirement *Requirements::new(inbuild_work *work,
inbuild_version_number min, inbuild_version_number max) {
inbuild_requirement *req = CREATE(inbuild_requirement);
req->work = work;
req->min_version = min;
req->max_version = max;
req->allow_malformed = FALSE;
return req;
}
inbuild_requirement *Requirements::any_version_of(inbuild_work *work) {
return Requirements::new(work, VersionNumbers::null(), VersionNumbers::null());
}
inbuild_requirement *Requirements::anything_of_genre(inbuild_genre *G) {
return Requirements::any_version_of(Works::new(G, I"", I""));
}
inbuild_requirement *Requirements::anything(void) {
return Requirements::anything_of_genre(NULL);
}
inbuild_requirement *Requirements::from_text(text_stream *T, text_stream *errors) {
inbuild_requirement *req = Requirements::anything();
int from = 0;
for (int at = 0; at < Str::len(T); at++) {
wchar_t c = Str::get_at(T, at);
if (c == ',') {
TEMPORARY_TEXT(initial);
Str::substr(initial, Str::at(T, from), Str::at(T, at));
Requirements::impose_clause(req, initial, errors);
DISCARD_TEXT(initial);
from = at + 1;
}
}
if (from < Str::len(T)) {
TEMPORARY_TEXT(final);
Str::substr(final, Str::at(T, from), Str::end(T));
Requirements::impose_clause(req, final, errors);
DISCARD_TEXT(final);
}
return req;
}
void Requirements::impose_clause(inbuild_requirement *req, text_stream *T, text_stream *errors) {
Str::trim_white_space(T);
if (Str::eq(T, I"all")) return;
TEMPORARY_TEXT(clause);
TEMPORARY_TEXT(value);
for (int at = 0; at < Str::len(T); at++) {
wchar_t c = Str::get_at(T, at);
if (c == '=') {
Str::substr(clause, Str::start(T), Str::at(T, at));
Str::substr(value, Str::at(T, at+1), Str::end(T));
break;
}
}
Str::trim_white_space(clause);
Str::trim_white_space(value);
if ((Str::len(clause) > 0) && (Str::len(value) > 0)) {
if (Str::eq(clause, I"genre")) {
inbuild_genre *G;
LOOP_OVER(G, inbuild_genre)
if (Str::eq_insensitive(G->genre_name, value)) {
req->work->genre = G;
break;
}
if (req->work->genre == NULL) {
if (Str::len(errors) == 0)
WRITE_TO(errors, "not a valid genre: '%S'", value);
}
} else if (Str::eq(clause, I"title")) Str::copy(req->work->title, value);
else if (Str::eq(clause, I"author")) Str::copy(req->work->author_name, value);
else if (Str::eq(clause, I"version")) {
inbuild_version_number V = VersionNumbers::from_text(value);
if (VersionNumbers::is_null(V)) {
if (Str::len(errors) == 0)
WRITE_TO(errors, "not a valid version number: '%S'", value);
}
req->min_version = V;
req->max_version = V;
} else if (Str::eq(clause, I"min")) {
inbuild_version_number V = VersionNumbers::from_text(value);
if (VersionNumbers::is_null(V)) {
if (Str::len(errors) == 0)
WRITE_TO(errors, "not a valid version number: '%S'", value);
}
req->min_version = V;
} else if (Str::eq(clause, I"max")) {
inbuild_version_number V = VersionNumbers::from_text(value);
if (VersionNumbers::is_null(V)) {
if (Str::len(errors) == 0)
WRITE_TO(errors, "not a valid version number: '%S'", value);
}
req->max_version = V;
} else {
if (Str::len(errors) == 0)
WRITE_TO(errors, "no such term as '%S'", clause);
}
} else {
if (Str::len(errors) == 0)
WRITE_TO(errors, "clause not in the form 'term=value': '%S'", T);
}
DISCARD_TEXT(clause);
DISCARD_TEXT(value);
}
int Requirements::meets(inbuild_edition *edition, inbuild_requirement *req) {
if (req == NULL) return TRUE;
if (req->work) {
if (req->work->genre) {
if (req->work->genre != edition->work->genre)
return FALSE;
}
if ((req->allow_malformed) && (Str::len(edition->work->title) == 0)) return TRUE;
if (Str::len(req->work->title) > 0) {
if (Str::ne_insensitive(req->work->title, edition->work->title))
return FALSE;
}
if (Str::len(req->work->author_name) > 0) {
if (Str::ne_insensitive(req->work->author_name, edition->work->author_name))
return FALSE;
}
}
if (VersionNumbers::is_null(req->min_version) == FALSE) {
if (VersionNumbers::is_null(edition->version)) return FALSE;
if (VersionNumbers::lt(edition->version, req->min_version)) return FALSE;
}
if (VersionNumbers::is_null(req->max_version) == FALSE) {
if (VersionNumbers::is_null(edition->version)) return TRUE;
if (VersionNumbers::gt(edition->version, req->max_version)) return FALSE;
}
return TRUE;
}
int Requirements::ratchet_minimum(inbuild_version_number V, inbuild_requirement *req) {
if (req == NULL) internal_error("no requirement");
if (VersionNumbers::is_null(V)) return FALSE;
if ((VersionNumbers::is_null(req->min_version)) ||
(VersionNumbers::gt(V, req->min_version))) {
req->min_version = V;
return TRUE;
}
return FALSE;
}