FWIW this is as far as I got in the code chase:
``inform7/Internal/Inter/BasicInformKit/Sections/Text.i6t```
[ SNIPPET_TY_to_TEXT_TY to_txt snippet;
return BlkValueCast(to_txt, SNIPPET_TY, snippet);
];
…
=
[ TEXT_TY_Cast to_txt from_kind from_value;
if (from_kind == TEXT_TY) {
BlkValueCopy(to_txt, from_value);
} else if (from_kind == SNIPPET_TY) {
TEXT_TY_Transmute(to_txt);
TEXT_TY_CastPrimitive(to_txt, true, from_value);
} else BlkValueError("impossible cast to text");
];
…
@h Data Conversion.
We use a single routine to handle two kinds of format translation: a
packed I6 string into an unpacked text, or a snippet into an unpacked text.
In each case, what we do is simply to print out the value we have, but with
the output stream set to memory rather than the screen. That gives us the
character by character version, neatly laid out in an array, and all we have
to do is to copy it into the text and add a null termination byte.
Nope nope nope. We want to very much not do this.
Drilling down to the Glulx version:
#ifnot; ! TARGET_ZCODE
[ TEXT_TY_CastPrimitive to_txt from_snippet from_value
len i stream saved_stream news buffer buffer_size memory_to_free results;
if (to_txt == 0) BlkValueError("no destination for cast");
buffer_size = (TEXT_TY_BufferSize + 2)*WORDSIZE;
RawBufferSize = TEXT_TY_BufferSize;
buffer = RawBufferAddress + TEXT_TY_CastPrimitiveNesting*buffer_size;
TEXT_TY_CastPrimitiveNesting++;
if (TEXT_TY_CastPrimitiveNesting > TEXT_TY_NoBuffers) {
buffer = VM_AllocateMemory(buffer_size); memory_to_free = buffer;
if (buffer == 0)
FlexError("ran out with too many simultaneous text conversions");
}
SuspendRTP();
.RetryWithLargerBuffer;
saved_stream = glk_stream_get_current();
stream = glk_stream_open_memory_uni(buffer, RawBufferSize, filemode_Write, 0);
glk_stream_set_current(stream);
@push say__p; @push say__pc;
ClearParagraphing(7);
if (from_snippet) print (PrintSnippet) from_value;
else print (PrintI6Text) from_value;
@pull say__pc; @pull say__p;
results = buffer + buffer_size - 2*WORDSIZE;
glk_stream_close(stream, results);
if (saved_stream) glk_stream_set_current(saved_stream);
ResumeRTP();
len = results-->1;
if (len > RawBufferSize-1) {
! Glulx had to truncate text output because the buffer ran out:
! len is the number of characters which it tried to print
news = RawBufferSize;
while (news < len) news=news*2;
i = VM_AllocateMemory(news*WORDSIZE);
if (i ~= 0) {
if (memory_to_free) VM_FreeMemory(memory_to_free);
memory_to_free = i;
buffer = i;
RawBufferSize = news;
buffer_size = (RawBufferSize + 2)*WORDSIZE;
jump RetryWithLargerBuffer;
}
! Memory allocation refused: all we can do is to truncate the text
len = RawBufferSize-1;
}
buffer-->(len) = 0;
TEXT_TY_CastPrimitiveNesting--;
BlkValueMassCopyFromArray(to_txt, buffer, 4, len+1);
if (memory_to_free) VM_FreeMemory(memory_to_free);
];
#endif;
This has to be rewritten – specifically this line has to be replaced:
if (from_snippet) print (PrintSnippet) from_value;
I am not, however, sure what to replace it with.
Alternatively, if the glk implementations are intelligent enough to know that we can write anything at all to memory buffers, then we just need to remove the check for valid characters in the I6 veneer code. I could probably test that with an extension which replaces the I6 veneer routine. Maybe.