~ubuntu-branches/ubuntu/wily/gargoyle-free/wily-proposed

« back to all changes in this revision

Viewing changes to terps/nitfol/zscii.c

  • Committer: Bazaar Package Importer
  • Author(s): Sylvain Beucler
  • Date: 2009-09-11 20:09:43 UTC
  • Revision ID: james.westby@ubuntu.com-20090911200943-idgzoyupq6650zpn
Tags: upstream-2009-08-25
ImportĀ upstreamĀ versionĀ 2009-08-25

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*  Nitfol - z-machine interpreter using Glk for output.
 
2
    Copyright (C) 1999  Evin Robertson
 
3
 
 
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.
 
8
 
 
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.
 
13
 
 
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.
 
17
 
 
18
    The author can be reached at nitfol@deja.com
 
19
*/
 
20
#include "nitfol.h"
 
21
#include <limits.h>
 
22
#include <stdio.h>
 
23
 
 
24
/* string.c - decode and encode strings */
 
25
 
 
26
 
 
27
#define NUM_CACHE 4
 
28
#define CACHE_SIZE 4096
 
29
 
 
30
/*
 
31
static offset recent[4];
 
32
static unsigned uses[4];
 
33
 
 
34
static int is_cached;
 
35
*/
 
36
 
 
37
int getstring(zword packedaddress)
 
38
{
 
39
  return decodezscii(UNPACKS(packedaddress), output_char);
 
40
}
 
41
 
 
42
 
 
43
/* Returns character for given alphabet, letter pair */
 
44
static unsigned char alphabetsoup(unsigned spoon, unsigned char letter)
 
45
{
 
46
  const char *alphabet;
 
47
 
 
48
  if(letter == 0)
 
49
    return 32;     /* space */
 
50
 
 
51
  if(letter < 6 || letter > 31)
 
52
    return 32;     /* gurgle */
 
53
 
 
54
  if(zversion == 1) {
 
55
    alphabet = "abcdefghijklmnopqrstuvwxyz"
 
56
               "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 
57
               " 0123456789.,!?_#'\"/\\<-:()";
 
58
    if(letter == 1)
 
59
      return 13;   /* newline */
 
60
  } else {
 
61
    alphabet = "abcdefghijklmnopqrstuvwxyz"
 
62
               "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 
63
               " ^0123456789.,!?_#'\"/\\-:()";
 
64
 
 
65
    if(spoon == 2 && letter == 7)
 
66
      return 13;   /* newline */
 
67
 
 
68
    if(zversion >= 5) { /* v5 can use its own bowl of soup */
 
69
      zword t = LOWORD(HD_ALPHABET);
 
70
      if(t != 0)
 
71
        return LOBYTE(t + spoon*26 + (letter-6));   /* alphabet = z_memory+t */
 
72
    }
 
73
  }
 
74
 
 
75
  return alphabet[spoon * 26 + (letter-6)];
 
76
}
 
77
 
 
78
 
 
79
#define END -1
 
80
 
 
81
 
 
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.
 
86
 */
 
87
static char untriplet(offset *location, int *shift_amt)
 
88
{
 
89
  unsigned triplet;
 
90
  unsigned char result;
 
91
  if(*shift_amt == END) {
 
92
    if(!testing_string)
 
93
      n_show_error(E_STRING, "attempt to read past end of string", *location);
 
94
    string_bad = TRUE;
 
95
    return 0;
 
96
  }
 
97
  triplet = HISTRWORD(*location);
 
98
  result = (triplet >> *shift_amt) & b00011111;
 
99
 
 
100
  *shift_amt -= 5;       /* next character is 5 bits to the right */
 
101
 
 
102
  if(*shift_amt < 0) {   /* Reached end of triplet; go on to next */
 
103
    *shift_amt = 10;
 
104
    *location += 2;
 
105
 
 
106
    if(triplet & 0x8000) /* High bit set - reached the end of the string */
 
107
      *shift_amt = END;
 
108
  }
 
109
  return result;
 
110
}
 
