home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / Epoc / Palmtime / files / FrotzS5_src.ZIP / TEXT.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-15  |  21.9 KB  |  1,081 lines

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