/* * @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 */ #ifdef REV_INFO #ifndef lint static char rcsid[] = "$TOG: XmString.c /main/34 1998/04/16 14:35:32 mgreess $" #endif #endif /* (c) Copyright 1989, 1990, DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS. */ /* (c) Copyright 1988, 1989, 1990, 1991, 1992 HEWLETT-PACKARD COMPANY */ #include #include /* for MB_LEN_MAX */ #ifndef X_NOT_STDC_ENV #include #endif #include #include #ifdef __cplusplus extern "C" { /* some 'locale.h' do not have prototypes (sun) */ #endif #include #ifdef __cplusplus } /* Close scope of 'extern "C"' declaration */ #endif /* __cplusplus */ #include #include /* for XmGetXmDisplay */ #include /* for noFontCallback list */ #include #include "MessagesI.h" #include "ResIndI.h" #include "XmI.h" #include "XmosI.h" #include "XmRenderTI.h" #include "XmStringI.h" #include "XmTabListI.h" # include # define Va_start(a,b) va_start(a,b) /* Warning Messages */ #define NO_FONT_MSG _XmMMsgXmString_0000 /* These are the os-specific environment variables checked for a language ** specification. */ #define env_variable "LANG" struct __Xmlocale { char *tag; int taglen; Boolean inited; }; /* enums for which_seg for calculating widths */ enum { XmSTRING_FIRST_SEG, XmSTRING_MIDDLE_SEG, XmSTRING_LAST_SEG, XmSTRING_SINGLE_SEG }; /* Enums for marking internal_flags field in XmParseMappings. */ enum { XmSTRING_UNPARSE_UNKNOWN, /* Parse mapping hasn't been examined. */ XmSTRING_UNPARSE_PLAUSIBLE, /* Parse mapping might unparse. */ XmSTRING_UNPARSE_IMPLAUSIBLE /* Parse mapping will never unparse. */ }; /* Values for drawing underlining renditions. */ #define SINGLE_OFFSET 1 #define DOUBLE_OFFSET 2 #define Half(x) (x >> 1) /* _XmStringEntry macros only acessible inside XmString code */ #define _XmEntryRendCountedBegins(entry, count) \ (_XmEntryOptimized(entry) ? \ (((count) && _XmEntryRendIndex(entry) != REND_INDEX_UNSET) ? \ &(_tag_cache[_XmEntryRendIndex(entry)]) : NULL) : \ _XmUnoptSegRendBegins(entry)) #define _XmEntryRendBegins(entry) \ (_XmEntryOptimized(entry) ? \ ((_XmEntryRendBeginCountGet(entry) && \ _XmEntryRendIndex(entry) != REND_INDEX_UNSET) ? \ &(_tag_cache[_XmEntryRendIndex(entry)]) : NULL) : \ _XmUnoptSegRendBegins(entry)) #define _XmEntryRendCountedEnds(entry, count) \ (_XmEntryOptimized(entry) ? \ (((count) && _XmEntryRendIndex(entry) != REND_INDEX_UNSET) ? \ &(_tag_cache[_XmEntryRendIndex(entry)]) : NULL) : \ _XmUnoptSegRendEnds(entry)) #define _XmEntryRendEnds(entry) \ (_XmEntryOptimized(entry) ? \ ((_XmEntryRendEndCountGet(entry) && \ _XmEntryRendIndex(entry) != REND_INDEX_UNSET) ? \ &(_tag_cache[_XmEntryRendIndex(entry)]) : NULL) : \ _XmUnoptSegRendEnds(entry)) /* * this set constructs ASN.1 XmString format object. The TLV version */ /* The ASN.1 version of XmString is: COMPOUND_STRING 4 or 6 bytes (see description below) component tag 1 byte length 1 or 3 bytes value n bytes component tag 1 byte length 1 or 3 bytes value n bytes eg. very simple... */ /* * ASN.1 header for compound string - 3 byte header, followed by length * which is three bytes maximum, but almost always 1 byte. * * The first byte defines the ASN.1 space: (0xdf) * 1 1 0 1 1 1 1 1 * class form ID code * * class is private, form is primitive (not constructed from other * forms), and the ID code value means the actual ID code value is * extended into one or more octets. * * The second and third bytes define the actual ID code value. The * value used for 1.2 is the inverse of the original XUI value. * second byte: (0x80) * 1 0000000 * MSB high seven bits of ID code * * third byte: (0x06) * 0 0000110 * LSB low seven bits of ID code * * The length field of the ASN.1 conformant compound string header * is dynamically constructed. There are two possible forms depending * upon the length of the string. Note that this length excludes the * header bytes. * * Short Form: range 0 .. 127 * one byte * 0 nnnnnnn * short 7 bit length * * Long Form: range 128 .. 2**16-1 * three bytes * first: 1 nnnnnnn * long number of bytes to follow * * second: * nnnnnnnn * MSB of length * * third: * nnnnnnnn * LSB of length * * This process for constructing the length field will also be * used to construct the length field within individual tag-length-value * triplets. */ #define ASNHEADERLEN 3 static XmConst unsigned char ASNHeader[ASNHEADERLEN] = { 0xdf, 0x80, 0x06 }; #define MAXSHORTVALUE 127 /* maximum len to be used for short length form */ #define CSLONGLEN 3 #define CSSHORTLEN 1 #define CSLONGLEN1 0x82 #define CSLONGBIT 0x80 #define ASNTAG 1 /* Num bytes for tag & length = ASNTAG + [CSSHORTLEN | CSLONGLEN] */ #define HEADER 3 /* num bytes for tag & length */ /* * calculates the number of bytes in the header of an external compound * string, given the total length of the components. */ #define _calc_header_size(len) \ ((((unsigned short)(len)) > MAXSHORTVALUE) ? (ASNHEADERLEN + CSLONGLEN) : \ (ASNHEADERLEN + CSSHORTLEN)) #define _asn1_size(len) \ ((((unsigned short)(len)) > MAXSHORTVALUE) ? (ASNTAG + CSLONGLEN) : \ (ASNTAG + CSSHORTLEN)) #define _is_asn1_long(p) \ ((*((unsigned char *)(p) + ASNTAG)) & ((unsigned char)CSLONGBIT)) /******** Static Function Declarations ********/ static Boolean _is_short_length( unsigned char *p) ; static void _write_long_length( unsigned char *p, #if NeedWidePrototypes unsigned int length) ; #else unsigned short length) ; #endif /* NeedWidePrototypes */ static unsigned char * _write_header( unsigned char *p, #if NeedWidePrototypes unsigned int length) ; #else unsigned short length) ; #endif /* NeedWidePrototypes */ static unsigned char * _read_header( unsigned char *p) ; static unsigned short _read_header_length( unsigned char *p) ; static unsigned short _read_length( unsigned char *p) ; static unsigned short _read_string_length( unsigned char *p) ; static unsigned char * _write_component( unsigned char *p, #if NeedWidePrototypes unsigned int tag, unsigned int length, #else unsigned char tag, unsigned short length, #endif /* NeedWidePrototypes */ unsigned char *value, #if NeedWidePrototypes int move_by_length) ; #else Boolean move_by_length) ; #endif /* NeedWidePrototypes */ static unsigned char * _read_component( unsigned char *p, unsigned char *tag, unsigned short *length, unsigned char *value) ; static Boolean RenditionsCompatible(_XmStringEntry seg1, _XmStringEntry seg2); static void MergeEnds(_XmStringEntry a, _XmStringEntry b); static void MergeBegins(_XmStringEntry a, _XmStringEntry b); static Boolean _is_asn1(unsigned char *string) ; static XmString Clone(XmString string, int lines); static void OptLineMetrics(XmRenderTable rendertable, _XmString line, XmRendition *rend_io, XmRendition base_rend, Dimension *width, Dimension *height, Dimension *ascender, Dimension *descender ); static Dimension OptLineAscender( XmRenderTable f, _XmStringOpt opt) ; static void LineMetrics(_XmStringEntry line, XmRenderTable r, XmRendition *rend_io, XmRendition base, XmDirection prim_dir, Dimension *width, Dimension *height, Dimension *ascender, Dimension *descender); static void SubStringPosition( #if NeedWidePrototypes int one_byte, #else Boolean one_byte, #endif /* NeedWidePrototypes */ XmRenderTable rt, XmRendition entry, _XmStringEntry seg, _XmStringEntry under_seg, #if NeedWidePrototypes int x, #else Position x, #endif /* NeedWidePrototypes */ Dimension *under_begin, Dimension *under_end) ; static void recursive_layout(_XmString string, int *line_index, int *seg_index, #if NeedWidePrototypes int direction, int p_direction, #else XmDirection direction, XmDirection p_direction, #endif /* NeedWidePrototypes */ int depth); static void last_direction(_XmStringEntry line, int *index, XmDirection *direction); static void DrawLine(Display *d, Window w, Screen **pscreen, int x, int y, _XmStringEntry line, XmRendition *scr_rend, XmRendition base, XmRenderTable rendertable, XmDirection prim_dir, #if NeedWidePrototypes int image, #else Boolean image, #endif /* NeedWidePrototypes */ _XmString *underline, #if NeedWidePrototypes int descender, int opt, int opt_width, int opt_height #else Dimension descender, Boolean opt, Dimension opt_width, Dimension opt_height #endif /* NeedWidePrototypes */ ); static void _calc_align_and_clip( Display *d, GC gc, Position *x, #if NeedWidePrototypes int y, int width, #else Position y, Dimension width, #endif /* NeedWidePrototypes */ int line_width, #if NeedWidePrototypes unsigned int lay_dir, #else unsigned char lay_dir, #endif /* NeedWidePrototypes */ XRectangle *clip, #if NeedWidePrototypes unsigned int align, #else unsigned char align, #endif /* NeedWidePrototypes */ int descender, int *restore) ; static void _draw( Display *d, Window w, XmRenderTable rendertable, _XmString string, GC gc, #if NeedWidePrototypes int x, int y, int width, unsigned int align, unsigned int lay_dir, #else Position x, Position y, Dimension width, unsigned char align, unsigned char lay_dir, #endif /* NeedWidePrototypes */ XRectangle *clip, #if NeedWidePrototypes int image, #else Boolean image, #endif /* NeedWidePrototypes */ _XmString underline) ; static void _render(Display *d, Drawable w, XmRenderTable rendertable, XmRendition rend, _XmString string, #if NeedWidePrototypes int x, int y, int width, unsigned int align, unsigned int lay_dir, int image, #else Position x, Position y, Dimension width, unsigned char align, unsigned char lay_dir, Boolean image, #endif /* NeedWidePrototypes */ _XmString underline, XRectangle *clip); static _XmString _XmStringOptCreate( unsigned char *c, unsigned char *end, #if NeedWidePrototypes unsigned int textlen, int havetag, #else unsigned short textlen, Boolean havetag, #endif /* NeedWidePrototypes */ unsigned int tag_index) ; static void finish_segment(_XmString str, _XmStringUnoptSeg seg, int *lc, int *sc, Boolean *unopt, XmStringDirection dir); static _XmString _XmStringNonOptCreate( unsigned char *c, unsigned char *end, #if NeedWidePrototypes int havetag) ; #else Boolean havetag) ; #endif /* NeedWidePrototypes */ static Boolean SpecifiedSegmentExtents(_XmStringEntry entry, XmRenderTable rendertable, XmRendition *rend_in_out, XmRendition base, int which_seg, Dimension *width, Dimension *height, Dimension *ascent, Dimension *descent); static void ComputeMetrics(XmRendition rend, XtPointer text, unsigned int byte_count, XmTextType type, int which_seg, Dimension *width, Dimension *height, Dimension *ascent, Dimension *descent); static Dimension ComputeWidth(unsigned char which, XCharStruct char_ret); static void _parse_locale( char *str, int *indx, int *len) ; static Boolean match_pattern(XtPointer text, XmStringTag tag, XmTextType type, XmParseMapping pattern, int char_len, Boolean dir_change); static void parse_unmatched(XmString *result, char **ptr, XmTextType text_type, int length); static Boolean parse_pattern(XmString *result, char **ptr, XtPointer text_end, XmStringTag tag, XmTextType type, XmParseMapping pat, int length, XtPointer call_data, Boolean *terminate); static void check_unparse_models(XmStringContext context, XmStringTag tag, XmTextType tag_type, XmParseModel parse_model, Boolean *prev_text_match, Boolean *next_text_match, Boolean *non_text_match); static void unparse_text(char **result, int *length, XmTextType output_type, XmStringComponentType c_type, unsigned int c_length, XtPointer c_value); static Boolean unparse_is_plausible(XmParseMapping pattern); static void unparse_components(char **result, int *length, XmTextType output_type, XmStringContext context, XmParseTable parse_table, Cardinal parse_count); static void begin_context_rends(_XmStringContext context, Boolean update_context, XmStringTag *renditions, int count); static void end_context_rends(_XmStringContext context, Boolean update_context, XmStringTag *rendition, int count); static XFontStruct * GetFont(XmRenderTable rt, _XmStringEntry entry); static _XmStringCache CacheGet(_XmStringEntry entry, int type, int create, XtPointer match_value); static _XmStringEntry EntryCvtToOpt(_XmStringEntry entry); static _XmStringEntry EntryCvtToUnopt(_XmStringEntry entry); static XmString StringTabCreate(void); static XmString StringEmptyCreate(void); static int _get_generate_parse_table (XmParseTable *gen_table); /******** End Static Function Declarations ********/ static struct __Xmlocale locale; static char **_tag_cache; static int _cache_count = 0; /* * Determines whether this string has a short or long length field */ static Boolean _is_short_length( unsigned char *p ) { unsigned char *uchar_p = (unsigned char *) p; uchar_p += ASNHEADERLEN; if (*uchar_p & (char)CSLONGBIT) return (FALSE); else return (TRUE); } /* * Routine that writes a long length field */ static void _write_long_length( unsigned char *p, #if NeedWidePrototypes unsigned int length ) #else unsigned short length ) #endif /* NeedWidePrototypes */ { unsigned char * uchar_p = (unsigned char *) p; /* * flag the long version */ *uchar_p = CSLONGLEN1; uchar_p++; /* * need to pull off the high 8 bits */ *uchar_p = (unsigned char) (length >> 8); uchar_p++; *uchar_p = (unsigned char) (length & 0xff); } /* * Private routines for manipulating the ASN.1 header of external * compound strings. */ static unsigned char * _write_header( unsigned char *p, #if NeedWidePrototypes unsigned int length ) #else unsigned short length ) #endif /* NeedWidePrototypes */ { unsigned char * uchar_p = p; int headlen; /* write the header in. */ headlen = ASNHEADERLEN; memcpy( uchar_p, ASNHeader, ASNHEADERLEN); uchar_p += ASNHEADERLEN; /* short or long length value? */ if (length > MAXSHORTVALUE) { _write_long_length(uchar_p, length); headlen += CSLONGLEN; } else { /* Short version */ *uchar_p = (unsigned char) length; headlen += CSSHORTLEN; } return (p + headlen); } /* * extracts the ASN.1 header from the external compound string. */ static unsigned char * _read_header( unsigned char *p ) { /* * Read past the ASN.1 header; get the first length byte and see if this * is a one or three byte length. */ if (_is_short_length(p)) return (p + ASNHEADERLEN + CSSHORTLEN); else return (p + ASNHEADERLEN + CSLONGLEN); } /* * reads the length the ASN.1 header of an external * compound string. */ static unsigned short _read_header_length( unsigned char *p ) { /* * Get the first length byte and see if this * is a one or three byte length. */ if (_is_short_length(p)) return (ASNHEADERLEN + CSSHORTLEN); else return (ASNHEADERLEN + CSLONGLEN); } /* * calculates the length of the external compound string, excluding the * ASN.1 header. */ static unsigned short _read_string_length( unsigned char *p ) { unsigned char * uchar_p = (unsigned char *) p; unsigned short totallen = 0; /* * Read past the ASN.1 header; get the first length byte and see if this * is a one or three byte length. */ uchar_p += ASNHEADERLEN; if (_is_short_length(p)) { totallen += (unsigned short) *uchar_p; } else { unsigned short i; uchar_p++; i = ((unsigned short) *uchar_p) << 8; uchar_p++; i |= ((unsigned short) *uchar_p); /* Mask on the low byte */ totallen += i; } return (totallen); } /* * calculates length of component marked by a tag-length-value triple. */ static unsigned short _read_asn1_length( unsigned char *p ) { unsigned char * uchar_p = (unsigned char *) p; unsigned short totallen = 0; /* * Read past the tag; get the first length byte and see if this * is a one or three byte length. */ uchar_p += ASNTAG; if (_is_asn1_long(p)) { unsigned short i; uchar_p++; i = ((unsigned short) *uchar_p) << 8; uchar_p++; i |= ((unsigned short) *uchar_p); /* Mask on the low byte */ totallen += i; } else { totallen += (unsigned short) *uchar_p; } return (totallen); } /* * determines length of ASN.1 length field of component of external * compound string. */ static unsigned short _read_length( unsigned char *p ) { /* * Read past the tag field; get the first length byte and see if this * is a one or three byte length. */ if (_is_asn1_long(p)) return ((unsigned short)(ASNTAG + CSLONGLEN)); else return ((unsigned short)(ASNTAG + CSSHORTLEN)); } /* * Private routines for reading/writing the individual compound string * components */ static unsigned char * _write_component( unsigned char *p, #if NeedWidePrototypes unsigned int tag, unsigned int length, #else unsigned char tag, unsigned short length, #endif /* NeedWidePrototypes */ unsigned char *value, #if NeedWidePrototypes int move_by_length ) #else Boolean move_by_length ) #endif /* NeedWidePrototypes */ { unsigned char * uchar_p = p; *uchar_p = tag; /* stuff tag */ uchar_p += ASNTAG; /* short or long length value? */ if (length > MAXSHORTVALUE) { _write_long_length(uchar_p, length); uchar_p += CSLONGLEN; } else { /* Short version */ *uchar_p = (unsigned char) length; uchar_p += CSSHORTLEN; } if (value != (unsigned char *) NULL) memcpy((char *)uchar_p, (char *)value, (size_t)length); if (move_by_length) return (uchar_p + length); else return (uchar_p); } static unsigned char * _read_component( unsigned char *p, unsigned char *tag, unsigned short *length, unsigned char *value) { unsigned char * uchar_p = (unsigned char *) p; *tag = *uchar_p; /* read tag */ *length = _read_asn1_length(p); uchar_p += _read_length(p); /* move to value */ if (value != NULL) memcpy(value, uchar_p, *length); return (uchar_p + *length); } /* Create a new XmString */ XmString XmStringCreate( char *text, XmStringTag tag ) { XmString ret_val; _XmProcessLock(); ret_val = _XmStringNCreate (text, tag, -1); _XmProcessUnlock(); return ret_val; } /* Create a new XmString */ XmString _XmStringNCreate(char *text, XmStringTag tag, int len) { XmString str; char *curtag = NULL; int t_length; unsigned int tag_index = 0; _XmString opt_str; XmTextType type = XmCHARSET_TEXT; if (!text) return ((XmString) NULL); if (!tag) return ((XmString) NULL); t_length = ((len >= 0) ? len : strlen (text)); if ((tag == XmFONTLIST_DEFAULT_TAG) || (strcmp(tag, XmFONTLIST_DEFAULT_TAG) == 0)) { curtag = tag; type = XmMULTIBYTE_TEXT; } else { if ((strcmp(tag, XmSTRING_DEFAULT_CHARSET) == 0)) curtag = _XmStringGetCurrentCharset(); else curtag = tag; } tag_index = _XmStringIndexCacheTag(curtag, XmSTRING_TAG_STRLEN); if ((tag_index < TAG_INDEX_UNSET) && (t_length < (1 << BYTE_COUNT_BITS))) /* Create optimized string. */ { _XmStrCreate(opt_str, XmSTRING_OPTIMIZED, t_length); _XmStrTagIndex(opt_str) = tag_index; _XmStrTextType(opt_str) = type; memcpy(_XmStrText(opt_str), text, t_length); return(opt_str); } else /* Non-optimized */ { _XmStringUnoptSegRec seg; _XmStrCreate(str, XmSTRING_MULTIPLE_ENTRY, 0); _XmEntryInit((_XmStringEntry)&seg, XmSTRING_ENTRY_UNOPTIMIZED); _XmUnoptSegTag(&seg) = _XmStringCacheTag(curtag, XmSTRING_TAG_STRLEN); _XmEntryTextTypeSet(&seg, type); _XmEntryTextSet((_XmStringEntry)&seg, text); _XmUnoptSegByteCount(&seg) = t_length; _XmStringSegmentNew(str, 0, (_XmStringEntry)&seg, True); return(str); } } /* * Convenience routine creating localized XmString from NULL terminated string. */ XmString XmStringCreateLocalized( String text ) { return (XmStringGenerate(text, NULL, XmCHARSET_TEXT, NULL)); } /* Create an optimized _XmString with only direction set. */ XmString XmStringDirectionCreate( #if NeedWidePrototypes int direction ) #else XmStringDirection direction ) #endif /* NeedWidePrototypes */ { /* Maintain a static cache of the common results. */ static XmConst XmStringDirection dir_index[] = { XmSTRING_DIRECTION_L_TO_R, XmSTRING_DIRECTION_R_TO_L, XmSTRING_DIRECTION_UNSET, XmSTRING_DIRECTION_DEFAULT }; static _XmString cache_str[] = { NULL, NULL, NULL, NULL }; int index; _XmString opt_str = NULL; _XmProcessLock(); /* Find the static cache index and string for this direction. */ assert(XtNumber(dir_index) == XtNumber(cache_str)); for (index = 0; index < XtNumber(dir_index); index++) if (dir_index[index] == direction) { opt_str = cache_str[index]; break; } /* Create the return string if necessary and this is a known direction. */ if (!opt_str && (index < XtNumber(dir_index))) { _XmStrCreate(opt_str, XmSTRING_OPTIMIZED, 0); _XmStrDirection(opt_str) = direction; cache_str[index] = opt_str; } /* Try to copy a cached string by incrementing its reference count. */ if ((index < XtNumber(dir_index)) && (_XmStrRefCountInc(opt_str) == 0)) { _XmStrRefCountDec(opt_str); /* Undo previous increment. */ XmStringFree(opt_str); /* Release our cached copy. */ cache_str[index] = NULL; opt_str = XmStringDirectionCreate(direction); _XmProcessUnlock(); return (XmString) opt_str; } _XmProcessUnlock(); return (XmString) opt_str; } /* Create an empty non-optimized _XmString containing a single newline */ XmString XmStringSeparatorCreate( void ) { static _XmString str = NULL; XmString ret_val; _XmProcessLock(); if (!str) { int i; _XmStrCreate(str, XmSTRING_MULTIPLE_ENTRY, 0); _XmStrImplicitLine(str) = True; _XmStrEntry(str) = (_XmStringEntry *)XtMalloc(2*sizeof(_XmStringEntry)); _XmStrEntryCount(str) = 2; for (i = 0; i < 2; i++) { _XmEntryCreate(_XmStrEntry(str)[i], XmSTRING_ENTRY_OPTIMIZED); } } /* If the reference count gets too big free the old string. */ if (_XmStrRefCountInc(str) == 0) { _XmStrRefCountDec(str); /* Undo previous increment. */ XmStringFree(str); /* Release our cached copy. */ str = NULL; ret_val = XmStringSeparatorCreate(); _XmProcessUnlock(); return ret_val; } ret_val = Clone(str, _XmStrEntryCountGet(str)); /* ??? */ _XmProcessUnlock(); return (XmString)ret_val; } /* Create an empty optimized _XmString containing a single tab. */ static XmString StringTabCreate( void ) { static _XmString opt_str = NULL; if (!opt_str) { _XmStrCreate(opt_str, XmSTRING_OPTIMIZED, 0); _XmStrTabs(opt_str) = 1; } /* If the reference count gets too big free the old string. */ if (_XmStrRefCountInc(opt_str) == 0) { _XmStrRefCountDec(opt_str); /* Undo previous increment. */ XmStringFree(opt_str); /* Release our cached copy. */ opt_str = NULL; return StringTabCreate(); } return (XmString)opt_str; } /* Create an empty optimized _XmString. */ static XmString StringEmptyCreate( void ) { static _XmString opt_str = NULL; if (!opt_str) { _XmStrCreate(opt_str, XmSTRING_OPTIMIZED, 0); } /* If the reference count gets too big free the old string. */ if (_XmStrRefCountInc(opt_str) == 0) { _XmStrRefCountDec(opt_str); /* Undo previous increment. */ XmStringFree(opt_str); /* Release our cached copy. */ opt_str = NULL; return StringEmptyCreate(); } return (XmString)opt_str; } /* * this set provides access to the internal components of XmStrings */ /* * set up the read-out context */ Boolean XmStringInitContext( XmStringContext *context, XmString string ) { XmStringContext ct; _XmProcessLock(); /* Initialize the out parameters. */ if (context) *context = NULL; /* make sure there is something in the string. we are going to assume a good string in the get next routine */ if (!(string && context)) { _XmProcessUnlock(); return (FALSE); } ct = (XmStringContext) XtMalloc(sizeof(_XmStringContextRec)); _XmStringContextReInit(ct, string); *context = ct; _XmProcessUnlock(); return (TRUE); } /* * free the read-out context */ void XmStringFreeContext( _XmStringContext context ) { _XmProcessLock(); if (context) { _XmStringContextFree(context); XtFree((char *) context); } _XmProcessUnlock(); } /* * this set is the TCS font list handling stuff */ XmStringTag _XmStringIndexGetTag(int index) { XmStringTag ret_val; _XmProcessLock(); if (index > _cache_count) { _XmProcessUnlock(); return NULL; } ret_val = _tag_cache[index]; _XmProcessUnlock(); return ret_val; } int _XmStringIndexCacheTag(XmStringTag tag, int length ) { char *a; register int i; /* Initialize cache with XmFONTLIST_DEFAULT_TAG, _MOTIF_DEFAULT_LOCALE, and locale.tag if necessary, to keep indices low. */ _XmProcessLock(); if (_cache_count == 0) { _tag_cache = (char **)XtMalloc(sizeof(char **) * 3); _tag_cache[_cache_count] = XmFONTLIST_DEFAULT_TAG; _cache_count++; _tag_cache[_cache_count] = _MOTIF_DEFAULT_LOCALE; _cache_count++; _tag_cache[_cache_count] = _XmStringGetCurrentCharset(); _cache_count++; } /* Look for an existing cache entry. */ for (i = 0; i < _cache_count; i++) { if (((tag == _tag_cache[i]) || ((length != XmSTRING_TAG_STRLEN) && (strncmp(tag, _tag_cache[i], length) == 0)) || ((length == XmSTRING_TAG_STRLEN) && (strcmp(tag, _tag_cache[i]) == 0))) && ((length == XmSTRING_TAG_STRLEN) || (_tag_cache[i][length] == '\0'))) { _XmProcessUnlock(); return( i) ; } } /* Add this entry to the cache. */ if (length == XmSTRING_TAG_STRLEN) length = strlen(tag); _tag_cache = (char **) XtRealloc ((char *) _tag_cache, sizeof (char **) * (_cache_count + 1)); a = XtMalloc (length + 1); memcpy(a, tag, length); a[length] = '\0'; _tag_cache[_cache_count] = a; _cache_count++; _XmProcessUnlock(); return(i) ; } XmStringTag _XmStringCacheTag(XmStringTag tag, int length ) { int tag_index ; XmStringTag ret_val; _XmProcessLock(); if (tag == NULL) { _XmProcessUnlock(); return NULL; } tag_index = _XmStringIndexCacheTag( tag, length) ; ret_val = _tag_cache[tag_index] ; _XmProcessUnlock(); return ret_val; } static Boolean RenditionsCompatible(_XmStringEntry seg1, _XmStringEntry seg2) { int i; XmStringTag *begin1, *begin2, *end1, *end2; short bcnt1, bcnt2, ecnt1, ecnt2, diff; _XmProcessLock(); bcnt1 = _XmEntryRendBeginCountGet(seg1); bcnt2 = _XmEntryRendBeginCountGet(seg2); ecnt1 = _XmEntryRendEndCountGet(seg1); ecnt2 = _XmEntryRendEndCountGet(seg2); begin1 = _XmEntryRendCountedBegins(seg1, bcnt1); begin2 = _XmEntryRendCountedBegins(seg2, bcnt2); end1 = _XmEntryRendCountedEnds(seg1, ecnt1); end2 = _XmEntryRendCountedEnds(seg2, ecnt2); _XmProcessUnlock(); /* if seg1 is optimized, we are very limited in what renditions will be compatible, since there is only one rend_index. */ if (_XmEntryOptimized(seg1) && (((ecnt1 != 0) && (bcnt2 != 0)) || ((bcnt1 > 0) && (bcnt2 > 0)) || ((ecnt1 > 0) && (ecnt2 > 0)) || ((bcnt1 > 0) && (ecnt2 > 0) && (begin1[0] != end2[0])))) return (FALSE); if ((_XmEntryByteCountGet(seg1) == 0) && (ecnt1 == 0)) return(TRUE); if ((_XmEntryByteCountGet(seg2) == 0) && (bcnt2 == 0)) return(TRUE); if ((ecnt1 == 0) && (bcnt2 == 0)) return(TRUE); return(FALSE); } static void MergeEnds(_XmStringEntry a, _XmStringEntry b) { int i; short a_count, b_count; a_count = _XmEntryRendEndCountGet(a); b_count = _XmEntryRendEndCountGet(b); if ((a_count == 0) && (b_count == 0)) return; if (_XmEntryOptimized(a)) { if (a_count == 0 && b_count == 1) { _XmEntryRendIndex(a) = _XmEntryOptimized(b) ? _XmEntryRendIndex(b) : _XmStringIndexCacheTag(_XmEntryRendEndGet(b, 0), XmSTRING_TAG_STRLEN); _XmEntryRendEndCountSet(a, 1); } return; } _XmUnoptSegRendEnds(a) = (XmStringTag *)XtRealloc((char *)_XmUnoptSegRendEnds(a), (sizeof(XmStringTag) * (a_count + b_count))); for (i = 0; i < b_count; i++) _XmUnoptSegRendEnds(a)[(a_count + i)] = _XmEntryRendEndGet(b, i); _XmEntryRendEndCountSet(a, (a_count + b_count)); } static void MergeBegins(_XmStringEntry a, _XmStringEntry b) { XmStringTag *b_begin; short a_b_cnt; short b_b_cnt; int i; a_b_cnt = _XmEntryRendBeginCountGet(a); b_b_cnt = _XmEntryRendBeginCountGet(b); b_begin = _XmEntryRendCountedBegins(b, b_b_cnt); if ((a_b_cnt == 0) && (b_b_cnt == 0)) return; if (_XmEntryOptimized(a)) { if (a_b_cnt == 0 && b_b_cnt == 1) { _XmEntryRendIndex(a) = _XmEntryOptimized(b) ? _XmEntryRendIndex(b) : _XmStringIndexCacheTag(b_begin[0], XmSTRING_TAG_STRLEN); _XmEntryRendBeginCountSet(a, 1); } return; } _XmUnoptSegRendBegins(a) = (XmStringTag *)XtRealloc((char *)_XmUnoptSegRendBegins(a), sizeof(XmStringTag) * (a_b_cnt + b_b_cnt)); for (i = 0; i < b_b_cnt; i++) _XmUnoptSegRendBegins(a)[(a_b_cnt + i)] = _XmEntryRendBeginGet(b, i); _XmEntryRendBeginCountSet(a, (a_b_cnt + b_b_cnt)); } /* * general external TCS utilties */ static Boolean IsUnopt(_XmString str, int lines) { _XmStringEntry line; if (lines > 0) { line = _XmStrEntry(str)[0]; if ((_XmEntrySegmentCountGet(line) > 0) && (_XmEntryType(_XmEntrySegmentGet(line)[0]) != XmSTRING_ENTRY_OPTIMIZED)) return True; } return False; } static _XmStringEntry Unoptimize(_XmStringEntry entry, int free) { _XmStringEntry new_entry = NULL; _XmStringNREntry tmp_seg; int j; if (entry == NULL) return NULL; if (_XmEntryType(entry) == XmSTRING_ENTRY_OPTIMIZED) { new_entry = EntryCvtToUnopt(entry); if (free) _XmStringEntryFree(entry); } else if (_XmEntryMultiple(entry)) { if (free) { for (j = 0; j < _XmEntrySegmentCount(entry); j++) { tmp_seg = _XmEntrySegment(entry)[j]; if (_XmEntryType(tmp_seg) == XmSTRING_ENTRY_OPTIMIZED) { _XmEntrySegment(entry)[j] = (_XmStringNREntry)EntryCvtToUnopt((_XmStringEntry)tmp_seg); _XmStringEntryFree((_XmStringEntry)tmp_seg); } } new_entry = entry; } else { _XmEntryCreate(new_entry, XmSTRING_ENTRY_ARRAY); _XmEntrySegmentCount(new_entry) = _XmEntrySegmentCount(entry); _XmEntrySoftNewlineSet(new_entry, _XmEntrySoftNewlineGet(entry)); _XmEntrySegment(new_entry) = (_XmStringNREntry *)XtMalloc(_XmEntrySegmentCount(entry) * sizeof(_XmStringNREntry)); for (j = 0; j < _XmEntrySegmentCount(entry); j++) { tmp_seg = _XmEntrySegment(entry)[j]; if (_XmEntryType(tmp_seg) == XmSTRING_ENTRY_OPTIMIZED) _XmEntrySegment(new_entry)[j] = (_XmStringNREntry)EntryCvtToUnopt((_XmStringEntry)tmp_seg); else _XmEntrySegment(new_entry)[j] = (_XmStringNREntry)_XmStringEntryCopy((_XmStringEntry)tmp_seg); } } } else { if (free) new_entry = entry; else new_entry = _XmStringEntryCopy(entry); } return new_entry; } XmString XmStringConcat(XmString a, XmString b ) { return XmStringConcatAndFree (XmStringCopy(a), XmStringCopy(b)); } XmString XmStringConcatAndFree(XmString a, XmString b) { _XmString opt_str; unsigned int a_len, b_len, a_lc, b_lc, a_sc, b_sc, lc; unsigned int a_index, b_index, a_rend_index, b_rend_index; unsigned int a_tabs, b_tabs; XmTextType a_type, b_type; XmString a_str, b_str; _XmStringMultiRec b_tmp; _XmStringEntry a_line, b_line, tmp_line, *segs=NULL; _XmStringNREntry a_last, b_seg, tmp_seg; String a_tag; String b_tag; int i, j; int merged = 0; XmStringDirection last = XmSTRING_DIRECTION_UNSET; Boolean modify_a, modify_b, free_b; Boolean a_needs_unopt=False, b_needs_unopt=False; _XmStringArraySegRec array_seg; _XmProcessLock(); if (a == NULL) { _XmProcessUnlock(); return b; } if (b == NULL) { _XmProcessUnlock(); return a; } if ((_XmStrOptimized(a) && _XmStrOptimized(b))) { /* Both optimized */ a_len = _XmStrByteCount(a); b_len = _XmStrByteCount(b); a_index = _XmStrTagIndex(a); b_index = _XmStrTagIndex(b); a_rend_index = _XmStrRendIndex(a); b_rend_index = _XmStrRendIndex(b); a_type = (XmTextType) _XmStrTextType(a); b_type = (XmTextType) _XmStrTextType(b); a_tabs = _XmStrTabs(a); b_tabs = _XmStrTabs(b); if (((a_index == b_index) || (a_index == TAG_INDEX_UNSET) || (b_index == TAG_INDEX_UNSET)) && RenditionsCompatible((_XmStringEntry)a, (_XmStringEntry)b) && ((_XmStrDirection(a) == _XmStrDirection(b)) || (_XmStrDirection(b) == XmSTRING_DIRECTION_UNSET) || ((_XmStrDirection(a) == XmSTRING_DIRECTION_UNSET) && (a_len == 0))) && (a_type == b_type || a_type == XmNO_TEXT || b_type == XmNO_TEXT) && ((a_len + b_len) < (1 << BYTE_COUNT_BITS)) && ((_XmStrText(a) && b_tabs==0) || (!_XmStrText(a) && a_tabs+b_tabs <= 3))) { /* Compatible strings. Make an optimized string. */ if ((b_len == 0) && (_XmStrRefCountGet(a) == 1)) opt_str = (_XmString) a; else if ((a_len == 0) && (_XmStrRefCountGet(b) == 1)) opt_str = (_XmString) b; else _XmStrCreate(opt_str, XmSTRING_OPTIMIZED, a_len + b_len); _XmStrByteCount((_XmString)opt_str) = a_len + b_len; _XmStrTextType((_XmString)opt_str) = (a_type == XmNO_TEXT) ? b_type : a_type; _XmStrTagIndex((_XmString)opt_str) = (a_index == TAG_INDEX_UNSET) ? b_index : a_index; _XmStrRendIndex((_XmString)opt_str) = (a_rend_index == REND_INDEX_UNSET) ? b_rend_index : a_rend_index; /* Push begin and end state. */ _XmStrRendBegin((_XmString)opt_str) = (_XmStrRendBegin(a) ? _XmStrRendBegin(a) : _XmStrRendBegin(b)); _XmStrRendEnd((_XmString)opt_str) = (_XmStrRendEnd(b) ? _XmStrRendEnd(b) : _XmStrRendEnd(a)); _XmStrDirection((_XmString)opt_str) = (_XmStrDirection(a) == XmSTRING_DIRECTION_UNSET) ? _XmStrDirection(b) : _XmStrDirection(a); _XmStrTabs((_XmString)opt_str) = a_tabs+b_tabs; if (a_len && (opt_str != a)) memcpy(_XmStrText((_XmString)opt_str), _XmStrText(a), a_len); if (b_len && (opt_str != b)) memcpy((_XmStrText((_XmString)opt_str) + a_len), _XmStrText(b), b_len); if (opt_str != a) XmStringFree(a); if (opt_str != b) XmStringFree(b); _XmProcessUnlock(); return (XmString)opt_str; } } /* Concatenate non-optimized versions */ a_lc = _XmStrEntryCountGet(a); b_lc = _XmStrEntryCountGet(b); if (_XmStrAddNewline(a)) { if (_XmStrAddNewline(b) && b_lc > 0) lc = a_lc + b_lc - 1; else lc = a_lc; } else { if (_XmStrAddNewline(b)) lc = b_lc ? b_lc : 1; else lc = a_lc + b_lc; } modify_a = !_XmStrOptimized(a) && (_XmStrRefCountGet(a) == 1); if (modify_a) { a_str = a; if (a_lc > 1 && !_XmStrAddNewline(a) && _XmStrAddNewline(b)) { segs = _XmStrEntry(a_str); _XmStrEntry(a_str) = NULL; } _XmStrEntry(a_str) = (_XmStringEntry *) XtRealloc((char*) _XmStrEntry(a_str), sizeof(_XmStringEntry) * lc); for (i = (segs ? 0 : a_lc); i < lc; i++) _XmStrEntry(a_str)[i] = NULL; } else if (_XmStrOptimized(a)) { a_str = _XmStringOptToNonOpt((_XmStringOpt)a); if (a_lc > 1 && !_XmStrAddNewline(a) && _XmStrAddNewline(b)) { segs = _XmStrEntry(a_str); _XmStrEntry(a_str) = NULL; } _XmStrEntry(a_str) = (_XmStringEntry *) XtRealloc((char*) _XmStrEntry(a_str), sizeof(_XmStringEntry) * lc); for (i = (segs ? 0 : a_lc); i < lc; i++) _XmStrEntry(a_str)[i] = NULL; } else { if (a_lc > 1 && !_XmStrAddNewline(a) && _XmStrAddNewline(b)) { segs = _XmStrEntry(a); _XmStrEntry(a) = NULL; _XmStrEntryCount(a) = 0; } a_str = Clone(a, lc); if (a_lc > 1 && !_XmStrAddNewline(a) && _XmStrAddNewline(b)) { _XmStrEntry(a) = segs; _XmStrEntryCount(a) = a_lc; if (segs) { segs = (_XmStringEntry *)XtMalloc(a_lc * sizeof(_XmStringEntry)); for (i = 0; i < a_lc; i++) segs[i] = _XmStringEntryCopy(_XmStrEntry(a)[i]); } } } if (segs) { /* need to move a:s segments down one level */ _XmStringEntry line; _XmEntryCreate(line, XmSTRING_ENTRY_ARRAY); _XmEntrySegmentCount(line) = a_lc; _XmEntrySegment(line) = (_XmStringNREntry *)segs; _XmStrEntry(a_str)[0] = line; _XmStrImplicitLine(a_str) = True; a_lc = 1; } modify_b = !_XmStrOptimized(b) && (_XmStrRefCountGet(b) == 1); free_b = True; if (modify_b) b_str = b; else if (_XmStrOptimized(b)) { #ifndef _XmDEBUG_XMSTRING_MEM /* This won't work in that case - _XmStrMalloc adds bytes at the beginning */ if (_XmStrRefCountGet(b) == 1) { /* * An optimized XmString looks very much like an * optimized segment. In this case we can use the * optimized XmString as the segment with a little * of poking around in the last byte of the header. * This saves us from allocating a new string, which * will get free:d anyway. */ b_str = (XmString)&b_tmp; _XmStrInit(b_str, XmSTRING_MULTIPLE_ENTRY); _XmStrEntryCount(b_str) = 1; _XmStrRefCountSet(b, 0); _XmEntryTabsSet(b, _XmStrTabs(b)); _XmEntryImm(b) = 1; if (_XmStrText(b) != (char *)_XmEntryTextGet((_XmStringEntry)b)) { /* If the XtPointer in the union in the * optimized segment leads to padding in the structure * between the header and the text data * (it will on some 64-bit architectures) we have * to move the text data, since the optimized * string does not have this padding. */ unsigned int size = sizeof(_XmStringOptSegRec); if (_XmStrByteCount(b) > sizeof(XtPointer)) size += _XmStrByteCount(b) - sizeof(XtPointer); b = (XmString)XtRealloc((char *)b, size); memmove(_XmEntryTextGet((_XmStringEntry)b), _XmStrText(b), _XmStrByteCount(b)); } _XmStrEntry(b_str) = (_XmStringEntry *)&b; free_b = False; } else { #endif b_str = _XmStringOptToNonOpt((_XmStringOpt)b); XmStringFree(b); #ifndef _XmDEBUG_XMSTRING_MEM } #endif modify_b = TRUE; } else b_str = b; assert((a != b) || (!modify_a && !modify_b)); /* convert a to unopt segs if necessary */ a_needs_unopt = IsUnopt(a_str, a_lc); if (!a_needs_unopt) { b_needs_unopt = IsUnopt(b_str, _XmStrEntryCount(b_str)); if (b_needs_unopt) for (i = 0; i < a_lc; i++) _XmStrEntry(a_str)[i] = Unoptimize(_XmStrEntry(a_str)[i], True); } _XmStrEntryCount(a_str) = lc; _XmStrImplicitLine(a_str) = _XmStrImplicitLine(a_str) || _XmStrImplicitLine(b_str); /* Add first line of b_str to last line of a_str */ a_line = _XmStrEntry(a_str)[a_lc - 1]; if (_XmStrImplicitLine(b_str)) { b_line = _XmStrEntry(b_str)[0]; } else { _XmEntryType(&array_seg) = XmSTRING_ENTRY_ARRAY; _XmEntrySegmentCount(&array_seg) = _XmStrEntryCount(b_str); _XmEntrySegment(&array_seg) = (_XmStringNREntry *)_XmStrEntry(b_str); b_line = (_XmStringEntry)&array_seg; b_lc = 1; } a_sc = _XmEntrySegmentCountGet(a_line); b_sc = _XmEntrySegmentCountGet(b_line); if ((a_sc != 0) && (b_sc != 0)) { /* Need to combine last segment of a with first of b if compatible. */ a_last = _XmEntrySegmentGet(a_line)[a_sc - 1]; b_seg = _XmEntrySegmentGet(b_line)[0]; a_len = _XmEntryByteCountGet((_XmStringEntry)a_last); b_len = _XmEntryByteCountGet((_XmStringEntry)b_seg); /* Remember last direction set. */ last = _XmEntryDirectionGet((_XmStringEntry)a_last); a_tag = _XmEntryTag((_XmStringEntry)a_last); b_tag = _XmEntryTag((_XmStringEntry)b_seg); a_type = (XmTextType) _XmEntryTextTypeGet((_XmStringEntry)a_last); b_type = (XmTextType) _XmEntryTextTypeGet((_XmStringEntry)b_seg); a_tabs = _XmEntryTabsGet((_XmStringEntry)a_last); b_tabs = _XmEntryTabsGet((_XmStringEntry)b_seg); merged = 0; if (((a_tag == b_tag) || (a_tag == NULL) || (b_tag == NULL)) && RenditionsCompatible((_XmStringEntry)a_last, (_XmStringEntry)b_seg) && (a_type == b_type || a_type == XmNO_TEXT || b_type == XmNO_TEXT) && ((last == _XmEntryDirectionGet((_XmStringEntry)b_seg)) || (_XmEntryDirectionGet((_XmStringEntry)b_seg) == XmSTRING_DIRECTION_UNSET) || ((last == XmSTRING_DIRECTION_UNSET) && (a_len == 0))) && !_XmEntryPopGet((_XmStringEntry)a_last) && !_XmEntryPushGet((_XmStringEntry)b_seg) && (((a_len != 0) && b_tabs==0) || ((a_len == 0) && a_tabs+b_tabs <= 7))) { if (b_len) { if ((_XmEntryType(a_last) == XmSTRING_ENTRY_OPTIMIZED) && _XmEntryImm(a_last)) { unsigned int size = sizeof(_XmStringOptSegRec); if (a_len + b_len > sizeof(XtPointer)) size += a_len + b_len - sizeof(XtPointer); if (a_line == (_XmStringEntry)a_last) { a_last = (_XmStringNREntry)XtRealloc((char *)a_last, size); _XmStrEntry(a_str)[a_lc - 1] = a_line = (_XmStringEntry)a_last; } else _XmEntrySegmentGet(a_line)[a_sc-1] = a_last = (_XmStringNREntry)XtRealloc((char *)a_last, size); } else { _XmEntryTextSet((_XmStringEntry)a_last, XtRealloc((char *) _XmEntryTextGet((_XmStringEntry)a_last), a_len + b_len)); } } if (_XmEntryOptimized(a_last)) _XmEntryTagIndex(a_last) = ((a_tag == NULL) ? (b_tag == NULL ? TAG_INDEX_UNSET : _XmStringIndexCacheTag(b_tag, XmSTRING_TAG_STRLEN)) : _XmEntryTagIndex(a_last)); else _XmUnoptSegTag(a_last) = (a_tag == NULL) ? b_tag : a_tag; /* Fixup rendition begins and ends */ if (a_len == 0) MergeBegins((_XmStringEntry)a_last, (_XmStringEntry)b_seg); if (_XmEntryRendEnds((_XmStringEntry)a_last) == NULL) { if (_XmEntryOptimized(a_last) && _XmEntryRendEndCountGet((_XmStringEntry)b_seg) > 0) { b_tag = _XmEntryRendEndGet((_XmStringEntry)b_seg, 0); _XmEntryRendIndex(a_last) = _XmStringIndexCacheTag(b_tag, XmSTRING_TAG_STRLEN); } if (!_XmEntryOptimized(a_last) && (_XmEntryRendEndCountGet((_XmStringEntry)b_seg) != 0)) if (_XmEntryOptimized(b_seg)) { _XmUnoptSegRendEnds(a_last) = (XmStringTag *)XtMalloc(sizeof(XmStringTag)); _XmUnoptSegRendEnds(a_last)[0] = _XmEntryRendEndGet((_XmStringEntry)b_seg, 0); } else if (modify_b) { _XmUnoptSegRendEnds(a_last) = _XmUnoptSegRendEnds(b_seg); } else { int end_count = _XmEntryRendEndCountGet((_XmStringEntry)b_seg); int k; _XmUnoptSegRendEnds(a_last) = (XmStringTag *)XtMalloc(end_count * sizeof(XmStringTag)); for (k = 0; k < end_count; k++) _XmUnoptSegRendEnds(a_last)[k] = _XmUnoptSegRendEnds(b_seg)[k]; } _XmEntryRendEndCountSet (a_last, _XmEntryRendEndCountGet((_XmStringEntry)b_seg)); } else MergeEnds((_XmStringEntry)a_last, (_XmStringEntry)b_seg); _XmEntryTextTypeSet(a_last, (a_type == XmNO_TEXT) ? b_type : a_type); memcpy(((char *)_XmEntryTextGet((_XmStringEntry)a_last)) + a_len, _XmEntryTextGet((_XmStringEntry)b_seg), b_len); _XmEntryByteCountSet(a_last, a_len + b_len); _XmEntryTabsSet(a_last, a_tabs+b_tabs); if (last == XmSTRING_DIRECTION_UNSET) _XmEntryDirectionSet((_XmStringEntry)a_last, _XmEntryDirectionGet((_XmStringEntry)b_seg)); _XmEntryPopSet(a_last, _XmEntryPopGet((_XmStringEntry)b_seg)); if (modify_b) { /* Free leftover bits of b_seg */ if (_XmEntryUnoptimized(b_seg)) { if (_XmEntryOptimized(a_last) || (_XmUnoptSegRendBegins(a_last) != _XmUnoptSegRendBegins(b_seg))) XtFree((char *)_XmUnoptSegRendBegins(b_seg)); if (_XmEntryOptimized(a_last) || (_XmUnoptSegRendEnds(a_last) != _XmUnoptSegRendEnds(b_seg))) XtFree((char *)_XmUnoptSegRendEnds(b_seg)); } if ( ! ((_XmEntryType(b_seg) == XmSTRING_ENTRY_OPTIMIZED) && _XmEntryImm(b_seg))) XtFree((char*)_XmEntryTextGet((_XmStringEntry)b_seg)); XtFree((char *)b_seg); } merged = 1; } } else /* Need to figure out last direction set. */ { for (i = a_lc; i > 0; i--) { tmp_line = _XmStrEntry(a_str)[i - 1]; for (j = _XmEntrySegmentCountGet(tmp_line); j > 0; j--) { tmp_seg = _XmEntrySegmentGet(tmp_line)[j - 1]; if (_XmEntryDirectionGet((_XmStringEntry)tmp_seg) != XmSTRING_DIRECTION_UNSET) { last = _XmEntryDirectionGet((_XmStringEntry)tmp_seg); break; } } if (last != XmSTRING_DIRECTION_UNSET) break; } } if (merged && !_XmStrImplicitLine(a_str)) _XmStrEntryCount(a_str)--; if (b_sc - merged > 0 && _XmStrImplicitLine(a_str)) { Boolean free_b_line = (modify_b && _XmEntryMultiple(b_line) && ((_XmStringEntry)b_seg != b_line)); if (_XmEntryMultiple(a_line)) { _XmEntrySegment(a_line) = (_XmStringNREntry *)XtRealloc((char *)_XmEntrySegment(a_line), sizeof(_XmStringNREntry) * (a_sc + b_sc - merged)); _XmEntrySegmentCount(a_line) = a_sc + b_sc - merged; } else { _XmEntryCreate(a_line, XmSTRING_ENTRY_ARRAY); _XmEntrySegmentCount(a_line) = a_sc + b_sc - merged; _XmEntrySegment(a_line) = (_XmStringNREntry *)XtMalloc(sizeof(_XmStringNREntry) * (a_sc + b_sc - merged)); _XmEntrySegment(a_line)[0] = (_XmStringNREntry)_XmStrEntry(a_str)[a_lc - 1]; _XmStrEntry(a_str)[a_lc - 1] = a_line; _XmStrImplicitLine(a_str) = True; } for (i = 0; i < (b_sc - merged); i++) { b_seg = _XmEntrySegmentGet(b_line)[i + merged]; if (a_needs_unopt && !b_needs_unopt) b_seg = (_XmStringNREntry)Unoptimize((_XmStringEntry)b_seg,modify_b); else if (!modify_b) b_seg = (_XmStringNREntry)_XmStringEntryCopy((_XmStringEntry)b_seg); if (_XmEntryDirectionGet((_XmStringEntry)b_seg) == XmSTRING_DIRECTION_UNSET) _XmEntryDirectionSet((_XmStringEntry)b_seg, last); else last = _XmEntryDirectionGet((_XmStringEntry)b_seg); _XmEntrySegment(a_line)[i + a_sc] = b_seg; } if (free_b_line) { if (_XmEntrySegment(b_line) != (_XmStringNREntry *)&b && _XmEntrySegment(b_line) != (_XmStringNREntry *)_XmStrEntry(b_str)) XtFree((char *)_XmEntrySegment(b_line)); if (b_line != (_XmStringEntry)&array_seg) XtFree((char *)b_line); } } else if (b_sc - merged > 0 && !_XmStrImplicitLine(a_str)) { for (i = 0; i < (b_sc - merged); i++) { b_line = _XmStrEntry(b_str)[i + merged]; if (a_needs_unopt && !b_needs_unopt) _XmStrEntry(a_str)[a_lc] = Unoptimize(b_line, modify_b); else if (modify_b) _XmStrEntry(a_str)[a_lc] = b_line; else _XmStrEntry(a_str)[a_lc] = _XmStringEntryCopy(b_line); a_lc++; } } /* Add rest of b's lines to a */ for (i = 0; i < (b_lc - 1); i++) { b_line = _XmStrEntry(b_str)[i + 1]; if (a_needs_unopt && !b_needs_unopt) b_line = Unoptimize(b_line, modify_b); else if (!modify_b) b_line = _XmStringEntryCopy(b_line); b_sc = _XmEntrySegmentCountGet(b_line); for (j = 0; j < b_sc; j++) { b_seg = _XmEntrySegmentGet(b_line)[j]; if (_XmEntryDirectionGet((_XmStringEntry)b_seg) == XmSTRING_DIRECTION_UNSET) _XmEntryDirectionSet((_XmStringEntry)b_seg, last); else break; } _XmStrEntry(a_str)[i + a_lc] = b_line; } if (modify_b && free_b) { /* Free leftover bits of b_str. */ XtFree((char *)_XmStrEntry(b_str)); _XmStrFree ((char *)b_str); } /* Set layout cache dirty */ if (a_str && _XmStrEntryCount(a_str) > 0 ) { tmp_line = _XmStrEntry(a_str)[0]; if (tmp_line && _XmEntrySegmentCountGet(tmp_line) > 0) { _XmStringCache cache; tmp_seg = _XmEntrySegmentGet(tmp_line)[0]; for (cache = _XmStringCacheGet(_XmEntryCacheGet((_XmStringEntry)tmp_seg), _XmSCANNING_CACHE); cache; cache = _XmStringCacheGet(cache->next, _XmSCANNING_CACHE)) _XmCacheDirty(cache) = True; } } if (!modify_a) XmStringFree(a); if (!modify_b) XmStringFree(b); _XmProcessUnlock(); return (XmString)a_str; } /************************************************************************ * * * XmStringCompare - compare two strings. * * * * Returns TRUE if the strings are equal, FALSE o.w. * * * ************************************************************************/ Boolean XmStringCompare( XmString a, XmString b ) { _XmProcessLock(); if ((a == NULL) && (b == NULL)) { _XmProcessUnlock(); return TRUE; } if ((a == NULL) || (b == NULL)) { _XmProcessUnlock(); return FALSE; } if (_XmStrOptimized(a)) { if (!((_XmStrTagGet(a) == _XmStrTagGet(b)) || (_XmStrTagGet(a) == NULL) || (_XmStrTagGet(b) == NULL) || ((strcmp(_XmStrTagGet(a), XmFONTLIST_DEFAULT_TAG) == 0) && _XmStringIsCurrentCharset(_XmStrTagGet(b))) || ((strcmp(_XmStrTagGet(b), XmFONTLIST_DEFAULT_TAG) == 0) && _XmStringIsCurrentCharset(_XmStrTagGet(a))))) { _XmProcessUnlock(); return (FALSE); } if (_XmStrByteCount(a) != _XmStrByteCount(b)) { _XmProcessUnlock(); return (FALSE); } if ((_XmStrDirection(a) != _XmStrDirection(b)) && (((_XmStrDirection(a) == XmSTRING_DIRECTION_UNSET) && (_XmStrDirection(b) != XmSTRING_DIRECTION_L_TO_R)) || ((_XmStrDirection(b) == XmSTRING_DIRECTION_UNSET) && (_XmStrDirection(a) != XmSTRING_DIRECTION_L_TO_R)))) { _XmProcessUnlock(); return (FALSE); } if (strncmp(_XmStrText(a), _XmStrText(b), _XmStrByteCount(a)) != 0) { _XmProcessUnlock(); return (FALSE); } } else { int i, j; _XmStringEntry *entry_a = _XmStrEntry(a); _XmStringEntry *entry_b = _XmStrEntry(b); if (_XmStrEntryCount(a) != _XmStrEntryCount(b)) { _XmProcessUnlock(); return (FALSE); } for (i = 0; i < _XmStrEntryCount(a); i++) { if (_XmEntryMultiple(entry_a[i]) && _XmEntryMultiple(entry_b[i])) { if (_XmEntrySegmentCount(entry_a[i]) != _XmEntrySegmentCount(entry_b[i])) { _XmProcessUnlock(); return (FALSE); } for (j=0; j<_XmEntrySegmentCount(entry_a[i]); j++) { _XmStringNREntry a_seg = _XmEntrySegment(entry_a[i])[j]; _XmStringNREntry b_seg = _XmEntrySegment(entry_b[i])[j]; unsigned int len; XmStringTag a_tag = _XmEntryTag((_XmStringEntry)a_seg); XmStringTag b_tag = _XmEntryTag((_XmStringEntry)b_seg); if (!((a_tag == b_tag) || (a_tag == NULL) || (b_tag == NULL) || ((strcmp(a_tag, XmFONTLIST_DEFAULT_TAG) == 0) && _XmStringIsCurrentCharset(b_tag)) || ((strcmp(b_tag, XmFONTLIST_DEFAULT_TAG) == 0) && _XmStringIsCurrentCharset(a_tag)))) { _XmProcessUnlock(); return (FALSE); } len = _XmEntryByteCountGet((_XmStringEntry)a_seg); if (len != _XmEntryByteCountGet((_XmStringEntry)b_seg)) { _XmProcessUnlock(); return (FALSE); } { unsigned int a_dir = _XmEntryDirectionGet((_XmStringEntry)a_seg); unsigned int b_dir = _XmEntryDirectionGet((_XmStringEntry)b_seg); if ((a_dir != b_dir) && (((a_dir == XmSTRING_DIRECTION_UNSET) && (b_dir != XmSTRING_DIRECTION_L_TO_R)) || ((b_dir == XmSTRING_DIRECTION_UNSET) && (a_dir != XmSTRING_DIRECTION_L_TO_R)))) { _XmProcessUnlock(); return (FALSE); } } if (strncmp ((char*)_XmEntryTextGet((_XmStringEntry)a_seg), (char*)_XmEntryTextGet((_XmStringEntry)b_seg), len) != 0) { _XmProcessUnlock(); return (FALSE); } } } else if (!_XmEntryMultiple(entry_a[i]) && !_XmEntryMultiple(entry_b[i])) { unsigned int len; if (!((_XmEntryTag(entry_a[i]) == _XmEntryTag(entry_b[i])) || (_XmEntryTag(entry_a[i]) == NULL) || (_XmEntryTag(entry_b[i]) == NULL) || ((strcmp(_XmEntryTag(entry_a[i]), XmFONTLIST_DEFAULT_TAG) == 0) && _XmStringIsCurrentCharset(_XmEntryTag(entry_b[i]))) || ((strcmp(_XmEntryTag(entry_b[i]), XmFONTLIST_DEFAULT_TAG) == 0) && _XmStringIsCurrentCharset(_XmEntryTag(entry_a[i]))))) { _XmProcessUnlock(); return (FALSE); } len = _XmEntryByteCountGet(entry_a[i]); if (len != _XmEntryByteCountGet(entry_b[i])) { _XmProcessUnlock(); return (FALSE); } if ((_XmEntryDirectionGet(entry_a[i]) != _XmEntryDirectionGet(entry_b[i])) && (((_XmEntryDirectionGet(entry_a[i]) == XmSTRING_DIRECTION_UNSET) && (_XmEntryDirectionGet(entry_b[i]) != XmSTRING_DIRECTION_L_TO_R)) || ((_XmEntryDirectionGet(entry_b[i]) == XmSTRING_DIRECTION_UNSET) && (_XmEntryDirectionGet(entry_a[i]) != XmSTRING_DIRECTION_L_TO_R)))) { _XmProcessUnlock(); return (FALSE); } if (strncmp ((char*) _XmEntryTextGet(entry_a[i]), (char*) _XmEntryTextGet(entry_b[i]), len) != 0) { _XmProcessUnlock(); return (FALSE); } } else { _XmProcessUnlock(); return (FALSE); } } } _XmProcessUnlock(); return (TRUE); } int XmStringLength( XmString string ) { unsigned int len; if (!string) return (0); if (!XmeStringIsValid(string)) return (0); len = XmCvtXmStringToByteStream(string, NULL); return((int)len); } /************************************************************************ * * * XmeStringIsXmString - returns TRUE if the parameter is an XmString. * * * ************************************************************************/ Boolean XmeStringIsValid( XmString string ) { if (string == NULL) return(FALSE); return(TRUE); } /* * determines from ASN.1 header whether this is an ASN.1 conformant * external compound string. Returns T or F. */ static Boolean _is_asn1( unsigned char *string ) { unsigned char *uchar_p = string; /* Compare the ASN.1 header. */ return (strncmp ((char *)uchar_p, (char *)ASNHeader, ASNHEADERLEN) == 0); } /* * optimized internal TCS structure handling routines */ /* * find the ascender for the given optimized line */ static Dimension OptLineAscender( XmRenderTable f, _XmStringOpt opt ) { Dimension width, height, ascent, descent; OptLineMetrics(f, (_XmString)opt, NULL, NULL, &width, &height, &ascent, &descent); return(ascent); } int _XmConvertFactor(unsigned char units, float *factor) { switch (units) { case XmINCHES: *factor = 1000.0; return(Xm1000TH_INCHES); case XmCENTIMETERS: *factor = 1000.0; return(Xm100TH_MILLIMETERS); case XmMILLIMETERS: *factor = 100.0; return(Xm100TH_MILLIMETERS); case XmPOINTS: *factor = 100.0; return(Xm100TH_POINTS); case XmFONT_UNITS: *factor = 100.0; return(Xm100TH_FONT_UNITS); default: *factor = 1.0; return(units); } } static int TabVal(Display *d, Screen **pscreen, Window w, XmTab tab) { int fromType; int intValue; float multiplier, convertValue; fromType = _XmConvertFactor(_XmTabUnits(tab), &multiplier); convertValue = multiplier * _XmTabValue(tab); /* error */ if (((convertValue < 0.0) ? -convertValue : convertValue) > (float)INT_MAX) return(0); convertValue += (convertValue > 0.0) ? 0.5 : -0.5; intValue = convertValue; /* * The pscreen storage should be pushed higher; we may still make * several round trips to the server to draw a single string??? */ /* All we really want is the screen, but we may only have a drawable. */ assert(w || *pscreen); if (*pscreen == NULL) { Widget widget = XtWindowToWidget(d, w); /* If this drawable is really a widget Xt will have cached it. */ if (widget) *pscreen = XtScreenOfObject(widget); else { /* Give up and ask the server. */ XWindowAttributes attr; XGetWindowAttributes(d, w, &attr); *pscreen = attr.screen; } } return _XmConvertUnits(*pscreen, XmHORIZONTAL, fromType, intValue, XmPIXELS); } /* * Find width, height, ascent and descent for the given optimized line. */ static void OptLineMetrics(XmRenderTable r, _XmString opt, XmRendition *rend_io, XmRendition base_rend, Dimension *width, Dimension *height, Dimension *ascent, Dimension *descent) { short rend_index; XmRendition rend = NULL; XmStringTag tags[1]; Display *d; Screen *screen; int prev_val, val, i, ref_cnt, rt_ref_cnt; XmTabList tl = NULL; XmTab tab; unsigned short tab_cnt; Dimension tab_w = 0; _XmRendition rend_int; /* compute rendition */ /* Find font as per I 198. */ /* 1. Find font from rendition tags. */ /* 2. Find font from locale/charset tag. */ if (base_rend == NULL) { if (_XmStrRendBegin(opt)) rend = _XmRenderTableFindRendition(r, _XmStrRendTagGet(opt), TRUE, FALSE, TRUE, &rend_index); if ((rend == NULL) || (_XmRendFont(rend) == NULL)) rend = _XmRenderTableFindRendition(r, _XmStrTagGet(opt), TRUE, FALSE, TRUE, &rend_index); } else { if (_XmStrRendBegin(opt)) { tags[0] = _XmStrRendTagGet(opt); rend = _XmRenditionMerge(_XmRendDisplay(base_rend), rend_io, base_rend, r, _XmStrTagGet(opt), tags, 1, FALSE); } else { rend = _XmRenditionMerge(_XmRendDisplay(base_rend), rend_io, base_rend, r, _XmStrTagGet(opt), NULL, 0, FALSE); } } /* 3. Default rendition. */ if ((rend == NULL) || (_XmRendFont(rend) == NULL)) { tags[0] = ((_XmStrTextType(opt) == XmCHARSET_TEXT) ? XmFONTLIST_DEFAULT_TAG : _MOTIF_DEFAULT_LOCALE); rend = _XmRenderTableFindRendition(r, tags[0], TRUE, FALSE, FALSE, NULL); if ((rend != NULL) && (_XmRendFont(rend) == NULL) && (((base_rend != NULL) && (_XmRendDisplay(base_rend) != NULL)) || (_XmRendDisplay(rend) != NULL))) /* Call noFontCallback. */ { XmDisplay dsp; XmDisplayCallbackStruct cb; rt_ref_cnt = _XmRTRefcount(r); rend = _XmRTRenditions(r)[0]; rend_int = *rend; ref_cnt = _XmRendRefcount(rend); if ((base_rend != NULL) && (_XmRendDisplay(base_rend) != NULL)) dsp = (XmDisplay)XmGetXmDisplay(_XmRendDisplay(base_rend)); else dsp = (XmDisplay)XmGetXmDisplay(_XmRendDisplay(rend)); cb.reason = XmCR_NO_FONT; cb.event = NULL; cb.rendition = rend; cb.font_name = XmS; XtCallCallbackList((Widget)dsp, dsp->display.noFontCallback, &cb); if (rend_int != *rend) /* Changed in callback. */ { /* Need to split ref counts. */ _XmRendRefcount(&rend_int) = ref_cnt - rt_ref_cnt; _XmRendRefcount(rend) = rt_ref_cnt; } if (_XmRendFont(rend) == NULL) rend = NULL; } /* 4a. Take the first one */ if ((rend == NULL) && ((_XmStrTextType(opt) == XmCHARSET_TEXT) || ((_XmStrTextType(opt) == XmMULTIBYTE_TEXT) && (_XmStrTagGet(opt) == XmFONTLIST_DEFAULT_TAG))) && (r != NULL) && (_XmRTCount(r) > 0)) _XmRenderTableFindFirstFont(r, &rend_index, &rend); if ((rend != NULL) &&(_XmRendFont(rend) == NULL) && (((base_rend != NULL) && (_XmRendDisplay(base_rend) != NULL)) || (_XmRendDisplay(rend) != NULL))) /* Call noFontCallback. */ { XmDisplay dsp; XmDisplayCallbackStruct cb; rt_ref_cnt = _XmRTRefcount(r); rend = _XmRTRenditions(r)[0]; rend_int = *rend; ref_cnt = _XmRendRefcount(rend); if ((base_rend != NULL) && (_XmRendDisplay(base_rend) != NULL)) dsp = (XmDisplay)XmGetXmDisplay(_XmRendDisplay(base_rend)); else dsp = (XmDisplay)XmGetXmDisplay(_XmRendDisplay(rend)); cb.reason = XmCR_NO_FONT; cb.event = NULL; cb.rendition = rend; cb.font_name = XmS; XtCallCallbackList((Widget)dsp, dsp->display.noFontCallback, &cb); if (rend_int != *rend) /* Changed in callback. */ { /* Need to split ref counts. */ _XmRendRefcount(&rend_int) = ref_cnt - rt_ref_cnt; _XmRendRefcount(rend) = rt_ref_cnt; } if (_XmRendFont(rend) == NULL) rend = NULL; } /* 4b/5a. Emit warning and don't render. */ if ((rend == NULL) || (_XmRendFont(rend) == NULL)) { /* Don't emit warning if no tags, e.g. just a dir component. */ if (_XmStrRendBegin(opt) || (_XmStrTagGet(opt) != NULL)) XmeWarning(NULL, NO_FONT_MSG); if ((base_rend != NULL) && (rend_io == NULL)) XmRenditionFree(rend); rend = NULL; return; } else if (rend_io != NULL) { _XmRendFont(*rend_io) = _XmRendFont(rend); _XmRendFontName(*rend_io) = _XmRendFontName(rend); _XmRendFontType(*rend_io) = _XmRendFontType(rend); } } /* Use the raster extent for a single line. */ if (rend != NULL) ComputeMetrics(rend, (XtPointer)_XmStrText(opt), _XmStrByteCount(opt), (XmTextType) _XmStrTextType(opt), XmSTRING_SINGLE_SEG, width, height, ascent, descent); if (rend != NULL) tl = _XmRendTabs(rend); d = (_XmRTDisplay(r) == NULL) ? _XmGetDefaultDisplay() : _XmRTDisplay(r); screen = XtScreenOfObject(XmGetXmDisplay(d)); tab = ((tl == NULL) || ((long)tl == XmAS_IS)) ? NULL : _XmTabLStart(tl); prev_val = 0; tab_cnt = 0; /* If this string is tabbed, set width accordingly. */ if ((tab != NULL) && (_XmStrTabs(opt) != 0) && (tab_cnt < _XmTabLCount(tl))) { for (i = 0; (i < _XmStrTabs(opt)) && (tab_cnt < _XmTabLCount(tl)); tab = _XmTabNext(tab), tab_cnt++, i++) { val = TabVal(d, &screen, None, tab); if (_XmTabModel(tab) == XmABSOLUTE) { tab_w = val; prev_val = val; } else /* XmRELATIVE */ { tab_w = prev_val + val; prev_val += val; } } } (*width) += tab_w; if ((base_rend != NULL) && (rend_io == NULL)) XmRenditionFree(rend); } /* * internal TCS structure handling routines */ /* * find biggest ascender and descender and width and height in this line */ static void LineMetrics(_XmStringEntry line, XmRenderTable r, XmRendition *rend_io, XmRendition base, XmDirection prim_dir, Dimension *width, Dimension *height, Dimension *ascender, Dimension *descender) { int i, seg_index = 0; Dimension w, tab_w = 0, h, max_h = 0, asc, max_asc = 0, dsc, max_dsc = 0; Display *d; Screen *screen; int prev_val, val; XmTabList tl = NULL; XmTab tab; unsigned short tab_cnt; _XmStringNREntry seg, peek_seg; XmDirection lay_dir; Boolean set_direction = FALSE; d = _XmRendDisplay(*rend_io); screen = XtScreenOfObject(XmGetXmDisplay(d)); seg = _XmEntrySegmentGet(line)[seg_index]; if (_XmEntryType(seg) != XmSTRING_ENTRY_OPTIMIZED) { lay_dir = _XmEntryLayoutGet(seg, prim_dir); if (XmDirectionMatch(lay_dir, XmLEFT_TO_RIGHT)) { while (_XmEntryLeftGet(seg, prim_dir) != NULL) seg = (_XmStringNREntry)_XmEntryLeftGet(seg, prim_dir); peek_seg = (_XmStringNREntry)_XmEntryRightGet(seg, prim_dir); } else { while (_XmEntryRightGet(seg, prim_dir) != NULL) seg = (_XmStringNREntry)_XmEntryRightGet(seg, prim_dir); peek_seg = (_XmStringNREntry)_XmEntryLeftGet(seg, prim_dir); } } else { peek_seg = ((seg_index + 1) < _XmEntrySegmentCountGet(line) ? _XmEntrySegmentGet(line)[seg_index + 1] : NULL); } if (_XmEntryDirectionGet((_XmStringEntry)seg) == XmSTRING_DIRECTION_UNSET) { _XmEntryDirectionSet((_XmStringEntry)seg, XmDirectionToStringDirection(prim_dir)); set_direction = True; } if (peek_seg != NULL) (void)SpecifiedSegmentExtents((_XmStringEntry)seg, r, rend_io, base, XmSTRING_FIRST_SEG, &w, &h, &asc, &dsc); else (void)SpecifiedSegmentExtents((_XmStringEntry)seg, r, rend_io, base, XmSTRING_SINGLE_SEG, &w, &h, &asc, &dsc); if (*rend_io != NULL) tl = _XmRendTabs(*rend_io); tab = ((tl == NULL) || ((long)tl == XmAS_IS)) ? NULL : _XmTabLStart(tl); prev_val = 0; tab_cnt = 0; while (seg != NULL) { /* If this segment is tabbed, set width accordingly. */ if ((tab != NULL) && (_XmEntryTabsGet((_XmStringEntry)seg) != 0) && (tab_cnt < _XmTabLCount(tl))) { for (i = 0; (i < _XmEntryTabsGet((_XmStringEntry)seg)) && (tab_cnt < _XmTabLCount(tl)); i++, tab = _XmTabNext(tab), tab_cnt++) { val = TabVal(d, &screen, None, tab); if (_XmTabModel(tab) == XmABSOLUTE) tab_w = MAX(tab_w, val); else /* XmRELATIVE */ tab_w = MAX(tab_w, prev_val + val); prev_val = tab_w; } } tab_w += w; if (h > max_h) max_h = h; if (asc > max_asc) max_asc = asc; if (dsc >max_dsc) max_dsc = dsc; if (set_direction) { _XmEntryDirectionSet((_XmStringEntry)seg, XmSTRING_DIRECTION_UNSET); set_direction = False; } if (_XmEntryType(seg) != XmSTRING_ENTRY_OPTIMIZED) { if (XmDirectionMatch(lay_dir, XmLEFT_TO_RIGHT)) { seg = (_XmStringNREntry)_XmEntryRightGet(seg, prim_dir); peek_seg = (_XmStringNREntry)_XmEntryRightGet(seg, prim_dir); } else { seg = (_XmStringNREntry)_XmEntryLeftGet(seg, prim_dir); peek_seg = (_XmStringNREntry)_XmEntryLeftGet(seg, prim_dir); } } else { seg_index++; seg = (seg_index < _XmEntrySegmentCountGet(line) ? _XmEntrySegmentGet(line)[seg_index] : NULL); peek_seg = ((seg_index + 1) < _XmEntrySegmentCountGet(line) ? _XmEntrySegmentGet(line)[seg_index + 1] : NULL); } if (seg != NULL) { if (_XmEntryDirectionGet((_XmStringEntry)seg) == XmSTRING_DIRECTION_UNSET) { _XmEntryDirectionSet((_XmStringEntry)seg, XmDirectionToStringDirection(prim_dir)); set_direction = True; } if (peek_seg != NULL) (void)SpecifiedSegmentExtents((_XmStringEntry)seg, r, rend_io, base, XmSTRING_MIDDLE_SEG, &w, &h, &asc, &dsc); else (void)SpecifiedSegmentExtents((_XmStringEntry)seg, r, rend_io, base, XmSTRING_LAST_SEG, &w, &h, &asc, &dsc); } } *width = tab_w; if (max_h > 0) *height = max_h; if (max_asc > 0) *ascender = max_asc; if (max_dsc > 0) *descender = max_dsc; } static XFontStruct * GetFont(XmRenderTable rt, _XmStringEntry entry) { XmRendition rend = NULL; short indx = -1; Cardinal n; Arg args[2]; XmFontType type; XtPointer font; rend = _XmEntryRenditionGet(entry, rt); if (rend == NULL) (void)_XmRenderTableFindFallback(rt, _XmEntryTag(entry), TRUE, &indx, &rend); if (rend != NULL) { n = 0; XtSetArg(args[n], XmNfontType, &type); n++; XtSetArg(args[n], XmNfont, &font); n++; XmRenditionRetrieve(rend, args, n); if (type == XmFONT_IS_FONT) return (XFontStruct *)font; else return (XFontStruct *)NULL; } return (XFontStruct *)NULL; } unsigned char _XmStringCharacterCount(XtPointer text, XmTextType text_type, int byte_count, XFontStruct *font) { if (text == NULL) return 0; if (byte_count == 0) byte_count = strlen((char *)text); switch (text_type) { case XmCHARSET_TEXT: { if (font && two_byte_font(font)) return (byte_count/2); else return byte_count; } case XmMULTIBYTE_TEXT: { char *s = (char *) text; if (MB_CUR_MAX == 1) return byte_count; else { int cnt = 0; int len; while (byte_count > 0 && (len = mblen(s, MB_CUR_MAX)) > 0) { cnt++; s += len; byte_count -= len; } return cnt; } } case XmWIDECHAR_TEXT: { wchar_t *wcs = (wchar_t *)text; int cnt = 0; while (byte_count > 0 && wcs[cnt]) { cnt++; byte_count -= sizeof(wchar_t); } return cnt; } default: return byte_count; } } unsigned char _XmEntryCharCountGet(_XmStringEntry entry, XmRenderTable rt) { unsigned int len; if (_XmEntryOptimized(entry)) { if ((len = _XmEntryByteCountGet(entry)) == 0) { return 0; } else { return _XmStringCharacterCount((char *)_XmEntryTextGet(entry), (XmTextType) _XmEntryTextTypeGet(entry), len, GetFont(rt, entry)); } } if (_XmEntryUnoptimized(entry)) { if (((_XmStringUnoptSeg)entry)->char_count == 0 && (len = _XmEntryByteCountGet(entry)) != 0) { ((_XmStringUnoptSeg)entry)->char_count = _XmStringCharacterCount((char *)_XmEntryTextGet(entry), (XmTextType) _XmEntryTextTypeGet(entry), len, GetFont(rt, entry)); } return ((_XmStringUnoptSeg)entry)->char_count; } return(0); } _XmStringCache _XmStringCacheGet(_XmStringCache caches, int type) { _XmStringCache cache = caches; while (cache && cache->cache_type != type) cache = cache->next; return cache; } void _XmStringCacheFree(_XmStringCache caches) { _XmStringCache prev = NULL, current = caches; while (current) { prev = current; current = current->next; if (prev) { if (prev->cache_type == _XmRENDERING_CACHE && ((_XmStringRenderingCache)prev)->rendition != NULL) XmRenditionFree(((_XmStringRenderingCache)prev)->rendition); XtFree((char *)prev); } } } static _XmStringCache CacheGet(_XmStringEntry entry, int type, int create, XtPointer match_value) { _XmStringCache cache; if (!entry || !_XmEntryUnoptimized(entry)) return NULL; switch (type) { case _XmSCANNING_CACHE: { XmDirection d; d = (XmDirection)(long)match_value; if (d) { cache = _XmEntryCacheGet(entry); while (cache && !(cache->cache_type == type && (XmDirectionMatch(((_XmStringScanningCache)cache)->prim_dir, d)))) cache = cache->next; if (!cache && create) { cache = (_XmStringCache)XtCalloc(1, sizeof(_XmStringScanningRec)); cache->cache_type = type; cache->dirty = True; cache->next = _XmEntryCacheGet(entry); _XmEntryCacheSet(entry, cache); ((_XmStringScanningCache)cache)->prim_dir = d; } } else cache = NULL; } break; case _XmRENDERING_CACHE: { XmRenderTable rt; rt = (XmRenderTable)match_value; if (rt) { cache = _XmEntryCacheGet(entry); while (cache && !(cache->cache_type == type && ((_XmStringRenderingCache)cache)->rt == rt)) cache = cache->next; if (!cache && create) { cache = (_XmStringCache)XtCalloc(1, sizeof(_XmStringRenderingRec)); cache->cache_type = type; cache->dirty = True; cache->next = _XmEntryCacheGet(entry); _XmEntryCacheSet(entry, cache); ((_XmStringRenderingCache)cache)->rt = rt; } } else cache = NULL; } break; default: cache = NULL; break; } return cache; } XtPointer _XmScanningCacheGet(_XmStringNREntry entry, #if NeedWidePrototypes int d, #else XmDirection d, #endif /* NeedWidePrototypes */ int field) { _XmStringScanningCache cache; cache = (_XmStringScanningCache)CacheGet((_XmStringEntry)entry, _XmSCANNING_CACHE, False, (XtPointer)(long)d); if (!cache) { if (entry && _XmEntryUnoptimized(entry) && (field == _XmCACHE_DIRTY)) return (XtPointer)True; else return NULL; } switch (field) { case _XmCACHE_DIRTY: return (XtPointer)(long)cache->header.dirty; case _XmCACHE_SCAN_LEFT: return (XtPointer)cache->left; case _XmCACHE_SCAN_RIGHT: return (XtPointer)cache->right; case _XmCACHE_SCAN_LAYOUT: return (XtPointer)(long)cache->layout_direction; case _XmCACHE_SCAN_DEPTH: return (XtPointer)(long)cache->depth; default: return NULL; } } void _XmScanningCacheSet(_XmStringNREntry entry, #if NeedWidePrototypes int d, #else XmDirection d, #endif /* NeedWidePrototypes */ int field, XtPointer value) { _XmStringScanningCache cache; cache = (_XmStringScanningCache)CacheGet((_XmStringEntry)entry, _XmSCANNING_CACHE, True, (XtPointer)(long)d); if (!cache) return; switch (field) { case _XmCACHE_DIRTY: cache->header.dirty = (Boolean)(long)value; break; case _XmCACHE_SCAN_LEFT: cache->left = (_XmStringEntry)value; break; case _XmCACHE_SCAN_RIGHT: cache->right = (_XmStringEntry)value; break; case _XmCACHE_SCAN_LAYOUT: cache->layout_direction = (XmDirection)(long)value; break; case _XmCACHE_SCAN_DEPTH: cache->depth = (unsigned short)(long)value; break; } } XtPointer _XmRenderCacheGet(_XmStringEntry entry, XmRenderTable rt, int field) { _XmStringRenderingCache cache; cache = (_XmStringRenderingCache)CacheGet(entry, _XmRENDERING_CACHE, False, (XtPointer)rt); if (!cache) { if (entry && _XmEntryUnoptimized(entry) && (field == _XmCACHE_DIRTY)) return (XtPointer)True; else return NULL; } switch (field) { case _XmCACHE_DIRTY: return (XtPointer)(long)cache->header.dirty; case _XmCACHE_RENDER_X: return (XtPointer)(long)cache->x; case _XmCACHE_RENDER_Y: return (XtPointer)(long)cache->y; case _XmCACHE_RENDER_WIDTH: return (XtPointer)(long)cache->width; case _XmCACHE_RENDER_HEIGHT: return (XtPointer)(long)cache->height; case _XmCACHE_RENDER_BASELINE: return (XtPointer)(long)cache->baseline; case _XmCACHE_RENDER_ASCENT: return (XtPointer)(long)cache->ascent; case _XmCACHE_RENDER_DESCENT: return (XtPointer)(long)cache->descent; case _XmCACHE_RENDER_RENDITION: return (XtPointer)cache->rendition; case _XmCACHE_RENDER_PREV_TABS: return (XtPointer)(long)cache->prev_tabs; default: return NULL; } } void _XmRenderCacheSet(_XmStringEntry entry, XmRenderTable rt, int field, XtPointer value) { _XmStringRenderingCache cache; cache = (_XmStringRenderingCache)CacheGet(entry, _XmRENDERING_CACHE, True, (XtPointer)rt); if (!cache) return; switch (field) { case _XmCACHE_DIRTY: cache->header.dirty = (Boolean)(long)value; break; case _XmCACHE_RENDER_X: cache->x = (int)(long)value; break; case _XmCACHE_RENDER_Y: cache->y = (int)(long)value; break; case _XmCACHE_RENDER_WIDTH: cache->width = (int)(long)value; break; case _XmCACHE_RENDER_HEIGHT: cache->height = (int)(long)value; break; case _XmCACHE_RENDER_BASELINE: cache->baseline = (int)(long)value; break; case _XmCACHE_RENDER_ASCENT: cache->ascent = (int)(long)value; break; case _XmCACHE_RENDER_DESCENT: cache->descent = (int)(long)value; break; case _XmCACHE_RENDER_RENDITION: if (cache->rendition != NULL) XmRenditionFree(cache->rendition); cache->rendition = (XmRendition)value; break; case _XmCACHE_RENDER_PREV_TABS: cache->prev_tabs = (char)(long)value; break; } } /* * find width of widest line in XmString */ Dimension XmStringWidth( XmRenderTable rendertable, XmString string ) { Dimension width, height; XmStringExtent(rendertable, string, &width, &height); return(width); } /* * find total height of an XmString */ Dimension XmStringHeight( XmRenderTable rendertable, XmString string ) { Dimension width, height; XmStringExtent(rendertable, string, &width, &height); return(height); } /* * find the rectangle which will enclose the text */ void XmStringExtent( XmRenderTable rendertable, XmString string, Dimension *width, Dimension *height ) { Dimension cur_width = 0, max_width = 0; Dimension cur_height = 0, line_height = 0; Dimension asc, dsc; int j; Display *d; XtAppContext app = NULL; *width = 0, *height = 0; if ((rendertable == NULL) || (string == NULL)) return; #ifdef XTHREADS if (_XmRTDisplay(rendertable)) app = XtDisplayToApplicationContext(_XmRTDisplay(rendertable)); if (app) { _XmAppLock(app); } else { _XmProcessLock(); } #endif if (_XmStrOptimized(string)) OptLineMetrics(rendertable, string, NULL, NULL, width, height, NULL, NULL); else { _XmRenditionRec scratch; _XmRendition tmp; XmRendition rend; _XmStringArraySegRec array_seg; bzero((char*) &scratch, sizeof(_XmRenditionRec)); tmp = &scratch; rend = &tmp; /* Initialize for tabs. */ d = (_XmRTDisplay(rendertable) == NULL) ? _XmGetDefaultDisplay() : _XmRTDisplay(rendertable); _XmRendDisplay(rend) = d; _XmStringLayout(string, XmLEFT_TO_RIGHT); for (j = 0; j < _XmStrLineCountGet(string); j++) { _XmStringEntry line; if (_XmStrImplicitLine(string)) line = _XmStrEntry(string)[j]; else { _XmEntryType(&array_seg) = XmSTRING_ENTRY_ARRAY; _XmEntrySegmentCount(&array_seg) = _XmStrEntryCount(string); _XmEntrySegment(&array_seg) = (_XmStringNREntry *)_XmStrEntry(string); line = (_XmStringEntry)&array_seg; } LineMetrics(line, rendertable, &rend, NULL, XmLEFT_TO_RIGHT, &cur_width, &cur_height, &asc, &dsc); /* Returned height for empty lines is zero, so go with previous in that case. */ if (cur_height != 0) line_height = cur_height; *height += line_height; if (cur_width > max_width) max_width = cur_width; } *width = max_width; if (_XmRendTags(rend) != NULL) XtFree((char *)_XmRendTags(rend)); } #ifdef XTHREADS if (app) { _XmAppUnlock(app); } else { _XmProcessUnlock(); } #endif } Boolean XmStringEmpty( XmString string ) { int i, j; _XmProcessLock(); if (!string) { _XmProcessUnlock(); return (TRUE); } if (_XmStrOptimized(string)) { if (_XmStrByteCount(string) > 0) { _XmProcessUnlock(); return FALSE; } } else { _XmStringEntry *entry = _XmStrEntry(string); for (i = 0; i < _XmStrEntryCount(string); i++) { if (_XmEntryMultiple(entry[i])) { int segcount = _XmEntrySegmentCount(entry[i]); for (j = 0; j < segcount; j++) { _XmStringNREntry seg = _XmEntrySegment(entry[i])[j]; if (_XmEntryByteCountGet((_XmStringEntry)seg) > 0) { _XmProcessUnlock(); return (FALSE); } } } else { if (_XmEntryByteCountGet(entry[i]) > 0) { _XmProcessUnlock(); return (FALSE); } } } } _XmProcessUnlock(); return (TRUE); } Boolean XmStringIsVoid(XmString string) { XmStringComponentType type; _XmStringContextRec stack_context; unsigned int len; XtPointer val; _XmProcessLock(); if (!string) { _XmProcessUnlock(); return (TRUE); } _XmStringContextReInit(&stack_context, string); while ((type = XmeStringGetComponent(&stack_context, TRUE, FALSE, &len, &val)) != XmSTRING_COMPONENT_END) { switch(type) { case XmSTRING_COMPONENT_TAB: case XmSTRING_COMPONENT_TEXT: case XmSTRING_COMPONENT_LOCALE_TEXT: case XmSTRING_COMPONENT_WIDECHAR_TEXT: case XmSTRING_COMPONENT_SEPARATOR: _XmStringContextFree(&stack_context); _XmProcessUnlock(); return(FALSE); default: break; } } _XmStringContextFree(&stack_context); _XmProcessUnlock(); return(TRUE); } /**************************************************************** * EntryCvtToOpt: * * Converts a single segment to a single Opt segment. * Returns NULL if no conversion could be done. * ****************************************************************/ static _XmStringEntry EntryCvtToOpt(_XmStringEntry entry) { char *text; _XmStringEntry new_entry; if (!entry) return NULL; /* Array segment */ if (_XmEntryMultiple(entry)) return NULL; /* Unoptimized, convert if possible */ if (_XmEntryUnoptimized(entry)) { if (_XmEntryPushGet(entry) || _XmEntryPopGet(entry) || _XmUnoptSegRendBeginCount(entry) > 1 || _XmUnoptSegRendEndCount(entry) > 1 || _XmEntryTabsGet(entry) > 7 || _XmEntryByteCountGet(entry) > 255 || (_XmUnoptSegRendBeginCount(entry) && _XmStringIndexCacheTag(_XmEntryRendBeginGet(entry, 0), XmSTRING_TAG_STRLEN) >= REND_INDEX_MAX) || (_XmUnoptSegRendEndCount(entry) && _XmStringIndexCacheTag(_XmEntryRendEndGet(entry, 0), XmSTRING_TAG_STRLEN) >= REND_INDEX_MAX) || (_XmUnoptSegRendBeginCount(entry) && _XmUnoptSegRendEndCount(entry) && _XmEntryRendEndGet(entry, 0) != _XmEntryRendBeginGet(entry, 0)) || (_XmUnoptSegTag(entry) && _XmStringIndexCacheTag(_XmUnoptSegTag(entry), XmSTRING_TAG_STRLEN) >= TAG_INDEX_MAX)) return NULL; new_entry = (_XmStringEntry)XtCalloc(1, sizeof(_XmStringOptSegRec)); _XmEntryType(new_entry) = XmSTRING_ENTRY_OPTIMIZED; _XmEntryImm(new_entry) = 0; _XmEntryTextTypeSet(new_entry, (XmTextType) _XmEntryTextTypeGet(entry)); _XmEntryTagIndex(new_entry) = (_XmUnoptSegTag(entry) ? _XmStringIndexCacheTag(_XmUnoptSegTag(entry), XmSTRING_TAG_STRLEN) : TAG_INDEX_UNSET); _XmEntryByteCountSet(new_entry, _XmUnoptSegByteCount(entry)); _XmEntryRendIndex(new_entry) = (_XmUnoptSegRendBeginCount(entry) ? _XmStringIndexCacheTag(_XmEntryRendBeginGet(entry, 0), XmSTRING_TAG_STRLEN) : (_XmUnoptSegRendEndCount(entry) ? _XmStringIndexCacheTag(_XmEntryRendEndGet(entry, 0), XmSTRING_TAG_STRLEN) : REND_INDEX_UNSET)); _XmEntryRendBeginCountSet(new_entry, _XmUnoptSegRendBeginCount(entry)); _XmEntryRendEndCountSet(new_entry, _XmUnoptSegRendEndCount(entry)); _XmEntryTabsSet(new_entry, _XmEntryTabsGet(entry)); _XmEntryDirectionSet(new_entry, _XmEntryDirectionGet(entry)); _XmEntryFlippedSet(new_entry, _XmEntryFlippedGet(entry)); _XmEntryPermSet(new_entry, _XmEntryPermGet(entry)); _XmEntrySoftNewlineSet(new_entry, _XmEntrySoftNewlineGet(entry)); if (_XmEntryPermGet(entry)) _XmEntryTextSet(new_entry, _XmEntryTextGet(entry)); else { unsigned int len = _XmEntryByteCountGet(entry); text = (char *)XtMalloc(len); memcpy(text, _XmEntryTextGet(entry), len); _XmEntryTextSet(new_entry, text); } return new_entry; } /* If we were already opt., return a copy */ return _XmStringEntryCopy(entry); } /**************************************************************** * EntryCvtToUnOpt: * * Converts a single segment to a single UnOpt segment. * Returns NULL if no conversion could be done (only for Array segs) * ****************************************************************/ static _XmStringEntry EntryCvtToUnopt(_XmStringEntry entry) { char *text; _XmStringEntry new_entry; unsigned int len; if (!entry) return NULL; /* Array segment */ if (_XmEntryMultiple(entry)) return NULL; /* Unoptimized, return copy */ if (_XmEntryUnoptimized(entry)) return _XmStringEntryCopy(entry); /* Optimized: convert */ len = _XmEntryByteCountGet(entry); new_entry = (_XmStringEntry)XtCalloc(1, sizeof(_XmStringUnoptSegRec)); _XmEntryType(new_entry) = XmSTRING_ENTRY_UNOPTIMIZED; _XmEntryTextTypeSet(new_entry, (XmTextType) _XmEntryTextTypeGet(entry)); _XmUnoptSegTag(new_entry) = _XmEntryTag(entry); _XmUnoptSegByteCount(new_entry) = len; _XmUnoptSegRendBeginCount(new_entry) = _XmEntryRendBeginCountGet(entry); _XmUnoptSegRendEndCount(new_entry) = _XmEntryRendEndCountGet(entry); if (_XmEntryRendBeginCountGet(entry)) { _XmUnoptSegRendBegins(new_entry) = (XmStringTag *)XtMalloc(sizeof(XmStringTag)); _XmUnoptSegRendBegins(new_entry)[0] = _XmEntryRendBeginGet(entry, 0); } if (_XmEntryRendEndCountGet(entry)) { _XmUnoptSegRendEnds(new_entry) = (XmStringTag *)XtMalloc(sizeof(XmStringTag)); _XmUnoptSegRendEnds(new_entry)[0] = _XmEntryRendEndGet(entry, 0); } _XmEntryTabsSet(new_entry, _XmEntryTabsGet(entry)); _XmEntryDirectionSet(new_entry, _XmEntryDirectionGet(entry)); _XmEntryFlippedSet(new_entry, _XmEntryFlippedGet(entry)); _XmEntryPermSet(new_entry, _XmEntryPermGet(entry)); _XmEntrySoftNewlineSet(new_entry, _XmEntrySoftNewlineGet(entry)); _XmEntryPushSet(new_entry, _XmEntryPushGet(entry)); _XmEntryPopSet(new_entry, _XmEntryPopGet(entry)); if (_XmEntryPermGet(entry)) _XmEntryTextSet(new_entry, _XmEntryTextGet(entry)); else if (len>0) { text = (char *)XtMalloc(len); memcpy(text, _XmEntryTextGet(entry), len); _XmEntryTextSet(new_entry, text); } else _XmEntryTextSet(new_entry, NULL); return new_entry; } /* Convert an optimized _XmString to an equivalent non-optimized _XmString */ _XmString _XmStringOptToNonOpt(_XmStringOpt string) { _XmString str; _XmStringOptSegRec seg; _XmStrCreate(str, XmSTRING_MULTIPLE_ENTRY, 0); _XmEntryInit((_XmStringEntry)&seg, XmSTRING_ENTRY_OPTIMIZED); _XmEntryTagIndex(&seg) = _XmStrTagIndex((_XmString)string); _XmEntryRendIndex(&seg) = _XmStrRendIndex((_XmString)string); _XmEntryRendBeginCountSet(&seg, _XmStrRendBegin((_XmString)string)); _XmEntryRendEndCountSet(&seg, _XmStrRendEnd((_XmString)string)); _XmEntryTextTypeSet(&seg, (XmTextType) _XmStrTextType((_XmString)string)); _XmEntryByteCountSet(&seg, _XmStrByteCount((_XmString)string)); _XmEntryDirectionSet((_XmStringEntry)&seg, _XmStrDirection((_XmString)string)); _XmEntryTabsSet(&seg, _XmStrTabs((_XmString)string)); _XmEntryFlippedSet(&seg, _XmStrFlipped((_XmString)string)); _XmEntryTextSet((_XmStringEntry)&seg, _XmStrText((_XmString)string)); _XmStringSegmentNew(str, 0, (_XmStringEntry)&seg, True); return(str); } /* * figure out if there is sub string match, and if so the begining * and end of the match section in pixels. Don't touch anything if * there is no match */ static void SubStringPosition( #if NeedWidePrototypes int one_byte, #else Boolean one_byte, #endif /* NeedWidePrototypes */ XmRenderTable rt, XmRendition entry, _XmStringEntry seg, _XmStringEntry under_seg, #if NeedWidePrototypes int x, #else Position x, #endif /* NeedWidePrototypes */ Dimension *under_begin, Dimension *under_end ) { char *a = (char*) _XmEntryTextGet(seg); char *b = (char*) _XmEntryTextGet(under_seg); int i, j, k, begin, max, width; unsigned int seg_len, under_seg_len; Boolean fail; if (!((_XmEntryTag(seg) == _XmEntryTag(under_seg)) || ((strcmp(_XmEntryTag(seg), XmFONTLIST_DEFAULT_TAG) == 0) && _XmStringIsCurrentCharset(_XmEntryTag(under_seg))) || ((strcmp(_XmEntryTag(under_seg), XmFONTLIST_DEFAULT_TAG) == 0) && _XmStringIsCurrentCharset(_XmEntryTag(seg))))) return; seg_len = _XmEntryByteCountGet(seg); under_seg_len = _XmEntryByteCountGet(under_seg); if (seg_len < under_seg_len) return; max = (seg_len - under_seg_len); if (_XmRendFontType(entry) == XmFONT_IS_FONT) { XFontStruct *font_struct = (XFontStruct *)_XmRendFont(entry); if (one_byte) { for (i = 0; i <= max; i++) { fail = FALSE; begin = i; for (j = 0; j < under_seg_len; j++) { if (a[i+j] != b[j]) { fail = TRUE; break; } } if ( ! fail) { /* found it */ if (begin == 0) *under_begin = x; else *under_begin = x + abs(XTextWidth (font_struct, a, begin)); width = _XmEntryWidthGet((_XmStringEntry)under_seg, rt); if (width == 0) { width = abs(XTextWidth(font_struct, b, under_seg_len)); _XmEntryWidthSet((_XmStringEntry)under_seg, rt, width); } *under_end = *under_begin + width; return; } } } else { /* * If either string isn't even byte length, it can't be * two bytes/char. */ if (((seg_len % 2) != 0) || ((under_seg_len % 2) != 0)) return; /* * search for the substring */ for (i = 0; i <= max; i+=2) { fail = FALSE; begin = i; for (j = 0; j < under_seg_len; j+=2) { if ((a[i+j] != b[j]) || (a[i+j+1] != b[j+1])) { fail = TRUE; break; } } if ( ! fail) { /* found it */ if (begin == 0) *under_begin = x; else *under_begin = x + abs(XTextWidth16 (font_struct, (XChar2b *) a, begin/2)); width = _XmEntryWidthGet((_XmStringEntry)under_seg, rt); if (width == 0) { width = abs(XTextWidth16(font_struct, (XChar2b *) b, under_seg_len/2)); _XmEntryWidthSet((_XmStringEntry)under_seg, rt, width); } *under_end = *under_begin + width; return; } } } } else { XFontSet font_set = (XFontSet)_XmRendFont(entry); XmTextType type = (XmTextType) _XmEntryTextTypeGet(under_seg); int len_a, len_a1, len_b; for (i = 0; i <= max; i += len_a) { fail = FALSE; begin = i; if (type == XmWIDECHAR_TEXT) { len_a = sizeof(wchar_t); for (j = 0; j < under_seg_len; j += sizeof(wchar_t)) if (((wchar_t *)a)[(i+j)/len_a] != ((wchar_t *)b)[j/len_a]) { fail = TRUE; break; } } else { len_a = mblen(&a[i], MB_CUR_MAX); if (len_a < 1) return; len_a1 = len_a; for (j = 0; j < under_seg_len; j += len_b) { len_b = mblen(&b[j], MB_CUR_MAX); if (len_b < 1) return; if (len_b == len_a1) { for (k = 0; k < len_b; k++) { if (a[i+j+k] != b[j+k]) { fail = TRUE; break; } } if (fail == TRUE) break; } else { fail = TRUE; break; } } } if (!fail) { /* found it */ if (begin == 0) *under_begin = x; else if (type == XmWIDECHAR_TEXT) *under_begin = x + abs(XwcTextEscapement(font_set, (wchar_t *)a, begin/sizeof(wchar_t))); else *under_begin = x + abs(XmbTextEscapement(font_set, a, begin)); width = _XmEntryWidthGet((_XmStringEntry)under_seg, rt); if (width == 0) { width = (type == XmWIDECHAR_TEXT) ? abs(XwcTextEscapement(font_set, (wchar_t *)b, under_seg_len / sizeof(wchar_t))) : abs(XmbTextEscapement(font_set, b, under_seg_len)); _XmEntryWidthSet((_XmStringEntry)under_seg, rt, width); } *under_end = *under_begin + width; return; } } } } /*ARGSUSED*/ extern void _XmStringDrawLining(Display *d, Drawable w, Position x, Position y, Dimension width, Dimension height, Dimension descender, XmRendition rend, Pixel select_color, /* unused */ XmHighlightMode mode, Boolean colors_set) { GC gc; XGCValues xgcv; Pixel fg, bg, old_fg, old_bg; unsigned char under, thru; XGCValues current_gcv; int style, old_style=LineSolid, cur_style=LineSolid; old_fg = old_bg = XmUNSPECIFIED_PIXEL; _XmRendDisplay(rend) = d; gc = _XmRendGC(rend); fg = _XmRendFG(rend); bg = _XmRendBG(rend); under = _XmRendUnderlineType(rend); thru = _XmRendStrikethruType(rend); if (!colors_set) { if (fg != XmUNSPECIFIED_PIXEL) { XGetGCValues(d, gc, GCForeground, ¤t_gcv); if (current_gcv.foreground != fg) { old_fg = current_gcv.foreground; xgcv.foreground = fg; XChangeGC(d, gc, GCForeground, &xgcv); } } if (bg != XmUNSPECIFIED_PIXEL) { XGetGCValues(d, gc, GCBackground, ¤t_gcv); if (current_gcv.background != bg) { old_bg = current_gcv.background; xgcv.background = bg; XChangeGC(d, gc, GCBackground, &xgcv); } } } if (mode == XmHIGHLIGHT_SECONDARY_SELECTED) { /* Draw lines */ XGetGCValues(d, gc, GCLineStyle, ¤t_gcv); old_style = current_gcv.line_style; style = LineSolid; if (old_style != style) { cur_style = xgcv.line_style = style; XChangeGC(d, gc, GCLineStyle, &xgcv); } XDrawLine (d, w, gc, x, y + SINGLE_OFFSET, x + width - 1, y + SINGLE_OFFSET); } else { XGetGCValues(d, gc, GCLineStyle, ¤t_gcv); cur_style = old_style = current_gcv.line_style; if ((under != XmAS_IS) && (under != XmNO_LINE)) { if ((under == XmSINGLE_DASHED_LINE) || (under == XmDOUBLE_DASHED_LINE)) style = LineDoubleDash; else style = LineSolid; if (cur_style != style) { cur_style = xgcv.line_style = style; XChangeGC(d, gc, GCLineStyle, &xgcv); } if ((under == XmSINGLE_LINE) || (under == XmSINGLE_DASHED_LINE)) { XDrawLine(d, w, gc, x, y + SINGLE_OFFSET, (x + width - 1), y + SINGLE_OFFSET); } else if ((under == XmDOUBLE_LINE) || (under == XmDOUBLE_DASHED_LINE)) { XSegment segs[2]; segs[0].x1 = segs[1].x1 = x; segs[0].x2 = segs[1].x2 = x + width - 1; segs[0].y1 = segs[0].y2 = y; segs[1].y1 = segs[1].y2 = y + DOUBLE_OFFSET; XDrawSegments(d, w, gc, segs, 2); } } if ((thru != XmAS_IS) && (thru != XmNO_LINE)) { if ((thru == XmSINGLE_DASHED_LINE) || (thru == XmDOUBLE_DASHED_LINE)) style = LineDoubleDash; else style = LineSolid; if (cur_style != style) { cur_style = xgcv.line_style = style; XChangeGC(d, gc, GCLineStyle, &xgcv); } if ((thru == XmSINGLE_LINE) || (thru == XmSINGLE_DASHED_LINE)) { XDrawLine(d, w, gc, x, (y + descender - height/2 - 1), (x + width - 1), (y + descender - height/2 - 1)); } else if ((thru == XmDOUBLE_LINE) || (thru == XmDOUBLE_DASHED_LINE)) { XSegment segs[2]; segs[0].x1 = segs[1].x1 = x; segs[0].x2 = segs[1].x2 = x + width - 1; segs[0].y1 = segs[0].y2 = (y + descender - height/2) - 2; segs[1].y1 = segs[1].y2 = (y + descender - height/2) + 1; XDrawSegments(d, w, gc, segs, 2); } } } if ((cur_style != old_style) && ((old_style == LineSolid) || (old_style == LineOnOffDash) || (old_style == LineDoubleDash))) { xgcv.line_style = old_style; XChangeGC(d, gc, GCLineStyle, &xgcv); } if (!colors_set) { if (old_fg != XmUNSPECIFIED_PIXEL) { xgcv.foreground = old_fg; XChangeGC(d, gc, GCForeground, &xgcv); } if (old_bg != XmUNSPECIFIED_PIXEL) { xgcv.background = old_bg; XChangeGC(d, gc, GCBackground, &xgcv); } } } extern void _XmStringDrawSegment(Display *d, Drawable w, #if NeedWidePrototypes int x, int y, int width, int height, #else Position x, Position y, Dimension width, Dimension height, #endif /* NeedWidePrototypes */ _XmStringNREntry seg, XmRendition rend, XmRenderTable rendertable, #if NeedWidePrototypes int image, #else Boolean image, #endif /* NeedWidePrototypes */ XmString *underline, #if NeedWidePrototypes unsigned int descender #else Dimension descender #endif /* NeedWidePrototypes */ ) { Boolean text16 = False, multibyte, widechar; Font oldfont = (Font) 0; GC gc; XGCValues xgcv; char *draw_text; /* text to be drawn - flipped in RtoL mode */ char flip_char[100]; /* but simple */ char *flip_char_extra = NULL; Pixel fg, bg, old_fg, old_bg; XGCValues current_gcv; Dimension under_begin, under_end; unsigned int seg_len; old_fg = old_bg = XmUNSPECIFIED_PIXEL; _XmRendDisplay(rend) = d; seg_len = _XmEntryByteCountGet((_XmStringEntry)seg); if (seg_len > 0) { multibyte = (((_XmEntryTextTypeGet((_XmStringEntry)seg) == XmMULTIBYTE_TEXT) || (_XmEntryTextTypeGet((_XmStringEntry)seg) == XmCHARSET_TEXT)) && (_XmRendFontType(rend) == XmFONT_IS_FONTSET)); widechar = ((_XmEntryTextTypeGet((_XmStringEntry)seg) == XmWIDECHAR_TEXT) && (_XmRendFontType(rend) == XmFONT_IS_FONTSET)); gc = _XmRendGC(rend); fg = _XmRendFG(rend); bg = _XmRendBG(rend); if (fg != XmUNSPECIFIED_PIXEL) { XGetGCValues(d, gc, GCForeground, ¤t_gcv); if (current_gcv.foreground != fg) { old_fg = current_gcv.foreground; xgcv.foreground = fg; XChangeGC(d, gc, GCForeground, &xgcv); } } if (bg != XmUNSPECIFIED_PIXEL) { XGetGCValues(d, gc, GCBackground, ¤t_gcv); if (current_gcv.background != bg) { old_bg = current_gcv.background; xgcv.background = bg; XChangeGC(d, gc, GCBackground, &xgcv); } } if (!multibyte && !widechar) { XFontStruct *f = (XFontStruct *)_XmRendFont(rend); /* If we don't have a font, don't render. */ if (f == NULL) return; text16 = two_byte_font(f); XGetGCValues(d, gc, GCFont, ¤t_gcv) ; xgcv.font = f->fid; /* get segment font */ if (current_gcv.font != xgcv.font) /* not right one */ { /* change it */ oldfont = current_gcv.font; XChangeGC(d, gc, GCFont, &xgcv); } } if (_XmEntryDirectionGet((_XmStringEntry)seg) == XmSTRING_DIRECTION_R_TO_L) { /* Flip the bytes. */ char *p = flip_char, *q; char *ltor_text; int i, j; if (seg_len > 100) p = flip_char_extra = (char *) ALLOCATE_LOCAL(seg_len); draw_text = p; ltor_text = (char *)_XmEntryTextGet((_XmStringEntry)seg); if (multibyte) /* Have to flip a mb character at time. */ { int len; q = ltor_text; p += seg_len; for (i = 0; i < seg_len; i += len) { len = mblen(q, MB_CUR_MAX); if (len < 1) /* Something went wrong, just return for now. */ return; p -= len; for (j = 0; j < len; j++) { p[j] = q[j]; } q += len; } } else if (!text16) { q = (ltor_text + seg_len - 1); for (i = 0; i < seg_len; i++) *p++ = *q--; } else /* Have to flip two at a time, maintaining their order. */ { char tmp; q = (ltor_text + seg_len - 1); for (i = 0; i < Half(seg_len); i++) { tmp = *q--; *p++ = *q--; *p++ = tmp; } } } else /* LtoR */ { draw_text = (char *)_XmEntryTextGet((_XmStringEntry)seg); } if (*underline != (_XmString)NULL) { under_begin = under_end = 0; if (_XmStrOptimized(*underline)) { /* * This is an optimized string; coerce underline to segment * and call the sub-string search routine. */ Boolean imm; _XmStringOptSegRec under_seg; if (_XmStrText(*underline) != (char *)_XmEntryTextGet((_XmStringEntry)*underline)) /* If XtPointer in union in optimized segment leads to * padding in struct between header and text data * (on some 64-bit architectures) we have to move * text data, since optimized string does not have padding. */ { bzero((char*)&under_seg, sizeof(_XmStringOptSegRec)); _XmEntryType(&under_seg) = XmSTRING_ENTRY_OPTIMIZED; _XmEntryTagIndex(&under_seg) = _XmStrTagIndex(*underline); _XmEntryByteCountSet(&under_seg, _XmStrByteCount(*underline)); _XmEntryTextTypeSet(&under_seg, (XmTextType)_XmStrTextType(*underline)); _XmEntryTextSet((_XmStringEntry)&under_seg, (char *)_XmStrText(*underline)); SubStringPosition((!text16), rendertable, rend, (_XmStringEntry)seg, (_XmStringEntry)&under_seg, x, &under_begin, &under_end); } else { imm = _XmEntryImm((_XmStringEntry)*underline); _XmEntryImm((_XmStringEntry)*underline) = TRUE; SubStringPosition((!text16), rendertable, rend, (_XmStringEntry)seg, (_XmStringEntry)*underline, x, &under_begin, &under_end); _XmEntryImm((_XmStringEntry)*underline) = imm; } } else { _XmStringEntry line; line = _XmStrEntry(*underline)[0]; if ((_XmStrEntryCount(*underline) > 0) && (_XmEntrySegmentCountGet(line) > 0)) { _XmStringNREntry under_seg; under_seg = (_XmStringNREntry)_XmEntrySegmentGet(line)[0]; SubStringPosition((!text16), rendertable, rend, (_XmStringEntry)seg, (_XmStringEntry)under_seg, x, &under_begin, &under_end); } } } if (image) { if (text16) XDrawImageString16(d, w, gc, x, y, (XChar2b*)draw_text, Half(seg_len)); else if (multibyte) XmbDrawImageString (d, w, (XFontSet)_XmRendFont(rend), gc, x, y, draw_text, seg_len); else if (widechar) XwcDrawImageString (d, w, (XFontSet)_XmRendFont(rend), gc, x, y, (wchar_t *) draw_text, (seg_len / sizeof(wchar_t))); else XDrawImageString (d, w, gc, x, y, draw_text, seg_len); } else { if (text16) XDrawString16 (d, w, gc, x, y, (XChar2b *)draw_text, Half(seg_len)); else if (multibyte) XmbDrawString (d, w, (XFontSet)_XmRendFont(rend), gc, x, y, draw_text, seg_len); else if (widechar) XwcDrawString (d, w, (XFontSet)_XmRendFont(rend), gc, x, y, (wchar_t *) draw_text, (seg_len / sizeof(wchar_t))); else XDrawString(d, w, gc, x, y, draw_text, seg_len); } /* Draw lines */ if ((*underline != NULL) && (under_begin != under_end)) { *underline = (_XmString) NULL; /* only once */ XDrawLine (d, w, gc, under_begin, (y + descender), under_end, (y + descender)); } _XmStringDrawLining(d, w, x, y, width, height, descender, rend, XmUNSPECIFIED_PIXEL, XmHIGHLIGHT_NORMAL, TRUE); if (((Font)0 != oldfont) && /* if font was changed */ ((Font)~0 != oldfont)) /* put it back */ { xgcv.font = oldfont; XChangeGC (d, gc, GCFont, &xgcv); } if (old_fg != XmUNSPECIFIED_PIXEL) { xgcv.foreground = old_fg; XChangeGC(d, gc, GCForeground, &xgcv); } if (old_bg != XmUNSPECIFIED_PIXEL) { xgcv.background = old_bg; XChangeGC(d, gc, GCBackground, &xgcv); } if (flip_char_extra != NULL) { DEALLOCATE_LOCAL(flip_char_extra); } } } /**************************************************************** * recursive_layout: * This (partly) recursive function sets up the left/right * pointers for segments to ensure that segments will be * laid out in the correct order ****************************************************************/ static void recursive_layout(_XmString string, int *line_index, int *seg_index, #if NeedWidePrototypes int direction, int p_direction, #else XmDirection direction, XmDirection p_direction, #endif int depth) { _XmStringEntry line; _XmStringNREntry seg, seg2; _XmStringNREntry last; XmDirection pop_dir; int pop_index = -1; int nseg, nline; int push_line; if (*line_index >= (nline = _XmStrLineCountGet(string))) return; if (_XmStrImplicitLine(string)) { line = _XmStrEntry(string)[*line_index]; nseg = _XmEntrySegmentCountGet(line); } else nseg = _XmStrEntryCount(string); if (*seg_index >= nseg) { (*line_index)++; (*seg_index) = 0; if (*line_index >= nline) return; } if (*seg_index > 0) if (_XmStrImplicitLine(string)) last = _XmEntrySegmentGet(line)[*seg_index-1]; else last = (_XmStringNREntry)_XmStrEntry(string)[*seg_index-1]; else last = NULL; while (*line_index < nline) { if (_XmStrImplicitLine(string)) { line = _XmStrEntry(string)[*line_index]; nseg = _XmEntrySegmentCountGet(line); } else nseg = _XmStrEntryCount(string); while (*seg_index < nseg) { if (_XmStrImplicitLine(string)) seg = _XmEntrySegmentGet(line)[*seg_index]; else seg = (_XmStringNREntry)_XmStrEntry(string)[*seg_index]; if (_XmEntryPushGet((_XmStringEntry)seg) && !_XmEntryPopGet((_XmStringEntry)seg)) { push_line = *line_index; (*seg_index)++; _XmEntryLayoutSet(seg, p_direction, (long)_XmEntryPushGet((_XmStringEntry)seg)); _XmEntryLayoutDepthSet(seg, p_direction, (long)++depth); recursive_layout(string, line_index, seg_index, _XmEntryPushGet((_XmStringEntry)seg), p_direction, depth); if (XmDirectionMatch(_XmEntryPushGet((_XmStringEntry)seg),direction)) { /* False push - treat as normal case */ if (XmDirectionMatch(_XmEntryPushGet((_XmStringEntry)seg), XmLEFT_TO_RIGHT)) { if (last) { _XmEntryRightSet(last, p_direction, seg); _XmEntryLeftSet(seg, p_direction, last); _XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False); } } else if (last) { _XmEntryLeftSet(last, p_direction, seg); _XmEntryRightSet(seg, p_direction, last); _XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False); } if (_XmStrImplicitLine(string)) { if (*line_index < nline) { line = _XmStrEntry(string)[*line_index]; nseg = _XmEntrySegmentCountGet(line); last = _XmEntrySegmentGet(line)[*seg_index]; } else { line = NULL; nseg = 0; last = NULL; } } else { nseg = _XmStrEntryCount(string); last = (_XmStringNREntry)_XmStrEntry(string)[*seg_index]; } } else if (*line_index == push_line) { /* connect segment before push with pop segment */ if (_XmStrImplicitLine(string)) seg2 = _XmEntrySegmentGet(line)[*seg_index]; else seg2 = (_XmStringNREntry)_XmStrEntry(string)[*seg_index]; if (XmDirectionMatch(_XmEntryPushGet((_XmStringEntry)seg), XmLEFT_TO_RIGHT)) { if (last) { _XmEntryLeftSet(last, p_direction, seg2); _XmEntryRightSet(seg2, p_direction, last); _XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False); _XmEntryDirtySet(seg2, _XmSCANNING_CACHE, p_direction, False); } } else { if (last){ _XmEntryRightSet(last, p_direction, seg2); _XmEntryLeftSet(seg2, p_direction, last); _XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False); _XmEntryDirtySet(seg2, _XmSCANNING_CACHE, p_direction, False); } } last = seg; } else { /* pop is on a different line */ if (last && nseg > 0) { /* connect last segment on line with the one before push */ _XmStringNREntry conn_seg; if (_XmStrImplicitLine(string)) conn_seg = _XmEntrySegmentGet(line)[nseg-1]; else conn_seg = (_XmStringNREntry)_XmStrEntry(string)[nseg-1]; if (XmDirectionMatch(_XmEntryPushGet((_XmStringEntry)seg), XmLEFT_TO_RIGHT)) { while (_XmEntryRightGet(conn_seg, p_direction)) conn_seg = (_XmStringNREntry)_XmEntryRightGet(conn_seg, p_direction); _XmEntryLeftSet(last, p_direction, conn_seg); _XmEntryRightSet(conn_seg, p_direction, last); _XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False); _XmEntryDirtySet(conn_seg, _XmSCANNING_CACHE, p_direction, False); } else { while (_XmEntryLeftGet(conn_seg, p_direction)) conn_seg = (_XmStringNREntry)_XmEntryLeftGet(conn_seg, p_direction); _XmEntryRightSet(last, p_direction, conn_seg); _XmEntryLeftSet(conn_seg, p_direction, last); _XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False); _XmEntryDirtySet(conn_seg, _XmSCANNING_CACHE, p_direction, False); } last = NULL; } if (_XmStrImplicitLine(string)) { if (*line_index < nline) { line = _XmStrEntry(string)[*line_index]; nseg = _XmEntrySegmentCountGet(line); } else { line = NULL; nseg = 0; } } else if (*line_index > 0) { line = NULL; nseg = 0; } else nseg = _XmStrEntryCount(string); /* save these things till we return from this level */ pop_index = *seg_index; pop_dir = _XmEntryPushGet((_XmStringEntry)seg); } (*seg_index)++; } else if (!_XmEntryPushGet((_XmStringEntry)seg) && _XmEntryPopGet((_XmStringEntry)seg)) { /* attach this segment to the previous one */ if (last) { if (XmDirectionMatch(direction, XmLEFT_TO_RIGHT)) { _XmEntryLeftSet(seg, p_direction, last); _XmEntryRightSet(last, p_direction, seg); } else { _XmEntryRightSet(seg, p_direction, last); _XmEntryLeftSet(last, p_direction, seg); } _XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False); } _XmEntryLayoutSet(seg, p_direction, (long)direction); _XmEntryLayoutDepthSet(seg, p_direction, (long)depth); /* If we had a pop with its matching push on another line, now we know what will be adjacent to it in the layout If we popped from left-to-right, we will attach the leftmost segment in the previous level with the rightmost segment in the current level. Vice versa for right-to-left. */ if (pop_index >= 0 && pop_index != *seg_index) { if (_XmStrImplicitLine(string)) last = _XmEntrySegmentGet(line)[pop_index]; else last = (_XmStringNREntry)_XmStrEntry(string)[pop_index]; if (XmDirectionMatch(pop_dir, XmLEFT_TO_RIGHT)) { while (_XmEntryLeftGet(last, p_direction)) last = (_XmStringNREntry)_XmEntryLeftGet(last, p_direction); while (_XmEntryRightGet(seg, p_direction)) seg = (_XmStringNREntry)_XmEntryRightGet(seg, p_direction); _XmEntryRightSet(seg, p_direction, last); _XmEntryLeftSet(last, p_direction, seg); _XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False); _XmEntryDirtySet(seg, _XmSCANNING_CACHE, p_direction, False); } else { while (_XmEntryRightGet(last, p_direction)) last = (_XmStringNREntry)_XmEntryRightGet(last, p_direction); while (_XmEntryLeftGet(seg, p_direction)) seg = (_XmStringNREntry)_XmEntryLeftGet(seg, p_direction); _XmEntryLeftSet(seg, p_direction, last); _XmEntryRightSet(last, p_direction, seg); _XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False); _XmEntryDirtySet(seg, _XmSCANNING_CACHE, p_direction, False); } } return; } else { /* Default: No push/pop or push, pop in same segment */ /* set up connection */ if (last) { if (XmDirectionMatch(direction, XmLEFT_TO_RIGHT)) { _XmEntryLeftSet(seg, p_direction, last); _XmEntryRightSet(last, p_direction, seg); } else { _XmEntryRightSet(seg, p_direction, last); _XmEntryLeftSet(last, p_direction, seg); } _XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False); } last = seg; _XmEntryLayoutSet(seg, p_direction, (long)direction); _XmEntryLayoutDepthSet(seg, p_direction, (long)depth); (*seg_index)++; } } /* If we had a pop with its matching push on another line, now we know what will be adjacent to it in the layout, namely the last segment on this line. */ if (pop_index >= 0 && last) { if (pop_index != *seg_index-1) { if (_XmStrImplicitLine(string)) seg2 = _XmEntrySegmentGet(line)[pop_index]; else seg2 = (_XmStringNREntry)_XmStrEntry(string)[pop_index]; if (XmDirectionMatch(pop_dir, XmLEFT_TO_RIGHT)) { _XmEntryRightSet(seg2, p_direction, last); _XmEntryLeftSet(last, p_direction, seg2); } else { _XmEntryLeftSet(seg2, p_direction, last); _XmEntryRightSet(last, p_direction, seg2); } _XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False); _XmEntryDirtySet(seg2, _XmSCANNING_CACHE, p_direction, False); } pop_index = -1; } (*line_index)++; (*seg_index) = 0; last = NULL; } } void _XmStringLayout(_XmString string, #if NeedWidePrototypes int direction) #else XmDirection direction) #endif { int seg_index=0, line_index=0; _XmStringEntry line; _XmStringNREntry seg; Boolean needs_recompute = False; if (!_XmStrMultiple(string)) return; if (_XmStrEntryCount(string)) { line = _XmStrEntry(string)[0]; if (_XmEntrySegmentCountGet(line)) { seg = _XmEntrySegmentGet(line)[0]; needs_recompute = _XmEntryDirtyGet(seg, _XmSCANNING_CACHE, direction); } } if (!needs_recompute) return; while (line_index < _XmStrEntryCount(string)) { line = _XmStrEntry(string)[line_index]; while (seg_index < _XmEntrySegmentCountGet(line)) { seg = _XmEntrySegmentGet(line)[seg_index]; if (_XmEntrySegmentCountGet(line) > 1) { _XmEntryDirtySet(seg, _XmSCANNING_CACHE, direction, True); _XmEntryLeftSet(seg, direction, NULL); _XmEntryRightSet(seg, direction, NULL); } seg_index++; } seg_index = 0; line_index++; } line_index = seg_index = 0; recursive_layout(string, &line_index, &seg_index, direction, direction, 0); /* if there are pops w/o matching pushes, ignore them */ while (line_index < _XmStrLineCountGet(string) && seg_index < _XmEntrySegmentCountGet(_XmStrEntry(string)[line_index])) { line = _XmStrEntry(string)[line_index]; seg = _XmEntrySegmentGet(line)[seg_index]; _XmEntryPopSet(seg, False); recursive_layout(string, &line_index, &seg_index, direction, direction, 0); _XmEntryPopSet(seg, True); } } /**************************************************************** * What's the layout direction at the end of the line? ****************************************************************/ static void last_direction(_XmStringEntry line, int *index, XmDirection *direction) { _XmStringNREntry seg; XmDirection sub_dir = *direction; while (*index < _XmEntrySegmentCountGet(line)) { seg = _XmEntrySegmentGet(line)[*index]; if (_XmEntryPushGet((_XmStringEntry)seg) && !_XmEntryPopGet((_XmStringEntry)seg)) { sub_dir = _XmEntryPushGet((_XmStringEntry)seg); (*index)++; last_direction(line, index, &sub_dir); if (*index < _XmEntrySegmentCountGet(line)) sub_dir = *direction; (*index)++; } else if (!_XmEntryPushGet((_XmStringEntry)seg) && _XmEntryPopGet((_XmStringEntry)seg)) return; else (*index)++; } *direction = sub_dir; } /* * Draw a single internal TCS line */ static void DrawLine( Display *d, Window w, Screen **pscreen, int x, int y, _XmStringEntry line, XmRendition *scr_rend, XmRendition base, XmRenderTable rendertable, XmDirection prim_dir, #if NeedWidePrototypes int image, #else Boolean image, #endif /* NeedWidePrototypes */ _XmString *underline, #if NeedWidePrototypes int descender, int opt, int opt_width, int opt_height #else Dimension descender, Boolean opt, Dimension opt_width, Dimension opt_height #endif /* NeedWidePrototypes */ ) { int i, prev_val, val, offset; XmTabList tl = NULL; XmTab tab; unsigned short tab_cnt; /* Absolute tabs use this as left margin */ offset = x; if (opt) { /* * This is optimized; build an optimized segment and call the drawing * routine. */ _XmStringOptSegRec segm; _XmString optline = (_XmString)line; _XmEntryInit((_XmStringEntry)&segm, XmSTRING_ENTRY_OPTIMIZED); _XmEntryTagIndex(&segm) = _XmStrTagIndex(optline); _XmEntryByteCountSet(&segm, _XmStrByteCount(optline)); _XmEntryTextTypeSet(&segm, (XmTextType) _XmStrTextType(optline)); _XmEntryTextSet((_XmStringEntry)&segm, _XmStrText(optline)); if (_XmStrDirection(optline) != XmSTRING_DIRECTION_UNSET) _XmEntryDirectionSet((_XmStringEntry)&segm, _XmStrDirection(optline)); else _XmEntryDirectionSet((_XmStringEntry)&segm, XmDirectionToStringDirection(prim_dir)); if (_XmStrRendBegin(optline)) _XmEntryRendIndex(&segm) = _XmStrRendIndex(optline); if (*scr_rend != NULL) tl = _XmRendTabs(*scr_rend); tab = (tl == NULL) ? NULL : _XmTabLStart(tl); prev_val = x; tab_cnt = 0; if ((tab != NULL) && (_XmEntryTabsGet((_XmStringEntry)&segm) != 0) && (tab_cnt < _XmTabLCount(tl)) && _XmEntryDirectionGet((_XmStringEntry)&segm) != XmSTRING_DIRECTION_R_TO_L) { for (i = 0; (i < _XmEntryTabsGet((_XmStringEntry)&segm)) && (tab_cnt < _XmTabLCount(tl)); i++, tab = _XmTabNext(tab), tab_cnt++) { val = TabVal(d, pscreen, w, tab); if (_XmTabModel(tab) == XmABSOLUTE) { x = val + offset; prev_val = x; } else /* XmRELATIVE */ { x = prev_val + val; prev_val += val; } } } _XmStringDrawSegment(d, w, x, y, opt_width, opt_height, (_XmStringNREntry)&segm, *scr_rend, rendertable, image, underline, descender); } else { _XmStringNREntry seg; int seg_index = 0; Boolean ok; Dimension width, height; Boolean set_direction = False; XmDirection lay_dir = prim_dir; /* layout direction of this line */ seg = _XmEntrySegmentGet(line)[seg_index]; if (_XmEntryType(seg) != XmSTRING_ENTRY_OPTIMIZED) { lay_dir = _XmEntryLayoutGet(seg, prim_dir); } if (XmDirectionMatch(lay_dir, XmLEFT_TO_RIGHT)) { if (_XmEntryType(seg) != XmSTRING_ENTRY_OPTIMIZED) { while (_XmEntryLeftGet(seg, prim_dir) != NULL) seg = (_XmStringNREntry)_XmEntryLeftGet(seg, prim_dir); } if (_XmEntryDirectionGet((_XmStringEntry)seg) == XmSTRING_DIRECTION_UNSET) { _XmEntryDirectionSet((_XmStringEntry)seg, XmDirectionToStringDirection(prim_dir)); set_direction = True; } ok = SpecifiedSegmentExtents((_XmStringEntry)seg, rendertable, scr_rend, base, XmSTRING_MIDDLE_SEG, &width, &height, NULL, NULL); if (*scr_rend != NULL) tl = _XmRendTabs(*scr_rend); tab = (tl == NULL) ? NULL : _XmTabLStart(tl); prev_val = x; tab_cnt = 0; while (seg != NULL) { /* If this segment is tabbed, set x accordingly. */ if ((tab != NULL) && (_XmEntryTabsGet((_XmStringEntry)seg) != 0) && (tab_cnt < _XmTabLCount(tl))) { int start_x = x; for (i = 0; (i < _XmEntryTabsGet((_XmStringEntry)seg)) && (tab_cnt < _XmTabLCount(tl)); i++, tab = _XmTabNext(tab), tab_cnt++) { val = TabVal(d, pscreen, w, tab); if (_XmTabModel(tab) == XmABSOLUTE) x = MAX(x, (val + offset)); else /* XmRELATIVE */ x = MAX(x, prev_val + val); prev_val = x; } _XmStringDrawLining(d, w, start_x, y, (x - start_x), height, descender, *scr_rend, XmUNSPECIFIED_PIXEL, XmHIGHLIGHT_NORMAL, FALSE); } if (ok) _XmStringDrawSegment(d, w, x, y, width, height, seg, *scr_rend, rendertable, image, underline, descender); x += width; if (set_direction) { _XmEntryDirectionSet((_XmStringEntry)seg, XmSTRING_DIRECTION_UNSET); set_direction = False; } if (_XmEntryType(seg) != XmSTRING_ENTRY_OPTIMIZED) { seg = (_XmStringNREntry)_XmEntryRightGet(seg, prim_dir); } else { seg_index++; seg = (seg_index < _XmEntrySegmentCountGet(line) ? _XmEntrySegmentGet(line)[seg_index] : NULL); } if (seg != NULL) { if (_XmEntryDirectionGet((_XmStringEntry)seg) == XmSTRING_DIRECTION_UNSET) { _XmEntryDirectionSet((_XmStringEntry)seg, XmDirectionToStringDirection(prim_dir)); set_direction = True; } ok = SpecifiedSegmentExtents((_XmStringEntry)seg, rendertable, scr_rend, base, XmSTRING_MIDDLE_SEG, &width, &height, NULL, NULL); } } } else { if (_XmEntryType(seg) != XmSTRING_ENTRY_OPTIMIZED) { while (_XmEntryRightGet(seg, prim_dir) != NULL) seg = (_XmStringNREntry)_XmEntryRightGet(seg, prim_dir); } if (_XmEntryDirectionGet((_XmStringEntry)seg) == XmSTRING_DIRECTION_UNSET) { _XmEntryDirectionSet((_XmStringEntry)seg, XmDirectionToStringDirection(prim_dir)); set_direction = True; } ok = SpecifiedSegmentExtents((_XmStringEntry)seg, rendertable, scr_rend, base, XmSTRING_MIDDLE_SEG, &width, &height, NULL, NULL); if (*scr_rend != NULL) tl = _XmRendTabs(*scr_rend); tab = (tl == NULL) ? NULL : _XmTabLStart(tl); x += opt_width; offset = prev_val = x; tab_cnt = 0; while (seg != NULL) { /* If this segment is tabbed, set x accordingly. */ if ((tab != NULL) && (_XmEntryTabsGet((_XmStringEntry)seg) != 0) && (tab_cnt < _XmTabLCount(tl))) { int start_x = x; for (i = 0; (i < _XmEntryTabsGet((_XmStringEntry)seg)) && (tab_cnt < _XmTabLCount(tl)); i++, tab = _XmTabNext(tab), tab_cnt++) { val = TabVal(d, pscreen, w, tab); if (_XmTabModel(tab) == XmABSOLUTE) x = MIN(x, offset - val); else /* XmRELATIVE */ x = MIN(x, prev_val - val); prev_val = x; } _XmStringDrawLining(d, w, x, y, (start_x - x), height, descender, *scr_rend, XmUNSPECIFIED_PIXEL, XmHIGHLIGHT_NORMAL, FALSE); } x -= width; if (ok) _XmStringDrawSegment(d, w, x, y, width, height, seg, *scr_rend, rendertable, image, underline, descender); if (set_direction) { _XmEntryDirectionSet((_XmStringEntry)seg, XmSTRING_DIRECTION_UNSET); set_direction = False; } if (_XmEntryType(seg) != XmSTRING_ENTRY_OPTIMIZED) { seg = (_XmStringNREntry)_XmEntryLeftGet(seg, prim_dir); } else { seg_index++; seg = (seg_index < _XmEntrySegmentCountGet(line) ? _XmEntrySegmentGet(line)[seg_index] : NULL); } if (seg != NULL) { if (_XmEntryDirectionGet((_XmStringEntry)seg) == XmSTRING_DIRECTION_UNSET) { _XmEntryDirectionSet((_XmStringEntry)seg, XmDirectionToStringDirection(prim_dir)); set_direction = True; } ok = SpecifiedSegmentExtents((_XmStringEntry)seg, rendertable, scr_rend, base, XmSTRING_MIDDLE_SEG, &width, &height, NULL, NULL); } } } } } /* * calculate the alignment, position and clipping for the string */ static void _calc_align_and_clip( Display *d, GC gc, Position *x, #if NeedWidePrototypes int y, int width, #else Position y, Dimension width, #endif /* NeedWidePrototypes */ int line_width, #if NeedWidePrototypes unsigned int lay_dir, #else unsigned char lay_dir, #endif /* NeedWidePrototypes */ XRectangle *clip, #if NeedWidePrototypes unsigned int align, #else unsigned char align, #endif /* NeedWidePrototypes */ int descender, int *restore ) { Boolean l_to_r = XmDirectionMatch(lay_dir, XmSTRING_DIRECTION_L_TO_R); switch (align) { case XmALIGNMENT_BEGINNING: if ( ! l_to_r) *x += width - line_width; break; case XmALIGNMENT_CENTER: *x += Half (width) - Half (line_width); break; case XmALIGNMENT_END : if (l_to_r) *x += width - line_width; break; } if ((clip != NULL) && ( ! *restore)) /* BEGIN OSF Fix CR 5106 */ if ((line_width > clip->width) || /* END OSF Fix CR 5106 */ (y + descender) > (clip->y + clip->height)) { *restore = TRUE; XSetClipRectangles (d, gc, 0, 0, clip, 1, YXBanded); } } /* * draw a complete internal format TCS */ static void _draw( Display *d, Window w, XmRenderTable rendertable, _XmString string, GC gc, #if NeedWidePrototypes int x, int y, int width, unsigned int align, unsigned int lay_dir, #else Position x, Position y, Dimension width, unsigned char align, unsigned char lay_dir, #endif /* NeedWidePrototypes */ XRectangle *clip, #if NeedWidePrototypes int image, #else Boolean image, #endif /* NeedWidePrototypes */ _XmString underline ) { static XmRendition rend = NULL; if (!string) return; _XmProcessLock(); if (rend == NULL) rend = XmRenditionCreate(NULL, XmS, NULL, 0); _XmRendDisplay(rend) = d; _XmRendGC(rend) = gc; _XmRendTags(rend) = NULL; _XmRendTagCount(rend) = 0; _render(d, w, rendertable, rend, string, x, y, width, align, lay_dir, image, underline, clip); _XmProcessUnlock(); } /* * render a complete internal format TCS */ static void _render(Display *d, Drawable w, XmRenderTable rendertable, XmRendition rend, _XmString string, #if NeedWidePrototypes int x, int y, int width, unsigned int align, unsigned int lay_dir, int image, #else Position x, Position y, Dimension width, unsigned char align, unsigned char lay_dir, Boolean image, #endif /* NeedWidePrototypes */ _XmString underline, XRectangle *clip) { Position base_x = x, draw_x; Dimension line_width, line_height, ascender = 0, descender = 0; _XmStringEntry line; int i; int restore_clip = FALSE; _XmRenditionRec scratch1, scratch2; _XmRendition tmp1, tmp2; XmRendition rend1, rend2; GC gc; Screen *screen = NULL; if (!string) return; tmp1 = &scratch1; bzero((char *)tmp1, sizeof(_XmRenditionRec)); rend1 = &tmp1; tmp2 = &scratch2; bzero((char *)tmp2, sizeof(_XmRenditionRec)); rend2 = &tmp2; _XmRendDisplay(rend1) = _XmRendDisplay(rend2) = d; gc = _XmRendGC(rend1) = _XmRendGC(rend2) = _XmRendGC(rend); _XmRendTags(rend1) = _XmRendTags(rend2) = NULL; _XmRendTagCount(rend1) = _XmRendTagCount(rend2) = 0; if (lay_dir <= 1) /* got passed XmStringDirection value */ lay_dir = XmStringDirectionToDirection(lay_dir); if (_XmStrOptimized(string)) { OptLineMetrics(rendertable, string, &rend2, rend, &line_width, &line_height, &ascender, &descender); y += ascender; if (line_width != 0) { draw_x = base_x ; /* most left position */ _calc_align_and_clip( d, gc, &draw_x, y, width, line_width, lay_dir, clip, align, descender, &restore_clip) ; DrawLine(d, w, &screen, draw_x, y, (_XmStringEntry)string, &rend2, rend, rendertable, lay_dir, image, &underline, descender, TRUE, line_width, line_height); } y += descender ; /* go to bottom of this line */ } else { XmDirection direction = lay_dir; int val; _XmStringArraySegRec array_seg; _XmStringLayout(string, lay_dir); for (i = 0; i < _XmStrLineCountGet(string); i++) { if (_XmStrImplicitLine(string)) { line = _XmStrEntry(string)[i]; } else { _XmEntryType(&array_seg) = XmSTRING_ENTRY_ARRAY; _XmEntrySegmentCount(&array_seg) = _XmStrEntryCount(string); _XmEntrySegment(&array_seg) = (_XmStringNREntry *)_XmStrEntry(string); line = (_XmStringEntry)&array_seg; } /* width, height, ascent, descent of this line */ LineMetrics(line, rendertable, &rend2, rend, lay_dir, &line_width, &line_height, &ascender, &descender); y += ascender; if (line_width != 0) { draw_x = base_x; /* most left position */ _calc_align_and_clip(d, gc, &draw_x, y, width, line_width, direction, clip, align, descender, &restore_clip); DrawLine(d, w, &screen, draw_x, y, line, &rend1, rend, rendertable, lay_dir, image, &underline, descender, FALSE, line_width, line_height); val = 0; last_direction((_XmStringEntry)line, &val, &direction); if (val < _XmEntrySegmentCountGet(line)) /* found an 'unmatched' pop */ direction = lay_dir; } y += descender; /* go to bottom of this line */ } } if (restore_clip) XSetClipMask (d, gc, None); if (_XmRendTags(rend1) != NULL) XtFree((char *)_XmRendTags(rend1)); if (_XmRendTags(rend2) != NULL) XtFree((char *)_XmRendTags(rend2)); } void _XmStringRender(Display *d, Drawable w, XmRenderTable rendertable, XmRendition rend, _XmString string, #if NeedWidePrototypes int x, int y, int width, unsigned int align, unsigned int lay_dir #else Position x, Position y, Dimension width, unsigned char align, unsigned char lay_dir #endif /* NeedWidePrototypes */ ) { _render(d, w, rendertable, rend, string, x, y, width, align, lay_dir, FALSE, NULL, NULL); } /* * add a new segment to a particular line in an XmString */ void _XmStringSegmentNew( _XmString string, int line_index, _XmStringEntry value, int copy) { _XmStringEntry line; _XmStringEntry seg; int sc; int lc = _XmStrEntryCount(string); if (lc == 0 || lc-1 < line_index) { _XmStrEntry(string) = (_XmStringEntry *) XtRealloc((char *) _XmStrEntry(string), sizeof(_XmStringEntry) * (lc + 1)); _XmStrEntryCount(string)++; if (line_index > lc) line_index = lc; if (copy) line = _XmStringEntryCopy(value); else { line = value; } _XmStrEntry(string)[line_index] = line; } else { line = _XmStrEntry(string)[line_index]; if (!_XmEntryMultiple(line)) { /* have to create an array entry */ sc = 1; seg = line; _XmEntryCreate(line, XmSTRING_ENTRY_ARRAY); _XmEntrySegmentCount(line) = sc; _XmEntrySoftNewlineSet(line, _XmEntrySoftNewlineGet(seg)); _XmEntrySegment(line) = (_XmStringNREntry *) XtMalloc(sizeof(_XmStringEntry) * 2); _XmEntrySegment(line)[0] = (_XmStringNREntry)seg; _XmStrEntry(string)[line_index] = line; _XmStrImplicitLine(string) = True; } else { sc = _XmEntrySegmentCount(line); _XmEntrySegment(line) = (_XmStringNREntry *) XtRealloc((char *) _XmEntrySegment(line), sizeof(_XmStringEntry) * (sc+1)); } seg = (copy ? _XmStringEntryCopy(value) : value); _XmEntrySegment(line)[sc] = (_XmStringNREntry)seg; _XmEntrySegmentCount(line)++; } } static _XmString _XmStringOptCreate( unsigned char *c, unsigned char *end, #if NeedWidePrototypes unsigned int textlen, int havetag, #else unsigned short textlen, Boolean havetag, #endif /* NeedWidePrototypes */ unsigned int tag_index ) { _XmString string; char *tag = NULL; unsigned short length; _XmStrCreate(string, XmSTRING_OPTIMIZED, textlen); if (havetag) { _XmStrTagIndex((_XmString)string) = tag_index ; } else { tag = XmFONTLIST_DEFAULT_TAG; _XmStrTagIndex((_XmString)string) = _XmStringIndexCacheTag((char *) tag, XmSTRING_TAG_STRLEN); } while (c < end) { length = _read_asn1_length (c); switch (*c) { case XmSTRING_COMPONENT_RENDITION_BEGIN: _XmStrRendIndex(string) = _XmStringIndexCacheTag((char *)(c + _asn1_size(length)), (int)length); _XmStrRendBegin(string) = TRUE; break; case XmSTRING_COMPONENT_LOCALE: _XmStrTextType((_XmString)string) = XmMULTIBYTE_TEXT; break; case XmSTRING_COMPONENT_TAG: _XmStrTextType((_XmString)string) = XmCHARSET_TEXT; break; case XmSTRING_COMPONENT_TAB: _XmStrTabs(string)++; break; case XmSTRING_COMPONENT_DIRECTION: /* record dir */ _XmStrDirection((_XmString) string) = ((XmStringDirection)*(c + _asn1_size(length))); break; case XmSTRING_COMPONENT_TEXT: _XmStrTextType((_XmString)string) = XmCHARSET_TEXT; memcpy(_XmStrText((_XmString)string), (c + _asn1_size(length)), textlen); break; case XmSTRING_COMPONENT_LOCALE_TEXT: _XmStrTextType((_XmString)string) = XmMULTIBYTE_TEXT; memcpy(_XmStrText((_XmString)string), (c + _asn1_size(length)), textlen); break; case XmSTRING_COMPONENT_RENDITION_END: _XmStrRendIndex(string) = _XmStringIndexCacheTag((char *)(c + _asn1_size(length)), (int)length); _XmStrRendEnd(string) = TRUE; break; case XmSTRING_COMPONENT_SEPARATOR: /* start new line */ _XmStrFree ((char *) string); return (NULL); /* break; */ default: break; } c += length + _asn1_size(length); } return((_XmString) string); } static void finish_segment(_XmString str, _XmStringUnoptSeg seg, int *lc, int *sc, Boolean *unopt, XmStringDirection dir) { _XmStringEntry opt_seg; _XmEntryDirectionSet((_XmStringEntry)seg, dir); if (!*unopt && (opt_seg = EntryCvtToOpt((_XmStringEntry)seg))) _XmStringSegmentNew(str, _XmStrImplicitLine(str) ? *lc : *sc, opt_seg, False); else _XmStringSegmentNew(str, _XmStrImplicitLine(str) ? *lc : *sc, (_XmStringEntry)seg, True); (*sc)++; *unopt = False; _XmEntryInit((_XmStringEntry)seg, XmSTRING_ENTRY_UNOPTIMIZED); } static _XmString _XmStringNonOptCreate( unsigned char *c, unsigned char *end, #if NeedWidePrototypes int havetag ) #else Boolean havetag ) #endif /* NeedWidePrototypes */ { int lc, sc; _XmStringUnoptSegRec seg; unsigned short length; _XmString string ; char *tag = NULL; Boolean needs_unopt = False; Boolean txt_seen = False; Boolean push_seen = False; Boolean pop_seen = False; Boolean need_finish = False; int rend_cnt; int tab_cnt; XmTextType prev_type = XmCHARSET_TEXT; XmStringDirection dir = XmSTRING_DIRECTION_UNSET; _XmStrCreate(string, XmSTRING_MULTIPLE_ENTRY, 0); _XmEntryInit((_XmStringEntry)&seg, XmSTRING_ENTRY_UNOPTIMIZED); if (!havetag) { tag = XmFONTLIST_DEFAULT_TAG; _XmUnoptSegTag(&seg) = _XmStringCacheTag((char *) (tag), XmSTRING_TAG_STRLEN); } _XmEntryDirectionSet((_XmStringEntry)&seg, XmSTRING_DIRECTION_L_TO_R); lc = sc = 0; while (c < end) { length = _read_asn1_length (c); need_finish = True; switch (*c) { case XmSTRING_COMPONENT_LAYOUT_PUSH: /* record dir */ if ((txt_seen) || (push_seen)) { finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir); push_seen = txt_seen = pop_seen = False; } needs_unopt = True; push_seen = True; _XmEntryPushSet(&seg, (XmDirection)*(c + _asn1_size(length))); break; case XmSTRING_COMPONENT_RENDITION_BEGIN: if (txt_seen) { finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir); push_seen = txt_seen = pop_seen = False; } rend_cnt = ++(_XmUnoptSegRendBeginCount(&seg)); if (rend_cnt > 1) needs_unopt = True; _XmUnoptSegRendBegins(&seg) = (XmStringTag *) XtRealloc((char *)_XmUnoptSegRendBegins(&seg), rend_cnt); _XmUnoptSegRendBegins(&seg)[rend_cnt - 1] = _XmStringCacheTag((char *)(c + _asn1_size(length)), (int)length); break; case XmSTRING_COMPONENT_LOCALE: if (txt_seen) { finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir); push_seen = txt_seen = pop_seen = False; } _XmEntryTextTypeSet(&seg, XmMULTIBYTE_TEXT); prev_type = XmMULTIBYTE_TEXT; _XmUnoptSegTag(&seg) = _XmStringCacheTag((char *)(c+_asn1_size(length)), (int)length); break; case XmSTRING_COMPONENT_TAG: if (txt_seen) { finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir); push_seen = txt_seen = pop_seen = False; } _XmEntryTextTypeSet(&seg, XmCHARSET_TEXT); prev_type = XmCHARSET_TEXT; _XmUnoptSegTag(&seg) = _XmStringCacheTag((char *)(c+_asn1_size(length)), (int)length); break; case XmSTRING_COMPONENT_TAB: if (txt_seen) { finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir); push_seen = txt_seen = pop_seen = False; } tab_cnt = _XmEntryTabsGet((_XmStringEntry)&seg); if (++tab_cnt > 7) needs_unopt = True; _XmEntryTabsSet(&seg, tab_cnt); break; case XmSTRING_COMPONENT_DIRECTION: /* record dir */ if (txt_seen) { finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir); push_seen = txt_seen = pop_seen = False; } dir = (XmStringDirection)*(c + _asn1_size(length)); break; case XmSTRING_COMPONENT_WIDECHAR_TEXT: if (txt_seen) { finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir); push_seen = txt_seen = pop_seen = False; } _XmEntryTextTypeSet(&seg, XmWIDECHAR_TEXT); prev_type = XmWIDECHAR_TEXT; /* Fall through */ case XmSTRING_COMPONENT_LOCALE_TEXT: if (txt_seen) { finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir); push_seen = txt_seen = pop_seen = False; } /* from above */ if (_XmEntryTextTypeGet((_XmStringEntry)&seg) != XmWIDECHAR_TEXT) { _XmEntryTextTypeSet(&seg, XmMULTIBYTE_TEXT); prev_type = XmMULTIBYTE_TEXT; } _XmUnoptSegTag(&seg) = _XmStringCacheTag((char *) XmFONTLIST_DEFAULT_TAG, XmSTRING_TAG_STRLEN); /* Fall through to regular text. */ case XmSTRING_COMPONENT_TEXT: if (txt_seen) { push_seen = txt_seen = pop_seen = False; finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir); } if (_XmEntryTextTypeGet((_XmStringEntry)&seg) == XmNO_TEXT) _XmEntryTextTypeSet(&seg, prev_type); _XmEntryTextSet((_XmStringEntry)&seg, (c + _asn1_size(length))); _XmUnoptSegByteCount(&seg) = length; txt_seen = True; break; case XmSTRING_COMPONENT_RENDITION_END: txt_seen = True; rend_cnt = ++(_XmUnoptSegRendEndCount(&seg)); if (rend_cnt > 1) needs_unopt = True; _XmUnoptSegRendEnds(&seg) = (XmStringTag *) XtRealloc((char *)_XmUnoptSegRendEnds(&seg), rend_cnt); _XmUnoptSegRendEnds(&seg)[rend_cnt - 1] = _XmStringCacheTag((char *)(c + _asn1_size(length)), (int)length); break; case XmSTRING_COMPONENT_LAYOUT_POP: if (pop_seen) { finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir); push_seen = txt_seen = pop_seen = False; } needs_unopt = True; txt_seen = True; pop_seen = True; _XmEntryPopSet(&seg, TRUE); break; case XmSTRING_COMPONENT_SEPARATOR: /* start new line */ finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir); need_finish = push_seen = txt_seen = pop_seen = False; if (!_XmStrImplicitLine(string) && _XmStrEntryCount(string) > 1) { /* need to move segments down one level */ _XmStringEntry line; line = (_XmStringEntry)XtMalloc(sizeof(_XmStringArraySegRec)); _XmEntryType(line) = XmSTRING_ENTRY_ARRAY; _XmEntrySoftNewlineSet(line, False); _XmEntrySegmentCount(line) = _XmStrEntryCount(string); _XmEntrySegment(line) = (_XmStringNREntry *)_XmStrEntry(string); _XmStrEntry(string) = (_XmStringEntry *)XtMalloc(sizeof(_XmStringEntry)); _XmStrEntry(string)[0] = line; _XmStrEntryCount(string) = 1; } _XmStrImplicitLine(string) = True; lc++; break; default: break; } c += length + _asn1_size(length); } if (need_finish) finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir); return(string); } /* * Converts from ASN.1 formatted byte stream to XmString. */ /*ARGSUSED*/ XmString XmCvtByteStreamToXmString(unsigned char *property) { unsigned char *c; unsigned char *c_opt; unsigned char *end; unsigned short length; unsigned short txtlength; XmString string ; Boolean continue_flag; Boolean optimized; Boolean havetag; Boolean begin_seen, end_seen; Boolean txt_seen; unsigned int tag_index = TAG_INDEX_MAX; unsigned int begin_index = REND_INDEX_MAX; unsigned int end_index = REND_INDEX_MAX; unsigned char tab_cnt; _XmProcessLock(); if (!property) { _XmProcessUnlock(); return((XmString) NULL); } /* If property isn't an asn.1 conformant string, return NULL. */ if (!_is_asn1(property)) { _XmProcessUnlock(); return ((XmString) NULL); } c = (unsigned char *) _read_header((unsigned char *) property); end = c + _read_string_length ((unsigned char *) property); if (c >= end) { _XmProcessUnlock(); return ((_XmString) NULL); } /* * In order to build an optimized string, we have to see if this one * qualifies. Do some preprocessing to see. * We also need to know if this CS contains a character set component, * so look for that too. */ c_opt = c; continue_flag = TRUE; optimized = TRUE; txtlength = 0; /* For strings with no text component. */ havetag = FALSE; end_seen = begin_seen = FALSE; txt_seen = FALSE; tab_cnt = 0; while (continue_flag) { length = _read_asn1_length (c_opt); switch (*c_opt) { /* All non-optimized */ case XmSTRING_COMPONENT_LAYOUT_PUSH: case XmSTRING_COMPONENT_LAYOUT_POP: case XmSTRING_COMPONENT_SEPARATOR: /* start new line */ optimized = FALSE; break; case XmSTRING_COMPONENT_RENDITION_BEGIN: if (begin_seen || txt_seen) { optimized = FALSE; break; } else { begin_seen = TRUE; begin_index = _XmStringIndexCacheTag((char *)(c_opt + _asn1_size(length)), (int)length); if (begin_index >= REND_INDEX_MAX) optimized = FALSE ; } break; case XmSTRING_COMPONENT_LOCALE: case XmSTRING_COMPONENT_TAG: tag_index = _XmStringIndexCacheTag ((char *) (c_opt + _asn1_size(length)), (int) length); if (txt_seen || (tag_index >= TAG_INDEX_MAX)) optimized = FALSE ; havetag = TRUE; break; case XmSTRING_COMPONENT_TAB: if (++tab_cnt > 3) optimized = FALSE; break; case XmSTRING_COMPONENT_DIRECTION: if (txt_seen) optimized = FALSE; break; case XmSTRING_COMPONENT_WIDECHAR_TEXT: optimized = FALSE; txtlength = length; break; case XmSTRING_COMPONENT_LOCALE_TEXT: /* Check the tag. */ tag_index = _XmStringIndexCacheTag((char *)XmFONTLIST_DEFAULT_TAG, XmSTRING_TAG_STRLEN); havetag = TRUE; if ((txt_seen) || (tag_index >= TAG_INDEX_MAX)) { optimized = FALSE; break; } /* Else fall through to text case. */ case XmSTRING_COMPONENT_TEXT: if (txt_seen || (((c_opt + length + _asn1_size(length)) < end) || (length >= (1 << BYTE_COUNT_BITS)))) optimized = FALSE; txtlength = length; txt_seen = TRUE; break; case XmSTRING_COMPONENT_RENDITION_END: if (end_seen) { optimized = FALSE; break; } else { end_seen = TRUE; txt_seen = TRUE; end_index = _XmStringIndexCacheTag((char *)(c_opt + _asn1_size(length)), (int)length); if ((end_index >= REND_INDEX_MAX) || (end_index != begin_index)) optimized = FALSE; } break; default: break; } c_opt += length + _asn1_size(length); if ((c_opt >= end) || (!optimized)) continue_flag = FALSE; } if (optimized) string = (_XmString) _XmStringOptCreate(c, end, txtlength, havetag, tag_index); else string = _XmStringNonOptCreate(c, end, havetag); _XmProcessUnlock(); return (string); } _XmStringEntry _XmStringEntryCopy(_XmStringEntry entry) { int i; int size; XtPointer text; _XmStringEntry new_entry = NULL; unsigned int entry_len; if (!entry) return NULL; entry_len = _XmEntryByteCountGet(entry); switch (_XmEntryType(entry)) { case XmSTRING_ENTRY_OPTIMIZED: if (_XmEntryImm(entry)) { if (entry_len > sizeof(XtPointer)) size = sizeof(_XmStringOptSegRec) + entry_len - sizeof(XtPointer); else size = sizeof(_XmStringOptSegRec); new_entry = (_XmStringEntry)XtMalloc(size); memcpy((char *)new_entry, (char *)entry, size); } else { new_entry = (_XmStringEntry)XtMalloc(sizeof(_XmStringOptSegRec)); memcpy((char *)new_entry, (char *)entry, sizeof(_XmStringOptSegRec)); if (_XmEntryPermGet(entry)) { _XmEntryTextSet(new_entry, _XmEntryTextGet(entry)); } else if (entry_len > 0) { text = (XtPointer)XtMalloc(entry_len); memcpy((char *)text, (char *)_XmEntryTextGet(entry), entry_len); _XmEntryTextSet(new_entry, text); } else _XmEntryTextSet(new_entry, NULL); } break; case XmSTRING_ENTRY_ARRAY: { _XmStringNREntry *arr; new_entry = (_XmStringEntry)XtMalloc(sizeof(_XmStringArraySegRec)); memcpy((char *)new_entry, (char *)entry, sizeof(_XmStringArraySegRec)); if (_XmEntrySegmentCount(entry) > 0) { arr = (_XmStringNREntry *)XtMalloc(_XmEntrySegmentCount(entry) * sizeof(_XmStringNREntry)); for (i = 0; i < _XmEntrySegmentCount(entry); i++) arr[i] = (_XmStringNREntry) _XmStringEntryCopy((_XmStringEntry)_XmEntrySegment(entry)[i]); _XmEntrySegment(new_entry) = arr; } else _XmEntrySegment(new_entry) = NULL; } break; case XmSTRING_ENTRY_UNOPTIMIZED: { new_entry = (_XmStringEntry)XtMalloc(sizeof(_XmStringUnoptSegRec)); memcpy((char *)new_entry, (char *)entry, sizeof(_XmStringUnoptSegRec)); if (_XmEntryPermGet(entry)) { _XmEntryTextSet(new_entry, _XmEntryTextGet(entry)); } else if (entry_len > 0) { text = (XtPointer)XtMalloc(entry_len); memcpy((char *)text, (char *)_XmEntryTextGet((_XmStringEntry)entry), entry_len); _XmEntryTextSet(new_entry, text); } else _XmEntryTextSet(new_entry, NULL); if (_XmUnoptSegRendBegins(entry)) { _XmUnoptSegRendBegins(new_entry) = (XmStringTag *)XtMalloc(_XmUnoptSegRendBeginCount(entry) * sizeof(XmStringTag)); for (i = 0; i < _XmUnoptSegRendBeginCount(entry); i++) _XmUnoptSegRendBegins(new_entry)[i] = _XmUnoptSegRendBegins(entry)[i]; } else _XmUnoptSegRendBegins(new_entry) = NULL; if (_XmUnoptSegRendEnds(entry)) { _XmUnoptSegRendEnds(new_entry) = (XmStringTag *)XtMalloc(_XmUnoptSegRendEndCount(entry) * sizeof(XmStringTag)); for (i = 0; i < _XmUnoptSegRendEndCount(entry); i++) _XmUnoptSegRendEnds(new_entry)[i] = _XmUnoptSegRendEnds(entry)[i]; } else _XmUnoptSegRendEnds(new_entry) = NULL; _XmEntryCacheSet(new_entry, NULL); } break; } return(new_entry); } /** Begin macros converted to functions. **/ XmStringTag _XmEntryTag(_XmStringEntry entry) { #if 1 XmStringTag rettag; if (_XmEntryOptimized(entry)) { if (_XmEntryTagIndex(entry) != TAG_INDEX_UNSET) rettag = _XmStringIndexGetTag(_XmEntryTagIndex(entry)); else rettag = NULL; } else rettag = _XmUnoptSegTag(entry); return rettag; #else return (_XmEntryOptimized(entry) ? (_XmEntryTagIndex(entry) != TAG_INDEX_UNSET ? _XmStringIndexGetTag(_XmEntryTagIndex(entry)) : NULL) : _XmUnoptSegTag(entry)); #endif } void _XmEntryTagSet(_XmStringEntry entry, XmStringTag tag) { if (_XmEntryOptimized(entry)) { if (tag == NULL) _XmEntryTagIndex(entry) = TAG_INDEX_UNSET; else _XmEntryTagIndex(entry) = _XmStringIndexCacheTag(tag, XmSTRING_TAG_STRLEN); } else { _XmUnoptSegTag(entry) = tag; } } XmDirection _XmEntryPushGet(_XmStringEntry entry) { return (_XmEntryUnoptimized(entry) ? ((_XmStringEntry)(entry))->unopt_single.push_before : False); } unsigned int _XmEntryByteCountGet(_XmStringEntry entry) { switch (_XmEntryType(entry)) { case XmSTRING_ENTRY_OPTIMIZED: return ((_XmStringEntry)(entry))->single.byte_count; case XmSTRING_ENTRY_ARRAY: return 0; case XmSTRING_ENTRY_UNOPTIMIZED: return _XmUnoptSegByteCount(entry); default: assert(FALSE); return 0; } } void _XmEntryTextSet(_XmStringEntry entry, XtPointer val) { (_XmEntryOptimized(entry) ? (!_XmEntryImm(entry) ? (((_XmStringOptSeg)(entry))->data.text = val) : /* This below is potentially dangerous. This function needs a length parameter, or requires that the byte count is set in the segment. However, to my knowledge, nobody needs this now. But it needs to be looked at.. */ strcpy((char *)((_XmStringOptSeg)(entry))->data.chars, (char *)val)) : (((_XmStringUnoptSeg)(entry))->data.text = val)); } XtPointer _XmEntryTextGet(_XmStringEntry entry) { return(_XmEntryOptimized(entry) ? (!_XmEntryImm(entry) ? ((_XmStringOptSeg)(entry))->data.text : (XtPointer)((_XmStringOptSeg)(entry))->data.chars) : (((_XmStringUnoptSeg)(entry))->data.text)); } unsigned int _XmEntryDirectionGet(_XmStringEntry entry) { return(_XmEntryOptimized(entry) ? ((_XmStringEntry)(entry))->single.str_dir : ((_XmStringEntry)(entry))->unopt_single.str_dir); } void _XmEntryDirectionSet(_XmStringEntry entry, XmDirection val) { (_XmEntryOptimized(entry) ? (((_XmStringEntry)entry)->single.str_dir = val) : (((_XmStringEntry)entry)->unopt_single.str_dir = val)); } unsigned int _XmEntryTextTypeGet(_XmStringEntry entry) { return(_XmEntryOptimized(entry) ? ((_XmStringEntry)(entry))->single.text_type : ((_XmStringEntry)(entry))->unopt_single.text_type); } _XmStringCache _XmEntryCacheGet(_XmStringEntry entry) { return (_XmEntryUnoptimized(entry) ? ((_XmStringUnoptSeg)(entry))->cache : NULL); } unsigned char _XmEntryRendEndCountGet(_XmStringEntry entry) { return(_XmEntryOptimized(entry) ? ((_XmStringEntry)(entry))->single.rend_end : _XmUnoptSegRendEndCount(entry)); } unsigned char _XmEntryRendBeginCountGet(_XmStringEntry entry) { return(_XmEntryOptimized(entry) ? ((_XmStringEntry)(entry))->single.rend_begin : _XmUnoptSegRendBeginCount(entry)); } Boolean _XmEntryPopGet(_XmStringEntry entry) { return (_XmEntryUnoptimized(entry) ? ((_XmStringEntry)(entry))->unopt_single.pop_after : False); } XmStringTag _XmEntryRendEndGet(_XmStringEntry entry, int n) { return((_XmEntryRendEndCountGet(entry) > n) ? (_XmEntryOptimized(entry) ? (_XmEntryRendIndex(entry) != REND_INDEX_UNSET ? _XmStringIndexGetTag(_XmEntryRendIndex(entry)) : NULL) : (((_XmStringUnoptSeg)(entry))->rend_end_tags)[n]) : NULL); } XmStringTag _XmEntryRendBeginGet(_XmStringEntry entry, int n) { return((_XmEntryRendBeginCountGet(entry) > n) ? (_XmEntryOptimized(entry) ? (_XmEntryRendIndex(entry) != REND_INDEX_UNSET ? _XmStringIndexGetTag(_XmEntryRendIndex(entry)) : NULL) : (((_XmStringUnoptSeg)(entry))->rend_begin_tags)[n]) : NULL); } void _XmEntryRendEndSet(_XmStringEntry entry, XmStringTag tag, int n) { int i; if (_XmEntryOptimized(entry)) { if (tag == NULL) { if (_XmEntryRendBeginCountGet(entry) == 0) _XmEntryRendIndex(entry) = REND_INDEX_UNSET; } else { _XmEntryRendIndex(entry) = _XmStringIndexCacheTag(tag, XmSTRING_TAG_STRLEN); } _XmEntryRendEndCountSet(entry, ((tag == NULL) ? 0 : 1)); } else { if (tag == NULL) { if (_XmEntryRendEndCountGet(entry) > n) { for (i = n; i < _XmEntryRendEndCountGet(entry) - 1; i++) _XmUnoptSegRendEnds(entry)[i] = _XmUnoptSegRendEnds(entry)[i+1]; _XmUnoptSegRendEndCount(entry)--; _XmUnoptSegRendEnds(entry)[_XmEntryRendEndCountGet(entry)] = NULL; if (_XmEntryRendEndCountGet(entry) == 0) { XtFree((char *)_XmUnoptSegRendEnds(entry)); _XmUnoptSegRendEnds(entry) = NULL; } } } else { if (n >= _XmUnoptSegRendEndCount(entry)) { n = _XmUnoptSegRendEndCount(entry); _XmUnoptSegRendEndCount(entry)++; _XmUnoptSegRendEnds(entry) = (XmStringTag *)XtRealloc((char *)_XmUnoptSegRendEnds(entry), _XmUnoptSegRendEndCount(entry) * sizeof(XmStringTag)); } _XmUnoptSegRendEnds(entry)[n] = tag; } } } void _XmEntryRendBeginSet(_XmStringEntry entry, XmStringTag tag, int n) { int i; if (_XmEntryOptimized(entry)) { if (tag == NULL) { if (_XmEntryRendEndCountGet(entry) == 0) _XmEntryRendIndex(entry) = REND_INDEX_UNSET; } else { _XmEntryRendIndex(entry) = _XmStringIndexCacheTag(tag, XmSTRING_TAG_STRLEN); } _XmEntryRendBeginCountSet(entry, ((tag == NULL) ? 0 : 1)); } else { if (tag == NULL) { if (_XmEntryRendBeginCountGet(entry) > n) { for (i = n; i < _XmEntryRendBeginCountGet(entry) - 1; i++) _XmUnoptSegRendBegins(entry)[i] = _XmUnoptSegRendBegins(entry)[i+1]; _XmUnoptSegRendBeginCount(entry)--; _XmUnoptSegRendBegins(entry)[_XmEntryRendBeginCountGet(entry)] = NULL; if (_XmEntryRendBeginCountGet(entry) == 0) { XtFree((char *)_XmUnoptSegRendBegins(entry)); _XmUnoptSegRendBegins(entry) = NULL; } } } else { if (n >= _XmUnoptSegRendBeginCount(entry)) { n = _XmUnoptSegRendBeginCount(entry); _XmUnoptSegRendBeginCount(entry)++; _XmUnoptSegRendBegins(entry) = (XmStringTag *)XtRealloc((char *)_XmUnoptSegRendBegins(entry), _XmUnoptSegRendBeginCount(entry) * sizeof(XmStringTag)); } _XmUnoptSegRendBegins(entry)[n] = tag; } } } unsigned char _XmEntryTabsGet(_XmStringEntry entry) { return(_XmEntryOptimized(entry) ? ((_XmStringEntry)(entry))->single.tabs_before : ((_XmStringEntry)(entry))->unopt_single.tabs_before); } /** End macros converted to functions. **/ void _XmStringEntryFree(_XmStringEntry entry) { int i; if (!entry) return; switch (_XmEntryType(entry)) { case XmSTRING_ENTRY_OPTIMIZED: if (!_XmEntryImm(entry) && !_XmEntryPermGet(entry) && _XmEntryTextGet(entry)) XtFree((char *)_XmEntryTextGet(entry)); XtFree((char *)entry); break; case XmSTRING_ENTRY_ARRAY: for (i = 0; i < _XmEntrySegmentCount(entry); i++) _XmStringEntryFree((_XmStringEntry)_XmEntrySegment(entry)[i]); if (_XmEntrySegment(entry)) XtFree((char *)_XmEntrySegment(entry)); XtFree((char *)entry); break; case XmSTRING_ENTRY_UNOPTIMIZED: _XmStringCacheFree(_XmEntryCacheGet(entry)); if (_XmUnoptSegRendBegins(entry)) XtFree((char *)_XmUnoptSegRendBegins(entry)); if (_XmUnoptSegRendEnds(entry)) XtFree((char *)_XmUnoptSegRendEnds(entry)); if (_XmEntryTextGet(entry) && !_XmEntryPermGet(entry)) XtFree((char *)_XmEntryTextGet(entry)); XtFree((char *)entry); break; } } /* * free the XmString internal data structure */ void XmStringFree( XmString string ) { int i; int lcount; _XmProcessLock(); if (!string) { _XmProcessUnlock(); return; } /* Decrement refcount. If not zero, just return. */ if (_XmStrRefCountDec(string) != 0) { _XmProcessUnlock(); return; } if (!_XmStrOptimized(string)) { lcount = _XmStrEntryCount(string); for (i = 0; i < lcount; i++) { _XmStringEntryFree(_XmStrEntry(string)[i]); } XtFree((char *)_XmStrEntry(string)); } _XmStrFree ((char *) string); _XmProcessUnlock(); } static void ComputeMetrics(XmRendition rend, XtPointer text, unsigned int byte_count, XmTextType type, int which_seg, Dimension *width, Dimension *height, Dimension *ascent, Dimension *descent) { Dimension wid, hi; int dir, asc, desc; wid = 0; hi = 0; asc = 0; desc = 0; if (_XmRendFontType(rend) == XmFONT_IS_FONT) { XFontStruct *font_struct = (XFontStruct *)_XmRendFont(rend); XCharStruct char_ret; if (two_byte_font(font_struct)) { if (byte_count >= 2) { XTextExtents16(font_struct, (XChar2b *)text, Half(byte_count), &dir, &asc, &desc, &char_ret); wid = ComputeWidth(which_seg, char_ret); /* pir 2967 */ if (wid == 0) wid = Half(byte_count) * (font_struct->max_bounds.width); hi = asc + desc; } } else { if (byte_count >= 1) { XTextExtents(font_struct, (char *)text, byte_count, &dir, &asc, &desc, &char_ret); wid = ComputeWidth(which_seg, char_ret); /* pir 2967 */ if (wid == 0) wid = byte_count * (font_struct->max_bounds.width); hi = asc + desc; } } } else if (_XmRendFontType(rend) == XmFONT_IS_FONTSET) { if (byte_count >= 1) { XFontSet font_set = (XFontSet)_XmRendFont(rend); XRectangle ink, logical; if (type == XmWIDECHAR_TEXT) XwcTextExtents(font_set, (wchar_t *)text, byte_count/sizeof(wchar_t), &ink, &logical); else XmbTextExtents(font_set, (char *)text, byte_count, &ink, &logical); if (logical.height == 0) { XFontSetExtents *extents = XExtentsOfFontSet(font_set); logical.height = extents->max_logical_extent.height; } wid = logical.width; hi = logical.height; asc = -(logical.y); desc = logical.height + logical.y; } } /* Adjust for underlining. Add one pixel for line and one pixel at bottom so * that line doesn't bleed into background with select color of * XmREVERSED_GROUND_COLORS. */ switch (_XmRendUnderlineType(rend)) { case XmSINGLE_LINE: case XmSINGLE_DASHED_LINE: if (desc < (SINGLE_OFFSET + 2)) { hi += (SINGLE_OFFSET + 2) - desc; desc = SINGLE_OFFSET + 2; } break; case XmDOUBLE_LINE: case XmDOUBLE_DASHED_LINE: if (desc < (DOUBLE_OFFSET + 2)) { hi += (DOUBLE_OFFSET + 2) - desc; desc = DOUBLE_OFFSET + 2; } break; default: break; } if (width != NULL) *width = wid; if (height != NULL) *height = hi; if (ascent != NULL) *ascent = asc; if (descent != NULL) *descent = desc; } static Dimension ComputeWidth(unsigned char which, XCharStruct char_ret) { Dimension wid = 0; int bearing; /* Width of first segment is -leftbearing + width. */ /* Width of last segment is max of width and rightbearing. */ /* Width of single segment is max of width and rightbearing - leftbearing. */ /* Width of all other segments is width. */ switch (which) { case XmSTRING_FIRST_SEG: if (char_ret.lbearing < 0) wid = -(char_ret.lbearing); /* Fall through */ case XmSTRING_MIDDLE_SEG: wid += char_ret.width; break; case XmSTRING_LAST_SEG: wid = ((char_ret.width > char_ret.rbearing) ? char_ret.width : char_ret.rbearing); break; case XmSTRING_SINGLE_SEG: bearing = char_ret.rbearing - char_ret.lbearing; wid = (char_ret.width > bearing) ? char_ret.width : bearing; break; } return(wid); } /**************************************************************** * ****************************************************************/ Boolean _XmStringSegmentExtents(_XmStringEntry entry, XmRenderTable rendertable, XmRendition * rend_in_out, XmRendition base, Dimension * width, Dimension * height, Dimension * ascent, Dimension * descent) { return(SpecifiedSegmentExtents(entry, rendertable, rend_in_out, base, XmSTRING_MIDDLE_SEG, width, height, ascent, descent)); } static Boolean SpecifiedSegmentExtents(_XmStringEntry entry, XmRenderTable rendertable, XmRendition * rend_in_out, XmRendition base, int which_seg, Dimension * width, Dimension * height, Dimension * ascent, Dimension * descent) { unsigned short count; XmStringTag *tags; unsigned int tag_count; Display *d; XmStringTag def_tag; XmStringTag entry_tag; XmRendition rend, cached_rend = NULL, def_rend; int i, j, depth, hits, ref_cnt, rt_ref_cnt; Dimension h, w, asc, dsc; Boolean can_do = TRUE; _XmRendition rend_int; _XmStringRenderingCache render_cache; /* Fetching the cache once and accessing the fields directly saves * substantial time searching the cache */ render_cache = (_XmStringRenderingCache)CacheGet(entry, _XmRENDERING_CACHE, False, (XtPointer)rendertable); if ((render_cache != NULL) && !render_cache->header.dirty) { if (width != NULL) *width = (Dimension)render_cache->width; if (height != NULL) *height = (Dimension)render_cache->height; if (ascent != NULL) *ascent = (Dimension)render_cache->ascent; if (descent != NULL) *descent = (Dimension)render_cache->descent; if (rend_in_out != NULL) *rend_in_out = render_cache->rendition; return True; } else if (rend_in_out == NULL) { if (render_cache != NULL) cached_rend = render_cache->rendition; if (cached_rend == NULL) return(FALSE); else rend_in_out = &cached_rend; } entry_tag = _XmEntryTag(entry); if (cached_rend == NULL) /* Update *rend_in_out. */ { /* Add rendition begins */ d = _XmRendDisplay(*rend_in_out); /* Prepare tags. */ count = _XmEntryRendBeginCountGet(entry); tags = _XmRendTags(*rend_in_out); tag_count = _XmRendTagCount(*rend_in_out); /* Update tag stack. */ if (count > 0) { tags = (XmStringTag *)XtRealloc((char *)tags, (sizeof(XmStringTag) * (tag_count + count))); for (i = 0; i < count; i++) tags[tag_count + i] = _XmEntryRendBeginGet(entry, i); tag_count += count; } /* compute rendition */ /* Find font as per I 198. */ /* 1. Find font from rendition tags. */ /* 2. Find font from locale/charset tag. */ if ((_XmRendTag(*rend_in_out) != entry_tag) || (count != 0) || _XmRendHadEnds(*rend_in_out)) { *rend_in_out = _XmRenditionMerge(d, rend_in_out, base, rendertable, entry_tag, tags, tag_count, (render_cache != NULL)); _XmRendTag(*rend_in_out) = entry_tag; } /* 3. Default rendition. */ if (_XmRendFont(*rend_in_out) == NULL) { def_tag = ((_XmEntryTextTypeGet(entry) == XmCHARSET_TEXT) ? XmFONTLIST_DEFAULT_TAG : _MOTIF_DEFAULT_LOCALE); rend = _XmRenditionMerge(d, rend_in_out, base, rendertable, def_tag, NULL, 0, (render_cache != NULL)); if ((rend != NULL) && (_XmRendFont(rend) == NULL) && ((def_rend = _XmRenderTableFindRendition(rendertable, def_tag, TRUE, FALSE, FALSE, NULL)) != NULL)) /* Call noFontCallback. */ { XmDisplay dsp; XmDisplayCallbackStruct cb; rt_ref_cnt = _XmRTRefcount(rendertable); def_rend = _XmRTRenditions(rendertable)[0]; rend_int = *def_rend; ref_cnt = _XmRendRefcount(def_rend); dsp = (XmDisplay)XmGetXmDisplay(d); cb.reason = XmCR_NO_FONT; cb.event = NULL; cb.rendition = def_rend; cb.font_name = XmS; XtCallCallbackList((Widget)dsp, dsp->display.noFontCallback, &cb); if (rend_int != *def_rend) /* Changed in callback. */ { /* Need to split ref counts. */ _XmRendRefcount(&rend_int) = ref_cnt - rt_ref_cnt; _XmRendRefcount(def_rend) = rt_ref_cnt; } if (_XmRendFont(def_rend) != NULL) { _XmRendFontType(rend) = _XmRendFontType(def_rend); _XmRendFont(rend) = _XmRendFont(def_rend); } else rend = NULL; } /* 4a. Take the first one */ if ((rend == NULL) && ((_XmEntryTextTypeGet(entry) == XmCHARSET_TEXT) || ((_XmEntryTextTypeGet(entry) == XmMULTIBYTE_TEXT) && (entry_tag == XmFONTLIST_DEFAULT_TAG))) && (rendertable != NULL) && (_XmRTCount(rendertable) > 0)) rend = _XmRenditionMerge(d, rend_in_out, base, rendertable, NULL, NULL, 0, (render_cache != NULL)); if ((rend != NULL) && (_XmRendFont(rend) == NULL)) /* Call noFontCallback. */ { XmDisplay dsp; XmDisplayCallbackStruct cb; rt_ref_cnt = _XmRTRefcount(rendertable); def_rend = _XmRTRenditions(rendertable)[0]; rend_int = *def_rend; ref_cnt = _XmRendRefcount(def_rend); dsp = (XmDisplay)XmGetXmDisplay(d); cb.reason = XmCR_NO_FONT; cb.event = NULL; cb.rendition = def_rend; cb.font_name = XmS; XtCallCallbackList((Widget)dsp, dsp->display.noFontCallback, &cb); if (rend_int != *def_rend) /* Changed in callback. */ { /* Need to split ref counts. */ _XmRendRefcount(&rend_int) = ref_cnt - rt_ref_cnt; _XmRendRefcount(def_rend) = rt_ref_cnt; } if (_XmRendFont(def_rend) != NULL) { _XmRendFontType(rend) = _XmRendFontType(def_rend); _XmRendFont(rend) = _XmRendFont(def_rend); } else rend = NULL; } /* 4b/5a. Emit warning and don't render. */ if ((rend == NULL) || (_XmRendFont(rend) == NULL)) { /* No warning if no tags, e.g. just dir component. */ if ((tag_count > 0) || (entry_tag != NULL)) XmeWarning(NULL, NO_FONT_MSG); if (width != NULL) { *width = 0; if (render_cache) render_cache->width = 0; } if (height != NULL) { *height = 0; if (render_cache) render_cache->height = 0; } if (ascent != NULL) { *ascent = 0; if (render_cache) render_cache->ascent = 0; } if (descent != NULL) { *descent = 0; if (render_cache) render_cache->descent = 0; } can_do = FALSE; } } } if (can_do) { /* compute width & height */ ComputeMetrics(*rend_in_out, _XmEntryTextGet(entry), _XmEntryByteCountGet(entry), (XmTextType) _XmEntryTextTypeGet(entry), which_seg, &w, &h, &asc, &dsc); /* If cache exists, set it. */ if (render_cache != NULL) { if (width != NULL) render_cache->width = w; if (height != NULL) render_cache->height = h; if (ascent != NULL) render_cache->ascent = asc; if (descent != NULL) render_cache->descent = dsc; render_cache->rendition = *rend_in_out; render_cache->header.dirty = False; } if (width != NULL) *width = w; if (height != NULL) *height = h; if (ascent != NULL) *ascent = asc; if (descent != NULL) *descent = dsc; } if (cached_rend == NULL) /* Update *rend_in_out */ { /* Remove rendition ends. */ count = _XmEntryRendEndCountGet(entry); if (count > 0) { depth = tag_count; hits = 0; for (i = 0; i < count; i++) for (j = (tag_count - 1); j >= 0; j--) if (_XmEntryRendEndGet(entry, i) == (tags)[j]) { tags[j] = NULL; depth = j; hits++; break; } j = depth; for (i = (depth + 1); i < tag_count; i++) if (tags[i] != NULL) { tags[j] = tags[i]; j++; } if(tags != NULL && tag_count - hits) tags = (XmStringTag *)XtRealloc((char *)tags, (sizeof(XmStringTag) * (tag_count - hits))); tag_count -= hits; _XmRendHadEnds(*rend_in_out) = TRUE; } else { _XmRendHadEnds(*rend_in_out) = FALSE; } _XmRendTagCount(*rend_in_out) = tag_count; _XmRendTags(*rend_in_out) = tags; } return(can_do); } static void _parse_locale( char *str, int *indx, int *len ) { char *temp; int start; int end; /* * Set the return variables to zero. If we find what we're looking * for, we reset them. */ *indx = 0; *len = 0; /* * The format of the locale string is: * language[_territory[.codeset]] */ temp = str; end = 0; while ((temp[end] != '.') && (temp[end] != 0)) end++; if (temp[end] == '.') { start = end + 1; *indx = start; end = start; while (temp[end] != 0) end++; *len = end - start; } } /* This function returns current default charset being used. This is */ /* determined from the value of the $LANG environment variable or */ /* XmFALLBACK_CHARSET. */ char * _XmStringGetCurrentCharset( void ) { char *str; char *ptr; int chlen; int indx; int len; char *ret_val; _XmProcessLock(); if (!locale.inited) { locale.tag = NULL; locale.taglen = 0; str = (char *)getenv(env_variable); if (str) { _parse_locale(str, &indx, &chlen); if (chlen > 0) { ptr = &str[indx]; len = chlen; } else { len = strlen(XmFALLBACK_CHARSET); ptr = XmFALLBACK_CHARSET; } } else { len = strlen(XmFALLBACK_CHARSET); ptr = XmFALLBACK_CHARSET; } locale.tag = (char *) XtMalloc(len + 1); strncpy(locale.tag, ptr, len); locale.tag[len] = '\0'; locale.taglen = len; /* Register XmSTRING_DEFAULT_CHARSET for compound text conversion. */ XmRegisterSegmentEncoding(XmSTRING_DEFAULT_CHARSET, XmFONTLIST_DEFAULT_TAG); locale.inited = TRUE; } ret_val = locale.tag; _XmProcessUnlock(); return (ret_val); } /* This function compares a given charset to the current default charset being used. It return TRUE if they match, FALSE otherwise. */ Boolean _XmStringIsCurrentCharset( XmStringCharSet c ) { return (strcmp(c, _XmStringGetCurrentCharset()) == 0); } /* * copy a refcounted string */ XmString XmStringCopy( XmString string ) { _XmProcessLock(); if (string == NULL) { _XmProcessUnlock(); return((XmString)NULL); } /* If the refcount wraps around, have to make clone, otherwise just return. */ if (_XmStrRefCountInc(string) != 0) { _XmProcessUnlock(); return(string); } else { XmString ret_val; _XmStrRefCountDec(string); ret_val = Clone(string, _XmStrEntryCountGet(string)); _XmProcessUnlock(); return ret_val; } } /* * duplicate structure of an internal string */ static XmString Clone(XmString string, int lines) { XmString new_string; if (_XmStrOptimized(string)) { _XmStringOpt n_o_string = (_XmStringOpt) _XmStrMalloc(sizeof(_XmStringOptRec) + _XmStrByteCount(string) - TEXT_BYTES_IN_STRUCT); memcpy(n_o_string, string, sizeof(_XmStringOptRec) + _XmStrByteCount(string) - TEXT_BYTES_IN_STRUCT) ; new_string = (XmString)n_o_string; } else { int i; _XmString n_string; _XmStrCreate(n_string, XmSTRING_MULTIPLE_ENTRY, 0); _XmStrImplicitLine(n_string) = _XmStrImplicitLine(string); _XmStrEntryCount(n_string) = _XmStrEntryCount(string); _XmStrEntry(n_string) = (_XmStringEntry *) XtMalloc(sizeof(_XmStringEntry) * lines); for (i = 0; i < _XmStrEntryCount(string); i++) _XmStrEntry(n_string)[i] = _XmStringEntryCopy(_XmStrEntry(string)[i]); for (i = _XmStrEntryCount(string); i < lines; i++) _XmStrEntry(n_string)[i] = NULL; new_string = (XmString)n_string; } _XmStrRefCountSet(new_string, 1); return(new_string); } /* * Given a string in ASN.1 format, return the size of the * string, including the header. */ unsigned int XmStringByteStreamLength(unsigned char *string) { unsigned int len; _XmProcessLock(); len = _read_string_length( string ); len += _calc_header_size(len); _XmProcessUnlock(); return (len); } /* * build the ASN.1 format given an XmString. * This makes a pass to figure out how big it * needs to be and builds the ASN.1 string in-place. * If prop_return is NULL, just computes size. */ unsigned int XmCvtXmStringToByteStream(XmString string, unsigned char **prop_return) { /* Using XmeStringGetComponent makes this almost trivial. */ _XmStringContextRec stack_context; unsigned int length; XtPointer value; unsigned int len; unsigned int str_len; unsigned char *ext; XmStringComponentType tag; _XmProcessLock(); if (!string) { if (prop_return != NULL) *prop_return = NULL; _XmProcessUnlock(); return(0); } _XmStringContextReInit(&stack_context, string); /* Compute size */ len = 0; while (XmeStringGetComponent(&stack_context, TRUE, FALSE, &length, &value) != XmSTRING_COMPONENT_END) len += _asn1_size(length) + length; str_len = len; len += _calc_header_size(len); _XmStringContextFree(&stack_context); /* We're just computing size. */ if (prop_return == NULL) { _XmProcessUnlock(); return(len); } /* Allocate. */ ext = (unsigned char *)XtMalloc(len); *prop_return = ext; /* Write components. */ ext = _write_header(ext, str_len); _XmStringContextReInit(&stack_context, string); while ((tag = XmeStringGetComponent(&stack_context, TRUE, FALSE, &length, &value)) != XmSTRING_COMPONENT_END) ext = _write_component(ext, tag, length, (unsigned char *)value, TRUE); _XmStringContextFree(&stack_context); _XmProcessUnlock(); return(len); } Dimension XmStringBaseline( XmRenderTable rendertable, XmString string ) { Dimension width, height, asc = 0, desc; _XmRenditionRec scratch; _XmRendition tmp; XmRendition rend; _XmStringEntry line; _XmStringArraySegRec array_seg; Display *d; XtAppContext app = NULL; if ((rendertable == NULL) || (string == NULL)) return(0); #ifdef XTHREADS if (_XmRTDisplay(rendertable)) app = XtDisplayToApplicationContext(_XmRTDisplay(rendertable)); if (app) { _XmAppLock(app); } else { _XmProcessLock(); } #endif bzero((char*) &scratch, sizeof(_XmRenditionRec)); tmp = &scratch; rend = &tmp; /* Initialize for tabs. */ d = (_XmRTDisplay(rendertable) == NULL) ? _XmGetDefaultDisplay() : _XmRTDisplay(rendertable); _XmRendDisplay(rend) = d; _XmStringLayout(string, XmLEFT_TO_RIGHT); if (!_XmStrOptimized(string)) { if (_XmStrImplicitLine(string)) line = _XmStrEntry(string)[0]; else { _XmEntryType(&array_seg) = XmSTRING_ENTRY_ARRAY; _XmEntrySegmentCount(&array_seg) = _XmStrEntryCount(string); _XmEntrySegment(&array_seg) = (_XmStringNREntry *)_XmStrEntry(string); line = (_XmStringEntry)&array_seg; } LineMetrics(line, rendertable, &rend, NULL, XmLEFT_TO_RIGHT, &width, &height, &asc, &desc); if (app) { _XmAppUnlock(app); } else { _XmProcessUnlock(); } return(asc); } else { if (app) { _XmAppUnlock(app); } else { _XmProcessUnlock(); } return (OptLineAscender(rendertable, (_XmStringOpt)string)); } } void _XmStringGetBaselines(XmRenderTable rendertable, _XmString string, Dimension **baselines, Cardinal *line_count) { /* Initialize the return values. */ *baselines = NULL; *line_count = 0; if (rendertable && string) *line_count = XmStringLineCount(string); if (*line_count == 1) { *baselines = (Dimension*) XtMalloc(*line_count * sizeof(Dimension)); (*baselines)[0] = XmStringBaseline(rendertable, string); } else if (*line_count > 1) { Cardinal line_num; Dimension offset; Dimension prev_height; Dimension width, height, asc, desc; _XmRenditionRec scratch; _XmRendition tmp = &scratch; XmRendition rend = &tmp; _XmStringArraySegRec array_seg; *baselines = (Dimension*) XtMalloc(*line_count * sizeof(Dimension)); /* Initialize the scratch rendition for tabs. */ bzero((char*) &scratch, sizeof(_XmRenditionRec)); _XmRendDisplay(rend) = ((_XmRTDisplay(rendertable) == NULL) ? _XmGetDefaultDisplay() : _XmRTDisplay(rendertable)); _XmStringLayout(string, XmLEFT_TO_RIGHT); offset = prev_height = 0; for (line_num = 0; line_num < *line_count; line_num++) { _XmStringEntry line; if (_XmStrImplicitLine(string)) line = _XmStrEntry(string)[line_num]; else { _XmEntryType(&array_seg) = XmSTRING_ENTRY_ARRAY; _XmEntrySegmentCount(&array_seg) = _XmStrEntryCount(string); _XmEntrySegment(&array_seg) = (_XmStringNREntry *)_XmStrEntry(string); line = (_XmStringEntry)&array_seg; } LineMetrics(line, rendertable, &rend, NULL, XmLEFT_TO_RIGHT, &width, &height, &asc, &desc); /* Treat empty lines as the same height as the previous line. */ if (height) prev_height = height; (*baselines)[line_num] = offset + asc; offset += prev_height; } } } /* * count the number of lines in an XmString. */ int XmStringLineCount( XmString string ) { int ret_val; _XmProcessLock(); if ((string == NULL)) { _XmProcessUnlock(); return(0); } if (_XmStrOptimized(string)) { _XmProcessUnlock(); return( 1) ; } ret_val = (int) _XmStrLineCountGet(string) ; _XmProcessUnlock(); return ret_val; } /* * drawing routine for external TCS */ void XmStringDraw( Display *d, Window w, XmRenderTable rendertable, XmString string, GC gc, #if NeedWidePrototypes int x, int y, int width, unsigned int align, unsigned int lay_dir, #else Position x, Position y, Dimension width, unsigned char align, unsigned char lay_dir, #endif /* NeedWidePrototypes */ XRectangle *clip ) { _XmDisplayToAppContext(d); _XmAppLock(app); if (string) _draw (d, w, rendertable, (_XmString)string, gc, x, y, width, align, lay_dir, clip, FALSE, NULL); _XmAppUnlock(app); } void XmStringDrawImage( Display *d, Window w, XmRenderTable rendertable, XmString string, GC gc, #if NeedWidePrototypes int x, int y, int width, unsigned int align, unsigned int lay_dir, #else Position x, Position y, Dimension width, unsigned char align, unsigned char lay_dir, #endif /* NeedWidePrototypes */ XRectangle *clip ) { _XmDisplayToAppContext(d); _XmAppLock(app); if (string) _draw (d, w, rendertable, (_XmString)string, gc, x, y, width, align, lay_dir, clip, TRUE, NULL); _XmAppUnlock(app); } void XmStringDrawUnderline( Display *d, Window w, XmRenderTable fntlst, XmString str, GC gc, #if NeedWidePrototypes int x, int y, int width, unsigned int align, unsigned int lay_dir, #else Position x, Position y, Dimension width, unsigned char align, unsigned char lay_dir, #endif /* NeedWidePrototypes */ XRectangle *clip, XmString under ) { _XmDisplayToAppContext(d); _XmAppLock(app); if (str) _draw (d, w, fntlst, (_XmString)str, gc, x, y, width, align, lay_dir, clip, FALSE, (_XmString)under); _XmAppUnlock(app); } #ifdef _XmDEBUG_XMSTRING void _Xm_dump_stream( unsigned char *cs ) { unsigned char *c; unsigned char *end; int k; if (_is_asn1(cs)) { printf ("Compound string\n"); printf ("overall length = %d\n", _read_string_length(cs)); c = _read_header(cs); } else { printf ("Not a compound string\n"); return; } c = (unsigned char *) cs; end = c + _read_string_length (c) + _read_header_length(c); while (c < end) { unsigned short length = _read_asn1_length (c); switch (*c) { case XmSTRING_COMPONENT_CHARSET: case XmSTRING_COMPONENT_LOCALE: if (*c == XmSTRING_COMPONENT_LOCALE) printf ("\tLocale name component\n"); else printf ("\tCharacter set component\n"); printf ("\tlength = %d\n", length); printf ("\tvalue = <"); for (k=0; k\n"); c += length + _asn1_size(length); break; case XmSTRING_COMPONENT_TEXT: case XmSTRING_COMPONENT_LOCALE_TEXT: if (*c == XmSTRING_COMPONENT_TEXT) printf ("\tText component\n"); else printf ("\tLocalized text component\n"); printf ("\tlength = %d\n", length); printf ("\tvalue = <"); for (k=0; k\n"); c += length + _asn1_size(length); break; case XmSTRING_COMPONENT_WIDECHAR_TEXT: printf ("\tWide char text component\n"); printf ("\tlength = %d\n", length); printf ("\tvalue = <"); for (k=0; k\n"); c += length + _asn1_size(length); break; case XmSTRING_COMPONENT_DIRECTION: /* record dir */ printf ("\tDirection component\n"); printf ("\tlength = %d\n", length); printf ("\tvalue = %d\n", *(c + _asn1_size(length))); c += length + _asn1_size(length); break; case XmSTRING_COMPONENT_SEPARATOR: /* start new line */ printf ("\tSeparator component\n"); printf ("\tlength = %d\n", length); c += length + _asn1_size(length); break; default: printf ("\tUnknown component\n"); printf ("\tlength = %d\n", length); printf ("\tvalue = <"); for (k=0; k\n", _XmStrRendIndex(string), (_XmStrRendTagGet(string) ? _XmStrRendTagGet(string) : "(unset)")); printf ("\t tab_before = %4d\n", _XmStrTabs(string)); printf ("\t refcount = %4d\n", _XmStrRefCountGet(string)); printf ("\t char count = %4d\n", _XmStrByteCount(string)); printf ("\t text = <"); for (k=0; k<_XmStrByteCount(string); k++) printf ("%c", _XmStrText(string)[k]); printf (">\n"); } else { _XmStringEntry line; int line_count; _XmStringEntry seg; int seg_count; _XmStringArraySegRec array_seg; line_count = _XmStrLineCountGet(string); printf ("string with %d lines\n", line_count); for (i = 0; i < line_count; i++) { if (_XmStrImplicitLine(string)) { line = _XmStrEntry(string)[i]; } else { _XmEntryType(&array_seg) = XmSTRING_ENTRY_ARRAY; _XmEntrySegmentCount(&array_seg) = _XmStrEntryCount(string); _XmEntrySegment(&array_seg) = (_XmStringNREntry *)_XmStrEntry(string); line = (_XmStringEntry)&array_seg; } if (_XmEntryMultiple(line)) seg_count = _XmEntrySegmentCount(line); else seg_count = 1; printf ("\tline [%d] has %d segments\n", i, seg_count); for (j = 0; j < seg_count; j++) { if (_XmEntryMultiple(line)) seg = (_XmStringEntry)_XmEntrySegment(line)[j]; else seg = line; printf ("\t segment [%d]\n", j); if (seg == NULL) { printf ("\t\tNULL?\n"); continue; } printf ("\t\ttype = %d (%s)\n", _XmEntryType(seg), entry_type_image(_XmEntryType(seg))); printf ("\t\tpush before = %d \n", _XmEntryPushGet(seg)); printf ("\t\trend_begin_tags = (%d)\n", _XmEntryRendBeginCountGet(seg)); for (k=0; k<_XmEntryRendBeginCountGet(seg); k++) printf ("\t\t %4d <%s>\n", _XmStringIndexCacheTag(_XmEntryRendBeginGet(seg,k), XmSTRING_TAG_STRLEN), _XmEntryRendBeginGet(seg,k)); printf ("\t\ttag = <%s>\n", _XmEntryTag(seg)); printf ("\t\ttabs = %d\n", _XmEntryTabsGet(seg)); printf ("\t\tdirection = %d\n", _XmEntryDirectionGet(seg)); printf ("\t\ttext type = %d (%s)\n", _XmEntryTextTypeGet(seg), type_image(_XmEntryTextTypeGet(seg))); printf ("\t\ttext = <"); for (k=0; k<_XmEntryByteCountGet(seg); k++) printf ("%c", ((char *)_XmEntryTextGet(seg))[k]); printf (">\n"); printf ("\t\tbyte count = %d\n", _XmEntryByteCountGet(seg)); printf ("\t\trend_end_tags = (%d)\n", _XmEntryRendEndCountGet(seg)); for (k=0; k<_XmEntryRendEndCountGet(seg); k++) printf ("\t\t %4d <%s>\n", _XmStringIndexCacheTag(_XmEntryRendEndGet(seg,k), XmSTRING_TAG_STRLEN), _XmEntryRendEndGet(seg,k)); printf ("\t\tpop after = %d \n", _XmEntryPopGet(seg)); } } } printf("\n\n"); } #endif /* _XmDEBUG_XMSTRING */ /**************************************************************** * _XmStringGetTextConcat: * Note: at some point this could be reimplemented as two pass * process to eliminate calls to XtRealloc. ****************************************************************/ char * _XmStringGetTextConcat( XmString string) { _XmStringContextRec stack_context; XmStringComponentType type ; unsigned int len ; XtPointer val ; size_t OldLen ; size_t OutLen = 0 ; char * OutStr = NULL ; if (string) { _XmStringContextReInit(&stack_context, string); while((type = XmeStringGetComponent(&stack_context, TRUE, FALSE, &len, &val)) != XmSTRING_COMPONENT_END) { switch( type) { case XmSTRING_COMPONENT_TEXT: case XmSTRING_COMPONENT_LOCALE_TEXT: case XmSTRING_COMPONENT_WIDECHAR_TEXT: OldLen = OutLen; OutLen += len; OutStr = XtRealloc( OutStr, OutLen + 1) ; memcpy( &OutStr[OldLen], (char *)val, len) ; OutStr[OutLen] = '\0'; break ; default: break ; } } _XmStringContextFree(&stack_context); } return( OutStr) ; } /**************************************************************** * Allocates a copy of the text and character set of the specified XmString * if the XmString is composed of a single segment. * Returns TRUE if str is a single segment, FALSE otherwise. * If TRUE, pTextOut is valid; if FALSE, pTextOut and pTagOut are NULL. ****************/ Boolean _XmStringSingleSegment( XmString str, char **pTextOut, XmStringTag *pTagOut ) { _XmStringContextRec stack_context ; Boolean retVal; unsigned int len; XtPointer val; XmStringComponentType type; /* Initialize the return parameters. */ retVal = FALSE; *pTextOut = NULL; *pTagOut = NULL; if (str) { _XmStringContextReInit(&stack_context, str); /** Get the first tag and text. **/ /* Peak ahead and only copy tag or text. */ while ((type = XmeStringGetComponent(&stack_context, FALSE, FALSE, &len, &val)) != XmSTRING_COMPONENT_END) { switch (type) { case XmSTRING_COMPONENT_TAG: case XmSTRING_COMPONENT_LOCALE: XmeStringGetComponent(&stack_context, TRUE, TRUE, &len, &val); XtFree((char *)*pTagOut); *pTagOut = (XmStringTag)val; break; case XmSTRING_COMPONENT_TEXT: case XmSTRING_COMPONENT_LOCALE_TEXT: case XmSTRING_COMPONENT_WIDECHAR_TEXT: XmeStringGetComponent(&stack_context, TRUE, TRUE, &len, &val); retVal = TRUE; *pTextOut = (char *)val; if (type == XmSTRING_COMPONENT_LOCALE_TEXT) { XtFree((char *)*pTagOut); *pTagOut = (XmStringTag)XtNewString(XmFONTLIST_DEFAULT_TAG); } /* Make sure there are no more segments. */ while ((type = XmeStringGetComponent(&stack_context, TRUE, FALSE, &len, &val)) != XmSTRING_COMPONENT_END) switch (type) { /* These are all okay */ case XmSTRING_COMPONENT_RENDITION_END: case XmSTRING_COMPONENT_LAYOUT_POP: case XmSTRING_COMPONENT_SEPARATOR: break; /* Anything else is a second segment. */ default: retVal = FALSE; continue; } continue; /* Advance the context. */ default: XmeStringGetComponent(&stack_context, TRUE, FALSE, &len, &val); break; } } _XmStringContextFree(&stack_context); } if (!retVal) { XtFree(*pTextOut); XtFree((char *)*pTagOut); *pTextOut = NULL; *pTagOut = NULL; } return retVal; } /**************************************************************************** *** *** *** This next function SUPERCEDES UpdateWMShellTitle() in BulletinB.c! *** *** REMOVE other copy and reuse for 1.2.1! *** *** *** ****************************************************************************/ #define STRING_CHARSET "ISO8859-1" void XmeSetWMShellTitle( XmString xmstr, Widget shell) { char * text = (char*) NULL; XmStringTag tag = (XmStringTag) NULL; Arg al[10] ; Cardinal ac ; XrmValue from ; Atom encoding = None; XrmValue to ; _XmWidgetToAppContext(shell); _XmAppLock(app); /* Set WMShell title (if present). */ if( XtIsWMShell( shell) ) { /* Shell is a Window Manager Shell, so set WMShell title * from XmNdialogTitle. */ text = NULL ; ac = 0 ; if (_XmStringSingleSegment(xmstr, &text, &tag)) { if ((tag != NULL) && (strcmp(STRING_CHARSET, tag) == 0)) { /* dialog_title is a single segment of charset STRING_CHARSET, * so use atom of "STRING". Otherwise, convert to compound * text and use atom of "COMPOUND_TEXT". */ XtFree( (char *) tag) ; encoding = XA_STRING; } else if ((tag != NULL) && (strcmp(XmFONTLIST_DEFAULT_TAG, tag) == 0)) { /* dialog_title locale encoded so use constant of None */ XtFree((char *)tag); encoding = None; } else { /* Don't need this, since dialog_title will be converted from * original XmString to compound text. */ XtFree( (char *) tag) ; XtFree( (char *) text) ; text = NULL ; } } if (!text) { from.addr = (char *) xmstr; if( XmCvtXmStringToText( XtDisplay( shell), NULL, NULL, &from, &to, NULL) ) { text = to.addr ; encoding = XInternAtom(XtDisplay(shell), XmSCOMPOUND_TEXT, FALSE); } } if( text ) { XtSetArg( al[ac], XtNtitle, text) ; ++ac ; XtSetArg( al[ac], XtNtitleEncoding, encoding) ; ++ac ; XtSetArg( al[ac], XtNiconName, text) ; ++ac ; XtSetArg( al[ac], XtNiconNameEncoding, encoding) ; ++ac ; XtSetValues( shell, al, ac) ; XtFree( (char *) text) ; } } _XmAppUnlock(app); } /* * XmeGetDirection: An XmParseProc to insert a direction component. * Does not consume the triggering character. */ /*ARGSUSED*/ XmIncludeStatus XmeGetDirection(XtPointer *in_out, XtPointer text_end, /* unused */ XmTextType type, XmStringTag tag, XmParseMapping entry, /* unused */ int pattern_length, /* unused */ XmString *str_include, XtPointer call_data) /* unused */ { XmCharDirectionProc char_proc = _XmOSGetCharDirection; XmStringDirection dir; (void) XmOSGetMethod(NULL, XmMCharDirection, (XtPointer *)&char_proc, NULL); /* Create a component for the new direction. */ dir = XmDirectionToStringDirection((*char_proc)(*in_out, type, tag)); *str_include = XmStringComponentCreate(XmSTRING_COMPONENT_DIRECTION, sizeof (dir), (XtPointer) &dir); /* Don't consume the triggering character. */ return XmINSERT; } /* * match_pattern: A helper for XmStringParseText. Determine whether * the text matches a XmParseMapping pattern. */ /*ARGSUSED*/ static Boolean match_pattern(XtPointer text, XmStringTag tag, /* unused */ XmTextType type, XmParseMapping pattern, int char_len, Boolean dir_change) { if (pattern == NULL) { return False; } else if (pattern->pattern == XmDIRECTION_CHANGE) { return dir_change; } else if ((pattern->pattern_type == XmWIDECHAR_TEXT) && (type == XmWIDECHAR_TEXT)) { /* Compare wchar_t text to wchar_t pattern. */ return (*((wchar_t*) text) == *((wchar_t*) pattern->pattern)); } else if (type == XmWIDECHAR_TEXT) { /* Compare wchar_t text to a mbs pattern. */ char mb_text[MB_LEN_MAX]; wctomb(mb_text, (wchar_t) '\0'); wctomb(mb_text, *((wchar_t*)text)); return !strncmp(mb_text, (char*) pattern->pattern, char_len); } else if (pattern->pattern_type == XmWIDECHAR_TEXT) { /* Compare mbs text to wchar_t pattern. */ char mb_pattern[MB_LEN_MAX]; wctomb(mb_pattern, (wchar_t) '\0'); wctomb(mb_pattern, *((wchar_t*)pattern->pattern)); return !strncmp((char*) text, mb_pattern, char_len); } else if (strlen((char*) pattern->pattern) == char_len) { /* The normal case: mbs text and pattern. */ return !strncmp((char*) text, (char*) pattern->pattern, char_len); } return False; } /* * parse_unmatched: A Helper routine for XmStringParseText. Produce * a component for characters that weren't matched by any pattern. */ static void parse_unmatched(XmString *result, char **ptr, XmTextType text_type, int length) { /* Insert length bytes from ptr into result, and update ptr. */ XmString tmp_1, tmp_2; XmStringComponentType ctype; /* Do nothing if there are no unmatched bytes. */ if (length <= 0) return; /* Choose a component type. */ switch (text_type) { case XmCHARSET_TEXT: ctype = XmSTRING_COMPONENT_TEXT; break; case XmMULTIBYTE_TEXT: ctype = XmSTRING_COMPONENT_LOCALE_TEXT; break; case XmWIDECHAR_TEXT: ctype = XmSTRING_COMPONENT_WIDECHAR_TEXT; break; default: return; } /* Can't concat without copying both strings? */ tmp_1 = *result; tmp_2 = XmStringComponentCreate(ctype, length, (XtPointer) *ptr); if (tmp_2 == NULL) return; *result = XmStringConcatAndFree(tmp_1, tmp_2); *ptr += length; } /* * parse_pattern: A helper routine for XmStringParseText. Process a * pattern that has matched. */ static Boolean parse_pattern(XmString *result, char **ptr, XtPointer text_end, XmStringTag tag, XmTextType type, XmParseMapping pat, int length, XtPointer call_data, Boolean *terminate) { /* Process a matched pattern. Return True if ptr is updated. */ char* orig_ptr = *ptr; XmIncludeStatus action = pat->include_status; XmString insertion = NULL; /* Compute the action and insertion. */ if (action == XmINVOKE) { /* Resolve parse procs. */ if (pat->parse_proc) action = (pat->parse_proc) ((XtPointer*) ptr, text_end, type, tag, pat, length, &insertion, call_data); /* Recursive parse procs are not supported. */ if (action == XmINVOKE) { *ptr = orig_ptr; XmStringFree (insertion); return False; } } else { /* Non-parse_procs always advance the pointer and terminate matching. */ *ptr += length; insertion = XmStringCopy(pat->substitute); } /* Insert the substitution. */ switch (action) { case XmTERMINATE: *terminate = True; /* Fall through. */ case XmINSERT: if (insertion != NULL) *result = XmStringConcatAndFree(*result, insertion); break; default: /* Ignore substitution string. */ XmStringFree(insertion); break; } /* Advancing the pointer prevents multiple matches. */ return (*ptr != orig_ptr); } XmString XmStringParseText(XtPointer text, XtPointer *text_end, XmStringTag tag, XmTextType type, XmParseTable parse_table, Cardinal parse_count, XtPointer call_data) { /* This routine needs to be reentrant so application supplied */ /* XmParseProcs can make recursive calls. */ static XmParseMapping default_dir_pattern = NULL; char* ptr = (char*) text; char* prev_ptr = ptr; XtPointer end_ptr = (text_end ? *text_end : NULL); XmString result; Boolean has_dir_pattern; Boolean wide_char = False; Boolean advanced; Boolean halt; unsigned int index; char* dir_ptr; XmStringComponentType tag_type; XmInitialDirectionProc init_char_proc = _XmOSGetInitialCharsDirection; _XmProcessLock(); /* Check some error conditions. */ if (parse_count && !parse_table) { _XmProcessUnlock(); return NULL; } if (!text) { _XmProcessUnlock(); return NULL; } /* Validate the tag and set the tag_type. */ switch (type) { case XmCHARSET_TEXT: if (tag == NULL) tag = XmFONTLIST_DEFAULT_TAG; tag_type = XmSTRING_COMPONENT_CHARSET; break; case XmWIDECHAR_TEXT: wide_char = True; /* Fall through */ case XmMULTIBYTE_TEXT: /* Non-NULL values (except _MOTIF_DEFAULT_LOCALE) are not accepted in Motif 2.0. */ if (tag != NULL && !(tag == _MOTIF_DEFAULT_LOCALE || strcmp(tag, _MOTIF_DEFAULT_LOCALE) == 0)) { _XmProcessUnlock(); return NULL; } if (tag == NULL) tag = _MOTIF_DEFAULT_LOCALE; tag_type = XmSTRING_COMPONENT_LOCALE; break; default: /* Error: bad text type. */ _XmProcessUnlock(); return NULL; } /* Create an empty segment with the right tag. */ result = XmStringComponentCreate(tag_type, strlen(tag), (XtPointer) tag); /* Did the user provide an XmDIRECTION_CHANGE pattern? */ has_dir_pattern = False; for (index = 0; (index < parse_count) && !has_dir_pattern; index++) has_dir_pattern = (parse_table[index]->pattern == XmDIRECTION_CHANGE); if (!has_dir_pattern && !default_dir_pattern) { /* Create a default direction pattern. */ Arg args[10]; Cardinal nargs = 0; XtSetArg(args[nargs], XmNincludeStatus, XmINVOKE), nargs++; XtSetArg(args[nargs], XmNinvokeParseProc, XmeGetDirection), nargs++; XtSetArg(args[nargs], XmNpattern, XmDIRECTION_CHANGE), nargs++; assert(nargs < XtNumber(args)); default_dir_pattern = XmParseMappingCreate(args, nargs); } /* Process characters until text has been consumed. */ dir_ptr = NULL; (void) mblen((char*) NULL, MB_CUR_MAX); (void) XmOSGetMethod(NULL, XmMInitialCharsDirection, (XtPointer *)&init_char_proc, NULL); halt = (end_ptr && (ptr >= (char*) end_ptr)); while (!halt && (wide_char ? *((wchar_t*) ptr) : *ptr)) { int len = (wide_char ? sizeof(wchar_t) : mblen(ptr, MB_CUR_MAX)); advanced = False; /* If we have an invalid character, treat it as a single byte. */ if (len < 0) len = 1; /* Reset dir_ptr if the input text has changed directions. */ if (ptr > dir_ptr) { XmDirection xm_dir; if ((*init_char_proc)((XtPointer) ptr, type, tag, &index, &xm_dir) == Success) dir_ptr = ptr + index; } /* Match against an implicit XmDIRECTION_CHANGE pattern. */ if (!has_dir_pattern && (ptr == dir_ptr)) { parse_unmatched(&result, &prev_ptr, type, ptr - prev_ptr); advanced = parse_pattern(&result, &ptr, end_ptr, tag, type, default_dir_pattern, len, call_data, &halt); } /* Try to match this character against the patterns. */ for (index = 0; !advanced && !halt && (index < parse_count); index++) { XmParseMapping pat = parse_table[index]; if (match_pattern(ptr, tag, type, pat, len, (ptr == dir_ptr))) { parse_unmatched(&result, &prev_ptr, type, ptr - prev_ptr); advanced = parse_pattern(&result, &ptr, end_ptr, tag, type, pat, len, call_data, &halt); } } /* Match an implicit "self-insert" pattern if all else fails. */ if (!advanced) { /* Buffer unmatched characters into one long insertion. */ ptr += len; } else { /* Discard this character and reset unmatched pointer. */ prev_ptr = ptr; } /* Stop processing at the end of the text. */ halt |= (end_ptr && (ptr >= (char*) end_ptr)); } /* Output and trailing unmatched characters. */ parse_unmatched(&result, &prev_ptr, type, ptr - prev_ptr); /* Return the true end of parsing if possible. */ if (text_end) *text_end = (XtPointer) ptr; _XmProcessUnlock(); return result; } /* * check_unparse_models: A helper for XmStringUnparse. Invoked * after a text component is processed, this routine determines * whether future non-text and text components will be unparsed. */ static void check_unparse_models(XmStringContext context, XmStringTag tag, XmTextType tag_type, XmParseModel parse_model, Boolean *prev_text_match, Boolean *next_text_match, Boolean *non_text_match) { /* Scan ahead to see whether the next text segment will match. */ { /* Peek ahead in the iterator for a real text segment. */ Boolean done = False; _XmStringContextRec n_context; XtPointer n_value; unsigned int n_length; XmStringComponentType n_ctype; /* Compute text_match for the next text segment. */ *prev_text_match = *next_text_match; _XmStringContextCopy(&n_context, context); while (!done) { n_ctype = XmeStringGetComponent(&n_context, True, False, &n_length, &n_value); switch (n_ctype) { case XmSTRING_COMPONENT_TEXT: case XmSTRING_COMPONENT_LOCALE_TEXT: case XmSTRING_COMPONENT_WIDECHAR_TEXT: if (!tag) *next_text_match = True; else if ((tag_type == _XmStrContTagType(&n_context)) && (!_XmStrContTag(&n_context) || (tag == _XmStrContTag(&n_context)) || (strcmp(tag, _XmStrContTag(&n_context)) == 0))) *next_text_match = True; else *next_text_match = False; done = True; break; case XmSTRING_COMPONENT_END: *next_text_match = False; done = True; break; } } _XmStringContextFree(&n_context); } /* Compute parse_match for components up to the next text segment. */ switch (parse_model) { case XmOUTPUT_ALL: *non_text_match = True; break; case XmOUTPUT_BETWEEN: *non_text_match = *prev_text_match && *next_text_match; break; case XmOUTPUT_BEGINNING: *non_text_match = *next_text_match; break; case XmOUTPUT_END: *non_text_match = *prev_text_match; break; case XmOUTPUT_BOTH: *non_text_match = *prev_text_match || *next_text_match; break; default: /* This is an error. */ *non_text_match = False; break; } } /* * unparse_text: A helper for XmStringUnparse. Output a matched text * component. */ static void unparse_text(char **result, int *length, XmTextType output_type, XmStringComponentType c_type, unsigned int c_length, XtPointer c_value) { /* If we have an invalid character, treat it as a single byte. */ if ((int)c_length < 0) c_length = 1; /* Convert c_value to the appropriate type and insert it. */ if ((c_type == XmSTRING_COMPONENT_WIDECHAR_TEXT) == (output_type == XmWIDECHAR_TEXT)) { /* No conversion is necessary. */ *result = XtRealloc(*result, *length + c_length); memcpy(*result + *length, c_value, c_length); *length += c_length; } else if (output_type != XmWIDECHAR_TEXT) { /* Convert c_value to a multibyte string. */ int len; int max_bytes = c_length * MB_CUR_MAX / sizeof(wchar_t); wchar_t *null_text = (wchar_t*) XtMalloc(c_length + sizeof(wchar_t)); memcpy(null_text, c_value, c_length); null_text[c_length / sizeof(wchar_t)] = (wchar_t) '\0'; *result = XtRealloc(*result, *length + max_bytes); len = wcstombs(*result + *length, null_text, max_bytes); if (len > 0) *length += len; XtFree((char*) null_text); } else { /* Convert c_value to a widechar string. */ int len; char *null_text = XtMalloc(c_length + 1); memcpy(null_text, c_value, c_length); null_text[c_length] = '\0'; *result = XtRealloc(*result, *length + c_length * sizeof(wchar_t)); len = mbstowcs((wchar_t*) (*result + *length), null_text, c_length); if (len > 0) *length += len * sizeof(wchar_t); XtFree(null_text); } } /* * unparse_is_plausible: A helper routine for unparse_components. * Decided whether a pattern is even eligible for unparsing. */ static Boolean unparse_is_plausible(XmParseMapping pattern) { /* Look for a cached result from previous computations. */ switch (pattern->internal_flags) { case XmSTRING_UNPARSE_UNKNOWN: break; case XmSTRING_UNPARSE_PLAUSIBLE: return True; case XmSTRING_UNPARSE_IMPLAUSIBLE: return False; } /* Test the pattern to see if it might ever be unparsed. */ if (/* Filter patterns based on the include status. */ (pattern->include_status == XmINVOKE) || /* Filter patterns based on the substitution. */ (!pattern->substitute) || /* Filter patterns based on the pattern. */ (pattern->pattern == XmDIRECTION_CHANGE)) { pattern->internal_flags = XmSTRING_UNPARSE_IMPLAUSIBLE; return False; } else { /* Give up and compare the segments component by component. */ pattern->internal_flags = XmSTRING_UNPARSE_PLAUSIBLE; return True; } } /* * unparse_components: A helper for XmStringUnparse. Compare * components against the parse table. */ static void unparse_components(char **result, int *length, XmTextType output_type, XmStringContext context, XmParseTable parse_table, Cardinal parse_count) { Boolean match = False; XmParseMapping pat; int n_pat; int n_comp; /* Compare each pattern component. */ for (n_pat = 0; !match && (n_pat < parse_count); n_pat++) { pat = parse_table[n_pat]; if (unparse_is_plausible(pat)) { _XmStringContextRec m_context, p_context; XmStringComponentType m_ctype, p_ctype; XtPointer m_value, p_value; unsigned int m_length, p_length; /* Setup master and pattern context iterators. */ _XmStringContextCopy(&m_context, context); _XmStringContextReInit(&p_context, pat->substitute); /* Iterate over each of the strings. */ match = True; for (n_comp = 0; match; n_comp++) { /* Get the next component from each source. */ m_ctype = XmeStringGetComponent(&m_context, True, False, &m_length, &m_value); p_ctype = XmeStringGetComponent(&p_context, True, False, &p_length, &p_value); /* It's a match! */ if (p_ctype == XmSTRING_COMPONENT_END) break; /* Comparison of text components always fails. */ if ((p_ctype == XmSTRING_COMPONENT_TEXT) || (p_ctype == XmSTRING_COMPONENT_LOCALE_TEXT) || (p_ctype == XmSTRING_COMPONENT_WIDECHAR_TEXT)) { pat->internal_flags = XmSTRING_UNPARSE_IMPLAUSIBLE; match = False; } /* Bit-compare components. */ else if ((m_ctype != p_ctype) || (m_length != p_length) || ((m_value != p_value) && memcmp(m_value, p_value, m_length))) match = False; } /* Should we undo this substitution? */ if (match) { /* Output the original pattern. */ if (pat->pattern_type == XmWIDECHAR_TEXT) unparse_text(result, length, output_type, XmSTRING_COMPONENT_WIDECHAR_TEXT, sizeof(wchar_t), pat->pattern); else unparse_text(result, length, output_type, XmSTRING_COMPONENT_TEXT, mblen((char*) pat->pattern, MB_CUR_MAX), pat->pattern); /* Skip all but the last matched component. */ while (--n_comp > 0) { m_ctype = XmeStringGetComponent(context, True, False, &m_length, &m_value); assert(m_ctype != XmSTRING_COMPONENT_END); } } /* Cleanup. */ _XmStringContextFree(&m_context); _XmStringContextFree(&p_context); } } } XtPointer XmStringUnparse(XmString string, XmStringTag tag, XmTextType tag_type, XmTextType output_type, XmParseTable parse_table, Cardinal parse_count, XmParseModel parse_model) { char *result = NULL; int length = 0; _XmStringContextRec stack_context; Boolean prev_text_match; Boolean next_text_match; Boolean non_text_match; Boolean done; XmStringComponentType c_type; unsigned int c_length; XtPointer c_value; _XmProcessLock(); /* Convert special tags to real values. */ if ((tag_type == XmCHARSET_TEXT) && tag && ((tag == XmSTRING_DEFAULT_CHARSET) || (strcmp(tag, XmSTRING_DEFAULT_CHARSET) == 0))) tag = _XmStringGetCurrentCharset(); /* Process the components of string individually. */ prev_text_match = next_text_match = non_text_match = False; done = (string == NULL); if (!done) { _XmStringContextReInit(&stack_context, string); check_unparse_models(&stack_context, tag, tag_type, parse_model, &prev_text_match, &next_text_match, &non_text_match); } while (!done) { /* Peek at the next component. */ c_type = XmeStringGetComponent(&stack_context, False, False, &c_length, &c_value); switch (c_type) { case XmSTRING_COMPONENT_TEXT: case XmSTRING_COMPONENT_LOCALE_TEXT: case XmSTRING_COMPONENT_WIDECHAR_TEXT: /* Text component matches are computed in advance. */ if (next_text_match) unparse_text(&result, &length, output_type, c_type, c_length, c_value); /* Advance to the next component. */ (void) XmeStringGetComponent(&stack_context, True, False, &c_length, &c_value); /* Update the text match values. */ check_unparse_models(&stack_context, tag, tag_type, parse_model, &prev_text_match, &next_text_match, &non_text_match); break; case XmSTRING_COMPONENT_END: done = True; /* We're done after processing this component. */ default: /* Non-text components are under the control of parse_model. */ if (non_text_match) unparse_components(&result, &length, output_type, &stack_context, parse_table, parse_count); /* Advance to the next component. */ if (!done) (void) XmeStringGetComponent(&stack_context, True, False, &c_length, &c_value); break; } } /* Clean up. */ if (string != NULL) _XmStringContextFree(&stack_context); /* Null terminate the result. */ switch(output_type) { case XmWIDECHAR_TEXT: { wchar_t zero = 0; unparse_text(&result, &length, output_type, XmSTRING_COMPONENT_WIDECHAR_TEXT, sizeof(wchar_t), (XtPointer) &zero); } break; case XmCHARSET_TEXT: case XmMULTIBYTE_TEXT: case XmNO_TEXT: unparse_text(&result, &length, output_type, XmSTRING_COMPONENT_TEXT, 1, (XtPointer) ""); break; } _XmProcessUnlock(); return (XtPointer) result; } XmString XmStringComponentCreate(XmStringComponentType c_type, unsigned int length, XtPointer value) { _XmString str; _XmStringUnoptSegRec seg; _XmStringEntry opt_seg; _XmStringOptRec opt; int tag_index = TAG_INDEX_UNSET; Boolean optimized = False; XmStringTag rend_tags[1]; _XmProcessLock(); /* We can't do anything if a needed value is missing. */ if ((length > 0) && (value == NULL)) { _XmProcessUnlock(); return NULL; } /* Initialize the proto-segments */ _XmEntryInit((_XmStringEntry)&seg, XmSTRING_ENTRY_UNOPTIMIZED); _XmStrInit((_XmString)&opt, XmSTRING_OPTIMIZED); /* Modify a proto-segment appropriately or return a special value. */ switch (c_type) { case XmSTRING_COMPONENT_CHARSET: if (!value || (length != strlen((char*) value))) { _XmProcessUnlock(); return NULL; } if ((value == XmSTRING_DEFAULT_CHARSET) || (strcmp((char*) value, XmSTRING_DEFAULT_CHARSET) == 0)) { value = _XmStringGetCurrentCharset(); length = strlen((char*) value); } tag_index = _XmStringIndexCacheTag((char*) value, length); optimized = (tag_index < TAG_INDEX_MAX); if (optimized) { _XmStrTextType((_XmString)&opt) = XmCHARSET_TEXT; _XmStrTagIndex((_XmString)&opt) = tag_index; } else { _XmEntryTextTypeSet(&seg, XmCHARSET_TEXT); _XmUnoptSegTag(&seg) = _XmStringCacheTag((char*) value, length); } break; case XmSTRING_COMPONENT_TEXT: optimized = (length < (1 << BYTE_COUNT_BITS)); if (optimized) { _XmStrTextType((_XmString)&opt) = XmCHARSET_TEXT; _XmStrByteCount((_XmString)&opt) = length; } else { _XmEntryTextTypeSet(&seg, XmCHARSET_TEXT); if (value != NULL) { _XmEntryTextSet((_XmStringEntry)&seg, value); _XmEntryByteCountSet(&seg, length); } } break; case XmSTRING_COMPONENT_DIRECTION: if (length != sizeof(XmStringDirection)) { _XmProcessUnlock(); return NULL; } _XmProcessUnlock(); return XmStringDirectionCreate(*((XmStringDirection*) value)); case XmSTRING_COMPONENT_SEPARATOR: if (value != NULL) { _XmProcessUnlock(); return NULL; } _XmProcessUnlock(); return XmStringSeparatorCreate(); case XmSTRING_COMPONENT_LOCALE_TEXT: tag_index = _XmStringIndexCacheTag( (char*) XmFONTLIST_DEFAULT_TAG, XmSTRING_TAG_STRLEN); if (length < (1 << BYTE_COUNT_BITS)) optimized = (tag_index < TAG_INDEX_MAX); if (optimized) { _XmStrTextType((_XmString)&opt) = XmMULTIBYTE_TEXT; _XmStrTagIndex((_XmString)&opt) = tag_index; _XmStrByteCount((_XmString)&opt) = length; } else { _XmEntryTextTypeSet(&seg, XmMULTIBYTE_TEXT); _XmUnoptSegTag(&seg) = _tag_cache[tag_index]; if (value != NULL) { _XmEntryTextSet((_XmStringEntry)&seg, value); _XmEntryByteCountSet(&seg, length); } } break; case XmSTRING_COMPONENT_LOCALE: if (!value || (length != strlen((char*) value))) { _XmProcessUnlock(); return NULL; } if ((value != _MOTIF_DEFAULT_LOCALE) && (strcmp((char*) value, _MOTIF_DEFAULT_LOCALE) != 0)) { _XmProcessUnlock(); return NULL; } tag_index = _XmStringIndexCacheTag((char*) value, length); optimized = (tag_index < TAG_INDEX_MAX); if (optimized) { _XmStrTextType((_XmString)&opt) = XmMULTIBYTE_TEXT; _XmStrTagIndex((_XmString)&opt) = tag_index; } else { _XmEntryTextTypeSet(&seg, XmMULTIBYTE_TEXT); _XmUnoptSegTag(&seg) = _XmStringCacheTag((char*) value, length); } break; case XmSTRING_COMPONENT_WIDECHAR_TEXT: optimized = (length < (1 << BYTE_COUNT_BITS)); if (optimized) { _XmStrTextType((_XmString)&opt) = XmWIDECHAR_TEXT; _XmStrTagIndex((_XmString)&opt) = tag_index; _XmStrByteCount((_XmString)&opt) = length; } else { _XmEntryTextTypeSet(&seg, XmWIDECHAR_TEXT); if (value != NULL) { _XmEntryTextSet((_XmStringEntry)&seg, value); _XmEntryByteCountSet(&seg, length); } } break; case XmSTRING_COMPONENT_LAYOUT_POP: if (value != NULL) { _XmProcessUnlock(); return NULL; } /* There is no optimized representation for layout components? */ optimized = False; _XmEntryPopSet(&seg, TRUE); break; case XmSTRING_COMPONENT_LAYOUT_PUSH: if (length != sizeof(XmDirection)) { _XmProcessUnlock(); return NULL; } /* There is no optimized representation for layout components? */ optimized = False; _XmEntryPushSet(&seg, *((XmDirection *)value)); break; case XmSTRING_COMPONENT_RENDITION_BEGIN: if (!value || (length != strlen((char*)value))) { _XmProcessUnlock(); return NULL; } tag_index = _XmStringIndexCacheTag((char *)value, length); optimized = (tag_index < REND_INDEX_MAX); if (optimized) { _XmStrRendIndex((_XmString)&opt) = tag_index; _XmStrRendBegin((_XmString)&opt) = TRUE; } else { _XmUnoptSegRendBegins(&seg) = rend_tags; rend_tags[0] = _XmStringCacheTag((char *)value, length); _XmUnoptSegRendBeginCount(&seg) = 1; } break; case XmSTRING_COMPONENT_RENDITION_END: if (!value || (length != strlen((char*)value))) { _XmProcessUnlock(); return NULL; } tag_index = _XmStringIndexCacheTag((char *)value, length); optimized = (tag_index < REND_INDEX_MAX); if (optimized) { _XmStrRendIndex((_XmString)&opt) = tag_index; _XmStrRendEnd((_XmString)&opt) = TRUE; } else { _XmUnoptSegRendEnds(&seg) = rend_tags; rend_tags[0] = _XmStringCacheTag((char *)value, length); _XmUnoptSegRendEndCount(&seg) = 1; } break; case XmSTRING_COMPONENT_TAB: { XmString ret_val; if (value != NULL) { _XmProcessUnlock(); return NULL; } ret_val = StringTabCreate(); _XmProcessUnlock(); return ret_val; } case XmSTRING_COMPONENT_END: { XmString ret_val; if (value != NULL) { _XmProcessUnlock(); return NULL; } ret_val = StringEmptyCreate(); _XmProcessUnlock(); return ret_val; } case XmSTRING_COMPONENT_UNKNOWN: default: _XmProcessUnlock(); return NULL; } /* Convert one of the proto-segments into a real _XmString. */ if (optimized) { /* Convert opt into an optimized XmString. */ str = (_XmString) _XmStrMalloc(sizeof(_XmStringOptRec) + (_XmStrByteCount((_XmString)&opt) ? (_XmStrByteCount((_XmString)&opt) - TEXT_BYTES_IN_STRUCT) : 0)); memcpy(str, &opt, sizeof(_XmStringOptRec) - TEXT_BYTES_IN_STRUCT); memcpy(_XmStrText(str), value, _XmStrByteCount((_XmString)&opt)); _XmStrRefCountSet(str, 1); } else { /* Convert seg into a non-optimized XmString. */ _XmStrCreate(str, XmSTRING_MULTIPLE_ENTRY, 0); if ((opt_seg = EntryCvtToOpt((_XmStringEntry)&seg)) != NULL) _XmStringSegmentNew(str, 0, opt_seg, False); else _XmStringSegmentNew(str, 0, (_XmStringEntry)&seg, True); } _XmProcessUnlock(); return (XmString) str; } XmStringComponentType XmStringGetNextTriple(XmStringContext context, unsigned int *length, XtPointer *value) { return XmeStringGetComponent((_XmStringContext) context, True, True, length, value); } /* * XmeStringGetComponent: A generalized implementation of XmStringGetNextTriple. */ XmStringComponentType XmeStringGetComponent(_XmStringContext context, Boolean update_context, Boolean copy_data, unsigned int *length, XtPointer *value) { short tmp_index; Boolean optimized; char state; Boolean last_seg, last_line; Boolean pop_dir; XmDirection push_dir; XmStringDirection dir; XmStringTag tag; int char_count; XmTextType text_type; char *seg_text; XmStringTag *begin_rends; short begin_count; XmStringTag *end_rends; short end_count; unsigned char tabs; _XmString opt = NULL; _XmStringEntry seg = NULL; _XmStringArraySegRec array_seg; Boolean skip; _XmProcessLock(); /* Initialize the out parameters. */ if (length) *length = 0; if (value) *value = NULL; /* No NULL pointers allowed. */ if (! (length && value)) { _XmProcessUnlock(); return XmSTRING_COMPONENT_END; } /* We may be done already. */ if (_XmStrContError(context)) { _XmProcessUnlock(); return XmSTRING_COMPONENT_END; } /* Gather the current segment information. */ state = _XmStrContState(context); optimized = _XmStrContOpt(context); if (optimized) { XmStringTag *rend_tag = NULL; opt = (_XmString) _XmStrContString(context); last_seg = True; last_line = True; /* Only lookup pop_dir when we need it. */ /* Only lookup push_dir when we need it. */ /* Only lookup dir when we need it. */ /* Only lookup tag when we need it. */ char_count = _XmStrByteCount(opt); text_type = (XmTextType) _XmStrTextType(opt); seg_text = _XmStrText(opt); begin_count = _XmStrRendBegin(opt); end_count = _XmStrRendEnd(opt); if (begin_count || end_count) { assert(_XmStrRendIndex(opt) != REND_INDEX_UNSET); rend_tag = _tag_cache + _XmStrRendIndex(opt); } begin_rends = (begin_count ? rend_tag : NULL); end_rends = (end_count ? rend_tag : NULL); /* Only lookup tabs when we need it. */ } else { _XmString str = _XmStrContString(context); _XmStringEntry line; /* If we've run off the end we're done. */ if (_XmStrContCurrLine(context) >= _XmStrLineCountGet(str)) { if (update_context) _XmStrContError(context) = TRUE; _XmProcessUnlock(); return XmSTRING_COMPONENT_END; } if (_XmStrImplicitLine(str)) { line = _XmStrEntry(str)[_XmStrContCurrLine(context)]; } else { _XmEntryType(&array_seg) = XmSTRING_ENTRY_ARRAY; _XmEntrySegmentCount(&array_seg) = _XmStrEntryCount(str); _XmEntrySegment(&array_seg) = (_XmStringNREntry *)_XmStrEntry(str); line = (_XmStringEntry)&array_seg; } last_line = (_XmStrContCurrLine(context) + 1 >= _XmStrLineCountGet(str)); if (_XmEntryMultiple(line)) last_seg = (_XmStrContCurrSeg(context) + 1 >=_XmEntrySegmentCount(line)); else last_seg = True; if (_XmEntryMultiple(line) && _XmEntrySegmentCount(line) == 0) { /* Empty lines are separators. */ state = SEP_STATE; /* The normal state variables shouldn't be referenced. */ } else { /* Extract data from a real segment. */ if (_XmEntryMultiple(line)) seg = (_XmStringEntry)_XmEntrySegment(line)[_XmStrContCurrSeg(context)]; else seg = line; /* Only lookup pop_dir when we need it. */ /* Only lookup push_dir when we need it. */ /* Only lookup dir when we need it. */ /* Only lookup tag when we need it. */ char_count = _XmEntryByteCountGet(seg); text_type = (XmTextType) _XmEntryTextTypeGet(seg); seg_text = (char*) _XmEntryTextGet(seg); begin_count = _XmEntryRendBeginCountGet(seg); begin_rends = _XmEntryRendCountedBegins(seg, begin_count); end_count = _XmEntryRendEndCountGet(seg); end_rends = _XmEntryRendCountedEnds(seg, end_count); /* Only lookup tabs when we need it. */ } } /* Return the next non-default component. */ switch (state) { case PUSH_STATE: push_dir = (optimized ? 0 : _XmEntryPushGet(seg)); if (push_dir != 0) { if (copy_data) { XmDirection* tmp = XtNew(XmDirection); *tmp = push_dir; *value = (XtPointer) tmp; *length = sizeof(XmDirection); } else { _XmStrContTmpDir(context) = push_dir; *value = (XtPointer) &_XmStrContTmpDir(context); *length = sizeof(XmDirection); } if (update_context) { _XmStrContState(context) = BEGIN_REND_STATE; _XmStrContRendIndex(context) = 0; } _XmProcessUnlock(); return XmSTRING_COMPONENT_LAYOUT_PUSH; } /* Fall through if no push components exist. */ case BEGIN_REND_STATE: tmp_index = ((_XmStrContState(context) == BEGIN_REND_STATE) ? _XmStrContRendIndex(context) : 0); if (tmp_index < begin_count) { /* Process another rendition start. */ if (copy_data) *value = (XtPointer) XtNewString(begin_rends[tmp_index]); else *value = (XtPointer) begin_rends[tmp_index]; *length = strlen((char*) *value); if (update_context) { /* Add this rendition to the list of active renditions. */ begin_context_rends(context, update_context, begin_rends + tmp_index, 1); _XmStrContState(context) = BEGIN_REND_STATE; _XmStrContRendIndex(context) = tmp_index + 1; } _XmProcessUnlock(); return XmSTRING_COMPONENT_RENDITION_BEGIN; } /* Fall through if there are no more rendition starts. */ case TAG_STATE: /* Don't output implicit leading charset component. */ tag = (optimized ? _XmStrTagGet(opt) : _XmEntryTag(seg)); if ((tag == XmSTRING_DEFAULT_CHARSET) || (tag && !strcmp((char*) tag, XmSTRING_DEFAULT_CHARSET))) tag = _XmStringGetCurrentCharset(); if ((text_type != XmNO_TEXT && text_type != _XmStrContTagType(context)) || (tag && (tag != _XmStrContTag(context)) && (!_XmStrContTag(context) || strcmp(tag, _XmStrContTag(context))))) { skip = (tag == NULL); assert(tag != XmSTRING_DEFAULT_CHARSET); /* If we have MB text with FONTLIST_DEFAULT_TAG, we really have * oldstyle locale_text so don't output tag component, but set * context if necessary for GetNextSegment. */ if ((tag == XmFONTLIST_DEFAULT_TAG) && (text_type == XmMULTIBYTE_TEXT)) { skip = TRUE; _XmStrContTag(context) = tag; } if (!skip) { /* Tag is changing. */ if (copy_data) *value = (XtPointer) XtNewString(tag); else *value = (XtPointer) tag; *length = strlen(tag); if (update_context) { _XmStrContTag(context) = tag; _XmStrContTagType(context) = text_type; _XmStrContState(context) = TAB_STATE; _XmStrContTabCount(context) = 0; } _XmProcessUnlock(); return ((text_type == XmCHARSET_TEXT) ? XmSTRING_COMPONENT_CHARSET : XmSTRING_COMPONENT_LOCALE); } } /* Fall through if no tag set. */ case TAB_STATE: tmp_index = ((_XmStrContState(context) == TAB_STATE) ? _XmStrContTabCount(context) : 0); tabs = (optimized ? _XmStrTabs(opt) : _XmEntryTabsGet(seg)); if (tmp_index < tabs) { /* A Tab precedes this segment. */ if (update_context) { _XmStrContState(context) = TAB_STATE; _XmStrContTabCount(context) = tmp_index + 1; } _XmProcessUnlock(); return XmSTRING_COMPONENT_TAB; } /* Fall through if there are no tabs. */ case DIR_STATE: dir = (optimized ? _XmStrDirection(opt) : _XmEntryDirectionGet(seg)); if (dir != _XmStrContDir(context)) { skip = FALSE; /* Try to resolve unset directions. */ if (dir == XmSTRING_DIRECTION_UNSET) { if ((char_count > 0) || (_XmStrContDir(context) == XmSTRING_DIRECTION_UNSET)) { XmCharDirectionProc char_proc = _XmOSGetCharDirection; (void)XmOSGetMethod(NULL, XmMCharDirection, (XtPointer *)&char_proc, NULL); if (state > TAG_STATE) tag = (optimized ? _XmStrTagGet(opt) : _XmEntryTag(seg)); dir = XmDirectionToStringDirection ((*char_proc)(seg_text, text_type, tag)); } else skip = TRUE; } if (!skip) { /* Direction is changing. */ if (copy_data) { XmStringDirection* tmp = XtNew(XmStringDirection); *tmp = dir; *value = (XtPointer) tmp; *length = sizeof(XmStringDirection); } else { _XmStrContTmpStrDir(context) = dir; *value = (XtPointer) &_XmStrContTmpStrDir(context); *length = sizeof(XmStringDirection); } if (update_context) { _XmStrContDir(context) = dir; _XmStrContState(context) = TEXT_STATE; } _XmProcessUnlock(); return XmSTRING_COMPONENT_DIRECTION; } } /* Fall through if no direction set. */ case TEXT_STATE: switch (text_type) { case XmCHARSET_TEXT: case XmMULTIBYTE_TEXT: case XmWIDECHAR_TEXT: if (copy_data) { char* tmp = XtMalloc(char_count + sizeof(wchar_t)); memcpy(tmp, seg_text, char_count); bzero(tmp + char_count, sizeof(wchar_t)); *value = (XtPointer) tmp; } else { if (seg_text != NULL) *value = seg_text; else *value = XmS; } *length = char_count; if (update_context) { _XmStrContState(context) = END_REND_STATE; _XmStrContRendIndex(context) = 0; } switch (text_type) { case XmCHARSET_TEXT: _XmProcessUnlock(); return XmSTRING_COMPONENT_TEXT; case XmMULTIBYTE_TEXT: _XmProcessUnlock(); return XmSTRING_COMPONENT_LOCALE_TEXT; case XmWIDECHAR_TEXT: _XmProcessUnlock(); return XmSTRING_COMPONENT_WIDECHAR_TEXT; case XmNO_TEXT: assert(FALSE); } case XmNO_TEXT: break; default: /* Something is wrong! */ assert(False); if (update_context) _XmStrContError(context) = True; _XmProcessUnlock(); return XmSTRING_COMPONENT_END; } /* Fall through if there is no text. */ case END_REND_STATE: tmp_index = ((_XmStrContState(context) == END_REND_STATE) ? _XmStrContRendIndex(context) : 0); if (tmp_index < end_count) { /* Process another rendition end. */ if (copy_data) *value = (XtPointer) XtNewString(end_rends[tmp_index]); else *value = (XtPointer) end_rends[tmp_index]; *length = strlen((char*) *value); if (update_context) { /* Remove this rendition from the list of active renditions. */ end_context_rends(context, update_context, end_rends + tmp_index, 1); _XmStrContState(context) = END_REND_STATE; _XmStrContRendIndex(context) = tmp_index + 1; } _XmProcessUnlock(); return XmSTRING_COMPONENT_RENDITION_END; } /* Fall through if there are no more rendition ends. */ case POP_STATE: pop_dir = (optimized ? 0 : _XmEntryPopGet(seg)); if (pop_dir) { /* A pop layout direction follows this segment. */ if (update_context) _XmStrContState(context) = SEP_STATE; _XmProcessUnlock(); return XmSTRING_COMPONENT_LAYOUT_POP; } /* Fall through if there is no pop layout direction. */ case SEP_STATE: /* This is the last possible component for a segment. */ if (last_seg && last_line) { /* Separators only appear between lines. */ if (update_context) _XmStrContError(context) = True; _XmProcessUnlock(); return XmSTRING_COMPONENT_END; } else if (last_seg && _XmStrImplicitLine(_XmStrContString(context))) { /* Advance to the next line. */ if (update_context) { _XmStrContState(context) = PUSH_STATE; _XmStrContCurrSeg(context) = 0; _XmStrContCurrLine(context)++; } _XmProcessUnlock(); return XmSTRING_COMPONENT_SEPARATOR; } else { /* Try the next segment of this line recursively. */ XmStringComponentType answer; char saved_state = _XmStrContState(context); unsigned short saved_seg = _XmStrContCurrSeg(context); _XmStrContState(context) = PUSH_STATE; _XmStrContCurrSeg(context)++; answer = XmeStringGetComponent(context, update_context, copy_data, length, value); if (!update_context) { _XmStrContState(context) = saved_state; _XmStrContCurrSeg(context) = saved_seg; } _XmProcessUnlock(); return answer; } /*NOTREACHED*/ assert(False); default: /* An unknown _XmStrContState? */ assert(False); if (update_context) _XmStrContError(context) = True; _XmProcessUnlock(); return XmSTRING_COMPONENT_END; } } /* * _XmStringContextReInit: Initialize an allocated _XmStringContext. */ void _XmStringContextReInit(_XmStringContext context, _XmString string) { assert(context != NULL); bzero((char*) context, sizeof(_XmStringContextRec)); _XmStrContString(context) = string; _XmStrContOpt(context) = _XmStrOptimized(string); _XmStrContDir(context) = XmSTRING_DIRECTION_UNSET; } /* * _XmStringContextCopy: Copy allocated _XmStringContexts. The active * rendition list is always copied because expanding it to * contain new entries via XtRealloc may free the old pointer. * Use _XmStringContextFree() to deallocate storage. */ void _XmStringContextCopy(_XmStringContext target, _XmStringContext source) { int size; assert(source && target && (source != target)); /* Copy the normal fields. */ memcpy(target, source, sizeof(_XmStringContextRec)); /* Copy the active renditions list so we can modify it. */ if (_XmStrContRendCount(target) > 0) { size = sizeof(XmStringTag) * _XmStrContRendCount(target); _XmStrContRendTags(target) = (XmStringTag*) XtMalloc(size); memcpy(_XmStrContRendTags(target), _XmStrContRendTags(source), size); } } /* * _XmStringContextFree: Deallocate an _XmStringContext's internal storage. */ void _XmStringContextFree(_XmStringContext context) { assert(context); /* Free the active rendition list. */ if (_XmStrContRendTags(context)) { XtFree((char*) _XmStrContRendTags(context)); } _XmStrContRendTags(context) = NULL; } /* * begin_context_rends: Update an _XmStringContext to reflect some * newly active renditions. */ static void begin_context_rends(_XmStringContext context, Boolean update_context, XmStringTag *rends, int count) { /* Append these renditions the context's list of active renditions. */ _XmStrContRendTags(context) = (XmStringTag*) XtRealloc((char*) _XmStrContRendTags(context), sizeof(XmStringTag) * (_XmStrContRendCount(context) + count)); memcpy(_XmStrContRendTags(context) + _XmStrContRendCount(context), rends, sizeof(XmStringTag) * count); /* Update the total number only if we're advancing the context. */ if (update_context) _XmStrContRendCount(context) += count; } /* * end_context_rends: Remove some renditions from an _XmStringContext's * list of active renditions. */ static void end_context_rends(_XmStringContext context, Boolean update_context, XmStringTag *rends, int count) { int n_rend, n_tag; int i; /* Check some simple error conditions. */ if (!update_context || (count <= 0)) return; /* Remove the last matching instance of each rendition. */ for (n_rend = 0; n_rend < count; n_rend++) { /* Renditions are cached, so we can compare pointers. */ n_tag = _XmStrContRendCount(context); while (--n_tag >= 0) if (_XmStrContRendTags(context)[n_tag] == rends[n_rend]) { /* Delete rendition n_tag from the context's list. */ for (i = n_tag; i < (_XmStrContRendCount(context) - 1); i++) _XmStrContRendTags(context)[i] = _XmStrContRendTags(context)[i + 1]; _XmStrContRendCount(context)--; } } } XmString XmStringGenerate(XtPointer text, XmStringTag tag, XmTextType type, XmStringTag rendition) { XmString result; int table_size; XmParseTable gen_table; int i; _XmProcessLock(); /* ** Get the parse table shared by generate and ungenerate. */ table_size = _get_generate_parse_table (&gen_table); /* Parse the text into an XmString. */ result = XmStringParseText (text, NULL, tag, type, gen_table, table_size, NULL); /* If no rendition was supplied return the parsetext result. */ if (rendition == NULL) { _XmProcessUnlock(); return result; } /* Try to wrap this rendition around an optimized result. */ if (_XmStrOptimized(result) && (_XmStrRendIndex(result) == REND_INDEX_UNSET)) { unsigned int rend_index; assert (!_XmStrRendBegin(result) && !_XmStrRendEnd(result)); rend_index = _XmStringIndexCacheTag((char *)rendition, XmSTRING_TAG_STRLEN); if (rend_index < REND_INDEX_MAX) { _XmStrRendIndex(result) = rend_index; _XmStrRendBegin(result) = _XmStrRendEnd(result) = True; _XmProcessUnlock(); return result; } } /* Try to wrap this rendition around an unoptimized result. */ if (!_XmStrOptimized(result)) { /* We only know how to do this if there is at least one segment. */ XmStringTag cached_rend = _XmStringCacheTag(rendition, XmSTRING_TAG_STRLEN); int n_line; _XmStringEntry line; _XmStringEntry seg; /* Locate the first segment. */ for (n_line = 0; n_line < _XmStrEntryCount(result); n_line++) { line = _XmStrEntry(result)[n_line]; if (_XmEntrySegmentCountGet(line) > 0) { /* Prepend rendition_begin to the first segment. */ if (_XmStrImplicitLine(result)) seg = (_XmStringEntry)_XmEntrySegmentGet(line)[0]; else seg = line; if (_XmEntryOptimized(seg) && _XmEntryRendIndex(seg) == REND_INDEX_UNSET) { unsigned int rend_index; assert (!_XmEntryRendBeginCountGet(seg) && !_XmEntryRendEndCountGet(seg)); rend_index = _XmStringIndexCacheTag((char *)rendition, XmSTRING_TAG_STRLEN); if (rend_index < REND_INDEX_MAX) { _XmEntryRendIndex(seg) = rend_index; _XmEntryRendBeginCountSet(seg, 1); } } else { if (_XmEntryOptimized(seg)) { _XmStringEntry new_seg = EntryCvtToUnopt(seg); _XmStringEntryFree(seg); seg = new_seg; if (_XmEntryMultiple(line)) _XmEntrySegment(line)[0] = (_XmStringNREntry)seg; else _XmStrEntry(result)[n_line] = seg; } _XmUnoptSegRendBegins(seg) = (XmStringTag*) XtRealloc((char*) _XmUnoptSegRendBegins(seg), (_XmUnoptSegRendBeginCount(seg) + 1)* sizeof(XmStringTag)); /* Put rendition first in begins. */ for (i = 0; i < _XmUnoptSegRendBeginCount(seg); i++) _XmUnoptSegRendBegins(seg)[i + 1] = _XmUnoptSegRendBegins(seg)[i]; _XmUnoptSegRendBegins(seg)[0] = cached_rend; _XmUnoptSegRendBeginCount(seg)++; } break; } } /* Locate the last segment. */ n_line = _XmStrEntryCount(result); while (--n_line >= 0) { line = _XmStrEntry(result)[n_line]; if (_XmEntrySegmentCountGet(line) > 0) { /* Append rendition_end to the last segment. */ if (_XmStrImplicitLine(result)) seg = (_XmStringEntry) _XmEntrySegmentGet(line)[_XmEntrySegmentCountGet(line)-1]; else seg = line; if (_XmEntryOptimized(seg)) { unsigned int rend_index; rend_index = _XmStringIndexCacheTag((char *)rendition, XmSTRING_TAG_STRLEN); assert ((_XmEntryRendBeginCountGet(seg) <= 1) && (_XmEntryRendEndCountGet(seg) == 0)); if (((_XmEntryRendIndex(seg) == REND_INDEX_UNSET) || (_XmEntryRendIndex(seg) == rend_index)) && (rend_index < REND_INDEX_MAX)) { _XmEntryRendIndex(seg) = rend_index; _XmEntryRendEndCountSet(seg, 1); _XmProcessUnlock(); return result; } else { break; } } else { if (_XmEntryOptimized(seg)) { _XmStringEntry new_seg = EntryCvtToUnopt(seg); if (_XmEntryMultiple(line)) _XmEntrySegment(line)[0] = (_XmStringNREntry)new_seg; else _XmStrEntry(result)[n_line] = new_seg; _XmStringEntryFree(seg); seg = new_seg; } _XmUnoptSegRendEnds(seg) = (XmStringTag*) XtRealloc((char*) _XmUnoptSegRendEnds(seg), (_XmUnoptSegRendEndCount(seg) + 1) * sizeof(XmStringTag)); _XmUnoptSegRendEnds(seg)[_XmUnoptSegRendEndCount(seg)] = cached_rend; _XmUnoptSegRendEndCount(seg)++; _XmProcessUnlock(); return result; } } } } /* As a last resort merge the rendition components normally. */ { XmString tmp_1, tmp_2; /* Prepend the rendition begin. */ tmp_1 = XmStringComponentCreate(XmSTRING_COMPONENT_RENDITION_BEGIN, strlen(rendition), rendition); tmp_2 = result; result = XmStringConcatAndFree(tmp_1, tmp_2); /* Append the rendition end. */ tmp_1 = result; tmp_2 = XmStringComponentCreate(XmSTRING_COMPONENT_RENDITION_END, strlen(rendition), rendition); result = XmStringConcatAndFree(tmp_1, tmp_2); } _XmProcessUnlock(); return result; } XtPointer _XmStringUngenerate(XmString string, XmStringTag tag, XmTextType tag_type, XmTextType output_type) { XtPointer result; int table_size; XmParseTable gen_table; /* ** Get the parse table shared by generate and ungenerate. */ table_size = _get_generate_parse_table (&gen_table); /* Unparse the XmString into text. */ result = XmStringUnparse (string, tag, tag_type, output_type, gen_table, table_size, XmOUTPUT_ALL); /* ** It might be useful to figure out rendition here to return the reverse of ** what came in for XmStringGenerate. I'm not real sure about how to do that ** and it isn't necessary for the immediate needs of CSText, so... ** RJS */ return result; } XmParseMapping XmParseMappingCreate(ArgList arg_list, Cardinal arg_count) { /* Allocate and initialize the return value. */ XmParseMapping result = XtNew(_XmParseMappingRec); bzero((char*)result, sizeof(_XmParseMappingRec)); /* Default values are established by bzero(). * * result->pattern = XmDIRECTION_CHANGE = NULL; * result->pattern_type = XmCHARSET_TEXT; * result->substitute = NULL; * result->parse_proc = NULL; * result->client_data = NULL; * result->include_status = XmINSERT; * result->internal_flags = XmSTRING_UNPARSE_UNKNOWN; */ /* Insert specified values. */ XmParseMappingSetValues(result, arg_list, arg_count); return result; } void XmParseMappingSetValues(XmParseMapping mapping, ArgList arg_list, Cardinal arg_count) { register Cardinal i; register String arg_name; Cardinal unknown = 0; _XmProcessLock(); /* Do a little error checking. */ if (mapping == NULL) { _XmProcessUnlock(); return; } /* Modify the specified values. */ for (i = 0; i < arg_count; i++) { arg_name = arg_list[i].name; if ((arg_name == XmNpattern) || (strcmp(arg_name, XmNpattern) == 0)) mapping->pattern = (XtPointer) arg_list[i].value; else if ((arg_name == XmNpatternType) || (strcmp(arg_name, XmNpatternType) == 0)) mapping->pattern_type = (XmTextType) arg_list[i].value; else if ((arg_name == XmNsubstitute) || (strcmp(arg_name, XmNsubstitute) == 0)) mapping->substitute = XmStringCopy((XmString) arg_list[i].value); else if ((arg_name == XmNinvokeParseProc) || (strcmp(arg_name, XmNinvokeParseProc) == 0)) mapping->parse_proc = (XmParseProc) arg_list[i].value; else if ((arg_name == XmNclientData) || (strcmp(arg_name, XmNclientData) == 0)) mapping->client_data = (XtPointer) arg_list[i].value; else if ((arg_name == XmNincludeStatus) || (strcmp(arg_name, XmNincludeStatus) == 0)) mapping->include_status = (XmIncludeStatus) arg_list[i].value; else unknown++; } /* If there were any known values reset internal_flags. */ if (unknown < arg_count) mapping->internal_flags = XmSTRING_UNPARSE_UNKNOWN; _XmProcessUnlock(); } static int _get_generate_parse_table (XmParseTable *gen_table) /* ** ** Utility function to build and supply the parse table shared by ** XmStringGenerate and _XmStringUngenerate. All of the information about ** the size and real storage of the table is maintained here. ** */ { int table_size = 2; Arg args[10]; Cardinal nargs; XmString tmp; int index = 0; static XmParseTable table = NULL; _XmProcessLock(); /* Allocate a parse table only if necessary. */ if (table) { *gen_table = table; _XmProcessUnlock(); return table_size; } else { table = (XmParseTable) XtCalloc (table_size, sizeof(XmParseMapping)); *gen_table = table; } _XmProcessUnlock(); /* Parse tab characters. */ tmp = XmStringComponentCreate(XmSTRING_COMPONENT_TAB, 0, NULL); nargs = 0; XtSetArg(args[nargs], XmNincludeStatus, XmINSERT), nargs++; XtSetArg(args[nargs], XmNsubstitute, tmp), nargs++; XtSetArg(args[nargs], XmNpattern, "\t"), nargs++; assert(nargs < XtNumber(args)); _XmProcessLock(); table[index++] = XmParseMappingCreate(args, nargs); _XmProcessUnlock(); XmStringFree(tmp); /* Parse newline characters. */ tmp = XmStringSeparatorCreate(); nargs = 0; XtSetArg(args[nargs], XmNincludeStatus, XmINSERT), nargs++; XtSetArg(args[nargs], XmNsubstitute, tmp), nargs++; XtSetArg(args[nargs], XmNpattern, "\n"), nargs++; assert(nargs < XtNumber(args)); _XmProcessLock(); table[index++] = XmParseMappingCreate(args, nargs); _XmProcessUnlock(); assert(index == table_size); return (table_size); } /* Destructively truncates str to be n bytes or less, insuring that it remains a legal ASN.1 encoding. */ unsigned char * _XmStringTruncateASN1(unsigned char *str, int n) { unsigned char *a = str; unsigned short used , delta, d1; unsigned char *new_c, *a_end; unsigned char *ap; unsigned char d2; short head_size; int len, length, header; if (a == NULL) return((unsigned char *)NULL); if (n < ASNHEADERLEN + CSSHORTLEN) return((unsigned char *)NULL); head_size = used = _read_header_length(a); len = _read_string_length(a); ap = _read_header(a); a_end = ((unsigned char *) a) + len + head_size; length = _read_asn1_length(ap); header = _asn1_size(length); /* Read the components adding up their lengths. */ while (((length + header) < (n - used)) && (ap < a_end)) { new_c = _read_component(ap, &d2, &d1, NULL); delta = length + header; used += delta; ap = new_c; length = _read_asn1_length(ap); header = _asn1_size(length); } if ((head_size == (ASNHEADERLEN + CSLONGLEN)) && ((used - head_size) <= MAXSHORTVALUE)) { /* Have to reallocate string. */ unsigned char *tmp; short diff = (CSLONGLEN - CSSHORTLEN); used -= diff; tmp = (unsigned char *)XtMalloc(used * sizeof(unsigned char)); memcpy(tmp, (str + diff), used); XtFree((char *)str); str = tmp; } else { str = (unsigned char *)XtRealloc((char *)str, used); } _write_header(str, used); return (str); }