home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume4 / kterm / part01 / convert.c next >
Encoding:
C/C++ Source or Header  |  1989-05-31  |  12.6 KB  |  665 lines

  1. /*
  2.  *    convert.c -- code converters for kterm
  3.  */
  4.  
  5. /*
  6.  * Copyright (c) 1989  Software Research Associates, Inc.
  7.  *
  8.  * Permission to use, copy, modify, and distribute this software and its
  9.  * documentation for any purpose and without fee is hereby granted, provided
  10.  * that the above copyright notice appear in all copies and that both that
  11.  * copyright notice and this permission notice appear in supporting
  12.  * documentation, and that the name of Software Research Associates not be
  13.  * used in advertising or publicity pertaining to distribution of the
  14.  * software without specific, written prior permission.  Software Research
  15.  * Associates makes no representations about the suitability of this software
  16.  * for any purpose.  It is provided "as is" without express or implied
  17.  * warranty.
  18.  *
  19.  * Author:  Makoto Ishisone, Software Research Associates, Inc., Japan
  20.  */
  21.  
  22. #ifndef lint
  23. static char kterm_id[] = "$Header: convert.c,v 1.1 89/05/30 14:53:36 kagotani Rel $";
  24. #endif /* lint */
  25.  
  26. #ifdef KANJI
  27.  
  28. typedef unsigned short    wchar_t;
  29.  
  30. #define NULL    0
  31.  
  32. /* WS -> JIS */
  33. #define ASCII    0
  34. #define KANJI    1
  35. #define KANA    2
  36.  
  37. int
  38. convWStoJIS(ws, js)
  39. wchar_t        *ws;
  40. unsigned char    *js;
  41. {
  42.     int    c;
  43.     int    kanji = ASCII;
  44.     int    n = 0;
  45.  
  46.     while (c = *ws++) {
  47.         switch (c & 0x8080) {
  48.         case 0:
  49.             if (kanji != ASCII) {
  50.                 if (js) {
  51.                     *js++ = '\033';
  52.                     *js++ = '(';
  53.                     *js++ = 'J';
  54.                 }
  55.                 n += 3;
  56.             }
  57.             if (js)
  58.                 *js++ = c & 0x7f;
  59.             n++;
  60.             kanji = ASCII;
  61.             break;
  62.         case 0x80:
  63.             if (kanji != KANA) {
  64.                 if (js) {
  65.                     *js++ = '\033';
  66.                     *js++ = '(';
  67.                     *js++ = 'I';
  68.                 }
  69.                 n += 3;
  70.             }
  71.             if (js)
  72.                 *js++ = c & 0x7f;
  73.             n++;
  74.             kanji = KANA;
  75.             break;
  76.         case 0x8080:
  77.             if (kanji != KANJI) {
  78.                 if (js) {
  79.                     *js++ = '\033';
  80.                     *js++ = '$';
  81.                     *js++ = 'B';
  82.                 }
  83.                 n += 3;
  84.             }
  85.             if (js) {
  86.                 *js++ = (c >> 8) & 0x7f;
  87.                 *js++ = c & 0x7f;
  88.             }
  89.             n += 2;
  90.             kanji = KANJI;
  91.             break;
  92.         }
  93.     }
  94.     if (kanji != ASCII) {
  95.         if (js) {
  96.             *js++ = '\033';
  97.             *js++ = '(';
  98.             *js++ = 'J';
  99.         }
  100.         n += 3;
  101.     }
  102.     if (js)
  103.         *js = '\0';
  104.  
  105.     return n;
  106. }
  107.  
  108. /* WS -> EUC */
  109. int
  110. convWStoEUC(ws, es)
  111. wchar_t        *ws;
  112. unsigned char    *es;
  113. {
  114.     int    c;
  115.     int    n = 0;
  116.  
  117.     while (c = *ws++) {
  118.         switch (c & 0x8080) {
  119.         case 0:
  120.             if (es)
  121.                 *es++ = c & 0x7f;
  122.             n++;
  123.             break;
  124.         case 0x80:
  125.             if (es) {
  126.                 *es++ = 0x8e;    /* SS2 */
  127.                 *es++ = c & 0xff;
  128.             }
  129.             n += 2;
  130.             break;
  131.         case 0x8000:
  132.             if (es) {
  133.                 *es++ = 0x8f;    /* SS3 */
  134.                 *es++ = (c >> 8) | 0x80;
  135.                 *es++ = (c & 0xff) | 0x80;
  136.             }
  137.             n += 3;
  138.             break;
  139.         case 0x8080:
  140.             if (es) {
  141.                 *es++ = c >> 8;
  142.                 *es++ = c & 0xff;
  143.             }
  144.             n += 2;
  145.             break;
  146.         }
  147.     }
  148.     if (es)
  149.         *es = '\0';
  150.  
  151.     return n;
  152. }
  153.  
  154. /* WS -> SJIS */
  155. int
  156. convWStoSJIS(ws, ss)
  157. wchar_t        *ws;
  158. unsigned char    *ss;
  159. {
  160.     int    c1, c2;
  161.     int    n = 0;
  162.  
  163.     while (c1 = *ws++) {
  164.         switch (c1 & 0x8080) {
  165.         case 0:
  166.         case 0x80:
  167.             if (ss)
  168.                 *ss++ = c1 & 0xff;
  169.             n++;
  170.             break;
  171.         case 0x8080:
  172.             c2 = c1 & 0x7f;
  173.             c1 = (c1 >> 8) & 0x7f;
  174.             if (ss) {
  175.                 *ss++ = (c1 - 0x21) / 2 +
  176.                     ((c1 <= 0x5e) ? 0x81 : 0xc1);
  177.                 if (c1 & 1)    /* odd */
  178.                     *ss++ = c2 + ((c2 <= 0x5f) ? 0x1f : 0x20);
  179.                 else
  180.                     *ss++ = c2 + 0x7e;
  181.             }
  182.             n += 2;
  183.             break;
  184.         }
  185.     }
  186.     if (ss)
  187.         *ss = '\0';
  188.  
  189.     return n;
  190. }
  191.  
  192. /* WS -> ISO Latin-1 */
  193. int
  194. convJWStoLatin1(ws, ls)
  195. wchar_t *ws;
  196. unsigned char *ls;
  197. {
  198.     int    n = 0;
  199.     int c;
  200.  
  201.     if (ls == NULL) {
  202.     while (c = *ws++) {
  203.         if ((c & 0x8080) == 0)
  204.             n++;
  205.     }
  206.     } else {
  207.     while (c = *ws++) {
  208.         if ((c & 0x8080) == 0) {
  209.         *ls++ = c & 0x7f;
  210.         n++;
  211.         }
  212.     }
  213.     }
  214.     return n;
  215. }
  216.  
  217. /******************************************************************************
  218. COMPOUND_TEXT Summary (Comopund Text Encoding Version 1 -- public review)
  219. (1) Only G0 and G1 are used. G2 and G3 are not.
  220. (2) G0 is invoked into GL and G1 into GR. These invocation are not changed.
  221.     (In other words, Locking Shift and Single Shift are not used)
  222. (3) In initial state, ISO Latin-1 is designated into G0/G1.
  223. (4) To designate MBCS into G0, ESC-$-F is not used but ESC-$-(-F.
  224. (5) In C0, only HT, NL, and ESC are used.
  225. (6) In C1, only CSI is used.
  226. (7) Text direction can be indecated.
  227.     begin left-to-right string
  228.     begin right-to-left string
  229.     end of string
  230. ******************************************************************************/
  231.  
  232. #define CS96    0x100    /* 96chars CS */
  233. #define MBCS    0x200    /* Multibyte CS */
  234.  
  235. /* convJWStoCT -- Japanese Wide Character String -> COMPOUND_TEXT */
  236. int
  237. convJWStoCT(wstr, xstr, jisroman)
  238. register wchar_t *wstr;
  239. register unsigned char *xstr;
  240. int jisroman;    /* if true, map YEN-mark etc.to right part of Latin-1 */
  241. /* Convert Wide Character String wstr to COMPOUND_TEXT xstr, return
  242.  * length of xstr in bytes (not including the terminating null character).
  243.  * If xstr is NULL, no conversion is done, but return length of xstr.
  244.  */
  245. {
  246.     register int    c;
  247.     register int    g0, g1;
  248.     register int    n = 0;
  249.     
  250.     g0 = 'B';
  251.     g1 = CS96|'A';
  252.     
  253.     /*
  254.      * G0 and G1 are used for following character sets
  255.      *  G0: ASCII
  256.      *  G1: KANJI / KANA / JIS-ROMAN emulation (8859/1 right part)
  257.      */
  258.     
  259.     while (c = *wstr++) {
  260.         switch (c & 0x8080) {
  261.         case 0:        /* ASCII or C0 */
  262.             if (c < ' ') {
  263.                 /* C0 */
  264.                 if (c == '\t' || c == '\n') {
  265.                     if (xstr) *xstr++ = c;
  266.                     n++;
  267.                 }
  268.                 break;
  269.             }
  270.             if (jisroman && (c == '\\' || c == '|' || c == '~')) {
  271.                 if (g1 != (CS96|'A')) {
  272.                     if (xstr) {
  273.                         *xstr++ = '\033';
  274.                         *xstr++ = '-';
  275.                         *xstr++ = 'A';
  276.                     }
  277.                     n += 3;
  278.                     g1 = CS96|'A';
  279.                 }
  280.                 if (xstr) {
  281.                     if (c == '\\') *xstr++ = 0xa5;
  282.                     else if (c == '|') *xstr++ = 0xa6;
  283.                     else *xstr++ = 0xaf;
  284.                 }
  285.                 n++;
  286.                 break;
  287.             }
  288.             if (g0 != 'B') {
  289.                 if (xstr) {
  290.                     *xstr++ = '\033';
  291.                     *xstr++ = '(';
  292.                     *xstr++ = 'B';
  293.                 }
  294.                 n += 3;
  295.                 g0 = 'B';
  296.             }
  297.             if (xstr) *xstr++ = c & 0x7f;
  298.             n++;
  299.             break;
  300.         case 0x80:    /* KANA */
  301.             if (g1 != 'I') {
  302.                 if (xstr) {
  303.                     *xstr++ = '\033';
  304.                     *xstr++ = ')';
  305.                     *xstr++ = 'I';
  306.                 }
  307.                 n += 3;
  308.                 g1 = 'I';
  309.             }
  310.             if (xstr) *xstr++ = c & 0xff;
  311.             n++;
  312.             break;
  313.         case 0x8080:    /* KANJI */
  314.             if (g1 != (MBCS|'B')) {
  315.                 if (xstr) {
  316.                     *xstr++ = '\033';
  317.                     *xstr++ = '$';
  318.                     *xstr++ = ')';
  319.                     *xstr++ = 'B';
  320.                 }
  321.                 n += 4;
  322.                 g1 = MBCS|'B';
  323.             }
  324.             if (xstr) {
  325.                 *xstr++ = (c >> 8) & 0xff;
  326.                 *xstr++ = c & 0xff;
  327.             }
  328.             n += 2;
  329.             break;
  330.         default:
  331.             /* ignored */
  332.             break;
  333.         }
  334.     }
  335.     if (xstr) *xstr = '\0';
  336.     return n;
  337. }
  338.  
  339. static unsigned char *
  340. getesc(str, len)
  341. unsigned char *str;
  342. int len;
  343. {
  344.     register int    c;
  345.  
  346.     /* Find intermediate characters and final character
  347.      * following the escape character in an escape sequence.
  348.      */
  349.     /* The intermediate character is 02/00 to 02/15 */
  350.     while (len > 0) {
  351.         c = *str;
  352.         if (c < 0x20 || 0x2f < c)
  353.             break;
  354.         len--, str++;
  355.     }
  356.     /* The final character is 03/00 to 07/14 */
  357.     if (--len < 0 || (c = *str++) < 0x30 || 0x7e < c)
  358.         return (unsigned char *)NULL;
  359.  
  360.     return str;
  361. }
  362.  
  363. static unsigned char *
  364. getcsi(str, len)
  365. unsigned char *str;
  366. int len;
  367. {
  368.     register int    c;
  369.  
  370.     /* Find parameter characters, intermediate characters
  371.      * and final character following the CSI character
  372.      * in a CSI sequence.
  373.      */
  374.     /* The parameter characters is 03/00 to 03/15 */
  375.     while (len > 0) {
  376.         c = *str;
  377.         if (c < 0x30 || 0x3f < c)
  378.             break;
  379.         len--, str++;
  380.     }
  381.     /* The intermediate character is 02/00 to 02/15 */
  382.     while (len > 0) {
  383.         c = *str;
  384.         if (c < 0x20 || 0x2f < c)
  385.             break;
  386.         len--, str++;
  387.     }
  388.     /* The final character is 04/00 to 07/14 */
  389.     if (--len < 0 || (c = *str++) < 0x40 || 0x7e < c)
  390.         return (unsigned char *)NULL;
  391.  
  392.     return str;
  393. }
  394.  
  395. /* convCTtoJWS -- COMPOUND_TEXT -> Japanese Wide Character String */
  396. int
  397. convCTtoJWS(xstr, len, wstr)
  398. register unsigned char *xstr;
  399. int len;
  400. wchar_t *wstr;
  401. /* Convert COMPOUND_TEXT xstr to Wide Character String wstr, return
  402.  * length of wstr in characters (not including the terminating null character).
  403.  * If wstr is NULL, no conversion is done, but return length of wstr.
  404.  */
  405. {
  406.     register int    c;
  407.     int    nskip;
  408.     int    n = 0;
  409.     int    g0, g1, gs;
  410.     unsigned char    *xstr1;
  411.  
  412.     /*
  413.      * Compound Text can include null octet. Therefore the length
  414.      * of xstr is able to be specified by parameter len.
  415.      * But if len is zero or negative, get length by strlen() assuming
  416.      * that no null octet exists.
  417.      */
  418.     if (len <= 0) {
  419.         len = strlen((char *)xstr);
  420.     }
  421.  
  422.     /* In initial state, ISO 8859/1 is designated into G0/G1 */
  423.     g0 = 'B';    /* ASCII -> G0 */
  424.     g1 = CS96|'A';    /* Latin/1 right hand part -> G1 */
  425.  
  426.     while (len-- > 0) {
  427.         switch (c = *xstr++) {
  428.         case '\n':    /* NEWLINE */
  429.         case '\t':    /* TAB */
  430.             if (wstr) *wstr++ = c;
  431.             n++;
  432.             break;
  433.         case 0x9b:    /* CSI */
  434.             /*
  435.              * CSI sequence is generally in following form:
  436.              *    CSI {P} {I} F
  437.              *        P : 03/00 to 03/15
  438.              *        I : 02/00 to 02/15
  439.              *        F : 04/00 to 07/14
  440.              */
  441.             /*
  442.              * Currently only directionality is definde
  443.              * as following:
  444.              *    CSI-1-]        begin left-to-right text
  445.              *    CSI-2-]        begin right-to-left text
  446.              *    CSI-]        end of string
  447.              * But this implementation ignores them.
  448.              */
  449.             xstr1 = getcsi(xstr, len);
  450.             if (xstr1 == NULL)
  451.                 return -1;
  452.             len -= xstr1 - xstr;
  453.             xstr = xstr1;
  454.             break;
  455.         case '\033':    /* ESC */
  456.             /*
  457.              * ESC sequence is generally in following form:
  458.              *    ESC {I} F
  459.              *        I : 02/00 to 02/15
  460.              *        F : 03/00 to 07/14
  461.              */
  462.             /*
  463.              * Currently, following functions are defined:
  464.              *   Standard character set
  465.              *    ESC-(-F
  466.              *    ESC-$-(-F
  467.              *    ESC-)-F
  468.              *    ESC---F
  469.              *    ESC-$-)-F
  470.              *   Non standard character set
  471.              *    ESC-%-/-[0123]
  472.              * Standard character set must be accepted correctly.
  473.              * Non standard one is ignored but must be parsed
  474.              * for skipping data.
  475.              */
  476.             xstr1 = getesc(xstr, len);
  477.             if (xstr1 == NULL)
  478.                 return -1;
  479.             len -= xstr1 - xstr;
  480.             switch (xstr1 - xstr) {
  481.             case 2:        /* ESC - I - F */
  482.                 switch (*xstr++) {
  483.                 case '(':    /* 94chars CS -> G0 */
  484.                     g0 = *xstr;
  485.                     break;
  486.                 case ')':    /* 94chars CS -> G1 */
  487.                     g1 = *xstr;
  488.                     break;
  489.                 case '-':    /* 96chars CS -> G1 */
  490.                     g1 = *xstr | CS96;
  491.                     break;
  492.                 default:    /* ignore */
  493.                     break;
  494.                 }
  495.                 break;
  496.             case 3:        /* ESC - I - I - F */
  497.                 switch (*xstr++) {
  498.                 case '$':
  499.                     switch (*xstr++) {
  500.                     case '(':    /* 94chars MBCS -> G0 */
  501.                         g0 = *xstr | MBCS;
  502.                         break;
  503.                     case ')':    /* 94chars MBCS -> G1 */
  504.                         g1 = *xstr | MBCS;
  505.                         break;
  506.                     case '-':    /* 96chars MBCS -> G1 */
  507.                         g1 = *xstr | CS96 | MBCS;
  508.                         break;
  509.                     default:    /* ignore */
  510.                         break;
  511.                     }
  512.                     break;
  513.                 case '%':
  514.                     if (*xstr++ != '/') {
  515.                         /* unknown sequence */
  516.                         break;
  517.                     }
  518.                     /*
  519.                      * Private encoding is ignored.
  520.                      * But following data must be skipped.
  521.                      *    ESC-%-/-F-M-L
  522.                      */
  523.                     len -= 2;
  524.                     if (len < 0)
  525.                         return -1;
  526.                     nskip = (*xstr1 & 0x7f) * 128 +
  527.                         (*(xstr1 + 1) & 0x7f);
  528.                     if ((len -= nskip) < 0)
  529.                         return -1;
  530.                     xstr1 += nskip + 2;
  531.                     break;
  532.                 default:
  533.                     break;
  534.                 }
  535.                 break;
  536.             default:
  537.                 break;
  538.             }
  539.             xstr = xstr1;
  540.             break;
  541.         default:
  542.             if (!(c & 0x60)) {
  543.                 /*
  544.                  * Non NL/TAB/ESC/CSI character in C0 or C1
  545.                  * is an obvious error.
  546.                  */
  547.                 return -1;
  548.             }
  549.             gs = (c & 0x80) ? g1 : g0;
  550.             c &= 0x7f;
  551.             if (gs & MBCS) {
  552.                 switch (gs & 0x70) {
  553.                 case 0x70:    /* 4byte/char */
  554.                     if (--len < 0) return -1;
  555.                     c = (c << 8) | (*xstr++ & 0x7f);
  556.                 case 0x60:    /* 3byte/char */
  557.                     if (--len < 0) return -1;
  558.                     c = (c << 8) | (*xstr++ & 0x7f);
  559.                 case 0x50:    /* 2byte/char */
  560.                 case 0x40:    /* 2byte/char */
  561.                     if (--len < 0) return -1;
  562.                     c = (c << 8) | (*xstr++ & 0x7f);
  563.                     break;
  564.                 default:
  565.                     return -1;
  566.                 }
  567.             }
  568.             if (wstr) {
  569.                 switch (gs) {
  570.                 case 'B':
  571.                     *wstr++ = c;
  572.                     n++;
  573.                     break;
  574.                 case 'I':
  575.                     *wstr++ = 0x80 | c;
  576.                     n++;
  577.                     break;
  578.                 case CS96|'A':
  579.                     switch (c) {
  580.                     case 0x25:    /* yen */
  581.                         *wstr++ = '\\';
  582.                         n++;
  583.                         break;
  584.                     case 0x26:    /* bar */
  585.                         *wstr++ = '|';
  586.                         n++;
  587.                         break;
  588.                     case 0x2f:    /* upperscore */
  589.                         *wstr++ = '~';
  590.                         n++;
  591.                         break;
  592.                     }
  593.                     break;
  594.                 case MBCS|'B':
  595.                     *wstr++ = 0x8080 | c;
  596.                     n++;
  597.                     break;
  598.                 }
  599.             } else {
  600.                 switch (gs) {
  601.                 case 'B':
  602.                 case 'I':
  603.                     n++;
  604.                     break;
  605.                 case CS96|'A':
  606.                     switch (c) {
  607.                     case 0x25:    /* yen */
  608.                     case 0x26:    /* bar */
  609.                     case 0x2f:    /* upperscore */
  610.                         n++;
  611.                         break;
  612.                     }
  613.                     break;
  614.                 case MBCS|'B':
  615.                     n++;
  616.                     break;
  617.                 }
  618.             }
  619.             break;
  620.         }
  621.     }
  622.     if (wstr) *wstr = 0;
  623.     return n;
  624. }
  625.  
  626. #ifdef KCLIENT
  627. /* EUC -> WS */
  628. convEUCtoWS(es, ws)
  629. unsigned char    *es;
  630. wchar_t        *ws;
  631. {
  632.     int    c;
  633.     int    n = 0;
  634.  
  635.     while (c = *es++) {
  636.         if (c == 0x8e) {    /* SS2 */
  637.             if (ws)
  638.                 *ws++ = *es | 0x80;
  639.             es++;
  640.             n++;
  641.         } else if (c == 0x8f) {    /* SS3 */
  642.             c = *es++;
  643.             if (es)
  644.                 *ws++ = (c << 8) | (*es & 0x7f) | 0x8000;
  645.             es++;
  646.             n++;
  647.         } else if (c & 0x80) {
  648.             if (ws)
  649.                 *ws++ = (c << 8) | *es | 0x8080;
  650.             es++;
  651.             n++;
  652.         } else {
  653.             if (ws)
  654.                 *ws++ = c;
  655.             n++;
  656.         }
  657.     }
  658.     if (ws)
  659.         *ws = 0;
  660.  
  661.     return n;
  662. }
  663. #endif    /* KCLIENT */
  664. #endif
  665.