home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1997 December / Internet_Info_CD-ROM_Walnut_Creek_December_1997.iso / drafts / draft_ietf_a_c / draft-ietf-acap-mlsf-00.txt < prev    next >
Text File  |  1997-06-02  |  20KB  |  677 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7. Network Working Group                                          C. Newman
  8. Internet Draft: Multi-Lingual String Format                     Innosoft
  9. Document: draft-ietf-acap-mlsf-00.txt                           May 1997
  10.                                                    Expires in six months
  11.  
  12.  
  13.                    Multi-Lingual String Format (MLSF)
  14.  
  15.  
  16. Status of this memo
  17.  
  18.      This document is an Internet Draft.  Internet Drafts are working
  19.      documents of the Internet Engineering Task Force (IETF), its Areas,
  20.      and its Working Groups.  Note that other groups may also distribute
  21.      working documents as Internet Drafts.
  22.  
  23.      Internet Drafts are draft documents valid for a maximum of six
  24.      months.  Internet Drafts may be updated, replaced, or obsoleted by
  25.      other documents at any time.  It is not appropriate to use Internet
  26.      Drafts as reference material or to cite them other than as a
  27.      "working draft" or "work in progress".
  28.  
  29.      To learn the current status of any Internet-Draft, please check the
  30.      1id-abstracts.txt listing contained in the Internet-Drafts Shadow
  31.      Directories on ds.internic.net, nic.nordu.net, ftp.isi.edu, or
  32.      munnari.oz.au.
  33.  
  34.      A revised version of this draft document will be submitted to the
  35.      RFC editor as a Proposed Standard for the Internet Community.
  36.      Discussion and suggestions for improvement are requested.  This
  37.      document will expire six months after publication.  Distribution of
  38.      this draft is unlimited.
  39.  
  40.  
  41. Abstract
  42.  
  43.      While UTF-8 [UTF-8] solves most internationalization (I18N)
  44.      problems, it fails to solve multilingualization problems (M17N)
  45.      problems.  The two basic problems with UTF-8 are that CJK
  46.      unification fails to recognize glyph style differences between
  47.      Chinese, Japanese and Korean and that it is impossible to read
  48.      UTF-8 text to a blind person without knowing the language.
  49.  
  50.      Encoding language tagging in the coded character set itself can
  51.      unnecessarily complicate processing which doesn't need language
  52.      tags.  Encoding the language tagging at the application protocol
  53.      level will add unnecessary complexity to every application protocol
  54.      which needs multi-lingual support.  In addition, such higher level
  55.  
  56.  
  57.  
  58. Newman                                                          [Page 1]
  59.  
  60. Internet Draft        Multi-Lingual String Format               May 1997
  61.  
  62.  
  63.      language support may fail to deal with mixed language strings and
  64.      strings which have alternate representations in different
  65.      languages.
  66.  
  67.      This specification uses unused octet sequences in UTF-8 as a
  68.      framework to build a new encoding called MLSF (Multi-Lingual String
  69.      Format) which supports mixed language strings and alternative
  70.      language strings.  The goal is to make language tags easy to strip
  71.      when unnecessary, easy to support when necessary, and to preserve
  72.      the good searching characteristics of UTF-8 as much as possible.
  73.  
  74.  
  75. 1. Conventions used in this document
  76.  
  77.      The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
  78.      in this document are to be interpreted as defined in "Key words for
  79.      use in RFCs to Indicate Requirement Levels" [KEYWORDS].
  80.  
  81.  
  82. 2. MLSF simple form
  83.  
  84.      MLSF uses "Tags for the Identification of Languages" [LANG-TAGS] as
  85.      the basis for language identification.
  86.  
  87.      Language tags are encoded by mapping them to upper-case, then
  88.      adding hexidecimal A0 to each octet.  The result is broken up into
  89.      groups of five octets followed by a final group of five or fewer
  90.      octets.  Each group is prefixed by a UTF-8-style length count with
  91.      the low bits set to 0.  See Appendix D for sample source code to
  92.      perform this conversion.
  93.  
  94.      MLSF simple form is UTF-8 with embedded MLSF language tags.  An
  95.      important observation is that a UTF-8 interpreter which silently
  96.      ignores illegal characters will successfully process MLSF simple
  97.      form strings.  MLSF simple form is defined by the MLSF-SIMPLE rule
  98.      in section 7.  A quoted version of MLSF simple form is defined by
  99.      the MLSF-SIMPLE-QUOTED rule.
  100.  
  101.  
  102. 3. MLSF alternative form
  103.  
  104.      A MLSF alternative form string may contain alternative
  105.      representations of the same text in different primary languages.
  106.      The octet with hexidecimal representation of FE is used to
  107.      introduce a new alternative.  This MUST be followed by a MLSF
  108.      language tag for the primary language of the alternative.
  109.  
  110.      The component of the MLSF string prior to the first FE octet is
  111.  
  112.  
  113.  
  114. Newman                                                          [Page 2]
  115.  
  116. Internet Draft        Multi-Lingual String Format               May 1997
  117.  
  118.  
  119.      considered the "preferred" representation for the string.  This is
  120.      the version which will be displayed by MLSF clients which choose
  121.      not to support alternative representations.  The preferred
  122.      representation MAY be prefixed by a MLSF language tag.
  123.  
  124.      MLSF alternate form is defined by the MLSF-ALT rule in section 7.
  125.      A quoted version of MLSF alternate form is defined by the
  126.      MLSF-ALT-QUOTED rule.
  127.  
  128.  
  129. 4. Minimal Support: downconverting MLSF to UTF-8
  130.  
  131.      Minimal support for MLSF requires the ability to downconvert MLSF
  132.      to UTF-8.  This is a simple procedure which selects the preferred
  133.      alternative and strips all language tags.  Sample code is included
  134.      in Appendix B.  All UTF-8 strings which do not contain a 0 octet
  135.      are also MLSF strings.
  136.  
  137.  
  138. 5. MLSF MIME character sets
  139.  
  140.      The character set label "XXXX-simple" has been registered to
  141.      indicate the use of MLSF simple form.  The character set label
  142.      "XXXX-alt" has been registered to indicate the use of MLSF
  143.      alternate form.
  144.  
  145.      MLSF may be used in conjunction with MIME header [MIME-HDR]
  146.      encoding to permit language tagging and alternative representations
  147.      in header fields.
  148.  
  149.      For single language MIME body parts, the UTF-8 character set with
  150.      an appropriate Content-Language [LANG-TAG] header SHOULD be used
  151.      instead of MLSF.
  152.  
  153.  
  154. 6. Security Considerations
  155.  
  156.      Multi-Lingual String Format is not believed to have any security
  157.      considerations beyond those for simple US-ASCII strings.  In
  158.      particular, unfiltered display of certain US-ASCII control
  159.      characters by a terminal emulator may result in modifying the
  160.      behavior of the terminal emulator (e.g. by redefining function
  161.      keys) such that security can be breached.  Programs which display
  162.      text to a potentially insecure terminal emulator channel are
  163.      encouraged to remove control characters to avoid these problems.
  164.  
  165.  
  166.  
  167.  
  168.  
  169.  
  170. Newman                                                          [Page 3]
  171.  
  172. Internet Draft        Multi-Lingual String Format               May 1997
  173.  
  174.  
  175. 7. Formal Grammar
  176.  
  177.      This section defines the formal grammar for MLSF using Augmented
  178.      BNF [ABNF] notation.
  179.  
  180.      MLSF-ALT           = [[MLSF-LANG-TAG] MLSF-COMPONENT
  181.                            *(MLSF-ALTERNATE MLSF-COMPONENT)]
  182.  
  183.      MLSF-ALT-QUOTED    = <"> [[MLSF-LANG-TAG] MLSF-COMPONENT-Q
  184.                            *(MLSF-ALTERNATE MLSF-COMPONENT-Q)] <">
  185.  
  186.      MLSF-ALTERNATE     = %xFE MLSF-LANG-TAG
  187.  
  188.      MLSF-COMPONENT     = UTF8-NON-NUL *([MLSF-LANG-TAG] UTF8-NON-NUL)
  189.  
  190.      MLSF-COMPONENT-Q   = UTF8-QUOTED *([MLSF-LANG-TAG] UTF8-QUOTED)
  191.  
  192.      MLSF-LANG-TAG      = *MLSF-LANG-5 (MLSF-LANG-1 / MLSF-LANG-2 /
  193.                           MLSF-LANG-3 / MLSF-LANG-4 / MLSF-LANG-5)
  194.                           ;; Encoded version of Language-Tag from RFC 1766
  195.                           ;; characters converted to uppercase, with
  196.                           ;; A0 added and broken into MLSF-LANG components
  197.  
  198.      MLSF-LANG-CONT     = %xCD / %xE1..FA
  199.  
  200.      MLSF-LANG-1        = %xC0 MLSF-LANG-CONT
  201.  
  202.      MLSF-LANG-2        = %xE0 2MLSF-LANG-CONT
  203.  
  204.      MLSF-LANG-3        = %xF0 3MLSF-LANG-CONT
  205.  
  206.      MLSF-LANG-4        = %xF8 4MLSF-LANG-CONT
  207.  
  208.      MLSF-LANG-5        = %xFC 5MLSF-LANG-CONT
  209.  
  210.      MLSF-SIMPLE        = [[MLSF-LANG-TAG] MLSF-COMPONENT]
  211.  
  212.      MLSF-SIMPLE-QUOTED = <"> [[MLSF-LANG-TAG] MLSF-COMPONENT-Q] <">
  213.  
  214.      QUOTED             = "\" QUOTED-SPECIAL
  215.  
  216.      QUOTED-SPECIAL     = "\" / <">
  217.  
  218.      US-ASCII-SAFE      = %x01..09 / %x0B..0C / %x0E..21
  219.                           / %x23..2E / %x30..7F
  220.                          ;; US-ASCII except QUOTED-SPECIALs, CR, LF, NUL
  221.  
  222.      UTF8-NON-NUL       = UTF8-SAFE / CR / LF / QUOTED-SPECIAL
  223.  
  224.  
  225.  
  226. Newman                                                          [Page 4]
  227.  
  228. Internet Draft        Multi-Lingual String Format               May 1997
  229.  
  230.  
  231.      UTF8-QUOTED        = UTF8-SAFE / QUOTED
  232.  
  233.      UTF8-SAFE          = US-ASCII-SAFE / UTF8-1 / UTF8-2 / UTF8-3
  234.                           / UTF8-4 / UTF8-5
  235.  
  236.      UTF8-CONT          = %x80..BF
  237.  
  238.      UTF8-1             = %xC0..DF UTF8-CONT
  239.  
  240.      UTF8-2             = %xE0..EF 2UTF8-CONT
  241.  
  242.      UTF8-3             = %xF0..F7 3UTF8-CONT
  243.  
  244.      UTF8-4             = %xF8..FB 4UTF8-CONT
  245.  
  246.      UTF8-5             = %xFC..FD 5UTF8-CONT
  247.  
  248.  
  249. 8. References
  250.  
  251.      [ABNF] Crocker, D., "Augmented BNF for Syntax Specifications:
  252.      ABNF", Work in progress: draft-ietf-drums-abnf-xx.txt
  253.  
  254.      [KEYWORDS] Bradner, "Key words for use in RFCs to Indicate
  255.      Requirement Levels", RFC 2119, Harvard University, March 1997.
  256.  
  257.          <ftp://ds.internic.net/rfc/rfc2119.txt>
  258.  
  259.      [LANG-TAGS] Alvestrand, H., "Tags for the Identification of
  260.      Languages", RFC 1766.
  261.  
  262.          <ftp://ds.internic.net/rfc/rfc1766.txt>
  263.  
  264.      [MIME-HDR] Moore, "MIME (Multipurpose Internet Mail Extensions)
  265.      Part Three: Message Header Extensions for Non-ASCII Text", RFC
  266.      2047, University of Tennessee, November 1996.
  267.  
  268.          <ftp://ds.internic.net/rfc/rfc2047.txt>
  269.  
  270.      [MIME-IMB] Freed, Borenstein, "Multipurpose Internet Mail
  271.      Extensions (MIME) Part One: Format of Internet Message Bodies", RFC
  272.      2045, Innosoft, First Virtual, November 1996.
  273.  
  274.          <ftp://ds.internic.net/rfc/rfc2045.txt>
  275.  
  276.  
  277.  
  278.  
  279.  
  280.  
  281.  
  282. Newman                                                          [Page 5]
  283.  
  284. Internet Draft        Multi-Lingual String Format               May 1997
  285.  
  286.  
  287.      [UTF8] Yergeau, F. "UTF-8, a transformation format of Unicode and
  288.      ISO 10646", RFC 2044, Alis Technologies, October 1996.
  289.  
  290.          <ftp://ds.internic.net/rfc/rfc2044.txt>
  291.  
  292.  
  293. 9. Acknowledgements
  294.  
  295.      Special thanks to Mark Crispin for the idea of using unused UTF-8
  296.      codes for this purpose.   Thanks are also due to participants of
  297.      the ACAP WG mailing list who helped review this proposal.
  298.  
  299.  
  300. 10. Author's Address
  301.  
  302.      Chris Newman
  303.      Innosoft International, Inc.
  304.      1050 East Garvey Ave. South
  305.      West Covina, CA 91790 USA
  306.  
  307.      Email: chris.newman@innosoft.com
  308.  
  309.  
  310. Appendix A.  Client advice
  311.  
  312.      A simple UTF-8 client is likely to find the source code in Appendix
  313.      B useful.  A simple Latin-1 based client is likely to find the
  314.      source code in Appendix C useful.
  315.  
  316.      A more sophisticated client will allow the user to select a
  317.      preferred language and use something like the source code in
  318.      Appendix E to find the best alternative in an MLSF string.  Such
  319.      clients should also be aware that sometimes the client's preferred
  320.      language is misconfigured, and the user may wish to have the last
  321.      few messages repeated after they have changed languages.  For this
  322.      reason, such a client may wish to cache the last few MLSF strings
  323.      displayed to the user.
  324.  
  325.  
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.  
  337.  
  338. Newman                                                          [Page 6]
  339.  
  340. Internet Draft        Multi-Lingual String Format               May 1997
  341.  
  342.  
  343. Appendix B.  Sample code to convert to UTF-8
  344.  
  345. Here is sample C source code to convert from MLSF to UTF-8.
  346.  
  347. #include <stdio.h>
  348. #include <ctype.h>
  349.  
  350. /* a UTF8 lookup table */
  351. #define BAD 0x80
  352. #define SEP 0x40
  353. #define EXT 0x20
  354. static unsigned char utlen[256] = {
  355.         /* 0x00 */ BAD,   1,   1,   1,   1,   1,   1,   1,
  356.         /* 0x08 */   1,   1,   1,   1,   1,   1,   1,   1,
  357.         /* 0x10 */   1,   1,   1,   1,   1,   1,   1,   1,
  358.         /* 0x18 */   1,   1,   1,   1,   1,   1,   1,   1,
  359.         /* 0x20 */   1,   1,   1,   1,   1,   1,   1,   1,
  360.         /* 0x28 */   1,   1,   1,   1,   1,   1,   1,   1,
  361.         /* 0x30 */   1,   1,   1,   1,   1,   1,   1,   1,
  362.         /* 0x38 */   1,   1,   1,   1,   1,   1,   1,   1,
  363.         /* 0x40 */   1,   1,   1,   1,   1,   1,   1,   1,
  364.         /* 0x48 */   1,   1,   1,   1,   1,   1,   1,   1,
  365.         /* 0x50 */   1,   1,   1,   1,   1,   1,   1,   1,
  366.         /* 0x58 */   1,   1,   1,   1,   1,   1,   1,   1,
  367.         /* 0x60 */   1,   1,   1,   1,   1,   1,   1,   1,
  368.         /* 0x68 */   1,   1,   1,   1,   1,   1,   1,   1,
  369.         /* 0x70 */   1,   1,   1,   1,   1,   1,   1,   1,
  370.         /* 0x78 */   1,   1,   1,   1,   1,   1,   1,   1,
  371.         /* 0x80 */ EXT, EXT, EXT, EXT, EXT, EXT, EXT, EXT,
  372.         /* 0x88 */ EXT, EXT, EXT, EXT, EXT, EXT, EXT, EXT,
  373.         /* 0x90 */ EXT, EXT, EXT, EXT, EXT, EXT, EXT, EXT,
  374.         /* 0x98 */ EXT, EXT, EXT, EXT, EXT, EXT, EXT, EXT,
  375.         /* 0xA0 */ EXT, EXT, EXT, EXT, EXT, EXT, EXT, EXT,
  376.         /* 0xA8 */ EXT, EXT, EXT, EXT, EXT, EXT, EXT, EXT,
  377.         /* 0xB0 */ EXT, EXT, EXT, EXT, EXT, EXT, EXT, EXT,
  378.         /* 0xB8 */ EXT, EXT, EXT, EXT, EXT, EXT, EXT, EXT,
  379.         /* 0xC0 */   2,   2,   2,   2,   2,   2,   2,   2,
  380.         /* 0xC8 */   2,   2,   2,   2,   2,   2,   2,   2,
  381.         /* 0xD0 */   2,   2,   2,   2,   2,   2,   2,   2,
  382.         /* 0xD8 */   2,   2,   2,   2,   2,   2,   2,   2,
  383.         /* 0xE0 */   3,   3,   3,   3,   3,   3,   3,   3,
  384.         /* 0xE8 */   3,   3,   3,   3,   3,   3,   3,   3,
  385.         /* 0xF0 */   4,   4,   4,   4,   4,   4,   4,   4,
  386.         /* 0xF8 */   5,   5,   5,   5,   6,   6, SEP, BAD
  387. };
  388.  
  389.  
  390.  
  391.  
  392.  
  393.  
  394. Newman                                                          [Page 7]
  395.  
  396. Internet Draft        Multi-Lingual String Format               May 1997
  397.  
  398.  
  399. /* Down conversion from NUL terminated MLSF string to UTF-8.
  400.  *  this strips the language tags and only keeps the preferred
  401.  *  representation.
  402.  * It returns the length of the final string.
  403.  * The destination string will not be longer than the source string.
  404.  *  dst and src may be the same for in-place conversion.
  405.  */
  406. int MLSFtoUTF8(unsigned char *dst, unsigned char *src)
  407. {
  408.     unsigned char *start = dst;
  409.     int len;
  410.  
  411.     for (;;) {
  412.         len = utlen[*src];
  413.         if (len > 6) break;
  414.         /* skip language tags */
  415.         if (len > 1 && src[1] > 0xC0U) {
  416.             while (len && *src != '\0') {
  417.                 ++src;
  418.                 --len;
  419.             }
  420.             continue;
  421.         }
  422.         /* copy UTF8 character */
  423.         while (len && *src != '\0') {
  424.             *dst = *src;
  425.             ++dst;
  426.             ++src;
  427.             --len;
  428.         }
  429.     }
  430.     *dst = '\0';
  431.  
  432.     return (dst - start);
  433. }
  434.  
  435.  
  436.  
  437.  
  438.  
  439.  
  440.  
  441.  
  442.  
  443.  
  444.  
  445.  
  446.  
  447.  
  448.  
  449.  
  450. Newman                                                          [Page 8]
  451.  
  452. Internet Draft        Multi-Lingual String Format               May 1997
  453.  
  454.  
  455. Appendix C. Sample code to convert to Latin-1
  456.  
  457. /* Down conversion from NUL terminated MLSF string to 8859-1
  458.  * The destination string will not be longer than the source string.
  459.  *  fillc is used to fill untranslatable characters,
  460.  *  if fillc is NUL, untranslatable characters are ignored.
  461.  * returns 0 if source only contained latin-1, returns -1 otherwise.
  462.  */
  463. int MLSFtoLatin1(unsigned char *dst, unsigned char *src, int fillc)
  464. {
  465.     int len, result = 0;
  466.  
  467.     for (;;) {
  468.         len = utlen[*src];
  469.         /* copy US-ASCII */
  470.         if (len == 1) {
  471.             *dst = *src;
  472.             ++dst;
  473.             ++src;
  474.             continue;
  475.         }
  476.         /* stop at illegal character or end of string */
  477.         if (len > 6) break;
  478.         /* skip non-latin1 glyphs and language tags */
  479.         if (*src > 0xC3U || src[1] > 0xC0U) {
  480.             if (src[1] <= 0xC0U) {
  481.                 /* non-latin1 glyph found */
  482.                 result = -1;
  483.                 if (fillc) {
  484.                     *dst = fillc;
  485.                     ++dst;
  486.                 }
  487.             }
  488.             while (len && *src != '\0') {
  489.                 ++src;
  490.                 --len;
  491.             }
  492.             continue;
  493.         }
  494.         /* copy latin 1 character */
  495.         *dst = ((src[0] & 0x03) << 6) | (src[1] & 0x3F);
  496.         ++dst;
  497.         src += 2;
  498.     }
  499.     *dst = '\0';
  500.  
  501.     return (result);
  502. }
  503.  
  504.  
  505.  
  506. Newman                                                          [Page 9]
  507.  
  508. Internet Draft        Multi-Lingual String Format               May 1997
  509.  
  510.  
  511. Appendix D. Sample code for encoding/decoding language tags
  512.  
  513. /* encode a language tag
  514.  *  the destination must have a size of least (counting terminating NUL):
  515.  *        (6 * strlen(src) + 9) / 5
  516.  *  returns the length of the destination.
  517.  */
  518. int MLSFlangencode(unsigned char *dst, unsigned char *src)
  519. {
  520.     static unsigned char prefix[] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
  521.     unsigned char *start = dst;
  522.     int len;                    /* source length */
  523.     int complen;                /* component length */
  524.     int i;
  525.  
  526.     for (len = strlen(src); len > 0; len -= complen) {
  527.         /* find maximal component length */
  528.         complen = len;
  529.         if (len >= 5) {
  530.             complen = 5;
  531.         }
  532.         /* look up component prefix */
  533.         *dst = prefix[complen - 1];
  534.         ++dst;
  535.         /* copy and map characters in component */
  536.         for (i = 0; i < complen; ++i) {
  537.             *dst = (islower(*src) ? toupper(*src) : *src) + 0xA0U;
  538.             ++dst;
  539.             ++src;
  540.         }
  541.     }
  542.     *dst = '\0';
  543.  
  544.     return (dst - start);
  545. }
  546.  
  547.  
  548.  
  549.  
  550.  
  551.  
  552.  
  553.  
  554.  
  555.  
  556.  
  557.  
  558.  
  559.  
  560.  
  561.  
  562. Newman                                                         [Page 10]
  563.  
  564. Internet Draft        Multi-Lingual String Format               May 1997
  565.  
  566.  
  567. /* decode a language tag
  568.  *  the destination will not be longer than the source
  569.  *  dst and src may be the same for in-place conversion
  570.  * returns the length of the destination
  571.  */
  572. int MLSFlangdecode(unsigned char *dst, unsigned char *src)
  573. {
  574.     unsigned char *start = dst;
  575.     int complen;
  576.  
  577.     while (src[0] >= 0xC0U && src[1] > 0xC0U) {
  578.         for (complen = utlen[*src++]; complen > 1; --complen) {
  579.             *dst = *src - 0xA0U;
  580.             ++dst;
  581.             ++src;
  582.         }
  583.     }
  584.     *dst = '\0';
  585.  
  586.     return (dst - start);
  587. }
  588.  
  589.  
  590. Appendix E. Sample code for selecting the "best" alternative
  591.  
  592. /* select the "best" language match from an MLSF string
  593.  *  assume input language tag has been converted to upper case
  594.  *  assume language tags in string won't exceed 256 characters
  595.  *  "best" is calculated by matching RFC 1766 language tag components
  596.  * returns a pointer to the start of best matching component
  597.  */
  598. unsigned char *MLSFselect(unsigned char *str, unsigned char *tag)
  599. {
  600.     unsigned char ltag[256];
  601.     unsigned char *best, *match1, *match2;
  602.     int bestlen, mlen;
  603.  
  604.     /* start with match on preferred alternative */
  605.     best = str;
  606.     bestlen = 0;
  607.  
  608.     /* skip test if no language tag */
  609.     if (tag != NULL && *tag != '\0') {
  610.         do {
  611.             /* get language tag for this component */
  612.             MLSFlangdecode(ltag, str);
  613.  
  614.  
  615.  
  616.  
  617.  
  618. Newman                                                         [Page 11]
  619.  
  620. Internet Draft        Multi-Lingual String Format               May 1997
  621.  
  622.  
  623.             /* calculate match length of language tags */
  624.             match1 = ltag;
  625.             match2 = tag;
  626.             mlen = 0;
  627.             while (*match1 != '\0' && *match1 == *match2) {
  628.                 ++match1, ++match2;
  629.                 /* save length of partial match */
  630.                 if (*match2 == '-'
  631.                     && (*match1 == '-' || *match1 == '\0')) {
  632.                     mlen = match1 - ltag;
  633.                 }
  634.             }
  635.  
  636.             /* finish on exact match */
  637.             if (*match2 == '\0'
  638.                 && (*match1 == '-' || *match1 == '\0')) {
  639.                 best = str;
  640.                 break;
  641.             }
  642.  
  643.             /* remember best match */
  644.             if (mlen > bestlen) {
  645.                 best = str;
  646.                 bestlen = mlen;
  647.             }
  648.  
  649.             /* skip to next MLSF component */
  650.             while (*str != '\0' && *str++ != 0xFEU)
  651.                 ;
  652.         } while (*str != '\0');
  653.     }
  654.  
  655.     return (best);
  656. }
  657.  
  658.  
  659.  
  660.  
  661.  
  662.  
  663.  
  664.  
  665.  
  666.  
  667.  
  668.  
  669.  
  670.  
  671.  
  672.  
  673.  
  674. Newman                                                         [Page 12]
  675.  
  676.  
  677.