Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtudcfonted / libfal / _fallcCT.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* lcCT.c 1.1 - Fujitsu source for CDEnext    95/11/06 20:32:33         */ 
24 /* $XConsortium: _fallcCT.c /main/1 1996/04/08 15:15:33 cde-fuj $ */
25 /*
26  * Copyright 1992, 1993 by TOSHIBA Corp.
27  *
28  * Permission to use, copy, modify, and distribute this software and its
29  * documentation for any purpose and without fee is hereby granted, provided
30  * that the above copyright notice appear in all copies and that both that
31  * copyright notice and this permission notice appear in supporting
32  * documentation, and that the name of TOSHIBA not be used in advertising
33  * or publicity pertaining to distribution of the software without specific,
34  * written prior permission. TOSHIBA make no representations about the
35  * suitability of this software for any purpose.  It is provided "as is"
36  * without express or implied warranty.
37  *
38  * TOSHIBA DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40  * TOSHIBA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44  * SOFTWARE.
45  *
46  * Author: Katsuhisa Yano       TOSHIBA Corp.
47  *                              mopi@osa.ilab.toshiba.co.jp
48  */
49
50 #include "_fallibint.h"
51 #include "_fallcPubI.h"
52 #include <X11/Xos.h>
53 #include <stdio.h>
54
55 typedef struct _StateRec {
56     XlcCharSet charset;
57     XlcCharSet GL_charset;
58     XlcCharSet GR_charset;
59     XlcCharSet ext_seg_charset;
60     int ext_seg_left;
61 } StateRec, *State;
62
63 typedef struct _CTDataRec {
64     char *name;
65     char *encoding;             /* Compound Text encoding */
66 } CTDataRec, *CTData;
67
68 typedef struct _CTInfoRec {
69     XlcCharSet charset;
70     int encoding_len;
71     char *encoding;             /* Compound Text encoding */
72     int ext_segment_len;
73     char *ext_segment;          /* extended segment */
74     struct _CTInfoRec *next;
75 } CTInfoRec, *CTInfo;
76
77 static CTDataRec default_ct_data[] =
78 {
79     { "ISO8859-1:GL", "\033(B" },
80     { "ISO8859-1:GR", "\033-A" },
81     { "ISO8859-2:GR", "\033-B" },
82     { "ISO8859-3:GR", "\033-C" },
83     { "ISO8859-4:GR", "\033-D" },
84     { "ISO8859-7:GR", "\033-F" },
85     { "ISO8859-6:GR", "\033-G" },
86     { "ISO8859-8:GR", "\033-H" },
87     { "ISO8859-5:GR", "\033-L" },
88     { "ISO8859-9:GR", "\033-M" },
89     { "JISX0201.1976-0:GL", "\033(J" },
90     { "JISX0201.1976-0:GR", "\033)I" },
91
92     { "GB2312.1980-0:GL", "\033$(A" },
93     { "GB2312.1980-0:GR", "\033$)A" },
94     { "JISX0208.1983-0:GL", "\033$(B" },
95     { "JISX0208.1983-0:GR", "\033$)B" },
96     { "KSC5601.1987-0:GL", "\033$(C" },
97     { "KSC5601.1987-0:GR", "\033$)C" },
98 #ifdef notdef
99     { "JISX0212.1990-0:GL", "\033$(D" },
100     { "JISX0212.1990-0:GR", "\033$)D" },
101     { "CNS11643.1986-1:GL", "\033$(G" },
102     { "CNS11643.1986-1:GR", "\033$)G" },
103     { "CNS11643.1986-2:GL", "\033$(H" },
104     { "CNS11643.1986-2:GR", "\033$)H" },
105
106     /* Non-Standard Character Set Encodings */
107     { "TIS620.2533-1:GR", "\033-T"},
108 #endif
109 } ; 
110
111 #define XctC0           0x0000
112 #define XctHT           0x0009
113 #define XctNL           0x000a
114 #define XctESC          0x001b
115 #define XctGL           0x0020
116 #define XctC1           0x0080
117 #define XctCSI          0x009b
118 #define XctGR           0x00a0
119
120 #define XctCntrlFunc    0x0023
121 #define XctMB           0x0024
122 #define XctOtherCoding  0x0025
123 #define XctGL94         0x0028
124 #define XctGR94         0x0029
125 #define XctGR96         0x002d
126 #define XctNonStandard  0x002f
127 #define XctIgnoreExt    0x0030
128 #define XctNotIgnoreExt 0x0031
129 #define XctLeftToRight  0x0031
130 #define XctRightToLeft  0x0032
131 #define XctDirection    0x005d
132 #define XctDirectionEnd 0x005d
133
134 #define XctGL94MB       0x2428
135 #define XctGR94MB       0x2429
136 #define XctExtSeg       0x252f
137 #define XctOtherSeg     0x2f00
138
139 #define XctESCSeq       0x1b00
140 #define XctCSISeq       0x9b00
141
142 #define SKIP_I(str)     while (*(str) >= 0x20 && *(str) <=  0x2f) (str)++;
143 #define SKIP_P(str)     while (*(str) >= 0x30 && *(str) <=  0x3f) (str)++;
144
145 typedef struct {
146     XlcSide side;
147     int char_size;
148     int set_size;
149     int ext_seg_length;
150     int version;
151     CTInfo ct_info;
152 } CTParseRec, *CTParse;
153
154 static CTInfo ct_list = NULL;
155
156 static CTInfo
157 _XlcGetCTInfoFromEncoding(encoding, length)
158     register char *encoding;
159     register int length;
160 {
161     register CTInfo ct_info;
162
163     for (ct_info = ct_list; ct_info; ct_info = ct_info->next) {
164         if (length >= ct_info->encoding_len) {
165             if (ct_info->ext_segment) {
166                 if (!strncmp(ct_info->encoding, encoding, 4) &&
167                     !strncmp(ct_info->ext_segment, encoding + 6,
168                              ct_info->ext_segment_len))
169                     return ct_info;
170             } else if (!strncmp(ct_info->encoding, encoding,
171                                 ct_info->encoding_len)) {
172                 return ct_info;
173             }
174         }
175     }
176
177     return (CTInfo) NULL;
178 }
179
180 static unsigned int
181 _XlcParseCT(parse, text, length)
182     register CTParse parse;
183     char **text;
184     int *length;
185 {
186     unsigned int ret = 0;
187     unsigned char ch;
188     register unsigned char *str = (unsigned char *) *text;
189
190     bzero((char *) parse, sizeof(CTParseRec));
191
192     switch (ch = *str++) {
193         case XctESC:
194             if (*str == XctOtherCoding && *(str + 1) == XctNonStandard
195                 && *(str + 2) >= 0x30 && *(str + 2) <= 0x3f && *length >= 6) {
196
197                 /* non-standard encodings */
198                 parse->side = XlcGLGR;
199                 parse->set_size = 0;
200                 str += 2;
201                 if (*str <= 0x34) {
202                     parse->char_size = *str - 0x30;
203                     if (parse->char_size == 0) parse->char_size = 1;
204                     ret = XctExtSeg;
205                     parse->ct_info = _XlcGetCTInfoFromEncoding(*text, *length);
206                 } else
207                     ret = XctOtherSeg;
208                 str++;
209                 parse->ext_seg_length = (*str - 128) * 128 + *(str + 1) - 128;
210                 str += 2;
211
212                 goto done;
213             } else if (*str == XctCntrlFunc && *length >= 4 &&
214                        *(str + 1) >= 0x20 && *(str + 1) <= 0x2f &&
215                        (*(str + 2) == XctIgnoreExt ||
216                         *(str + 2) == XctNotIgnoreExt)) {
217                 
218                 /* ignore extension or not */
219                 str++;
220                 parse->version = *str++ - 0x20;
221                 ret = *str++;
222
223                 goto done;
224             }
225             
226             if (*str == XctMB) {        /* multiple-byte sets */
227                 parse->char_size = 2;
228                 str++;
229             } else
230                 parse->char_size = 1;
231         
232             switch (*str) {
233                 case XctGL94:
234                     parse->side = XlcGL;
235                     parse->set_size = 94;
236                     ret = (parse->char_size == 1) ? XctGL94 : XctGL94MB;
237                     break;
238                 case XctGR94:
239                     parse->side = XlcGR;
240                     parse->set_size = 94;
241                     ret = (parse->char_size == 1) ? XctGR94 : XctGR94MB;
242                     break;
243                 case XctGR96:
244                     if (parse->char_size == 1) {
245                         parse->side = XlcGR;
246                         parse->set_size = 96;
247                         ret = XctGR96;
248                     }
249                     break;
250             }
251             if (ret) {
252                 str++;
253                 if (*str >= 0x24 && *str <= 0x2f) {     /* non-standard */
254                     ret = 0;
255                     str++;
256                 }
257             }
258
259             SKIP_I(str)
260
261             if (ret && *str < 0x40)                     /* non-standard */
262                 ret = 0;
263
264             if (*str < 0x30 || *str > 0x7e || (char *) str - *text >= *length)
265                 break;
266             
267             if (ret == 0)
268                 ret = XctESCSeq;
269             else {
270                 if (parse->char_size == 2) {
271                     if (*str >= 0x70)
272                         parse->char_size = 4;
273                     else if (*str >= 0x60)
274                         parse->char_size = 3;
275                 }
276                 parse->ct_info = _XlcGetCTInfoFromEncoding(*text, *length);
277             }
278             str++;
279             goto done;
280         case XctCSI:
281             /* direction */
282             if (*str == XctLeftToRight && *(str + 1) == XctDirection) {
283                 ret = XctLeftToRight;
284                 str += 2;
285                 goto done;
286             } else if (*str == XctRightToLeft && *(str + 1) == XctDirection) {
287                 ret = XctRightToLeft;
288                 str += 2;
289                 goto done;
290             } else if (*str == XctDirectionEnd) {
291                 ret = XctDirectionEnd;
292                 str++;
293                 goto done;
294             }
295
296             SKIP_P(str)
297             SKIP_I(str)
298
299             if (*str < 0x40 && *str > 0x7e)
300                 break;
301
302             ret = XctCSISeq;
303             str++;
304             goto done;
305     }
306
307     if (ch & 0x80) {
308         if (ch < 0xa0)
309             ret = XctC1;
310         else
311             ret = XctGR;
312     } else {
313         if (ch == XctHT || ch == XctNL)
314             ret = ch;
315         else if (ch < 0x20)
316             ret = XctC0;
317         else
318             ret = XctGL;
319     }
320
321     return ret;
322
323 done:
324     *length -= (char *) str - *text;
325     *text = (char *) str;
326
327     return ret;
328 }
329
330 XlcCharSet
331 _fallcAddCT(name, encoding)
332     char *name;
333     char *encoding;
334 {
335     CTInfo ct_info;
336     XlcCharSet charset;
337     CTParseRec parse;
338     char *ct_ptr = encoding;
339     int length;
340     unsigned int type;
341
342     length = strlen(encoding);
343
344     switch (type = _XlcParseCT(&parse, &ct_ptr, &length)) {
345         case XctExtSeg:
346         case XctGL94:
347         case XctGL94MB:
348         case XctGR94:
349         case XctGR94MB:
350         case XctGR96:
351             if (parse.ct_info)          /* existed */
352                 return parse.ct_info->charset;
353             break;
354         default:
355             return (XlcCharSet) NULL;
356     }
357
358     charset = _fallcCreateDefaultCharSet(name, encoding);
359     if (charset == NULL)
360         return (XlcCharSet) NULL;
361     _fallcAddCharSet(charset);
362
363     ct_info = (CTInfo) Xmalloc(sizeof(CTInfoRec));
364     if (ct_info == NULL)
365         return (XlcCharSet) NULL;
366     
367     ct_info->charset = charset;
368     ct_info->encoding = charset->ct_sequence;
369     ct_info->encoding_len = strlen(ct_info->encoding);
370     if (type == XctExtSeg) {
371         ct_info->ext_segment = ct_info->encoding + 6;
372         ct_info->ext_segment_len = strlen(ct_info->ext_segment);
373     } else {
374         ct_info->ext_segment = NULL;
375         ct_info->ext_segment_len = 0;
376     }
377     ct_info->next = ct_list;
378     ct_list = ct_info;
379
380     return charset;
381 }
382
383 static CTInfo
384 _XlcGetCTInfoFromCharSet(charset)
385     register XlcCharSet charset;
386 {
387     register CTInfo ct_info;
388
389     for (ct_info = ct_list; ct_info; ct_info = ct_info->next)
390         if (ct_info->charset == charset)
391             return ct_info;
392
393     return (CTInfo) NULL;
394 }
395
396 Bool
397 _fallcParseCharSet(charset)
398     XlcCharSet charset;
399 {
400     CTParseRec parse;
401     char *ptr, buf[BUFSIZ];
402     unsigned int type;
403     int length;
404
405     if (charset->ct_sequence == NULL)
406         return False;
407
408     ptr = charset->ct_sequence;
409     length = strlen(ptr);
410
411     type = _XlcParseCT(&parse, &ptr, &length);
412         
413     if (charset->name) {
414         charset->xrm_name = falrmStringToQuark(charset->name);
415
416         strcpy(buf, charset->name);
417         if (ptr = strchr(buf, ':'))
418             *ptr = '\0';
419         charset->xrm_encoding_name = falrmStringToQuark(buf);
420         charset->encoding_name = falrmQuarkToString(charset->xrm_encoding_name);
421     } else {
422         charset->xrm_name = 0;
423         charset->encoding_name = NULL;
424         charset->xrm_encoding_name = 0;
425     }
426
427     charset->side = parse.side;
428     charset->char_size = parse.char_size;
429     charset->set_size = parse.set_size;
430
431     return True;
432 }
433
434 static void init_converter();
435
436 Bool
437 _fallcInitCTInfo()
438 {
439     register XlcCharSet charset;
440     register CTData ct_data;
441     register int num;
442
443     if (ct_list == NULL) {
444         num = sizeof(default_ct_data) / sizeof(CTDataRec);
445         for (ct_data = default_ct_data; num-- > 0; ct_data++) {
446             charset = _fallcAddCT(ct_data->name, ct_data->encoding);
447             if (charset == NULL)
448                 continue;
449         }
450         init_converter();
451     }
452
453     return True;
454 }
455
456
457 static int
458 _XlcCheckCTSequence(state, ctext, ctext_len)
459     State state;
460     char **ctext;
461     int *ctext_len;
462 {
463     XlcCharSet charset;
464     CTParseRec parse;
465     CTInfo ct_info;
466     int length;
467
468     _XlcParseCT(&parse, ctext, ctext_len);
469
470     ct_info = parse.ct_info;
471     if (parse.ext_seg_length > 0) {     /* XctExtSeg or XctOtherSeg */
472         if (ct_info) {
473             length = ct_info->ext_segment_len;
474             *ctext += length;
475             *ctext_len -= length;
476             state->ext_seg_left = parse.ext_seg_length - length;
477             state->ext_seg_charset = ct_info->charset;
478         } else {
479             state->ext_seg_left = parse.ext_seg_length;
480             state->ext_seg_charset = NULL;
481         }
482     } else if (ct_info) {
483         if (charset = ct_info->charset) {
484             if (charset->side == XlcGL)
485                 state->GL_charset = charset;
486             else if (charset->side == XlcGR)
487                 state->GR_charset = charset;
488         }
489     }
490
491     return 0;
492 }
493
494
495 static void
496 init_state(conv)
497     XlcConv conv;
498 {
499     State state = (State) conv->state;
500     static XlcCharSet GL_charset = NULL;
501     static XlcCharSet GR_charset = NULL;
502
503     if (GL_charset == NULL) {
504         GL_charset = _fallcGetCharSet("ISO8859-1:GL");
505         GR_charset = _fallcGetCharSet("ISO8859-1:GR");
506     }
507
508     state->GL_charset = state->charset = GL_charset;
509     state->GR_charset = GR_charset;
510     state->ext_seg_charset = NULL;
511     state->ext_seg_left = 0;
512 }
513
514 static int
515 cttocs(conv, from, from_left, to, to_left, args, num_args)
516     XlcConv conv;
517     XPointer *from;
518     int *from_left;
519     XPointer *to;
520     int *to_left;
521     XPointer *args;
522     int num_args;
523 {
524     register State state = (State) conv->state;
525     register unsigned char ch;
526     int length;
527     XlcCharSet charset = NULL;
528     char *ctptr, *bufptr;
529     int ctext_len, buf_len;
530
531     ctptr = *((char **) from);
532     bufptr = *((char **) to);
533     ctext_len = *from_left;
534     buf_len = *to_left;
535
536     while (ctext_len > 0 && buf_len > 0) {
537         if (state->ext_seg_left > 0) {
538             length = min(state->ext_seg_left, ctext_len);
539             length = min(length, buf_len);
540
541             ctext_len -= length;
542             state->ext_seg_left -= length;
543
544             if (state->ext_seg_charset) {
545                 charset = state->ext_seg_charset;
546                 buf_len -= length;
547                 if (charset->side == XlcGL) {
548                     while (length-- > 0)
549                         *bufptr++ = *ctptr++ & 0x7f;
550                 } else if (charset->side == XlcGR) {
551                     while (length-- > 0)
552                         *bufptr++ = *ctptr++ | 0x80;
553                 } else {
554                     while (length-- > 0)
555                         *bufptr++ = *ctptr++;
556                 }
557
558                 if (state->ext_seg_left < 1)
559                     state->ext_seg_charset = NULL;
560             }
561             break;
562         }
563         ch = *((unsigned char *) ctptr);
564         if (ch == 0x1b || ch == 0x9b) {
565             length = _XlcCheckCTSequence(state, &ctptr, &ctext_len);
566             if (length < 0)
567                 return -1;
568             if (state->ext_seg_left > 0 && charset)
569                 break;
570         } else {
571             if (charset) {
572                 if (charset != (ch & 0x80 ? state->GR_charset :
573                                 state->GL_charset))
574                     break;
575             } else
576                 charset = ch & 0x80 ? state->GR_charset : state->GL_charset;
577
578             if ((ch < 0x20 && ch != '\0' && ch != '\n' && ch != '\t') ||
579                     (ch >= 0x80 && ch < 0xa0))
580                 return -1;
581
582             *bufptr++ = *ctptr++;
583             ctext_len--;
584             buf_len--;
585         }
586     }
587
588     if (charset)
589         state->charset = charset;
590     if (num_args > 0)
591         *((XlcCharSet *) args[0]) = state->charset;
592
593     *from_left -= ctptr - *((char **) from);
594     *from = (XPointer) ctptr;
595
596     *to_left -= bufptr - *((char **) to);
597     *to = (XPointer) bufptr;
598
599     return 0;
600 }
601
602 static int
603 cstoct(conv, from, from_left, to, to_left, args, num_args)
604     XlcConv conv;
605     XPointer *from;
606     int *from_left;
607     XPointer *to;
608     int *to_left;
609     XPointer *args;
610     int num_args;
611 {
612     State state = (State) conv->state;
613     XlcSide side;
614     unsigned char min_ch, max_ch;
615     register unsigned char ch;
616     int length;
617     CTInfo ct_info;
618     XlcCharSet charset;
619     char *csptr, *ctptr;
620     int csstr_len, ct_len;
621
622     if (num_args < 1)
623         return -1;
624     
625     csptr = *((char **) from);
626     ctptr = *((char **) to);
627     csstr_len = *from_left;
628     ct_len = *to_left;
629     
630     charset = (XlcCharSet) args[0];
631
632     ct_info = _XlcGetCTInfoFromCharSet(charset);
633     if (ct_info == NULL)
634         return -1;
635
636     side = charset->side;
637
638     if (ct_info->ext_segment) {
639         if (charset != state->ext_seg_charset && state->ext_seg_left < 1) {
640             length = ct_info->encoding_len;
641             if (ct_len < length)
642                 return -1;
643             strcpy(ctptr, ct_info->encoding);
644             ctptr[4] = ((ct_info->ext_segment_len + csstr_len) / 128) | 0x80;
645             ctptr[5] = ((ct_info->ext_segment_len + csstr_len) % 128) | 0x80;
646             ctptr += length;
647             ct_len -= length;
648             state->ext_seg_left = csstr_len;
649         }
650         length = min(state->ext_seg_left, csstr_len);
651         state->ext_seg_left -= length;
652
653         if (side == XlcGL) {
654             while (length-- > 0)
655                 *ctptr++ = *csptr++ & 0x7f;
656         } else if (side == XlcGR) {
657             while (length-- > 0)
658                 *ctptr++ = *csptr++ | 0x80;
659         } else {
660             while (length-- > 0)
661                 *ctptr++ = *csptr++;
662         }
663         state->ext_seg_charset = (state->ext_seg_left > 0) ? charset : NULL;
664     } else {
665         if ((side == XlcGR && charset != state->GR_charset) ||
666             (side == XlcGL && charset != state->GL_charset)) {
667
668             ct_len -= ct_info->encoding_len;
669             if (ct_len < 0)
670                 return -1;
671             strcpy(ctptr, ct_info->encoding);
672             ctptr += ct_info->encoding_len;
673         }
674
675         min_ch = 0x20;
676         max_ch = 0x7f;
677
678         if (charset->set_size == 94) {
679             max_ch--;
680             if (charset->char_size > 1 || side == XlcGR)
681                 min_ch++;
682         }
683
684         while (csstr_len > 0 && ct_len > 0) {
685             ch = *((unsigned char *) csptr++) & 0x7f;
686             if (ch < min_ch || ch > max_ch)
687                 if (ch != 0x00 && ch != 0x09 && ch != 0x0a && ch != 0x1b)
688                     continue;   /* XXX */
689             if (side == XlcGL)
690                 *ctptr++ = ch & 0x7f;
691             else if (side == XlcGR)
692                 *ctptr++ = ch | 0x80;
693             else
694                 *ctptr++ = ch;
695             csstr_len--;
696             ct_len--;
697         }
698         if (side == XlcGR)
699             state->GR_charset = charset;
700         else if (side == XlcGL)
701             state->GL_charset = charset;
702     }
703
704     *from_left -= csptr - *((char **) from);
705     *from = (XPointer) csptr;
706
707     *to_left -= ctptr - *((char **) to);
708     *to = (XPointer) ctptr;
709
710     return 0;
711 }
712
713 static int
714 strtocs(conv, from, from_left, to, to_left, args, num_args)
715     XlcConv conv;
716     XPointer *from;
717     int *from_left;
718     XPointer *to;
719     int *to_left;
720     XPointer *args;
721     int num_args;
722 {
723     State state = (State) conv->state;
724     register char *src, *dst;
725     unsigned char side;
726     register length;
727
728     src = (char *) *from;
729     dst = (char *) *to;
730
731     length = min(*from_left, *to_left);
732     side = *((unsigned char *) src) & 0x80;
733
734     while (side == (*((unsigned char *) src) & 0x80) && length-- > 0)
735         *dst++ = *src++;
736     
737     *from_left -= src - (char *) *from;
738     *from = (XPointer) src;
739     *to_left -= dst - (char *) *to;
740     *to = (XPointer) dst;
741
742     if (num_args > 0)
743         *((XlcCharSet *)args[0]) = side ? state->GR_charset : state->GL_charset;
744
745     return 0;
746 }
747
748 static int
749 cstostr(conv, from, from_left, to, to_left, args, num_args)
750     XlcConv conv;
751     XPointer *from;
752     int *from_left;
753     XPointer *to;
754     int *to_left;
755     XPointer *args;
756     int num_args;
757 {
758     State state = (State) conv->state;
759     char *csptr, *string_ptr;
760     int csstr_len, str_len;
761     unsigned char ch;
762     int unconv_num = 0;
763
764     if (num_args < 1 || (state->GL_charset != (XlcCharSet) args[0] &&
765         state->GR_charset != (XlcCharSet) args[0]))
766         return -1;
767     
768     csptr = *((char **) from);
769     string_ptr = *((char **) to);
770     csstr_len = *from_left;
771     str_len = *to_left;
772
773     while (csstr_len-- > 0 && str_len > 0) {
774         ch = *((unsigned char *) csptr++);
775         if ((ch < 0x20 && ch != 0x00 && ch != 0x09 && ch != 0x0a) ||
776             ch == 0x7f || ((ch & 0x80) && ch < 0xa0)) {
777             unconv_num++;
778             continue;
779         }
780         *((unsigned char *) string_ptr++) = ch;
781         str_len--;
782     }
783
784     *from_left -= csptr - *((char **) from);
785     *from = (XPointer) csptr;
786
787     *to_left -= string_ptr - *((char **) to);
788     *to = (XPointer) string_ptr;
789
790     return unconv_num;
791 }
792
793
794 static void
795 close_converter(conv)
796     XlcConv conv;
797 {
798     if (conv->state)
799         Xfree((char *) conv->state);
800
801     Xfree((char *) conv);
802 }
803
804 static XlcConv
805 create_conv(methods)
806     XlcConvMethods methods;
807 {
808     register XlcConv conv;
809
810     conv = (XlcConv) Xmalloc(sizeof(XlcConvRec));
811     if (conv == NULL)
812         return (XlcConv) NULL;
813
814     conv->state = (XPointer) Xmalloc(sizeof(StateRec));
815     if (conv->state == NULL)
816         goto err;
817     
818     conv->methods = methods;
819
820     init_state(conv);
821
822     return conv;
823
824 err:
825     close_converter(conv);
826
827     return (XlcConv) NULL;
828 }
829
830 static XlcConvMethodsRec cttocs_methods = {
831     close_converter,
832     cttocs,
833     init_state
834 } ;
835
836 static XlcConv
837 open_cttocs(from_lcd, from_type, to_lcd, to_type)
838     XLCd from_lcd;
839     char *from_type;
840     XLCd to_lcd;
841     char *to_type;
842 {
843     return create_conv(&cttocs_methods);
844 }
845
846 static XlcConvMethodsRec cstoct_methods = {
847     close_converter,
848     cstoct,
849     init_state
850 } ;
851
852 static XlcConv
853 open_cstoct(from_lcd, from_type, to_lcd, to_type)
854     XLCd from_lcd;
855     char *from_type;
856     XLCd to_lcd;
857     char *to_type;
858 {
859     return create_conv(&cstoct_methods);
860 }
861
862 static XlcConvMethodsRec strtocs_methods = {
863     close_converter,
864     strtocs,
865     init_state
866 } ;
867
868 static XlcConv
869 open_strtocs(from_lcd, from_type, to_lcd, to_type)
870     XLCd from_lcd;
871     char *from_type;
872     XLCd to_lcd;
873     char *to_type;
874 {
875     return create_conv(&strtocs_methods);
876 }
877
878 static XlcConvMethodsRec cstostr_methods = {
879     close_converter,
880     cstostr,
881     init_state
882 } ;
883
884 static XlcConv
885 open_cstostr(from_lcd, from_type, to_lcd, to_type)
886     XLCd from_lcd;
887     char *from_type;
888     XLCd to_lcd;
889     char *to_type;
890 {
891     return create_conv(&cstostr_methods);
892 }
893
894 static void
895 init_converter()
896 {
897     _fallcSetConverter((XLCd) NULL, XlcNCompoundText, (XLCd) NULL, XlcNCharSet,
898                      open_cttocs);
899     _fallcSetConverter((XLCd) NULL, XlcNString, (XLCd) NULL, XlcNCharSet,
900                      open_strtocs);
901
902     _fallcSetConverter((XLCd) NULL, XlcNCharSet, (XLCd) NULL, XlcNCompoundText,
903                      open_cstoct);
904     _fallcSetConverter((XLCd) NULL, XlcNCharSet, (XLCd) NULL, XlcNString,
905                      open_cstostr);
906 }