1
/* Nitfol - z-machine interpreter using Glk for output.
2
Copyright (C) 1999 Evin Robertson
4
This program is free software; you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation; either version 2 of the License, or
7
(at your option) any later version.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with this program; if not, write to the Free Software
16
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
18
The author can be reached at nitfol@deja.com
24
/* string.c - decode and encode strings */
28
#define CACHE_SIZE 4096
31
static offset recent[4];
32
static unsigned uses[4];
37
int getstring(zword packedaddress)
39
return decodezscii(UNPACKS(packedaddress), output_char);
43
/* Returns character for given alphabet, letter pair */
44
static unsigned char alphabetsoup(unsigned spoon, unsigned char letter)
49
return 32; /* space */
51
if(letter < 6 || letter > 31)
52
return 32; /* gurgle */
55
alphabet = "abcdefghijklmnopqrstuvwxyz"
56
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
57
" 0123456789.,!?_#'\"/\\<-:()";
59
return 13; /* newline */
61
alphabet = "abcdefghijklmnopqrstuvwxyz"
62
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
63
" ^0123456789.,!?_#'\"/\\-:()";
65
if(spoon == 2 && letter == 7)
66
return 13; /* newline */
68
if(zversion >= 5) { /* v5 can use its own bowl of soup */
69
zword t = LOWORD(HD_ALPHABET);
71
return LOBYTE(t + spoon*26 + (letter-6)); /* alphabet = z_memory+t */
75
return alphabet[spoon * 26 + (letter-6)];
82
/* Text is arranged in triplets - this function takes a reference to location,
83
* and to shift_amt which says how many bits are left at that location. Each
84
* letter in 5 bits, shift_amt is decremented by this each time. When a
85
* location runs out, we move to another location.
87
static char untriplet(offset *location, int *shift_amt)
91
if(*shift_amt == END) {
93
n_show_error(E_STRING, "attempt to read past end of string", *location);
97
triplet = HISTRWORD(*location);
98
result = (triplet >> *shift_amt) & b00011111;
100
*shift_amt -= 5; /* next character is 5 bits to the right */
102
if(*shift_amt < 0) { /* Reached end of triplet; go on to next */
106
if(triplet & 0x8000) /* High bit set - reached the end of the string */
113
/* Decodes a zscii string at address 'zscii', sending the decoded characters
114
into putcharfunc. Returns number of zscii characters it ate until it
115
reached the end of the string. */
116
int decodezscii(offset zscii, void (*putcharfunc)(int))
118
const int alphaup[3] = { 1, 2, 0 };
119
const int alphadn[3] = { 2, 0, 1 };
125
offset startzscii = zscii;
126
static int depth = 0;
129
if(depth > 2) { /* Nested abbreviations */
130
if(!testing_string) {
131
int remdepth = depth;
133
n_show_error(E_STRING, "nested abbreviations", zscii);
144
if(zscii > total_size) {
146
n_show_error(E_STRING, "attempt to print string beyond end of story", zscii);
152
z = untriplet(&zscii, &shift_amt);
154
alphacurrent = alphashift;
155
alphashift = alphalock;
160
case 0: putcharfunc(32); break; /* space */
163
putcharfunc(13); /* newline */
164
} else { /* abbreviation */
165
x = untriplet(&zscii, &shift_amt);
166
decodezscii(((offset) HIWORD(z_synonymtable + x*ZWORD_SIZE)) * 2,
170
case 2: alphashift = alphaup[alphashift]; break;
171
case 3: alphashift = alphadn[alphashift]; break;
172
case 4: alphalock = alphashift = alphaup[alphalock]; break;
173
case 5: alphalock = alphashift = alphadn[alphalock]; break;
177
case 0: putcharfunc(32); break; /* space */
178
case 1: case 2: case 3: /* abbreviations */
179
x = untriplet(&zscii, &shift_amt);
180
decodezscii((offset) 2 * HIWORD(z_synonymtable +
181
(32*(z-1) + x) * ZWORD_SIZE),
185
case 4: alphashift = alphaup[alphashift]; break;
186
case 5: alphashift = alphadn[alphashift]; break;
191
if(alphacurrent == 2 && z == 6) {
196
multibyte = untriplet(&zscii, &shift_amt) << 5;
200
multibyte |= untriplet(&zscii, &shift_amt);
202
putcharfunc(multibyte);
204
putcharfunc(alphabetsoup(alphacurrent, z));
207
} while(shift_amt != END);
210
return zscii - startzscii;
214
static void tripletize(zbyte **location, unsigned *triplet, int *count,
215
char value, BOOL isend)
217
if(*location == NULL)
218
return; /* stop doing stuff if we're already done. */
220
*triplet = ((*triplet) << 5) | value;
225
*triplet = ((*triplet) << 5) | 5; /* 5 is the official pad char */
228
*triplet |= 0x8000; /* end bit */
232
(*location)[0] = *triplet >> 8; /* high byte first */
233
(*location)[1] = *triplet & 255; /* then lower */
244
static BOOL search_soup(zbyte c, int *rspoon, int *rletter)
247
for(spoon = 0; spoon < 3; spoon++)
248
for(letter = 0; letter < 32; letter++)
249
if(c == alphabetsoup(spoon, letter)) {
258
int encodezscii(zbyte *dest, int mindestlen, int maxdestlen,
259
const char *source, int sourcelen)
265
unsigned triplet = 0; int count = 0;
268
alphachanger[1] = 2; /* Shift up */
269
alphachanger[2] = 3; /* Shift down */
271
alphachanger[1] = 4; /* Shift up */
272
alphachanger[2] = 5; /* Shift down */
274
mindestlen *= 3; maxdestlen *= 3; /* Change byte sizes to zscii sizes */
275
mindestlen /= 2; maxdestlen /= 2;
277
for(i = 0; i < sourcelen && !done && dest != NULL; i++) {
279
if(search_soup(source[i], &spoon, &letter)) {
280
if(spoon != 0) { /* switch alphabet if necessary */
282
tripletize(&dest, &triplet, &count,
283
alphachanger[spoon], destlen >= maxdestlen);
287
done = ((destlen >= maxdestlen) || (i == sourcelen - 1)) &&
288
(destlen >= mindestlen);
290
tripletize(&dest, &triplet, &count, letter, done);
291
} else { /* The character wasn't found, so use multibyte encoding */
293
tripletize(&dest, &triplet, &count, alphachanger[2],destlen>=maxdestlen);
295
tripletize(&dest, &triplet, &count, 6, destlen >= maxdestlen);
297
/* Upper 5 bits (really 3) */
298
tripletize(&dest, &triplet, &count, source[i] >> 5, destlen>=maxdestlen);
301
done = ((destlen >= maxdestlen) || (i == sourcelen - 1)) &&
302
(destlen >= mindestlen);
304
tripletize(&dest, &triplet, &count, source[i] & b00011111, done);
309
if(!done) { /* come back here */
310
while(destlen < mindestlen - 1) { /* oh yeah you pad me out */
311
tripletize(&dest, &triplet, &count, 5, FALSE);/* uh huh */
312
destlen++; /* uh yup */
314
tripletize(&dest, &triplet, &count, 5, TRUE); /* uh huh, done */
319
void op_encode_text(void)
321
encodezscii(z_memory + operand[3], 6, 6,
322
(char *) z_memory + operand[0] + operand[2], operand[1]);