summaryrefslogtreecommitdiff
path: root/apps/plugins/frotz/text.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/frotz/text.c')
-rw-r--r--apps/plugins/frotz/text.c1109
1 files changed, 1109 insertions, 0 deletions
diff --git a/apps/plugins/frotz/text.c b/apps/plugins/frotz/text.c
new file mode 100644
index 0000000000..8145cfea29
--- /dev/null
+++ b/apps/plugins/frotz/text.c
@@ -0,0 +1,1109 @@
1/* text.c - Text manipulation functions
2 * Copyright (c) 1995-1997 Stefan Jokisch
3 *
4 * This file is part of Frotz.
5 *
6 * Frotz is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * Frotz is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 */
20
21#include "frotz.h"
22
23enum string_type {
24 LOW_STRING, ABBREVIATION, HIGH_STRING, EMBEDDED_STRING, VOCABULARY
25};
26
27extern zword object_name (zword);
28
29static zchar decoded[10];
30static zword encoded[3];
31
32/*
33 * According to Matteo De Luigi <matteo.de.luigi@libero.it>,
34 * 0xab and 0xbb were in each other's proper positions.
35 * Sat Apr 21, 2001
36 */
37static zchar zscii_to_latin1[] = {
38 0xe4, 0xf6, 0xfc, 0xc4, 0xd6, 0xdc, 0xdf, 0xbb,
39 0xab, 0xeb, 0xef, 0xff, 0xcb, 0xcf, 0xe1, 0xe9,
40 0xed, 0xf3, 0xfa, 0xfd, 0xc1, 0xc9, 0xcd, 0xd3,
41 0xda, 0xdd, 0xe0, 0xe8, 0xec, 0xf2, 0xf9, 0xc0,
42 0xc8, 0xcc, 0xd2, 0xd9, 0xe2, 0xea, 0xee, 0xf4,
43 0xfb, 0xc2, 0xca, 0xce, 0xd4, 0xdb, 0xe5, 0xc5,
44 0xf8, 0xd8, 0xe3, 0xf1, 0xf5, 0xc3, 0xd1, 0xd5,
45 0xe6, 0xc6, 0xe7, 0xc7, 0xfe, 0xf0, 0xde, 0xd0,
46 0xa3, 0x00, 0x00, 0xa1, 0xbf
47};
48
49/*
50 * translate_from_zscii
51 *
52 * Map a ZSCII character onto the ISO Latin-1 alphabet.
53 *
54 */
55
56zchar translate_from_zscii (zbyte c)
57{
58
59 if (c == 0xfc)
60 return ZC_MENU_CLICK;
61 if (c == 0xfd)
62 return ZC_DOUBLE_CLICK;
63 if (c == 0xfe)
64 return ZC_SINGLE_CLICK;
65
66 if (c >= 0x9b && story_id != BEYOND_ZORK) {
67
68 if (hx_unicode_table != 0) { /* game has its own Unicode table */
69
70 zbyte N;
71
72 LOW_BYTE (hx_unicode_table, N)
73
74 if (c - 0x9b < N) {
75
76 zword addr = hx_unicode_table + 1 + 2 * (c - 0x9b);
77 zword unicode;
78
79 LOW_WORD (addr, unicode)
80
81 return (unicode < 0x100) ? (zchar) unicode : '?';
82
83 } else return '?';
84
85 } else /* game uses standard set */
86
87 if (c <= 0xdf) {
88
89 if (c == 0xdc || c == 0xdd) /* Oe and oe ligatures */
90 return '?'; /* are not ISO-Latin 1 */
91
92 return zscii_to_latin1[c - 0x9b];
93
94 } else return '?';
95 }
96
97 return c;
98
99}/* translate_from_zscii */
100
101/*
102 * translate_to_zscii
103 *
104 * Map an ISO Latin-1 character onto the ZSCII alphabet.
105 *
106 */
107
108zbyte translate_to_zscii (zchar c)
109{
110 int i;
111
112 if (c == ZC_SINGLE_CLICK)
113 return 0xfe;
114 if (c == ZC_DOUBLE_CLICK)
115 return 0xfd;
116 if (c == ZC_MENU_CLICK)
117 return 0xfc;
118
119 if (c >= ZC_LATIN1_MIN) {
120
121 if (hx_unicode_table != 0) { /* game has its own Unicode table */
122
123 zbyte N;
124 int i;
125
126 LOW_BYTE (hx_unicode_table, N)
127
128 for (i = 0x9b; i < 0x9b + N; i++) {
129
130 zword addr = hx_unicode_table + 1 + 2 * (i - 0x9b);
131 zword unicode;
132
133 LOW_WORD (addr, unicode)
134
135 if (c == unicode)
136 return (zbyte) i;
137
138 }
139
140 return '?';
141
142 } else { /* game uses standard set */
143
144 for (i = 0x9b; i <= 0xdf; i++)
145 if (c == zscii_to_latin1[i - 0x9b])
146 return (zbyte) i;
147
148 return '?';
149
150 }
151 }
152
153 if (c == 0) /* Safety thing from David Kinder */
154 c = '?'; /* regarding his Unicode patches */
155 /* Sept 15, 2002 */
156
157 return c;
158
159}/* translate_to_zscii */
160
161/*
162 * alphabet
163 *
164 * Return a character from one of the three character sets.
165 *
166 */
167
168static zchar alphabet (int set, int index)
169{
170
171 if (h_alphabet != 0) { /* game uses its own alphabet */
172
173 zbyte c;
174
175 zword addr = h_alphabet + 26 * set + index;
176 LOW_BYTE (addr, c)
177
178 return translate_from_zscii (c);
179
180 } else /* game uses default alphabet */
181
182 if (set == 0)
183 return 'a' + index;
184 else if (set == 1)
185 return 'A' + index;
186 else if (h_version == V1)
187 return " 0123456789.,!?_#'\"/\\<-:()"[index];
188 else
189 return " ^0123456789.,!?_#'\"/\\-:()"[index];
190
191}/* alphabet */
192
193/*
194 * load_string
195 *
196 * Copy a ZSCII string from the memory to the global "decoded" string.
197 *
198 */
199
200static void load_string (zword addr, zword length)
201{
202 int resolution = (h_version <= V3) ? 2 : 3;
203 int i = 0;
204
205 while (i < 3 * resolution)
206
207 if (i < length) {
208
209 zbyte c;
210
211 LOW_BYTE (addr, c)
212 addr++;
213
214 decoded[i++] = translate_from_zscii (c);
215
216 } else decoded[i++] = 0;
217
218}/* load_string */
219
220/*
221 * encode_text
222 *
223 * Encode the Unicode text in the global "decoded" string then write
224 * the result to the global "encoded" array. (This is used to look up
225 * words in the dictionary.) Up to V3 the vocabulary resolution is
226 * two, since V4 it is three words. Because each word contains three
227 * Z-characters, that makes six or nine Z-characters respectively.
228 * Longer words are chopped to the proper size, shorter words are are
229 * padded out with 5's. For word completion we pad with 0s and 31s,
230 * the minimum and maximum Z-characters.
231 *
232 */
233
234static void encode_text (int padding)
235{
236 static zchar again[] = { 'a', 'g', 'a', 'i', 'n', 0 };
237 static zchar examine[] = { 'e', 'x', 'a', 'm', 'i', 'n', 'e', 0 };
238 static zchar wait[] = { 'w', 'a', 'i', 't', 0 };
239
240 zbyte zchars[12];
241 const zchar *ptr = decoded;
242 zchar c;
243 int resolution = (h_version <= V3) ? 2 : 3;
244 int i = 0;
245
246 /* Expand abbreviations that some old Infocom games lack */
247
248 if (f_setup.expand_abbreviations)
249
250 if (padding == 0x05 && decoded[1] == 0)
251
252 switch (decoded[0]) {
253 case 'g': ptr = again; break;
254 case 'x': ptr = examine; break;
255 case 'z': ptr = wait; break;
256 }
257
258 /* Translate string to a sequence of Z-characters */
259
260 while (i < 3 * resolution)
261
262 if ((c = *ptr++) != 0) {
263
264 int index, set;
265 zbyte c2;
266
267 /* Search character in the alphabet */
268
269 for (set = 0; set < 3; set++)
270 for (index = 0; index < 26; index++)
271 if (c == alphabet (set, index))
272 goto letter_found;
273
274 /* Character not found, store its ZSCII value */
275
276 c2 = translate_to_zscii (c);
277
278 zchars[i++] = 5;
279 zchars[i++] = 6;
280 zchars[i++] = c2 >> 5;
281 zchars[i++] = c2 & 0x1f;
282
283 continue;
284
285 letter_found:
286
287 /* Character found, store its index */
288
289 if (set != 0)
290 zchars[i++] = ((h_version <= V2) ? 1 : 3) + set;
291
292 zchars[i++] = index + 6;
293
294 } else zchars[i++] = padding;
295
296 /* Three Z-characters make a 16bit word */
297
298 for (i = 0; i < resolution; i++)
299
300 encoded[i] =
301 (zchars[3 * i + 0] << 10) |
302 (zchars[3 * i + 1] << 5) |
303 (zchars[3 * i + 2]);
304
305 encoded[resolution - 1] |= 0x8000;
306
307}/* encode_text */
308
309/*
310 * z_check_unicode, test if a unicode character can be read and printed.
311 *
312 * zargs[0] = Unicode
313 *
314 */
315
316void z_check_unicode (void)
317{
318 zword c = zargs[0];
319
320 if (c >= 0x20 && c <= 0x7e)
321 store (3);
322 else if (c == 0xa0)
323 store (1);
324 else if (c >= 0xa1 && c <= 0xff)
325 store (3);
326 else
327 store (0);
328
329}/* z_check_unicode */
330
331/*
332 * z_encode_text, encode a ZSCII string for use in a dictionary.
333 *
334 * zargs[0] = address of text buffer
335 * zargs[1] = length of ASCII string
336 * zargs[2] = offset of ASCII string within the text buffer
337 * zargs[3] = address to store encoded text in
338 *
339 * This is a V5+ opcode and therefore the dictionary resolution must be
340 * three 16bit words.
341 *
342 */
343
344void z_encode_text (void)
345{
346 int i;
347
348 load_string ((zword) (zargs[0] + zargs[2]), zargs[1]);
349
350 encode_text (0x05);
351
352 for (i = 0; i < 3; i++)
353 storew ((zword) (zargs[3] + 2 * i), encoded[i]);
354
355}/* z_encode_text */
356
357/*
358 * decode_text
359 *
360 * Convert encoded text to Unicode. The encoded text consists of 16bit
361 * words. Every word holds 3 Z-characters (5 bits each) plus a spare
362 * bit to mark the last word. The Z-characters translate to ZSCII by
363 * looking at the current current character set. Some select another
364 * character set, others refer to abbreviations.
365 *
366 * There are several different string types:
367 *
368 * LOW_STRING - from the lower 64KB (byte address)
369 * ABBREVIATION - from the abbreviations table (word address)
370 * HIGH_STRING - from the end of the memory map (packed address)
371 * EMBEDDED_STRING - from the instruction stream (at PC)
372 * VOCABULARY - from the dictionary (byte address)
373 *
374 * The last type is only used for word completion.
375 *
376 */
377
378#define outchar(c) if (st==VOCABULARY) *ptr++=c; else print_char(c)
379
380static void decode_text (enum string_type st, zword addr)
381{
382 zchar *ptr;
383 long byte_addr;
384 zchar c2;
385 zword code;
386 zbyte c, prev_c = 0;
387 int shift_state = 0;
388 int shift_lock = 0;
389 int status = 0;
390
391 ptr = NULL; /* makes compilers shut up */
392 byte_addr = 0;
393
394 /* Calculate the byte address if necessary */
395
396 if (st == ABBREVIATION)
397
398 byte_addr = (long) addr << 1;
399
400 else if (st == HIGH_STRING) {
401
402 if (h_version <= V3)
403 byte_addr = (long) addr << 1;
404 else if (h_version <= V5)
405 byte_addr = (long) addr << 2;
406 else if (h_version <= V7)
407 byte_addr = ((long) addr << 2) + ((long) h_strings_offset << 3);
408 else /* h_version == V8 */
409 byte_addr = (long) addr << 3;
410
411 if (byte_addr >= story_size)
412 runtime_error (ERR_ILL_PRINT_ADDR);
413
414 }
415
416 /* Loop until a 16bit word has the highest bit set */
417
418 if (st == VOCABULARY)
419 ptr = decoded;
420
421 do {
422
423 int i;
424
425 /* Fetch the next 16bit word */
426
427 if (st == LOW_STRING || st == VOCABULARY) {
428 LOW_WORD (addr, code)
429 addr += 2;
430 } else if (st == HIGH_STRING || st == ABBREVIATION) {
431 HIGH_WORD (byte_addr, code)
432 byte_addr += 2;
433 } else
434 CODE_WORD (code)
435
436 /* Read its three Z-characters */
437
438 for (i = 10; i >= 0; i -= 5) {
439
440 zword abbr_addr;
441 zword ptr_addr;
442
443 c = (code >> i) & 0x1f;
444
445 switch (status) {
446
447 case 0: /* normal operation */
448
449 if (shift_state == 2 && c == 6)
450 status = 2;
451
452 else if (h_version == V1 && c == 1)
453 new_line ();
454
455 else if (h_version >= V2 && shift_state == 2 && c == 7)
456 new_line ();
457
458 else if (c >= 6)
459 outchar (alphabet (shift_state, c - 6));
460
461 else if (c == 0)
462 outchar (' ');
463
464 else if (h_version >= V2 && c == 1)
465 status = 1;
466
467 else if (h_version >= V3 && c <= 3)
468 status = 1;
469
470 else {
471
472 shift_state = (shift_lock + (c & 1) + 1) % 3;
473
474 if (h_version <= V2 && c >= 4)
475 shift_lock = shift_state;
476
477 break;
478
479 }
480
481 shift_state = shift_lock;
482
483 break;
484
485 case 1: /* abbreviation */
486
487 ptr_addr = h_abbreviations + 64 * (prev_c - 1) + 2 * c;
488
489 LOW_WORD (ptr_addr, abbr_addr)
490 decode_text (ABBREVIATION, abbr_addr);
491
492 status = 0;
493 break;
494
495 case 2: /* ZSCII character - first part */
496
497 status = 3;
498 break;
499
500 case 3: /* ZSCII character - second part */
501
502 c2 = translate_from_zscii ((prev_c << 5) | c);
503 outchar (c2);
504
505 status = 0;
506 break;
507
508 }
509
510 prev_c = c;
511
512 }
513
514 } while (!(code & 0x8000));
515
516 if (st == VOCABULARY)
517 *ptr = 0;
518
519}/* decode_text */
520
521#undef outchar
522
523/*
524 * z_new_line, print a new line.
525 *
526 * no zargs used
527 *
528 */
529
530void z_new_line (void)
531{
532
533 new_line ();
534
535}/* z_new_line */
536
537/*
538 * z_print, print a string embedded in the instruction stream.
539 *
540 * no zargs used
541 *
542 */
543
544void z_print (void)
545{
546
547 decode_text (EMBEDDED_STRING, 0);
548
549}/* z_print */
550
551/*
552 * z_print_addr, print a string from the lower 64KB.
553 *
554 * zargs[0] = address of string to print
555 *
556 */
557
558void z_print_addr (void)
559{
560
561 decode_text (LOW_STRING, zargs[0]);
562
563}/* z_print_addr */
564
565/*
566 * z_print_char print a single ZSCII character.
567 *
568 * zargs[0] = ZSCII character to be printed
569 *
570 */
571
572void z_print_char (void)
573{
574
575 print_char (translate_from_zscii (zargs[0]));
576
577}/* z_print_char */
578
579/*
580 * z_print_form, print a formatted table.
581 *
582 * zargs[0] = address of formatted table to be printed
583 *
584 */
585
586void z_print_form (void)
587{
588 zword count;
589 zword addr = zargs[0];
590
591 bool first = TRUE;
592
593 for (;;) {
594
595 LOW_WORD (addr, count)
596 addr += 2;
597
598 if (count == 0)
599 break;
600
601 if (!first)
602 new_line ();
603
604 while (count--) {
605
606 zbyte c;
607
608 LOW_BYTE (addr, c)
609 addr++;
610
611 print_char (translate_from_zscii (c));
612
613 }
614
615 first = FALSE;
616
617 }
618
619}/* z_print_form */
620
621/*
622 * print_num
623 *
624 * Print a signed 16bit number.
625 *
626 */
627
628void print_num (zword value)
629{
630 int i;
631
632 /* Print sign */
633
634 if ((short) value < 0) {
635 print_char ('-');
636 value = - (short) value;
637 }
638
639 /* Print absolute value */
640
641 for (i = 10000; i != 0; i /= 10)
642 if (value >= i || i == 1)
643 print_char ('0' + (value / i) % 10);
644
645}/* print_num */
646
647/*
648 * z_print_num, print a signed number.
649 *
650 * zargs[0] = number to print
651 *
652 */
653
654void z_print_num (void)
655{
656
657 print_num (zargs[0]);
658
659}/* z_print_num */
660
661/*
662 * print_object
663 *
664 * Print an object description.
665 *
666 */
667
668void print_object (zword object)
669{
670 zword addr = object_name (object);
671 zword code = 0x94a5;
672 zbyte length;
673
674 LOW_BYTE (addr, length)
675 addr++;
676
677 if (length != 0)
678 LOW_WORD (addr, code)
679
680 if (code == 0x94a5) { /* encoded text 0x94a5 == empty string */
681
682 print_string ("object#"); /* supply a generic name */
683 print_num (object); /* for anonymous objects */
684
685 } else decode_text (LOW_STRING, addr);
686
687}/* print_object */
688
689/*
690 * z_print_obj, print an object description.
691 *
692 * zargs[0] = number of object to be printed
693 *
694 */
695
696void z_print_obj (void)
697{
698
699 print_object (zargs[0]);
700
701}/* z_print_obj */
702
703/*
704 * z_print_paddr, print the string at the given packed address.
705 *
706 * zargs[0] = packed address of string to be printed
707 *
708 */
709
710void z_print_paddr (void)
711{
712
713 decode_text (HIGH_STRING, zargs[0]);
714
715}/* z_print_paddr */
716
717/*
718 * z_print_ret, print the string at PC, print newline then return true.
719 *
720 * no zargs used
721 *
722 */
723
724void z_print_ret (void)
725{
726
727 decode_text (EMBEDDED_STRING, 0);
728 new_line ();
729 ret (1);
730
731}/* z_print_ret */
732
733/*
734 * print_string
735 *
736 * Print a string of ASCII characters.
737 *
738 */
739
740void print_string (const char *s)
741{
742 char c;
743
744 while ((c = *s++) != 0)
745
746 if (c == '\n')
747 new_line ();
748 else
749 print_char (c);
750
751}/* print_string */
752
753/*
754 * z_print_unicode
755 *
756 * zargs[0] = Unicode
757 *
758 */
759
760void z_print_unicode (void)
761{
762
763 print_char ((zargs[0] <= 0xff) ? zargs[0] : '?');
764
765}/* z_print_unicode */
766
767/*
768 * lookup_text
769 *
770 * Scan a dictionary searching for the given word. The first argument
771 * can be
772 *
773 * 0x00 - find the first word which is >= the given one
774 * 0x05 - find the word which exactly matches the given one
775 * 0x1f - find the last word which is <= the given one
776 *
777 * The return value is 0 if the search fails.
778 *
779 */
780
781static zword lookup_text (int padding, zword dct)
782{
783 zword entry_addr;
784 zword entry_count;
785 zword entry;
786 zword addr;
787 zbyte entry_len;
788 zbyte sep_count;
789 int resolution = (h_version <= V3) ? 2 : 3;
790 int entry_number;
791 int lower, upper;
792 int i;
793 bool sorted;
794
795 encode_text (padding);
796
797 LOW_BYTE (dct, sep_count) /* skip word separators */
798 dct += 1 + sep_count;
799 LOW_BYTE (dct, entry_len) /* get length of entries */
800 dct += 1;
801 LOW_WORD (dct, entry_count) /* get number of entries */
802 dct += 2;
803
804 if ((short) entry_count < 0) { /* bad luck, entries aren't sorted */
805
806 entry_count = - (short) entry_count;
807 sorted = FALSE;
808
809 } else sorted = TRUE; /* entries are sorted */
810
811 lower = 0;
812 upper = entry_count - 1;
813
814 while (lower <= upper) {
815
816 if (sorted) /* binary search */
817 entry_number = (lower + upper) / 2;
818 else /* linear search */
819 entry_number = lower;
820
821 entry_addr = dct + entry_number * entry_len;
822
823 /* Compare word to dictionary entry */
824
825 addr = entry_addr;
826
827 for (i = 0; i < resolution; i++) {
828 LOW_WORD (addr, entry)
829 if (encoded[i] != entry)
830 goto continuing;
831 addr += 2;
832 }
833
834 return entry_addr; /* exact match found, return now */
835
836 continuing:
837
838 if (sorted) /* binary search */
839
840 if (encoded[i] > entry)
841 lower = entry_number + 1;
842 else
843 upper = entry_number - 1;
844
845 else lower++; /* linear search */
846
847 }
848
849 /* No exact match has been found */
850
851 if (padding == 0x05)
852 return 0;
853
854 entry_number = (padding == 0x00) ? lower : upper;
855
856 if (entry_number == -1 || entry_number == entry_count)
857 return 0;
858
859 return dct + entry_number * entry_len;
860
861}/* lookup_text */
862
863/*
864 * tokenise_text
865 *
866 * Translate a single word to a token and append it to the token
867 * buffer. Every token consists of the address of the dictionary
868 * entry, the length of the word and the offset of the word from
869 * the start of the text buffer. Unknown words cause empty slots
870 * if the flag is set (such that the text can be scanned several
871 * times with different dictionaries); otherwise they are zero.
872 *
873 */
874
875static void tokenise_text (zword text, zword length, zword from, zword parse, zword dct, bool flag)
876{
877 zword addr;
878 zbyte token_max, token_count;
879
880 LOW_BYTE (parse, token_max)
881 parse++;
882 LOW_BYTE (parse, token_count)
883
884 if (token_count < token_max) { /* sufficient space left for token? */
885
886 storeb (parse++, token_count + 1);
887
888 load_string ((zword) (text + from), length);
889
890 addr = lookup_text (0x05, dct);
891
892 if (addr != 0 || !flag) {
893
894 parse += 4 * token_count;
895
896 storew ((zword) (parse + 0), addr);
897 storeb ((zword) (parse + 2), length);
898 storeb ((zword) (parse + 3), from);
899
900 }
901
902 }
903
904}/* tokenise_text */
905
906/*
907 * tokenise_line
908 *
909 * Split an input line into words and translate the words to tokens.
910 *
911 */
912
913void tokenise_line (zword text, zword token, zword dct, bool flag)
914{
915 zword addr1;
916 zword addr2;
917 zbyte length;
918 zbyte c;
919
920 length = 0; /* makes compilers shut up */
921
922 /* Use standard dictionary if the given dictionary is zero */
923
924 if (dct == 0)
925 dct = h_dictionary;
926
927 /* Remove all tokens before inserting new ones */
928
929 storeb ((zword) (token + 1), 0);
930
931 /* Move the first pointer across the text buffer searching for the
932 beginning of a word. If this succeeds, store the position in a
933 second pointer. Move the first pointer searching for the end of
934 the word. When it is found, "tokenise" the word. Continue until
935 the end of the buffer is reached. */
936
937 addr1 = text;
938 addr2 = 0;
939
940 if (h_version >= V5) {
941 addr1++;
942 LOW_BYTE (addr1, length)
943 }
944
945 do {
946
947 zword sep_addr;
948 zbyte sep_count;
949 zbyte separator;
950
951 /* Fetch next ZSCII character */
952
953 addr1++;
954
955 if (h_version >= V5 && addr1 == text + 2 + length)
956 c = 0;
957 else
958 LOW_BYTE (addr1, c)
959
960 /* Check for separator */
961
962 sep_addr = dct;
963
964 LOW_BYTE (sep_addr, sep_count)
965 sep_addr++;
966
967 do {
968
969 LOW_BYTE (sep_addr, separator)
970 sep_addr++;
971
972 } while (c != separator && --sep_count != 0);
973
974 /* This could be the start or the end of a word */
975
976 if (sep_count == 0 && c != ' ' && c != 0) {
977
978 if (addr2 == 0)
979 addr2 = addr1;
980
981 } else if (addr2 != 0) {
982
983 tokenise_text (
984 text,
985 (zword) (addr1 - addr2),
986 (zword) (addr2 - text),
987 token, dct, flag );
988
989 addr2 = 0;
990
991 }
992
993 /* Translate separator (which is a word in its own right) */
994
995 if (sep_count != 0)
996
997 tokenise_text (
998 text,
999 (zword) (1),
1000 (zword) (addr1 - text),
1001 token, dct, flag );
1002
1003 } while (c != 0);
1004
1005}/* tokenise_line */
1006
1007/*
1008 * z_tokenise, make a lexical analysis of a ZSCII string.
1009 *
1010 * zargs[0] = address of string to analyze
1011 * zargs[1] = address of token buffer
1012 * zargs[2] = address of dictionary (optional)
1013 * zargs[3] = set when unknown words cause empty slots (optional)
1014 *
1015 */
1016
1017void z_tokenise (void)
1018{
1019
1020 /* Supply default arguments */
1021
1022 if (zargc < 3)
1023 zargs[2] = 0;
1024 if (zargc < 4)
1025 zargs[3] = 0;
1026
1027 /* Call tokenise_line to do the real work */
1028
1029 tokenise_line (zargs[0], zargs[1], zargs[2], zargs[3] != 0);
1030
1031}/* z_tokenise */
1032
1033/*
1034 * completion
1035 *
1036 * Scan the vocabulary to complete the last word on the input line
1037 * (similar to "tcsh" under Unix). The return value is
1038 *
1039 * 2 ==> completion is impossible
1040 * 1 ==> completion is ambiguous
1041 * 0 ==> completion is successful
1042 *
1043 * The function also returns a string in its second argument. In case
1044 * of 2, the string is empty; in case of 1, the string is the longest
1045 * extension of the last word on the input line that is common to all
1046 * possible completions (for instance, if the last word on the input
1047 * is "fo" and its only possible completions are "follow" and "folly"
1048 * then the string is "ll"); in case of 0, the string is an extension
1049 * to the last word that results in the only possible completion.
1050 *
1051 */
1052
1053int completion (const zchar *buffer, zchar *result)
1054{
1055 zword minaddr;
1056 zword maxaddr;
1057 zchar *ptr;
1058 zchar c;
1059 int len;
1060 int i;
1061
1062 *result = 0;
1063
1064 /* Copy last word to "decoded" string */
1065
1066 len = 0;
1067
1068 while ((c = *buffer++) != 0)
1069
1070 if (c != ' ') {
1071
1072 if (len < 9)
1073 decoded[len++] = c;
1074
1075 } else len = 0;
1076
1077 decoded[len] = 0;
1078
1079 /* Search the dictionary for first and last possible extensions */
1080
1081 minaddr = lookup_text (0x00, h_dictionary);
1082 maxaddr = lookup_text (0x1f, h_dictionary);
1083
1084 if (minaddr == 0 || maxaddr == 0 || minaddr > maxaddr)
1085 return 2;
1086
1087 /* Copy first extension to "result" string */
1088
1089 decode_text (VOCABULARY, minaddr);
1090
1091 ptr = result;
1092
1093 for (i = len; (c = decoded[i]) != 0; i++)
1094 *ptr++ = c;
1095 *ptr = 0;
1096
1097 /* Merge second extension with "result" string */
1098
1099 decode_text (VOCABULARY, maxaddr);
1100
1101 for (i = len, ptr = result; (c = decoded[i]) != 0; i++, ptr++)
1102 if (*ptr != c) break;
1103 *ptr = 0;
1104
1105 /* Search was ambiguous or successful */
1106
1107 return (minaddr == maxaddr) ? 0 : 1;
1108
1109}/* completion */