111
 
 
112
 
 
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))
 
117
{
 
118
  const int alphaup[3] = { 1, 2, 0 };
 
119
  const int alphadn[3] = { 2, 0, 1 };
 
120
 
 
121
  int shift_amt = 10;
 
122
  int alphalock = 0;
 
123
  int alphashift = 0;
 
124
  int alphacurrent;
 
125
  offset startzscii = zscii;
 
126
  static int depth = 0;
 
127
  depth++;
 
128
 
 
129
  if(depth > 2) { /* Nested abbreviations */
 
130
    if(!testing_string) {
 
131
      int remdepth = depth;
 
132
      depth = 0;
 
133
      n_show_error(E_STRING, "nested abbreviations", zscii);
 
134
      depth = remdepth;
 
135
    }
 
136
    string_bad = TRUE;
 
137
    depth--;
 
138
    return 0;
 
139
  }
 
140
 
 
141
  do {
 
142
    unsigned char z, x;
 
143
 
 
144
    if(zscii > total_size) {
 
145
      if(!testing_string)
 
146
        n_show_error(E_STRING, "attempt to print string beyond end of story", zscii);
 
147
      string_bad = TRUE;
 
148
      depth--;
 
149
      return 0;
 
150
    }
 
151
 
 
152
    z = untriplet(&zscii, &shift_amt);
 
153
 
 
154
    alphacurrent = alphashift;
 
155
    alphashift = alphalock;
 
156
 
 
157
    if(z < 6) {
 
158
      if(zversion <= 2) {
 
159
        switch(z) {
 
160
        case 0: putcharfunc(32); break;                 /* space */
 
161
        case 1:
 
162
          if(zversion == 1) {
 
163
            putcharfunc(13);                            /* newline */
 
164
          } else {                                      /* abbreviation */
 
165
            x = untriplet(&zscii, &shift_amt);
 
166
            decodezscii(((offset) HIWORD(z_synonymtable + x*ZWORD_SIZE)) * 2,
 
167
                        putcharfunc);
 
168
          }
 
169
          break;
 
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;
 
174
        }
 
175
      } else {
 
176
        switch(z) {
 
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),
 
182
                      putcharfunc);
 
183
 
 
184
          break;
 
185
        case 4: alphashift = alphaup[alphashift]; break;
 
186
        case 5: alphashift = alphadn[alphashift]; break;
 
187
        }
 
188
      }
 
189
    } else {
 
190
 
 
191
      if(alphacurrent == 2 && z == 6) {
 
192
        int multibyte;
 
193
        if(shift_amt == END)
 
194
          break;
 
195
 
 
196
        multibyte = untriplet(&zscii, &shift_amt) << 5;
 
197
 
 
198
        if(shift_amt == END)
 
199
          break;
 
200
        multibyte |= untriplet(&zscii, &shift_amt);
 
201
 
 
202
        putcharfunc(multibyte);
 
203
      } else {
 
204
        putcharfunc(alphabetsoup(alphacurrent, z));
 
205
      }
 
206
    }
 
207
  } while(shift_amt != END);
 
208
  
 
209
  depth--;
 
210
  return zscii - startzscii;
 
211
}
 
212
 
 
213
 
 
214
static void tripletize(zbyte **location, unsigned *triplet, int *count,
 
215
                       char value, BOOL isend)
 
216
{
 
217
  if(*location == NULL)
 
218
    return;                  /* stop doing stuff if we're already done. */
 
219
 
 
220
  *triplet = ((*triplet) << 5) | value;
 
221
  *count += 1;
 
222
 
 
223
  if(isend) {
 
224
    while(*count < 3) {
 
225
      *triplet = ((*triplet) << 5) | 5;   /* 5 is the official pad char */
 
226
      *count += 1;
 
227
    }
 
228
    *triplet |= 0x8000;                   /* end bit */
 
229
  }
 
230
 
 
231
  if(*count == 3) {
 
232
    (*location)[0] = *triplet >> 8;        /* high byte first */
 
233
    (*location)[1] = *triplet & 255;       /* then lower */
 
234
    *triplet = 0;
 
235
    *count = 0;
 
236
    *location += 2;
 
237
 
 
238
    if(isend)
 
239
      *location = NULL;
 
240
  }
 
241
}
 
