/* $XConsortium: ResEncod.c /main/8 1996/11/12 05:37:04 pascale $ */ /* * @OPENGROUP_COPYRIGHT@ * COPYRIGHT NOTICE * Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc. * Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group * ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for * the full copyright text. * * This software is subject to an open license. It may only be * used on, with or for operating systems which are themselves open * source systems. You must contact The Open Group for a license * allowing distribution and sublicensing of this software on, with, * or for operating systems which are not Open Source programs. * * See http://www.opengroup.org/openmotif/license for full * details of the license agreement. Any use, reproduction, or * distribution of the program constitutes recipient's acceptance of * this agreement. * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS * PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY * WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY * OR FITNESS FOR A PARTICULAR PURPOSE * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT * NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE * EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * */ /* * HISTORY */ #include #ifndef X_NOT_STDC_ENV #include #endif #include #include #include #include "MessagesI.h" #include "ResEncodI.h" #include "XmI.h" #include "XmosI.h" #include "XmStringI.h" #include "ResConverI.h" #define MSG8 _XmMMsgResConvert_0007 #define MSG9 _XmMMsgResConvert_0008 #define MSG10 _XmMMsgResConvert_0009 #define MSG11 _XmMMsgResConvert_0010 #define MSG13 _XmMMsgResConvert_0012 #define MSG14 _XmMMsgResConvert_0013 typedef unsigned char Octet; typedef Octet *OctetPtr; typedef XmConst Octet *const_OctetPtr; typedef enum { ct_Dir_StackEmpty, ct_Dir_Undefined, ct_Dir_LeftToRight, ct_Dir_RightToLeft } ct_Direction; /* ** ct_Charset is used in the xmstring_to_text conversion to keep track ** of the prevous character set. The order is not important. */ typedef enum { cs_none, cs_Hanzi, cs_JapaneseGCS, cs_Katakana, cs_KoreanGCS, cs_Latin1, cs_Latin2, cs_Latin3, cs_Latin4, cs_Latin5, cs_LatinArabic, cs_LatinCyrillic, cs_LatinGreek, cs_LatinHebrew, cs_NonStandard } ct_Charset; /* Internal context block */ typedef struct _ct_context { OctetPtr octet; /* octet ptr into compound text stream */ OctetPtr lastoctet; /* ptr to last octet in stream */ struct { /* flags */ unsigned dircs : 1; /* direction control seq encountered */ unsigned gchar : 1; /* graphic characters encountered */ unsigned ignext : 1; /* ignore extensions */ unsigned gl : 1; /* text is for gl */ unsigned text : 1; /* current item is a text seq */ } flags; ct_Direction *dirstack; /* direction stack pointer */ unsigned int dirsp; /* current dir stack index */ unsigned int dirstacksize; /* size of direction stack */ OctetPtr encoding; /* ptr to current encoding sequence */ unsigned int encodinglen; /* length of encoding sequence */ OctetPtr item; /* ptr to current item */ unsigned int itemlen; /* length of current item */ unsigned int version; /* version of compound text */ XmConst char* gl_charset; /* ptr to GL character set */ unsigned char gl_charset_size; /* # of chars in GL charset */ unsigned char gl_octets_per_char; /* # of octets per GL char */ XmConst char* gr_charset; /* ptr to GR character set */ unsigned char gr_charset_size; /* # of chars in GR charset */ unsigned char gr_octets_per_char; /* # of octets per GR char */ XmString xmstring; /* compound string to be returned */ XmString xmsep; /* compound string separator segment */ XmString xmtab; /* compound string tab segment */ } ct_context; /* * Segment Encoding Registry datatype and macros */ typedef struct _EncodingRegistry { char *fontlist_tag; char *ct_encoding; struct _EncodingRegistry *next; } SegmentEncoding; #define EncodingRegistryTag(er) ((SegmentEncoding *)(er))->fontlist_tag #define EncodingRegistryEncoding(er) ((SegmentEncoding *)(er))->ct_encoding #define EncodingRegistryNext(er) ((SegmentEncoding *)(er))->next /* ** Define standard character set strings */ static XmConst char CS_ISO8859_1[] = "ISO8859-1" ; static XmConst char CS_ISO8859_2[] = "ISO8859-2" ; static XmConst char CS_ISO8859_3[] = "ISO8859-3" ; static XmConst char CS_ISO8859_4[] = "ISO8859-4" ; static XmConst char CS_ISO8859_5[] = "ISO8859-5" ; static XmConst char CS_ISO8859_6[] = "ISO8859-6" ; static XmConst char CS_ISO8859_7[] = "ISO8859-7" ; static XmConst char CS_ISO8859_8[] = "ISO8859-8" ; static XmConst char CS_ISO8859_9[] = "ISO8859-9" ; static XmConst char CS_JISX0201[] = "JISX0201.1976-0" ; static XmConst char CS_GB2312_0[] = "GB2312.1980-0" ; static XmConst char CS_GB2312_1[] = "GB2312.1980-1" ; static XmConst char CS_JISX0208_0[] = "JISX0208.1983-0" ; static XmConst char CS_JISX0208_1[] = "JISX0208.1983-1" ; static XmConst char CS_KSC5601_0[] = "KSC5601.1987-0" ; static XmConst char CS_KSC5601_1[] = "KSC5601.1987-1" ; /* Define handy macros (note: these constants are in OCTAL) */ #define EOS 00 #define STX 02 #define HT 011 #define NL 012 #define ESC 033 #define CSI 0233 static XmConst Octet NEWLINESTRING[] = "\012"; #define NEWLINESTRING_LEN sizeof(NEWLINESTRING)-1 static XmConst Octet TABSTRING[] = "\011"; #define TABSTRING_LEN sizeof(TABSTRING)-1 static XmConst Octet CTEXT_L_TO_R[] = "\233\061\135"; #define CTEXT_L_TO_R_LEN sizeof(CTEXT_L_TO_R)-1 static XmConst Octet CTEXT_R_TO_L[] = "\233\062\135"; #define CTEXT_R_TO_L_LEN sizeof(CTEXT_R_TO_L)-1 static XmConst Octet CTEXT_SET_ISO8859_1[] = "\033\050\102\033\055\101"; #define CTEXT_SET_ISO8859_1_LEN sizeof(CTEXT_SET_ISO8859_1)-1 static XmConst Octet CTEXT_SET_ISO8859_2[] = "\033\050\102\033\055\102"; #define CTEXT_SET_ISO8859_2_LEN sizeof(CTEXT_SET_ISO8859_2)-1 static XmConst Octet CTEXT_SET_ISO8859_3[] = "\033\050\102\033\055\103"; #define CTEXT_SET_ISO8859_3_LEN sizeof(CTEXT_SET_ISO8859_3)-1 static XmConst Octet CTEXT_SET_ISO8859_4[] = "\033\050\102\033\055\104"; #define CTEXT_SET_ISO8859_4_LEN sizeof(CTEXT_SET_ISO8859_4)-1 static XmConst Octet CTEXT_SET_ISO8859_5[] = "\033\050\102\033\055\114"; #define CTEXT_SET_ISO8859_5_LEN sizeof(CTEXT_SET_ISO8859_5)-1 static XmConst Octet CTEXT_SET_ISO8859_6[] = "\033\050\102\033\055\107"; #define CTEXT_SET_ISO8859_6_LEN sizeof(CTEXT_SET_ISO8859_6)-1 static XmConst Octet CTEXT_SET_ISO8859_7[] = "\033\050\102\033\055\106"; #define CTEXT_SET_ISO8859_7_LEN sizeof(CTEXT_SET_ISO8859_7)-1 static XmConst Octet CTEXT_SET_ISO8859_8[] = "\033\050\102\033\055\110"; #define CTEXT_SET_ISO8859_8_LEN sizeof(CTEXT_SET_ISO8859_8)-1 static XmConst Octet CTEXT_SET_ISO8859_9[] = "\033\050\102\033\055\115"; #define CTEXT_SET_ISO8859_9_LEN sizeof(CTEXT_SET_ISO8859_9)-1 static XmConst Octet CTEXT_SET_JISX0201[] = "\033\050\112\033\051\111"; #define CTEXT_SET_JISX0201_LEN sizeof(CTEXT_SET_JISX0201)-1 static XmConst Octet CTEXT_SET_GB2312_0[] = "\033\044\050\101\033\044\051\101"; #define CTEXT_SET_GB2312_0_LEN sizeof(CTEXT_SET_GB2312_0)-1 static XmConst Octet CTEXT_SET_JISX0208_0[] = "\033\044\050\102\033\044\051\102"; #define CTEXT_SET_JISX0208_0_LEN sizeof(CTEXT_SET_JISX0208_0)-1 static XmConst Octet CTEXT_SET_KSC5601_0[] = "\033\044\050\103\033\044\051\103"; #define CTEXT_SET_KSC5601_0_LEN sizeof(CTEXT_SET_KSC5601_0)-1 #define CTVERSION 1 #define _IsValidC0(ctx, c) (((c) == HT) || ((c) == NL) || ((ctx)->version > CTVERSION)) #define _IsValidC1(ctx, c) ((ctx)->version > CTVERSION) #define _IsValidESCFinal(c) (((c) >= 0x30) && ((c) <= 0x7e)) #define _IsValidCSIFinal(c) (((c) >= 0x40) && ((c) <= 0x7e)) #define _IsInC0Set(c) ((c) <= 0x1f) #define _IsInC1Set(c) (((c) >= 0x80) && ((c) <= 0x9f)) #define _IsInGLSet(c) (((c) >= 0x20) && ((c) <= 0x7f)) #define _IsInGRSet(c) ((c) >= 0xa0) #define _IsInColumn2(c) (((c) >= 0x20) && ((c) <= 0x2f)) #define _IsInColumn3(c) (((c) >= 0x30) && ((c) <= 0x3f)) #define _IsInColumn4(c) (((c) >= 0x40) && ((c) <= 0x4f)) #define _IsInColumn5(c) (((c) >= 0x50) && ((c) <= 0x5f)) #define _IsInColumn6(c) (((c) >= 0x60) && ((c) <= 0x6f)) #define _IsInColumn7(c) (((c) >= 0x70) && ((c) <= 0x7f)) #define _IsInColumn4or5(c) (((c) >= 0x40) && ((c) <= 0x5f)) #define _SetGL(ctx, charset, size, octets)\ (ctx)->flags.gl = True;\ (ctx)->gl_charset = (charset);\ (ctx)->gl_charset_size = (size);\ (ctx)->gl_octets_per_char = (octets) #define _SetGR(ctx, charset, size, octets)\ (ctx)->flags.gl = False;\ (ctx)->gr_charset = (charset);\ (ctx)->gr_charset_size = (size);\ (ctx)->gr_octets_per_char = (octets) #define _PushDir(ctx, dir)\ if ( (ctx)->dirsp == ((ctx)->dirstacksize - 1) ) {\ (ctx)->dirstacksize += 8;\ (ctx)->dirstack = \ (ct_Direction *)XtRealloc((char *)(ctx)->dirstack,\ (ctx)->dirstacksize * sizeof(ct_Direction));\ }\ (ctx)->dirstack[++((ctx)->dirsp)] = dir;\ (ctx)->flags.dircs = True #define _PopDir(ctx) ((ctx)->dirsp)-- #define _CurDir(ctx) (ctx)->dirstack[(ctx)->dirsp] /* this should probably be the other way around, (XmFONTLIST_DEFAULT_TAG map to _MOTIF_DEFAULT_LOCALE) but this is the smallest code change, and the code will not work any differently */ /* Define the MIT registered charset */ static SegmentEncoding _mit_KSC5601_1987_1_registry = { "KSC5601.1987-1", "KSC5601.1987-1", NULL}; static SegmentEncoding _mit_KSC5601_1987_0_registry = { "KSC5601.1987-0", "KSC5601.1987-0", &_mit_KSC5601_1987_1_registry}; static SegmentEncoding _mit_JISX0208_1983_1_registry = { "JISX0208.1983-1", "JISX0208.1983-1", &_mit_KSC5601_1987_0_registry}; static SegmentEncoding _mit_JISX0208_1983_0_registry = { "JISX0208.1983-0", "JISX0208.1983-0", &_mit_JISX0208_1983_1_registry}; static SegmentEncoding _mit_GB2312_1980_1_registry = { "GB2312.1980-1", "GB2312.1980-1", &_mit_JISX0208_1983_0_registry}; static SegmentEncoding _mit_GB2312_1980_0_registry = { "GB2312.1980-0", "GB2312.1980-0", &_mit_GB2312_1980_1_registry}; static SegmentEncoding _mit_JISX0201_1976_0_registry = { "JISX0201.1976-0", "JISX0201.1976-0", &_mit_GB2312_1980_0_registry}; static SegmentEncoding _mit_ISO8859_9_registry = { "ISO8859-9", "ISO8859-9", &_mit_JISX0201_1976_0_registry}; static SegmentEncoding _mit_ISO8859_8_registry = { "ISO8859-8", "ISO8859-8", &_mit_ISO8859_9_registry}; static SegmentEncoding _mit_ISO8859_7_registry = { "ISO8859-7", "ISO8859-7", &_mit_ISO8859_8_registry}; static SegmentEncoding _mit_ISO8859_6_registry = { "ISO8859-6", "ISO8859-6", &_mit_ISO8859_7_registry}; static SegmentEncoding _mit_ISO8859_5_registry = { "ISO8859-5", "ISO8859-5", &_mit_ISO8859_6_registry}; static SegmentEncoding _mit_ISO8859_4_registry = { "ISO8859-4", "ISO8859-4", &_mit_ISO8859_5_registry}; static SegmentEncoding _mit_ISO8859_3_registry = { "ISO8859-3", "ISO8859-3", &_mit_ISO8859_4_registry}; static SegmentEncoding _mit_ISO8859_2_registry = { "ISO8859-2", "ISO8859-2", &_mit_ISO8859_3_registry}; static SegmentEncoding _mit_ISO8859_1_registry = { "ISO8859-1", "ISO8859-1", &_mit_ISO8859_2_registry}; static SegmentEncoding _loc_encoding_registry = { _MOTIF_DEFAULT_LOCALE, XmFONTLIST_DEFAULT_TAG, &_mit_ISO8859_1_registry}; static SegmentEncoding _encoding_registry = { XmFONTLIST_DEFAULT_TAG, XmFONTLIST_DEFAULT_TAG, &_loc_encoding_registry}; static SegmentEncoding *_encoding_registry_ptr = &_encoding_registry; /******** Static Function Declarations ********/ static SegmentEncoding * FindEncoding( char *fontlist_tag) ; static Boolean processCharsetAndText(XmStringCharSet tag, OctetPtr ctext, #if NeedWidePrototypes int separator, #else Boolean separator, #endif /* NeedWidePrototypes */ OctetPtr *outc, unsigned int *outlen, ct_Charset *prev); static Boolean processESCHack( ct_context *ctx, #if NeedWidePrototypes int final) ; #else Octet final) ; #endif /* NeedWidePrototypes */ static Boolean processExtendedSegmentsHack( ct_context *ctx, #if NeedWidePrototypes int final) ; #else Octet final) ; #endif /* NeedWidePrototypes */ static Boolean cvtTextToXmString( XrmValue *from, XrmValue *to) ; static void outputXmString( ct_context *ctx, #if NeedWidePrototypes int separator) ; #else Boolean separator) ; #endif /* NeedWidePrototypes */ static XmString concatStringToXmString( XmString compoundstring, char *textstring, int textlen, char *charset, #if NeedWidePrototypes int direction, int separator) ; #else XmStringDirection direction, Boolean separator) ; #endif /* NeedWidePrototypes */ static Boolean processESC( ct_context *ctx, #if NeedWidePrototypes int final) ; #else Octet final) ; #endif /* NeedWidePrototypes */ static Boolean processCSI( ct_context *ctx, #if NeedWidePrototypes int final) ; #else Octet final) ; #endif /* NeedWidePrototypes */ static Boolean processExtendedSegments( ct_context *ctx, #if NeedWidePrototypes int final) ; #else Octet final) ; #endif /* NeedWidePrototypes */ static Boolean process94n( ct_context *ctx, #if NeedWidePrototypes int final) ; #else Octet final) ; #endif /* NeedWidePrototypes */ static Boolean process94GL( ct_context *ctx, #if NeedWidePrototypes int final) ; #else Octet final) ; #endif /* NeedWidePrototypes */ static Boolean process94GR( ct_context *ctx, #if NeedWidePrototypes int final) ; #else Octet final) ; #endif /* NeedWidePrototypes */ static Boolean process96GR( ct_context *ctx, #if NeedWidePrototypes int final) ; #else Octet final) ; #endif /* NeedWidePrototypes */ static Boolean cvtXmStringToText( XrmValue *from, XrmValue *to) ; static OctetPtr ctextConcat( OctetPtr str1, unsigned int str1len, const_OctetPtr str2, unsigned int str2len) ; /******** End Static Function Declarations ********/ /************************************************************************ * * FindEncoding * Find the SegmentEncoding with fontlist_tag. Return NULL if no * such SegmentEncoding exists. As a side effect, free any encodings * encountered that have been unregistered. * ************************************************************************/ static SegmentEncoding * FindEncoding(char *fontlist_tag) { SegmentEncoding *prevPtr, *encodingPtr = _encoding_registry_ptr; String encoding = NULL; if (encodingPtr) { if (strcmp(fontlist_tag, EncodingRegistryTag(encodingPtr)) == 0) { encoding = EncodingRegistryEncoding(encodingPtr); /* Free unregistered encodings. */ if (encoding == NULL) { _encoding_registry_ptr = EncodingRegistryNext(encodingPtr); XtFree( (char *) encodingPtr); encodingPtr = NULL; } return(encodingPtr); } } else return(encodingPtr); for (prevPtr = encodingPtr, encodingPtr = EncodingRegistryNext(encodingPtr); encodingPtr != NULL; prevPtr = encodingPtr, encodingPtr = EncodingRegistryNext(encodingPtr)) { if (strcmp(fontlist_tag, EncodingRegistryTag(encodingPtr)) == 0) { encoding = EncodingRegistryEncoding(encodingPtr); /* Free unregistered encodings. */ if (encoding == NULL) { EncodingRegistryNext(prevPtr) = EncodingRegistryNext(encodingPtr); XtFree( (char *) encodingPtr); encodingPtr = NULL; } return(encodingPtr); } /* Free unregistered encodings. */ else if (EncodingRegistryEncoding(encodingPtr) == NULL) { EncodingRegistryNext(prevPtr) = EncodingRegistryNext(encodingPtr); XtFree( (char *) encodingPtr); } } return(NULL); } /************************************************************************ * * XmRegisterSegmentEncoding * Register a compound text encoding format for a specified font list * element tag. Returns NULL for a new tag or a copy of the old encoding * for an already registered tag. * ************************************************************************/ char * XmRegisterSegmentEncoding( char *fontlist_tag, char *ct_encoding) { SegmentEncoding *encodingPtr = NULL; String ret_val = NULL; _XmProcessLock(); encodingPtr = FindEncoding(fontlist_tag); if (encodingPtr) { ret_val = XtNewString(EncodingRegistryEncoding(encodingPtr)); EncodingRegistryEncoding(encodingPtr) = ct_encoding ? XtNewString(ct_encoding) : (String)NULL; } else if (ct_encoding != NULL) { encodingPtr = (SegmentEncoding *)XtMalloc((Cardinal)sizeof(SegmentEncoding)); EncodingRegistryTag(encodingPtr) = XtNewString(fontlist_tag); EncodingRegistryEncoding(encodingPtr) = XtNewString(ct_encoding); EncodingRegistryNext(encodingPtr) = _encoding_registry_ptr; _encoding_registry_ptr = encodingPtr; } _XmProcessUnlock(); return(ret_val); } /************************************************************************ * * _XmGetEncodingRegistryTarget returns the current encoding registry * as a list of NULL separated items. The length is returned through * the passed length pointer. * ************************************************************************/ XtPointer _XmGetEncodingRegistryTarget(int *length) { int i, count, total_size; SegmentEncoding *current; char *rval; total_size = 0; _XmProcessLock(); current = _encoding_registry_ptr; while(current != NULL) { total_size += strlen(EncodingRegistryTag(current)) + strlen(EncodingRegistryEncoding(current)) + 2; current = EncodingRegistryNext(current); } *length = total_size; /* Create output buffer large enough for all the pairs of tags and encodings */ rval = XtMalloc(sizeof(char) * total_size); i = 0; current = _encoding_registry_ptr; while(current != NULL) { count = strlen(EncodingRegistryTag(current)); strcpy(&rval[i], EncodingRegistryTag(current)); i += count; rval[i] = 0; i++; count = strlen(EncodingRegistryEncoding(current)); strcpy(&rval[i], EncodingRegistryEncoding(current)); i += count; rval[i] = 0; i++; current = EncodingRegistryNext(current); } _XmProcessUnlock(); return((XtPointer) rval); } /************************************************************************ * * XmMapSegmentEncoding * Returns the compound text encoding format associated with the * specified font list element tag. Returns NULL if not found. * ************************************************************************/ char * XmMapSegmentEncoding(char *fontlist_tag) { SegmentEncoding *encodingPtr = NULL; String ret_val = NULL; _XmProcessLock(); encodingPtr = FindEncoding(fontlist_tag); if (encodingPtr) ret_val = XtNewString(EncodingRegistryEncoding(encodingPtr)); _XmProcessUnlock(); return(ret_val); } /************************************************************************ * * XmCvtCTToXmString * Convert a compound text string to a XmString. This is the public * version which takes only a compound text string as an argument. * Note: processESC and processExtendedSegments have to be hacked * for this to work. * ************************************************************************/ XmString XmCvtCTToXmString( char *text ) { ct_context *ctx; /* compound text context block */ Boolean ok = True; Octet c; XmString xmsReturned; /* returned Xm string */ ctx = (ct_context *) XtMalloc(sizeof(ct_context)); /* initialize the context block */ ctx->octet = (OctetPtr)text; ctx->flags.dircs = False; ctx->flags.gchar = False; ctx->flags.ignext = False; ctx->flags.gl = False; ctx->flags.text = False; ctx->dirstacksize = 8; ctx->dirstack = (ct_Direction *) XtMalloc(ctx->dirstacksize*sizeof(ct_Direction)); /* * Define XLIB_HANDLES_DIRECTION if vendor's X library knows how * to deal with direction control sequences in CT. Otherwise * no such ones will be output if there are no Rtol segments * in the XmString. Note that the MIT sample implementation * does not deal with direction control sequences... */ #ifdef XLIB_HANDLES_DIRECTION ctx->dirstack[0] = ct_Dir_StackEmpty; ctx->dirsp = 0; #else ctx->dirstack[0] = ct_Dir_StackEmpty; ctx->dirstack[1] = ct_Dir_LeftToRight; ctx->dirsp = 1; #endif ctx->encoding = NULL; ctx->encodinglen = 0; ctx->item = NULL; ctx->itemlen = 0; ctx->version = CTVERSION; ctx->gl_charset = CS_ISO8859_1; ctx->gl_charset_size = 94; ctx->gl_octets_per_char = 1; ctx->gr_charset = CS_ISO8859_1; ctx->gr_charset_size = 96; ctx->gr_octets_per_char = 1; ctx->xmstring = NULL; ctx->xmsep = NULL; ctx->xmtab = NULL; /* ** check for version/ignore extensions sequence (must be first if present) ** Format is: ESC 02/03 V 03/00 ignoring extensions is OK ** ESC 02/03 V 03/01 ignoring extensions is not OK ** where V is in the range 02/00 thru 02/15 and represents versions 1 thru 16 */ if ( (ctx->octet[0] == ESC) && (ctx->octet[1] == 0x23) && (_IsInColumn2(ctx->octet[2]) && ((ctx->octet[3] == 0x30) || ctx->octet[3] == 0x31)) ) { ctx->version = ctx->octet[2] - 0x1f; /* 0x20-0x2f => version 1-16 */ if (ctx->octet[3] == 0x30) /* 0x30 == can ignore extensions */ ctx->flags.ignext = True; ctx->octet += 4; /* advance ptr to next seq */ } while (ctx->octet[0] != 0) { switch (*ctx->octet) { /* look at next octet in seq */ case ESC: /* %%% TEMP ** if we have any text to output, do it ** this section needs to be optimized so that it handles ** paired character sets without outputting a new segment. */ if (ctx->flags.text) { outputXmString(ctx, False); /* with no separator */ } ctx->flags.text = False; ctx->item = ctx->octet; /* remember start of this item */ ctx->itemlen = 0; ctx->octet++; ctx->itemlen++; /* advance ptr to next char */ /* scan for final char */ while ( (ctx->octet[0] != 0) && (_IsInColumn2(*ctx->octet)) ) { ctx->octet++; ctx->itemlen++; /* advance ptr to next char */ } if (ctx->octet[0] == 0) { /* if nothing after this, it's an error */ ok = False; break; } c = *ctx->octet; /* get next char in seq */ ctx->octet++; ctx->itemlen++; /* advance ptr to next char */ if (_IsValidESCFinal(c)) { /* we have a valid ESC sequence - handle it */ ok = processESCHack(ctx, c); } else { ok = False; } if (ok) { ctx->encoding = ctx->item; ctx->encodinglen = ctx->itemlen; } break; case CSI: /* ** CSI format is: CSI P I F where ** 03/00 <= P <= 03/15 ** 02/00 <= I <= 02/15 ** 04/00 <= F <= 07/14 */ /* %%% TEMP ** if we have any text to output, do it ** This may need optimization. */ if (ctx->flags.text) { /* check whether we have a specific direction set */ if (((ctx->octet[1] == 0x31) && (ctx->octet[2] == 0x5d))|| ((ctx->octet[1] == 0x32) && (ctx->octet[2] == 0x5d))|| (ctx->octet[1] == 0x5d)) outputXmString(ctx, False); /* without a separator*/ else outputXmString(ctx, True); /* with a separator */ } ctx->flags.text = False; ctx->item = ctx->octet; /* remember start of this item */ ctx->itemlen = 0; ctx->octet++; ctx->itemlen++; /* advance ptr to next char */ /* scan for final char */ while ( (ctx->octet[0] != 0) && _IsInColumn3(*ctx->octet) ) { ctx->octet++; ctx->itemlen++; /* advance ptr to next char */ } while ( (ctx->octet[0] != 0) && _IsInColumn2(*ctx->octet) ) { ctx->octet++; ctx->itemlen++; /* advance ptr to next char */ } /* if nothing after this, it's an error */ if (ctx->octet[0] == 0) { ok = False; break; } c = *ctx->octet; /* get next char in seq */ ctx->octet++; ctx->itemlen++; /* advance ptr to next char */ if (_IsValidCSIFinal(c)) { /* we have a valid CSI sequence - handle it */ ok = processCSI(ctx, c); } else { ok = False; } break; case NL: /* new line */ /* if we have any text to output, do it */ if (ctx->flags.text) { outputXmString(ctx, True); /* with a separator */ ctx->flags.text = False; } else { if (ctx->xmsep == NULL) { ctx->xmsep = XmStringSeparatorCreate(); } ctx->xmstring = XmStringConcatAndFree(ctx->xmstring, XmStringCopy(ctx->xmsep)); } ctx->octet++; /* advance ptr to next char */ break; case HT: /* if we have any text to output, do it */ if (ctx->flags.text) { outputXmString(ctx, False); ctx->flags.text = False; } if (ctx->xmtab == NULL) { ctx->xmtab = XmStringComponentCreate(XmSTRING_COMPONENT_TAB, 0, NULL); } ctx->xmstring = XmStringConcatAndFree(ctx->xmstring, XmStringCopy(ctx->xmtab)); ctx->octet++; /* advance ptr to next char */ break; default: /* just 'normal' text */ ctx->item = ctx->octet; /* remember start of this item */ ctx->itemlen = 0; ctx->flags.text = True; while (ctx->octet[0] != 0) { c = *ctx->octet; if ((c == ESC) || (c == CSI) || (c == NL) || (c == HT)) { break; } if ( (_IsInC0Set(c) && (!_IsValidC0(ctx, c))) || (_IsInC1Set(c) && (!_IsValidC1(ctx, c))) ) { ok = False; break; } ctx->flags.gchar = True; /* We have a character! */ /* * We should look at the actual character to * decide whether it's a gl or gr character. * * We'll hit the problem if we get a CT that * isn't generated by Motif. */ if (isascii((unsigned char)c)) { ctx->itemlen += ctx->gl_octets_per_char; ctx->octet += ctx->gl_octets_per_char; } else { ctx->octet += ctx->gr_octets_per_char; ctx->itemlen += ctx->gr_octets_per_char; } } /* end while */ break; } /* end switch */ if (!ok) break; } /* end while */ /* if we have any text left to output, do it */ if (ctx->flags.text) { outputXmString(ctx, False); /* with no separator */ } XtFree((char *) ctx->dirstack); if (ctx->xmsep != NULL) XmStringFree(ctx->xmsep); if (ctx->xmtab != NULL) XmStringFree(ctx->xmtab); xmsReturned = (XmString)ctx->xmstring; XtFree((char *) ctx); if (ok) return ( xmsReturned ); else return ( (XmString)NULL ); } /*********************************************************************** * * Hacked procedures to work with XmCvtCTToXmString. * ***********************************************************************/ /* processESCHack - handle valid ESC sequences */ static Boolean processESCHack( ct_context *ctx, #if NeedWidePrototypes int final ) #else Octet final ) #endif /* NeedWidePrototypes */ { Boolean ok; switch (ctx->item[1]) { case 0x24: /* 02/04 - invoke 94(n) charset into GL or GR */ ok = process94n(ctx, final); break; case 0x25: /* 02/05 - extended segments */ /* if we have any text to output, do it */ if (ctx->flags.text) { outputXmString(ctx, False); /* with no separator */ ctx->flags.text = False; } ok = processExtendedSegmentsHack(ctx, final); break; case 0x28: /* 02/08 - invoke 94 charset into GL */ ok = process94GL(ctx, final); break; case 0x29: /* 02/09 - invoke 94 charset into GR */ ok = process94GR(ctx, final); break; case 0x2d: /* 02/13 - invoke 96 charset into GR */ ok = process96GR(ctx, final); break; default: ok = False; break; } return(ok); } static Boolean processExtendedSegmentsHack( ct_context *ctx, #if NeedWidePrototypes int final ) #else Octet final ) #endif /* NeedWidePrototypes */ { OctetPtr esptr; /* ptr into ext seg */ unsigned int seglen; /* length of ext seg */ unsigned int len; /* length */ String charset_copy; /* ptr to NULL-terminated copy of ext seg charset */ OctetPtr text_copy; /* ptr to NULL-terminated copy of ext seg text */ XmString tempxm1; Boolean ok = True; /* Extended segments ** 01/11 02/05 02/15 03/00 M L variable # of octets/char ** 01/11 02/05 02/15 03/01 M L 1 octet/char ** 01/11 02/05 02/15 03/02 M L 2 octets/char ** 01/11 02/05 02/15 03/03 M L 3 octets/char ** 01/11 02/05 02/15 03/04 M L 4 octets/char */ if ( (ctx->itemlen == 4) && (ctx->item[2] == 0x2f) && (_IsInColumn3(final)) ) { if ( (ctx->octet[0] < 0x80) || (ctx->octet[1] < 0x80) ) { return(False); } /* ** The most significant bit of M and L are always set to 1 ** The number is computed as ((M-128)*128)+(L-128) */ seglen = *ctx->octet - 0x80; ctx->octet++; ctx->itemlen++; /* advance pointer */ seglen = (seglen << 7) + (*ctx->octet - 0x80); ctx->octet++; ctx->itemlen++; /* advance pointer */ /* Check for premature end. */ for (esptr = ctx->octet; esptr < (ctx->octet + seglen); esptr++) { if (*esptr == 0) { return(False); } } esptr = ctx->octet; /* point to charset */ ctx->itemlen += seglen; /* advance pointer over segment */ ctx->octet += seglen; switch (final) { case 0x30: /* variable # of octets per char */ case 0x31: /* 1 octet per char */ case 0x32: /* 2 octets per char */ /* scan for STX separator between charset and text */ len = 0; while (esptr[len] != STX) len++; if (len > ctx->itemlen) { /* if we ran off the end, error */ ok = False; break; } charset_copy = XtMalloc(len + 1); strncpy(charset_copy, (char *) esptr, len); charset_copy[len] = EOS; esptr += len + 1; /* point to text part */ len = seglen - len - 1; /* calc length of text part */ /* For two-octets charsets, make sure the text * contains an integral number of characters. */ if (final == 0x32 && len % 2) { XtFree(charset_copy); return (False); } text_copy = (unsigned char *) XtMalloc(len + 1); memcpy( text_copy, esptr, len); text_copy[len] = EOS; tempxm1 = XmStringConcatAndFree( XmStringDirectionCreate((_CurDir(ctx) == ct_Dir_LeftToRight ? XmSTRING_DIRECTION_L_TO_R : (_CurDir(ctx) == ct_Dir_RightToLeft ? XmSTRING_DIRECTION_R_TO_L : XmSTRING_DIRECTION_UNSET))), XmStringCreate((char *)text_copy, charset_copy)); ctx->xmstring = XmStringConcatAndFree(ctx->xmstring, tempxm1); XtFree((char *) text_copy); XtFree((char *) charset_copy); ok = True; break; case 0x33: /* 3 octets per char */ case 0x34: /* 4 octets per char */ /* not supported */ ok = False; break; default: /* reserved for future use */ ok = False; break; } /* end switch */ } /* end if */ return(ok); } /************************************************************************ * * XmCvtTextToXmString * Convert a compound text string to a XmString. * ************************************************************************/ /*ARGSUSED*/ Boolean XmCvtTextToXmString( Display *display, XrmValuePtr args, /* unused */ Cardinal *num_args, /* unused */ XrmValue *from_val, XrmValue *to_val, XtPointer *converter_data ) /* unused */ { Boolean ok; if (from_val->addr == NULL) return( FALSE); ok = cvtTextToXmString(from_val, to_val); if (!ok) { to_val->addr = NULL; to_val->size = 0; XtAppWarningMsg(XtDisplayToApplicationContext(display), "conversionError","compoundText", "XtToolkitError", MSG13, (String *)NULL, (Cardinal *)NULL); } return(ok); } static Boolean cvtTextToXmString( XrmValue *from, XrmValue *to ) { ct_context *ctx; /* compound text context block */ Boolean ok = True; Octet c; ctx = (ct_context *) XtMalloc(sizeof(ct_context)); /* initialize the context block */ ctx->octet = (OctetPtr)from->addr; ctx->lastoctet = ctx->octet + from->size; ctx->flags.dircs = False; ctx->flags.gchar = False; ctx->flags.ignext = False; ctx->flags.gl = False; ctx->flags.text = False; ctx->dirstacksize = 8; ctx->dirstack = (ct_Direction *) XtMalloc(ctx->dirstacksize*sizeof(ct_Direction)); /* * Define XLIB_HANDLES_DIRECTION if vendor's X library knows how * to deal with direction control sequences in CT. Otherwise * no such ones will be output if there are no Rtol segments * in the XmString. Note that the MIT sample implementation * does not deal with direction control sequences... */ #ifdef XLIB_HANDLES_DIRECTION ctx->dirstack[0] = ct_Dir_StackEmpty; ctx->dirsp = 0; #else ctx->dirstack[0] = ct_Dir_StackEmpty; ctx->dirstack[1] = ct_Dir_LeftToRight; ctx->dirsp = 1; #endif ctx->encoding = NULL; ctx->encodinglen = 0; ctx->item = NULL; ctx->itemlen = 0; ctx->version = CTVERSION; ctx->gl_charset = CS_ISO8859_1; ctx->gl_charset_size = 94; ctx->gl_octets_per_char = 1; ctx->gr_charset = CS_ISO8859_1; ctx->gr_charset_size = 96; ctx->gr_octets_per_char = 1; ctx->xmstring = NULL; ctx->xmsep = NULL; ctx->xmtab = NULL; /* ** check for version/ignore extensions sequence (must be first if present) ** Format is: ESC 02/03 V 03/00 ignoring extensions is OK ** ESC 02/03 V 03/01 ignoring extensions is not OK ** where V is in the range 02/00 thru 02/15 and represents versions 1 thru 16 */ if ( (from->size >= 4) && (ctx->octet[0] == ESC) && (ctx->octet[1] == 0x23) && (_IsInColumn2(ctx->octet[2]) && ((ctx->octet[3] == 0x30) || ctx->octet[3] == 0x31)) ) { ctx->version = ctx->octet[2] - 0x1f; /* 0x20-0x2f => version 1-16 */ if (ctx->octet[3] == 0x30) /* 0x30 == can ignore extensions */ ctx->flags.ignext = True; ctx->octet += 4; /* advance ptr to next seq */ } while (ctx->octet < ctx->lastoctet) { switch (*ctx->octet) { /* look at next octet in seq */ case ESC: /* %%% TEMP ** if we have any text to output, do it ** this section needs to be optimized so that it handles ** paired character sets without outputting a new segment. */ if (ctx->flags.text) { outputXmString(ctx, False); /* with no separator */ } ctx->flags.text = False; ctx->item = ctx->octet; /* remember start of this item */ ctx->itemlen = 0; ctx->octet++; ctx->itemlen++; /* advance ptr to next char */ /* scan for final char */ while ( (ctx->octet != ctx->lastoctet) && (_IsInColumn2(*ctx->octet)) ) { ctx->octet++; ctx->itemlen++; /* advance ptr to next char */ } if (ctx->octet == ctx->lastoctet) { /* if nothing after this, it's an error */ ok = False; break; } c = *ctx->octet; /* get next char in seq */ ctx->octet++; ctx->itemlen++; /* advance ptr to next char */ if (_IsValidESCFinal(c)) { /* we have a valid ESC sequence - handle it */ ok = processESC(ctx, c); } else { ok = False; } if (ok) { ctx->encoding = ctx->item; ctx->encodinglen = ctx->itemlen; } break; case CSI: /* ** CSI format is: CSI P I F where ** 03/00 <= P <= 03/15 ** 02/00 <= I <= 02/15 ** 04/00 <= F <= 07/14 */ /* %%% TEMP ** if we have any text to output, do it ** This may need optimization. */ if (ctx->flags.text) { /* check whether we have a specific direction set */ if (((ctx->octet[1] == 0x31) && (ctx->octet[2] == 0x5d))|| ((ctx->octet[1] == 0x32) && (ctx->octet[2] == 0x5d))|| (ctx->octet[1] == 0x5d)) outputXmString(ctx, False); /* without a separator*/ else outputXmString(ctx, True); /* with a separator */ } ctx->flags.text = False; ctx->item = ctx->octet; /* remember start of this item */ ctx->itemlen = 0; ctx->octet++; ctx->itemlen++; /* advance ptr to next char */ /* scan for final char */ while ( (ctx->octet != ctx->lastoctet) && _IsInColumn3(*ctx->octet) ) { ctx->octet++; ctx->itemlen++; /* advance ptr to next char */ } while ( (ctx->octet != ctx->lastoctet) && _IsInColumn2(*ctx->octet) ) { ctx->octet++; ctx->itemlen++; /* advance ptr to next char */ } /* if nothing after this, it's an error */ if (ctx->octet == ctx->lastoctet) { ok = False; break; } c = *ctx->octet; /* get next char in seq */ ctx->octet++; ctx->itemlen++; /* advance ptr to next char */ if (_IsValidCSIFinal(c)) { /* we have a valid CSI sequence - handle it */ ok = processCSI(ctx, c); } else { ok = False; } break; case NL: /* new line */ /* if we have any text to output, do it */ if (ctx->flags.text) { outputXmString(ctx, True); /* with a separator */ ctx->flags.text = False; } else { if (ctx->xmsep == NULL) { ctx->xmsep = XmStringSeparatorCreate(); } ctx->xmstring = XmStringConcatAndFree(ctx->xmstring, XmStringCopy(ctx->xmsep)); } ctx->octet++; /* advance ptr to next char */ break; case HT: /* if we have any text to output, do it */ if (ctx->flags.text) { outputXmString(ctx, False); ctx->flags.text = False; } if (ctx->xmtab == NULL) { ctx->xmtab = XmStringComponentCreate(XmSTRING_COMPONENT_TAB, 0, NULL); } ctx->xmstring = XmStringConcatAndFree(ctx->xmstring, XmStringCopy(ctx->xmtab)); ctx->octet++; /* advance ptr to next char */ break; default: /* just 'normal' text */ ctx->item = ctx->octet; /* remember start of this item */ ctx->itemlen = 0; ctx->flags.text = True; while (ctx->octet < ctx->lastoctet) { c = *ctx->octet; if ((c == ESC) || (c == CSI) || (c == NL) || (c == HT)) { break; } if ( (_IsInC0Set(c) && (!_IsValidC0(ctx, c))) || (_IsInC1Set(c) && (!_IsValidC1(ctx, c))) ) { ok = False; break; } ctx->flags.gchar = True; /* We have a character! */ /* * We should look at the actual character to * decide whether it's a gl or gr character. * * We'll hit the problem if we get a CT that * isn't generated by Motif. */ if (isascii((unsigned char)c)) { ctx->octet += ctx->gl_octets_per_char; ctx->itemlen += ctx->gl_octets_per_char; } else { ctx->octet += ctx->gr_octets_per_char; ctx->itemlen += ctx->gr_octets_per_char; } if (ctx->octet > ctx->lastoctet) { ok = False; break; } } /* end while */ break; } /* end switch */ if (!ok) break; } /* end while */ /* if we have any text left to output, do it */ if (ctx->flags.text) { outputXmString(ctx, False); /* with no separator */ } XtFree((char *) ctx->dirstack); if (ctx->xmstring != NULL) { to->addr = (char *) ctx->xmstring; to->size = sizeof(XmString); } if (ctx->xmsep != NULL) XmStringFree(ctx->xmsep); if (ctx->xmtab != NULL) XmStringFree(ctx->xmtab); XtFree((char *) ctx); return (ok); } static char ** cvtCTsegment(ct_context *ctx, OctetPtr item, unsigned int length) { XTextProperty tmp_prop; OctetPtr octets; Boolean free_octets = False; int count; int ret_val; char **strings = NULL; if (ctx->encoding) { if (ctx->encoding + ctx->encodinglen != item) { octets = (OctetPtr)XtMalloc((ctx->encodinglen + length) * sizeof(Octet)); memcpy((char *)octets, (char *)ctx->encoding, ctx->encodinglen); memcpy((char *)(octets + ctx->encodinglen), (char *)item, length); free_octets = True; } else { octets = ctx->encoding; } } else { octets = ctx->item; } tmp_prop.value = octets; tmp_prop.encoding = XInternAtom(_XmGetDefaultDisplay(), XmSCOMPOUND_TEXT, False); tmp_prop.format = 8; tmp_prop.nitems = ctx->encodinglen + length; ret_val = XmbTextPropertyToTextList(_XmGetDefaultDisplay(), &tmp_prop, &strings, &count); if (ret_val > 0) { XFreeStringList(strings); strings = NULL; } if (free_octets) XtFree((char *)octets); return strings; } /* outputXmString */ static void outputXmString( ct_context *ctx, #if NeedWidePrototypes int separator ) #else Boolean separator ) #endif /* NeedWidePrototypes */ { char **strings = NULL; /* * CR # 8544: XmbTextListToTextProperty converts from locale encoding * to MIT registered encodings. We have to convert back - UNLESS the * CT was not created with XmbTextListToTextProperty. However, there * is no way to tell how we got the CT, but in most cases, the * tag will be FONTLIST_DEFAULT_TAG, and then we want to do this. So * we try this, and only use the encoding tags if we could not convert. */ strings = cvtCTsegment(ctx, ctx->item, ctx->itemlen); if (strings) { ctx->xmstring = concatStringToXmString (ctx->xmstring, strings[0], strlen(strings[0]), XmFONTLIST_DEFAULT_TAG, (XmStringDirection) ((_CurDir(ctx) == ct_Dir_LeftToRight) ? XmSTRING_DIRECTION_L_TO_R : ((_CurDir(ctx) == ct_Dir_RightToLeft) ? XmSTRING_DIRECTION_R_TO_L : XmSTRING_DIRECTION_UNSET)), separator ); XFreeStringList(strings); return; } /* If we couldn't convert to locale encoding... */ /* This is not really right. We can probably never draw this string and get something that looks right out of this */ /* * If the GL charset is ISO8859-1, and the GR charset is any ISO8859 * charset, then they're a pair, so we can create a single segment using * just the GR charset. * * If GL and GR are multibyte charsets and they match (both GB2312 or both * KSC5601) except for JISX0208, then we can create a single segment using * just the GR charset. If GL and GR are multibyte charsets and they DON'T * match, or if GL or GR is multibyte and the other is singlebyte, then * there's no way to tell which characters belong to GL and which to GR, * so treat it like a non-Latin1 in GL - 7 bit characters go to GL, 8 bit * characters to to GR. *** THIS APPEARS TO BE A HOLE IN THE COMPOUND * TEXT SPEC ***. * * Otherwise the charsets are not a pair and we will switch between GL * and GR segments each time the high bit changes. */ if (((ctx->gl_charset == CS_ISO8859_1) && ((ctx->gr_charset == CS_ISO8859_1) || (ctx->gr_charset == CS_ISO8859_2) || (ctx->gr_charset == CS_ISO8859_3) || (ctx->gr_charset == CS_ISO8859_4) || (ctx->gr_charset == CS_ISO8859_5) || (ctx->gr_charset == CS_ISO8859_6) || (ctx->gr_charset == CS_ISO8859_7) || (ctx->gr_charset == CS_ISO8859_8) || (ctx->gr_charset == CS_ISO8859_9))) || ((ctx->gl_charset == CS_GB2312_0) && (ctx->gr_charset == CS_GB2312_1)) || ((ctx->gl_charset == CS_KSC5601_0) && (ctx->gr_charset == CS_KSC5601_1))) { /* OK to do single segment output but always use GR charset */ ctx->xmstring = concatStringToXmString (ctx->xmstring, (char *) ctx->item, ctx->itemlen, (char *) ctx->gr_charset, (XmStringDirection) ((_CurDir(ctx) == ct_Dir_LeftToRight) ? XmSTRING_DIRECTION_L_TO_R : ((_CurDir(ctx) == ct_Dir_RightToLeft) ? XmSTRING_DIRECTION_R_TO_L : XmSTRING_DIRECTION_UNSET)), separator ); } else { /* have to create a new segment everytime the highbit changes */ unsigned int j = 0; unsigned int start = 0; Octet c; Boolean curseg_is_gl; curseg_is_gl = isascii((unsigned char)ctx->item[0]); while (j < ctx->itemlen) { c = ctx->item[j]; if (isascii((unsigned char)c)) { if (!curseg_is_gl) { /* output gr string */ assert(j > start); ctx->xmstring = concatStringToXmString (ctx->xmstring, (char *)ctx->item + start, j - start, (char *) ctx->gr_charset, (XmStringDirection) ((_CurDir(ctx) == ct_Dir_LeftToRight) ? XmSTRING_DIRECTION_L_TO_R : ((_CurDir(ctx) == ct_Dir_RightToLeft) ? XmSTRING_DIRECTION_R_TO_L : XmSTRING_DIRECTION_UNSET)), False ); start = j; curseg_is_gl = True; /* start gl segment */ }; j++; } else { if (curseg_is_gl) { /* output gl string */ assert(j > start); ctx->xmstring = concatStringToXmString (ctx->xmstring, (char *)ctx->item + start, j - start, (char *) ctx->gl_charset, (XmStringDirection) ((_CurDir(ctx) == ct_Dir_LeftToRight) ? XmSTRING_DIRECTION_L_TO_R : ((_CurDir(ctx) == ct_Dir_RightToLeft) ? XmSTRING_DIRECTION_R_TO_L : XmSTRING_DIRECTION_UNSET)), False ); start = j; curseg_is_gl = False; /* start gr segment */ }; j++; }; /* end if */ }; /* end while */ /* output last segment */ ctx->xmstring = concatStringToXmString (ctx->xmstring, (char *)ctx->item + start, ctx->itemlen - start, (char *) ((curseg_is_gl) ? ctx->gl_charset : ctx->gr_charset ), (XmStringDirection) ((_CurDir(ctx) == ct_Dir_LeftToRight) ? XmSTRING_DIRECTION_L_TO_R : ((_CurDir(ctx) == ct_Dir_RightToLeft) ? XmSTRING_DIRECTION_R_TO_L : XmSTRING_DIRECTION_UNSET)), False ); if (separator) { if (ctx->xmsep == NULL) { ctx->xmsep = XmStringSeparatorCreate(); }; ctx->xmstring = XmStringConcatAndFree(ctx->xmstring, XmStringCopy(ctx->xmsep)); }; }; /* end if paired */ } static XmString concatStringToXmString( XmString compoundstring, char *textstring, int textlen, char *charset, #if NeedWidePrototypes int direction, int separator ) #else XmStringDirection direction, Boolean separator ) #endif /* NeedWidePrototypes */ { XmString tempxm1; tempxm1 = XmStringConcatAndFree(XmStringDirectionCreate(direction), _XmStringNCreate(textstring, charset, textlen)); if (separator) tempxm1 = XmStringConcatAndFree(tempxm1, XmStringSeparatorCreate()); compoundstring = XmStringConcatAndFree(compoundstring, tempxm1); return (compoundstring); } /* processESC - handle valid ESC sequences */ static Boolean processESC( ct_context *ctx, #if NeedWidePrototypes int final ) #else Octet final ) #endif /* NeedWidePrototypes */ { Boolean ok; switch (ctx->item[1]) { case 0x24: /* 02/04 - invoke 94(n) charset into GL or GR */ ok = process94n(ctx, final); break; case 0x25: /* 02/05 - extended segments */ /* if we have any text to output, do it */ if (ctx->flags.text) { outputXmString(ctx, False); /* with no separator */ ctx->flags.text = False; } ok = processExtendedSegments(ctx, final); break; case 0x28: /* 02/08 - invoke 94 charset into GL */ ok = process94GL(ctx, final); break; case 0x29: /* 02/09 - invoke 94 charset into GR */ ok = process94GR(ctx, final); break; case 0x2d: /* 02/13 - invoke 96 charset into GR */ ok = process96GR(ctx, final); break; default: ok = False; break; } return(ok); } /* ** processCSI - handle valid CSI sequences ** CSI sequences ** 09/11 03/01 05/13 begin left-to-right text ** 09/11 03/02 05/13 begin right-to-left text ** 09/11 05/13 end of string ** 09/11 P I F reserved for use in future extensions */ static Boolean processCSI( ct_context *ctx, #if NeedWidePrototypes int final ) #else Octet final ) #endif /* NeedWidePrototypes */ { Boolean ok = True; switch (final) { case 0x5d: /* end of direction sequence */ switch (ctx->item[1]) { case 0x31: /* start left to right */ if (ctx->flags.gchar && ctx->dirsp == 0) { ok = False; } else { _PushDir(ctx, ct_Dir_LeftToRight); } break; case 0x32: /* start right to left */ if (ctx->flags.gchar && ctx->dirsp == 0) { ok = False; } else { _PushDir(ctx, ct_Dir_RightToLeft); } break; case 0x5d: /* Just CSI EOS - revert */ if (ctx->dirsp > 0) { _PopDir(ctx); } else { ok = False; } break; default: /* anything else is an error */ ok = False; } break; default: /* reserved for future extensions */ ok = False; break; } return(ok); } static Boolean processExtendedSegments( ct_context *ctx, #if NeedWidePrototypes int final ) #else Octet final ) #endif /* NeedWidePrototypes */ { OctetPtr esptr; /* ptr into ext seg */ unsigned int seglen; /* length of ext seg */ unsigned int len; /* length */ String charset_copy; /* ptr to NULL-terminated copy of ext seg charset */ OctetPtr text_copy; /* ptr to NULL-terminated copy of ext seg text */ XmString tempxm1; Boolean ok = True; /* Extended segments ** 01/11 02/05 02/15 03/00 M L variable # of octets/char ** 01/11 02/05 02/15 03/01 M L 1 octet/char ** 01/11 02/05 02/15 03/02 M L 2 octets/char ** 01/11 02/05 02/15 03/03 M L 3 octets/char ** 01/11 02/05 02/15 03/04 M L 4 octets/char */ if ( (ctx->itemlen == 4) && (ctx->item[2] == 0x2f) && (_IsInColumn3(final)) ) { if ( ((ctx->lastoctet - ctx->octet) < 2) || (ctx->octet[0] < 0x80) || (ctx->octet[1] < 0x80) ) { return(False); } /* ** The most significant bit of M and L are always set to 1 ** The number is computed as ((M-128)*128)+(L-128) */ seglen = *ctx->octet - 0x80; ctx->octet++; ctx->itemlen++; /* advance pointer */ seglen = (seglen << 7) + (*ctx->octet - 0x80); ctx->octet++; ctx->itemlen++; /* advance pointer */ if ((ctx->lastoctet - ctx->octet) < seglen) { return(False); } esptr = ctx->octet; /* point to charset */ ctx->itemlen += seglen; /* advance pointer over segment */ ctx->octet += seglen; switch (final) { case 0x30: /* variable # of octets per char */ case 0x31: /* 1 octet per char */ case 0x32: /* 2 octets per char */ /* scan for STX separator between charset and text */ len = 0; while (esptr[len] != STX) len++; if (len > ctx->itemlen) { /* if we ran off the end, error */ ok = False; break; } charset_copy = XtMalloc(len + 1); strncpy(charset_copy, (char *) esptr, len); charset_copy[len] = EOS; esptr += len + 1; /* point to text part */ len = seglen - len - 1; /* calc length of text part */ text_copy = (unsigned char *) XtMalloc(len + 1); memcpy( text_copy, esptr, len); text_copy[len] = EOS; tempxm1 = XmStringConcatAndFree( XmStringDirectionCreate((_CurDir(ctx) == ct_Dir_LeftToRight ? XmSTRING_DIRECTION_L_TO_R : (_CurDir(ctx) == ct_Dir_RightToLeft ? XmSTRING_DIRECTION_R_TO_L : XmSTRING_DIRECTION_UNSET))), XmStringCreate((char *)text_copy, charset_copy)); ctx->xmstring = XmStringConcatAndFree(ctx->xmstring, tempxm1); XtFree((char *) text_copy); XtFree(charset_copy); ok = True; break; case 0x33: /* 3 octets per char */ case 0x34: /* 4 octets per char */ /* not supported */ ok = False; break; default: /* reserved for future use */ ok = False; break; } /* end switch */ } /* end if */ return(ok); } static Boolean process94n( ct_context *ctx, #if NeedWidePrototypes int final ) #else Octet final ) #endif /* NeedWidePrototypes */ { if (ctx->itemlen > 3) { switch (ctx->item[2]) { case 0x28: /* into GL */ switch (final) { case 0x41: /* 04/01 - China (PRC) Hanzi */ _SetGL(ctx, CS_GB2312_0, 94, 2); break; case 0x42: /* 04/02 - Japanese GCS, level 2 */ _SetGL(ctx, CS_JISX0208_0, 94, 2); break; case 0x43: /* 04/03 - Korean GCS */ _SetGL(ctx, CS_KSC5601_0, 94, 2); break; default: /* other character sets are not supported */ return False; } /* end switch (final) */ break; case 0x29: /* into GR */ switch (final) { case 0x41: /* 04/01 - China (PRC) Hanzi */ _SetGR(ctx, CS_GB2312_1, 94, 2); break; case 0x42: /* 04/02 - Japanese GCS, level 2 */ _SetGR(ctx, CS_JISX0208_1, 94, 2); break; case 0x43: /* 04/03 - Korean GCS */ _SetGR(ctx, CS_KSC5601_1, 94, 2); break; default: /* other character sets are not supported */ return False; } /* end switch (final) */ break; default: /* error */ return False; } /* end switch item[2] */ } else { /* error */ return False; } /* end if */ return True; } static Boolean process94GL( ct_context *ctx, #if NeedWidePrototypes int final ) #else Octet final ) #endif /* NeedWidePrototypes */ { switch (final) { case 0x42: /* 04/02 - Left half, ISO8859* (ASCII) */ _SetGL(ctx, CS_ISO8859_1, 94, 1); break; case 0x4a: /* 04/10 - Left half, Katakana */ _SetGL(ctx, CS_JISX0201, 94, 1); break; default: return False; } return(True); } static Boolean process94GR( ct_context *ctx, #if NeedWidePrototypes int final ) #else Octet final ) #endif /* NeedWidePrototypes */ { switch (final) { case 0x49: /* 04/09 - Right half, Katakana */ _SetGR(ctx, CS_JISX0201, 94, 1); break; default: return False; } return(True); } static Boolean process96GR( ct_context *ctx, #if NeedWidePrototypes int final ) #else Octet final ) #endif /* NeedWidePrototypes */ { switch (final) { case 0x41: /* 04/01 - Right half, Latin 1 */ _SetGR(ctx, CS_ISO8859_1, 96, 1); break; case 0x42: /* 04/02 - Right half, Latin 2 */ _SetGR(ctx, CS_ISO8859_2, 96, 1); break; case 0x43: /* 04/03 - Right half, Latin 3 */ _SetGR(ctx, CS_ISO8859_3, 96, 1); break; case 0x44: /* 04/04 - Right half, Latin 4 */ _SetGR(ctx, CS_ISO8859_4, 96, 1); break; case 0x46: /* 04/06 - Right half, Latin/Greek */ _SetGR(ctx, CS_ISO8859_7, 96, 1); break; case 0x47: /* 04/07 - Right half, Latin/Arabic */ _SetGR(ctx, CS_ISO8859_6, 96, 1); break; case 0x48: /* 04/08 - Right half, Latin/Hebrew */ _SetGR(ctx, CS_ISO8859_8, 96, 1); break; case 0x4c: /* 04/12 - Right half, Latin/Cyrillic */ _SetGR(ctx, CS_ISO8859_5, 96, 1); break; case 0x4d: /* 04/13 - Right half, Latin 5 */ _SetGR(ctx, CS_ISO8859_9, 96, 1); break; default: return False; } return(True); } /************************************************************************ * * XmCvtXmStringToCT * Convert an XmString to a compound text string directly. * This is the public version of the resource converter and only * requires the XmString as an argument. * ************************************************************************/ char * XmCvtXmStringToCT( XmString string ) { Boolean ok; /* Dummy up some XrmValues to pass to cvtXmStringToText. */ XrmValue from_val; XrmValue to_val; if (string == NULL) return ( (char *) NULL ); from_val.addr = (char *) string; ok = cvtXmStringToText(&from_val, &to_val); if (!ok) { XtWarningMsg( "conversionError","compoundText", "XtToolkitError", MSG8, NULL, NULL) ; return( (char *) NULL ) ; } return( (char *) to_val.addr) ; } /*************************************************************************** * * * _XmConvertCSToString - Converts compound string to corresponding * * STRING if it can be fully converted. Otherwise returns NULL. * * * ***************************************************************************/ /*ARGSUSED*/ char * _XmConvertCSToString(XmString cs) /* unused */ { return((char *)NULL); } /*************************************************************************** * * * _XmCvtXmStringToCT - public wrapper for the widgets to use. * * This returns the length info as well - critical for the list widget * * * ***************************************************************************/ Boolean _XmCvtXmStringToCT( XrmValue *from, XrmValue *to ) { return (cvtXmStringToText( from, to )); } /************************************************************************ * * XmCvtXmStringToText * Convert an XmString to an ASCII string. * ************************************************************************/ /*ARGSUSED*/ Boolean XmCvtXmStringToText( Display *display, XrmValuePtr args, /* unused */ Cardinal *num_args, /* unused */ XrmValue *from_val, XrmValue *to_val, XtPointer *converter_data ) /* unused */ { Boolean ok; if (from_val->addr == NULL) return( FALSE) ; ok = cvtXmStringToText(from_val, to_val); if (!ok) { XtAppWarningMsg(XtDisplayToApplicationContext(display), "conversionError","compoundText", "XtToolkitError", MSG14, (String *)NULL, (Cardinal *)NULL); } return(ok); } /************************************************************************ * * cvtXmStringToText * Convert an XmString to a compound text string. This is the * underlying conversion routine for XmCvtXmStringToCT, * _XmCvtXmStringToCT, and XmCvtXmStringToText. * ************************************************************************/ static Boolean cvtXmStringToText( XrmValue *from, XrmValue *to ) { Boolean ok; OctetPtr outc = NULL; unsigned int outlen = 0; _XmStringContextRec stack_context; XmStringCharSet ct_encoding = NULL, cset_save = NULL; /* * Define XLIB_HANDLES_DIRECTION if vendor's X library knows how * to deal with direction control sequences in CT. Otherwise * no such beasts will be output if there are no Rtol segments * in the XmString. Note that the MIT sample implementation * does not deal with direction control sequences... */ #ifdef XLIB_HANDLES_DIRECTION ct_Direction prev_direction = ct_Dir_Undefined; #else ct_Direction prev_direction = ct_Dir_LeftToRight; #endif ct_Charset prev_charset = cs_Latin1; XmStringComponentType comp; unsigned int len; XtPointer val = NULL; Octet tmp_buf[256]; OctetPtr tmp; /* Initialize the return parameters. */ to->addr = (XPointer) NULL; to->size = 0; if (!from->addr) return(False); _XmStringContextReInit(&stack_context, (XmString) from->addr); /* BEGIN OSF Fix CR 7403 */ while ((comp = XmeStringGetComponent(&stack_context, True, False, &len, &val)) != XmSTRING_COMPONENT_END) { switch (comp) { case XmSTRING_COMPONENT_LOCALE_TEXT: cset_save = XmFONTLIST_DEFAULT_TAG; /* Fall through */ case XmSTRING_COMPONENT_TEXT: if (cset_save != NULL) { /* Check Registry */ if (ct_encoding) XtFree((char *)ct_encoding); ct_encoding = XmMapSegmentEncoding(cset_save); } /* We must duplicate val because the routines we want to */ /* call don't take a length parameter. */ tmp = (OctetPtr) XmStackAlloc(len + 1, tmp_buf); memcpy((char*)tmp, val, len); tmp[len] = EOS; if (ct_encoding != NULL) { /* We have a mapping. */ ok = processCharsetAndText(ct_encoding, tmp, FALSE, &outc, &outlen, &prev_charset); } else { /* No mapping. Vendor dependent. */ ok = _XmOSProcessUnmappedCharsetAndText(cset_save, tmp, FALSE, &outc, &outlen, &prev_charset); } /* Free our local copy of val. */ XmStackFree((char*) tmp, tmp_buf); if (!ok) { _XmStringContextFree(&stack_context); return(False); } break; case XmSTRING_COMPONENT_CHARSET: cset_save = (XmStringCharSet)val; break; case XmSTRING_COMPONENT_DIRECTION: /* Output the direction, if changed */ if (*(XmStringDirection *)val == XmSTRING_DIRECTION_L_TO_R) { if (prev_direction != ct_Dir_LeftToRight) { outc = ctextConcat(outc, outlen, (unsigned char *) CTEXT_L_TO_R, (unsigned int)CTEXT_L_TO_R_LEN); outlen += CTEXT_L_TO_R_LEN; prev_direction = ct_Dir_LeftToRight; } } else { if (prev_direction != ct_Dir_RightToLeft) { outc = ctextConcat(outc, outlen, (unsigned char *) CTEXT_R_TO_L, (unsigned int)CTEXT_R_TO_L_LEN); outlen += CTEXT_R_TO_L_LEN; prev_direction = ct_Dir_RightToLeft; } }; break; case XmSTRING_COMPONENT_SEPARATOR: if (ct_encoding != NULL) { /* We have a mapping. */ ok = processCharsetAndText(ct_encoding, NULL, TRUE, &outc, &outlen, &prev_charset); } else { /* No mapping. Vendor dependent. */ ok = _XmOSProcessUnmappedCharsetAndText(cset_save, NULL, TRUE, &outc, &outlen, &prev_charset); } if (!ok) { _XmStringContextFree(&stack_context); return(False); } break; case XmSTRING_COMPONENT_TAB: outc = ctextConcat(outc, outlen, (unsigned char *)TABSTRING, (unsigned int)TABSTRING_LEN); outlen++; break; default: /* Just ignore it. */ break; } } /* end while */ if (ct_encoding) XtFree((char *)ct_encoding); /* END OSF Fix CR 7403 */ if (outc != NULL) { to->addr = (char *) outc; to->size = outlen; } _XmStringContextFree(&stack_context); return(True); } static Boolean processCharsetAndText(XmStringCharSet tag, OctetPtr ctext, #if NeedWidePrototypes int separator, #else Boolean separator, #endif /* NeedWidePrototypes */ OctetPtr *outc, unsigned int *outlen, ct_Charset *prev) { unsigned int ctlen = 0, len; if (strcmp(tag, XmFONTLIST_DEFAULT_TAG) == 0) { XTextProperty prop_rtn; int ret_val; String msg; /* Call XmbTextListToTextProperty */ ret_val = XmbTextListToTextProperty(_XmGetDefaultDisplay(), (char **)&ctext, 1, XCompoundTextStyle, &prop_rtn); if (ret_val) { switch (ret_val) { case XNoMemory: msg = MSG9; break; case XLocaleNotSupported: msg = MSG10; break; default: msg = MSG11; break; } XtWarningMsg("conversionError", "textProperty", "XtToolkitError", msg, NULL, 0); return(False); } ctlen = strlen((char *)prop_rtn.value); /* Now copy in the text */ if (ctlen > 0) { *outc = ctextConcat(*outc, *outlen, prop_rtn.value, ctlen); *outlen += ctlen; }; XFree(prop_rtn.value); /* Finally, add the separator if any */ if (separator) { *outc = ctextConcat(*outc, *outlen, (unsigned char *)NEWLINESTRING, (unsigned int)NEWLINESTRING_LEN); (*outlen)++; }; *prev = cs_none; return(True); } if (ctext) ctlen = strlen((char *)ctext); /* Next output the charset */ if (strcmp(tag, CS_ISO8859_1) == 0) { if (*prev != cs_Latin1) { *outc = ctextConcat(*outc, *outlen, (unsigned char *)CTEXT_SET_ISO8859_1, (unsigned int)CTEXT_SET_ISO8859_1_LEN); *outlen += CTEXT_SET_ISO8859_1_LEN; *prev = cs_Latin1; }; } else if (strcmp(tag, CS_ISO8859_2) == 0) { if (*prev != cs_Latin2) { *outc = ctextConcat(*outc, *outlen, (unsigned char *)CTEXT_SET_ISO8859_2, (unsigned int)CTEXT_SET_ISO8859_2_LEN); *outlen += CTEXT_SET_ISO8859_2_LEN; *prev = cs_Latin2; }; } else if (strcmp(tag, CS_ISO8859_3) == 0) { if (*prev != cs_Latin3) { *outc = ctextConcat(*outc, *outlen, (unsigned char *)CTEXT_SET_ISO8859_3, (unsigned int)CTEXT_SET_ISO8859_3_LEN); *outlen += CTEXT_SET_ISO8859_3_LEN; *prev = cs_Latin3; }; } else if (strcmp(tag, CS_ISO8859_4) == 0) { if (*prev != cs_Latin4) { *outc = ctextConcat(*outc, *outlen, (unsigned char *)CTEXT_SET_ISO8859_4, (unsigned int)CTEXT_SET_ISO8859_4_LEN); *outlen += CTEXT_SET_ISO8859_4_LEN; *prev = cs_Latin4; }; } else if (strcmp(tag, CS_ISO8859_5) == 0) { if (*prev != cs_LatinCyrillic) { *outc = ctextConcat(*outc, *outlen, (unsigned char *)CTEXT_SET_ISO8859_5, (unsigned int)CTEXT_SET_ISO8859_5_LEN); *outlen += CTEXT_SET_ISO8859_5_LEN; *prev = cs_LatinCyrillic; }; } else if (strcmp(tag, CS_ISO8859_6) == 0) { if (*prev != cs_LatinArabic) { *outc = ctextConcat(*outc, *outlen, (unsigned char *)CTEXT_SET_ISO8859_6, (unsigned int)CTEXT_SET_ISO8859_6_LEN); *outlen += CTEXT_SET_ISO8859_6_LEN; *prev = cs_LatinArabic; }; } else if (strcmp(tag, CS_ISO8859_7) == 0) { if (*prev != cs_LatinGreek) { *outc = ctextConcat(*outc, *outlen, (unsigned char *)CTEXT_SET_ISO8859_7, (unsigned int)CTEXT_SET_ISO8859_7_LEN); *outlen += CTEXT_SET_ISO8859_7_LEN; *prev = cs_LatinGreek; }; } else if (strcmp(tag, CS_ISO8859_8) == 0) { if (*prev != cs_LatinHebrew) { *outc = ctextConcat(*outc, *outlen, (unsigned char *)CTEXT_SET_ISO8859_8, (unsigned int)CTEXT_SET_ISO8859_8_LEN); *outlen += CTEXT_SET_ISO8859_8_LEN; *prev = cs_LatinHebrew; }; } else if (strcmp(tag, CS_ISO8859_9) == 0) { if (*prev != cs_Latin5) { *outc = ctextConcat(*outc, *outlen, (unsigned char *)CTEXT_SET_ISO8859_9, (unsigned int)CTEXT_SET_ISO8859_9_LEN); *outlen += CTEXT_SET_ISO8859_9_LEN; *prev = cs_Latin5; }; } else if (strcmp(tag, CS_JISX0201) == 0) { if (*prev != cs_Katakana) { *outc = ctextConcat(*outc, *outlen, (unsigned char *)CTEXT_SET_JISX0201, (unsigned int)CTEXT_SET_JISX0201_LEN); *outlen += CTEXT_SET_JISX0201_LEN; *prev = cs_Katakana; }; } else if ((strcmp(tag, CS_GB2312_0) == 0) || (strcmp(tag, CS_GB2312_1) == 0)) { if (*prev != cs_Hanzi) { *outc = ctextConcat(*outc, *outlen, (unsigned char *)CTEXT_SET_GB2312_0, (unsigned int)CTEXT_SET_GB2312_0_LEN); *outlen += CTEXT_SET_GB2312_0_LEN; *prev = cs_Hanzi; }; } else if ((strcmp(tag, CS_JISX0208_0) == 0) || (strcmp(tag, CS_JISX0208_1) == 0)) { if (*prev != cs_JapaneseGCS) { *outc = ctextConcat(*outc, *outlen, (unsigned char *)CTEXT_SET_JISX0208_0, (unsigned int)CTEXT_SET_JISX0208_0_LEN); *outlen += CTEXT_SET_JISX0208_0_LEN; *prev = cs_JapaneseGCS; }; } else if ((strcmp(tag, CS_KSC5601_0) == 0) || (strcmp(tag, CS_KSC5601_1) == 0)) { if (*prev != cs_KoreanGCS) { *outc = ctextConcat(*outc, *outlen, (unsigned char *)CTEXT_SET_KSC5601_0, (unsigned int)CTEXT_SET_KSC5601_0_LEN); *outlen += CTEXT_SET_KSC5601_0_LEN; *prev = cs_KoreanGCS; }; } else { /* Must be a non-standard character set! */ OctetPtr temp; len = strlen(tag); temp = (unsigned char *) XtMalloc(*outlen + 6 + len + 2); /* orig + header + tag + STX + EOS */ memcpy( temp, *outc, *outlen); XtFree((char *) *outc); *outc = temp; temp = &(*outc[*outlen]); /* ** Format is: ** 01/11 02/05 02/15 03/nn M L tag 00/02 text */ *temp++ = 0x1b; *temp++ = 0x25; *temp++ = 0x2f; /* ** HACK! The next octet in the sequence is the # of octets/char. ** XmStrings don't have this information, so just set it to be ** variable # of octets/char, and hope the caller knows what to do. */ *temp++ = 0x30; /* encode len in next 2 octets */ *temp++ = 0x80 + (len+ctlen+1)/128; *temp++ = 0x80 + (len+ctlen+1)%128; strcpy((char *) temp, tag); temp += len; *temp++ = STX; *temp = EOS; /* make sure there's a \0 on the end */ *prev = cs_NonStandard; *outlen += 6 + len + 1; }; /* Now copy in the text */ if (ctlen > 0) { *outc = ctextConcat(*outc, *outlen, ctext, ctlen); *outlen += ctlen; }; /* Finally, add the separator if any */ if (separator) { *outc = ctextConcat(*outc, *outlen, (unsigned char *)NEWLINESTRING, (unsigned int)NEWLINESTRING_LEN); (*outlen)++; } return(True); } static OctetPtr ctextConcat( OctetPtr str1, unsigned int str1len, const_OctetPtr str2, unsigned int str2len ) { str1 = (OctetPtr)XtRealloc((char *)str1, (str1len + str2len + 1)); memcpy( &str1[str1len], str2, str2len); str1[str1len+str2len] = EOS; return(str1); }