242
 
 
243
 
 
244
static BOOL search_soup(zbyte c, int *rspoon, int *rletter)
 
245
{
 
246
  int spoon, letter;
 
247
  for(spoon = 0; spoon < 3; spoon++)
 
248
    for(letter = 0; letter < 32; letter++)
 
249
      if(c == alphabetsoup(spoon, letter)) {
 
250
        *rspoon = spoon;
 
251
        *rletter = letter;
 
252
        return TRUE;
 
253
      }
 
254
  return FALSE;
 
255
}
 
256
 
 
257
 
 
258
int encodezscii(zbyte *dest, int mindestlen, int maxdestlen,
 
259
                const char *source, int sourcelen)
 
260
{
 
261
  int alphachanger[3];
 
262
  int i;
 
263
  int destlen = 0;
 
264
  int done = FALSE;
 
265
  unsigned triplet = 0; int count = 0;
 
266
 
 
267
  if(zversion <= 2) {
 
268
    alphachanger[1] = 2;   /* Shift up */
 
269
    alphachanger[2] = 3;   /* Shift down */
 
270
  } else {
 
271
    alphachanger[1] = 4;   /* Shift up */
 
272
    alphachanger[2] = 5;   /* Shift down */
 
273
  }
 
274
  mindestlen *= 3; maxdestlen *= 3; /* Change byte sizes to zscii sizes */
 
275
  mindestlen /= 2; maxdestlen /= 2;
 
276
 
 
277
  for(i = 0; i < sourcelen && !done && dest != NULL; i++) {
 
278
    int spoon, letter;
 
279
    if(search_soup(source[i], &spoon, &letter)) {
 
280
      if(spoon != 0) {   /* switch alphabet if necessary */
 
281
        destlen++;
 
282
        tripletize(&dest, &triplet, &count,
 
283
                   alphachanger[spoon], destlen >= maxdestlen);
 
284
      }
 
285
 
 
286
      destlen++;
 
287
      done = ((destlen >= maxdestlen) || (i == sourcelen - 1)) &&
 
288
        (destlen >= mindestlen);
 
289
 
 
290
      tripletize(&dest, &triplet, &count, letter, done);
 
291
    } else {    /* The character wasn't found, so use multibyte encoding */
 
292
      destlen++;
 
293
      tripletize(&dest, &triplet, &count, alphachanger[2],destlen>=maxdestlen);
 
294
      destlen++;
 
295
      tripletize(&dest, &triplet, &count, 6, destlen >= maxdestlen);
 
296
      destlen++;
 
297
                                 /* Upper 5 bits (really 3) */
 
298
      tripletize(&dest, &triplet, &count, source[i] >> 5, destlen>=maxdestlen);
 
299
      
 
300
      destlen++;
 
301
      done = ((destlen >= maxdestlen) || (i == sourcelen - 1)) &&
 
302
        (destlen >= mindestlen);
 
303
                                           /* Lower 5 bits */
 
304
      tripletize(&dest, &triplet, &count, source[i] & b00011111, done);
 
305
    }
 
306
 
 
307
  }
 
308
 
 
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 */
 
313
    }                                              /* uh */
 
314
    tripletize(&dest, &triplet, &count, 5, TRUE); /* uh huh, done */
 
315
  }
 
316
  return i;
 
317
}
 
318
 
 
319
void op_encode_text(void)
 
320
{
 
321
  encodezscii(z_memory + operand[3], 6, 6,
 
322
              (char *) z_memory + operand[0] + operand[2], operand[1]);
 
323
}