1  /*
2  * Motif
3  *
4  * Copyright (c) 1987-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22 */
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 
28 #ifdef REV_INFO
29 #ifndef lint
30 static char rcsid[] = "$TOG: XmString.c /main/34 1998/04/16 14:35:32 mgreess $"
31 #endif
32 #endif
33 
34 #include <stdio.h>
35 #include <limits.h>		/* for MB_LEN_MAX */
36 #ifndef X_NOT_STDC_ENV
37 #include <stdlib.h>
38 #endif
39 #include <string.h>
40 #include <ctype.h>
41 
42 #ifdef __cplusplus
43 extern "C" { /* some 'locale.h' do not have prototypes (sun) */
44 #endif
45 #include <X11/Xlocale.h>
46 #ifdef __cplusplus
47 } /* Close scope of 'extern "C"' declaration */
48 #endif /* __cplusplus */
49 
50 #include <Xm/AtomMgr.h>
51 #include <Xm/Display.h>		/* for XmGetXmDisplay */
52 #include <Xm/DisplayP.h>	/* for noFontCallback list */
53 #include <Xm/XmosP.h>
54 #include "MessagesI.h"
55 #include "ResIndI.h"
56 #include "XmI.h"
57 #include "XmosI.h"
58 #include "XmRenderTI.h"
59 #include "XmStringI.h"
60 #include "XmTabListI.h"
61 
62 # include <stdarg.h>
63 
64 #define FIX_1434
65 #define FIX_1488
66 #define FIX_1532
67 
68 # define Va_start(a,b) va_start(a,b)
69 
70 /* Warning Messages */
71 #define NO_FONT_MSG	_XmMMsgXmString_0000
72 
73 /* These are the os-specific environment variables checked for a language
74 ** specification.
75 */
76 #define env_variable "LANG"
77 
78 struct __Xmlocale {
79     char   *tag;
80     int    taglen;
81     Boolean inited;
82 };
83 
84 /* enums for which_seg for calculating widths */
85 enum { XmSTRING_FIRST_SEG, XmSTRING_MIDDLE_SEG, XmSTRING_LAST_SEG,
86 	 XmSTRING_SINGLE_SEG
87 	 };
88 
89 /* Enums for marking internal_flags field in XmParseMappings. */
90 enum {
91   XmSTRING_UNPARSE_UNKNOWN,	/* Parse mapping hasn't been examined. */
92   XmSTRING_UNPARSE_PLAUSIBLE,	/* Parse mapping might unparse. */
93   XmSTRING_UNPARSE_IMPLAUSIBLE	/* Parse mapping will never unparse. */
94   };
95 
96 /* Values for drawing underlining renditions. */
97 #define SINGLE_OFFSET 1
98 #define DOUBLE_OFFSET 2
99 
100 #define Half(x)		(x >> 1)
101 
102 /* _XmStringEntry macros only acessible inside XmString code */
103 
104 #define _XmEntryRendCountedBegins(entry, count)				   \
105 	(_XmEntryOptimized(entry) ? 					   \
106 	 (((count) && _XmEntryRendIndex(entry) != REND_INDEX_UNSET) ? 	   \
107 	   &(_tag_cache[_XmEntryRendIndex(entry)]) : NULL) :	  	   \
108 	 _XmUnoptSegRendBegins(entry))
109 
110 #define _XmEntryRendBegins(entry) 					   \
111 	(_XmEntryOptimized(entry) ? 					   \
112 	 ((_XmEntryRendBeginCountGet(entry) && 				   \
113 	   _XmEntryRendIndex(entry) != REND_INDEX_UNSET) ? 		   \
114 	   &(_tag_cache[_XmEntryRendIndex(entry)]) : NULL) :	  	   \
115 	 _XmUnoptSegRendBegins(entry))
116 
117 #define _XmEntryRendCountedEnds(entry, count)				   \
118         (_XmEntryOptimized(entry) ?					   \
119 	 (((count) && _XmEntryRendIndex(entry) != REND_INDEX_UNSET) ? 	   \
120 	  &(_tag_cache[_XmEntryRendIndex(entry)]) : NULL) :		   \
121 	 _XmUnoptSegRendEnds(entry))
122 
123 #define _XmEntryRendEnds(entry) 					   \
124         (_XmEntryOptimized(entry) ?					   \
125 	 ((_XmEntryRendEndCountGet(entry) && 				   \
126 	   _XmEntryRendIndex(entry) != REND_INDEX_UNSET) ? 		   \
127 	  &(_tag_cache[_XmEntryRendIndex(entry)]) : NULL) :		   \
128 	 _XmUnoptSegRendEnds(entry))
129 
130 
131 /*
132  * this set constructs ASN.1 XmString format object.  The TLV version
133  */
134 
135 /*
136  	The ASN.1 version of XmString is:
137 
138 	COMPOUND_STRING			4 or 6 bytes (see description below)
139 
140 	    component tag		1 byte
141 	    length			1 or 3 bytes
142 	    value			n bytes
143 
144 	    component tag		1 byte
145 	    length			1 or 3 bytes
146 	    value			n bytes
147 
148 	eg. very simple...
149 */
150 
151 
152 /*
153  * ASN.1 header for compound string - 3 byte header, followed by length
154  * which is three bytes maximum, but almost always 1 byte.
155  *
156  * The first byte defines the ASN.1 space:  (0xdf)
157  *              1 1      0      1 1 1 1 1
158  *              class    form   ID code
159  *
160  *    class is private, form is primitive (not constructed from other
161  *    forms), and the ID code value means the actual ID code value is
162  *    extended into one or more octets.
163  *
164 
165  * The second and third bytes define the actual ID code value.  The
166  * value used for 1.2 is the inverse of the original XUI value.
167  *     second byte:  (0x80)
168  *               1       0000000
169  *              MSB      high seven bits of ID code
170  *
171  *     third byte:   (0x06)
172  *               0       0000110
173  *              LSB      low seven bits of ID code
174  *
175 
176  * The length field of the ASN.1 conformant compound string header
177  * is dynamically constructed.  There are two possible forms depending
178  * upon the length of the string.  Note that this length excludes the
179  * header bytes.
180  *
181  *    Short Form: range 0 .. 127
182  *    one byte
183  *                  0         nnnnnnn
184  *                 short       7 bit length
185  *
186  *    Long Form: range 128 .. 2**16-1
187  *    three bytes
188  *    first:        1         nnnnnnn
189  *                 long       number of bytes to follow
190  *
191  *    second:
192  *                  nnnnnnnn
193  *                  MSB of length
194  *
195  *    third:
196  *                  nnnnnnnn
197  *                  LSB of length
198  *
199 
200  * This process for constructing the length field will also be
201  * used to construct the length field within individual tag-length-value
202  * triplets.
203  */
204 
205 #define ASNHEADERLEN     3
206 static XmConst unsigned char ASNHeader[ASNHEADERLEN] = { 0xdf, 0x80, 0x06 };
207 
208 
209 #define MAXSHORTVALUE   127             /* maximum len to be used for short
210                                            length form */
211 #define CSLONGLEN       3
212 #define CSSHORTLEN      1
213 #define CSLONGLEN1      0x82
214 #define CSLONGBIT	0x80
215 
216 #define ASNTAG		1
217 /* Num bytes for tag & length = ASNTAG + [CSSHORTLEN | CSLONGLEN] */
218 
219 #define HEADER 3	/* num bytes for tag & length */
220 
221 /*
222  * calculates the number of bytes in the header of an external compound
223  * string, given the total length of the components.
224  */
225 
226 #define _calc_header_size(len) \
227     ((((unsigned short)(len)) > MAXSHORTVALUE) ? (ASNHEADERLEN + CSLONGLEN) : \
228      (ASNHEADERLEN + CSSHORTLEN))
229 
230 #define _asn1_size(len) \
231     ((((unsigned short)(len)) > MAXSHORTVALUE) ? (ASNTAG + CSLONGLEN) : \
232      (ASNTAG + CSSHORTLEN))
233 
234 #define _is_asn1_long(p) \
235   ((*((unsigned char *)(p) + ASNTAG)) & ((unsigned char)CSLONGBIT))
236 
237 /********    Static Function Declarations    ********/
238 
239 static Boolean _is_short_length(
240                         unsigned char *p) ;
241 static void _write_long_length(
242                         unsigned char *p,
243 #if NeedWidePrototypes
244                         unsigned int length) ;
245 #else
246                         unsigned short length) ;
247 #endif /* NeedWidePrototypes */
248 static unsigned char * _write_header(
249                         unsigned char *p,
250 #if NeedWidePrototypes
251                         unsigned int length) ;
252 #else
253                         unsigned short length) ;
254 #endif /* NeedWidePrototypes */
255 static unsigned char * _read_header(
256                         unsigned char *p) ;
257 static unsigned short _read_header_length(
258                         unsigned char *p) ;
259 static unsigned short _read_length(
260                         unsigned char *p) ;
261 static unsigned short _read_string_length(
262                         unsigned char *p) ;
263 static unsigned char * _write_component(
264                         unsigned char *p,
265 #if NeedWidePrototypes
266                         unsigned int tag,
267                         unsigned int length,
268 #else
269                         unsigned char tag,
270                         unsigned short length,
271 #endif /* NeedWidePrototypes */
272                         unsigned char *value,
273 #if NeedWidePrototypes
274                         int move_by_length) ;
275 #else
276                         Boolean move_by_length) ;
277 #endif /* NeedWidePrototypes */
278 static unsigned char * _read_component(
279                         unsigned char *p,
280                         unsigned char *tag,
281                         unsigned short *length,
282                         unsigned char *value) ;
283 static Boolean RenditionsCompatible(_XmStringEntry seg1,
284 				    _XmStringEntry seg2);
285 static void MergeEnds(_XmStringEntry a,
286 		      _XmStringEntry b);
287 static void MergeBegins(_XmStringEntry a,
288 			_XmStringEntry b);
289 static Boolean _is_asn1(unsigned char *string) ;
290 static XmString Clone(XmString string, int lines);
291 static void OptLineMetrics(XmRenderTable rendertable,
292 			   _XmString line,
293 			   XmRendition *rend_io,
294 			   XmRendition base_rend,
295 			   Dimension *width,
296 			   Dimension *height,
297 			   Dimension *ascender,
298 			   Dimension *descender );
299 static Dimension OptLineAscender(
300                         XmRenderTable f,
301                         _XmStringOpt opt) ;
302 static void LineMetrics(_XmStringEntry line,
303 			XmRenderTable r,
304 			XmRendition *rend_io,
305 			XmRendition base,
306 			XmDirection prim_dir,
307 			Dimension *width,
308 			Dimension *height,
309 			Dimension *ascender,
310 			Dimension *descender);
311 static void SubStringPosition(
312 #if NeedWidePrototypes
313                         int one_byte,
314 #else
315                         Boolean one_byte,
316 #endif /* NeedWidePrototypes */
317 			XmRenderTable rt,
318                         XmRendition entry,
319                         _XmStringEntry seg,
320                         _XmStringEntry under_seg,
321 #if NeedWidePrototypes
322                         int x,
323 #else
324                         Position x,
325 #endif /* NeedWidePrototypes */
326                         Dimension *under_begin,
327                         Dimension *under_end) ;
328 static void recursive_layout(_XmString string,
329 			     int *line_index,
330 			     int *seg_index,
331 #if NeedWidePrototypes
332 			     int direction,
333 			     int p_direction,
334 #else
335                              XmDirection direction,
336                              XmDirection p_direction,
337 #endif /* NeedWidePrototypes */
338 			     int depth);
339 static void last_direction(_XmStringEntry line,
340 			   int *index,
341 			   XmDirection *direction);
342 static void DrawLine(Display *d,
343 		     Window w,
344 		     Screen **pscreen,
345 		     int x,
346 		     int y,
347 		     _XmStringEntry line,
348 		     XmRendition *scr_rend,
349 		     XmRendition base,
350 		     XmRenderTable rendertable,
351 		     XmDirection prim_dir,
352 #if NeedWidePrototypes
353 		     int image,
354 #else
355 		     Boolean image,
356 #endif /* NeedWidePrototypes */
357 		     _XmString *underline,
358 #if NeedWidePrototypes
359 		     int descender,
360 		     int opt,
361 		     int opt_width,
362 		     int opt_height
363 #else
364 		     Dimension descender,
365                      Boolean opt,
366 		     Dimension opt_width,
367 		     Dimension opt_height
368 #endif /* NeedWidePrototypes */
369 		     );
370 static void _calc_align_and_clip(
371                         Display *d,
372 			Window w,
373                         GC gc,
374                         Position *x,
375 #if NeedWidePrototypes
376                         int y,
377                         int width,
378 #else
379                         Position y,
380                         Dimension width,
381 #endif /* NeedWidePrototypes */
382                         int line_width,
383 #ifdef FIX_1488
384                         int line_height,
385 #endif
386 #if NeedWidePrototypes
387                         unsigned int lay_dir,
388 #else
389                         unsigned char lay_dir,
390 #endif /* NeedWidePrototypes */
391                         XRectangle *clip,
392 #if NeedWidePrototypes
393                         unsigned int align,
394 #else
395                         unsigned char align,
396 #endif /* NeedWidePrototypes */
397                         int descender,
398                         int *restore,
399 			XmFontType font_type) ;
400 static void _draw(
401                         Display *d,
402                         Window w,
403                         XmRenderTable rendertable,
404                         _XmString string,
405                         GC gc,
406 #if NeedWidePrototypes
407                         int x,
408                         int y,
409                         int width,
410                         unsigned int align,
411                         unsigned int lay_dir,
412 #else
413                         Position x,
414                         Position y,
415                         Dimension width,
416                         unsigned char align,
417                         unsigned char lay_dir,
418 #endif /* NeedWidePrototypes */
419                         XRectangle *clip,
420 #if NeedWidePrototypes
421                         int image,
422 #else
423                         Boolean image,
424 #endif /* NeedWidePrototypes */
425                         _XmString underline) ;
426 static void _render(Display *d,
427 		    Drawable w,
428 		    XmRenderTable rendertable,
429 		    XmRendition rend,
430 		    _XmString string,
431 #if NeedWidePrototypes
432 		    int x,
433 		    int y,
434 		    int width,
435 		    unsigned int align,
436 		    unsigned int lay_dir,
437 		    int image,
438 #else
439 		    Position x,
440 		    Position y,
441 		    Dimension width,
442 		    unsigned char align,
443 		    unsigned char lay_dir,
444 		    Boolean image,
445 #endif						  /* NeedWidePrototypes */
446 		    _XmString underline,
447 		    XRectangle *clip);
448 
449 static _XmString _XmStringOptCreate(
450                         unsigned char *c,
451                         unsigned char *end,
452 #if NeedWidePrototypes
453                         unsigned int textlen,
454                         int havetag,
455 #else
456                         unsigned short textlen,
457                         Boolean havetag,
458 #endif /* NeedWidePrototypes */
459                         unsigned int tag_index) ;
460 static void finish_segment(_XmString str,
461 			   _XmStringUnoptSeg seg,
462 			   int *lc,
463 			   int *sc,
464 			   Boolean *unopt,
465 			   XmStringDirection dir);
466 static _XmString _XmStringNonOptCreate(
467                         unsigned char *c,
468                         unsigned char *end,
469 #if NeedWidePrototypes
470                         int havetag) ;
471 #else
472                         Boolean havetag) ;
473 #endif /* NeedWidePrototypes */
474 static Boolean SpecifiedSegmentExtents(_XmStringEntry entry,
475 				       XmRenderTable rendertable,
476 				       XmRendition *rend_in_out,
477 				       XmRendition base,
478 				       int which_seg,
479 				       Dimension *width,
480 				       Dimension *height,
481 				       Dimension *ascent,
482 				       Dimension *descent);
483 
484 static void ComputeMetrics(XmRendition rend,
485 			   XtPointer text,
486 			   unsigned int byte_count,
487 			   XmTextType type,
488 			   int which_seg,
489 			   Dimension *width,
490 			   Dimension *height,
491 			   Dimension *ascent,
492 			   Dimension *descent,
493                            Boolean utf8);
494 static Dimension ComputeWidth(unsigned char which,
495 			      XCharStruct char_ret);
496 static void _parse_locale(
497                         char *str,
498                         int *indx,
499                         int *len) ;
500 static Boolean match_pattern(XtPointer      text,
501 			     XmStringTag    tag,
502 			     XmTextType     type,
503 			     XmParseMapping pattern,
504 			     int            char_len,
505 			     Boolean        dir_change);
506 static void parse_unmatched(XmString  *result,
507 			    char     **ptr,
508 			    XmTextType text_type,
509 			    int        length);
510 static Boolean parse_pattern(XmString      *result,
511 			     char         **ptr,
512 			     XtPointer      text_end,
513 			     XmStringTag    tag,
514 			     XmTextType     type,
515 			     XmParseMapping pat,
516 			     int            length,
517 			     XtPointer      call_data,
518 			     Boolean       *terminate);
519 static void check_unparse_models(XmStringContext   context,
520 				 XmStringTag       tag,
521 				 XmTextType        tag_type,
522 				 XmParseModel      parse_model,
523 				 Boolean	  *prev_text_match,
524 				 Boolean	  *next_text_match,
525 				 Boolean	  *non_text_match);
526 static void unparse_text(char                **result,
527 			 int                  *length,
528 			 XmTextType            output_type,
529 			 XmStringComponentType c_type,
530 			 unsigned int          c_length,
531 			 XtPointer             c_value);
532 static Boolean unparse_is_plausible(XmParseMapping pattern);
533 static void unparse_components(char          **result,
534 			       int            *length,
535 			       XmTextType      output_type,
536 			       XmStringContext context,
537 			       XmParseTable    parse_table,
538 			       Cardinal        parse_count);
539 
540 static void begin_context_rends(_XmStringContext context,
541 				Boolean	         update_context,
542 				XmStringTag	*renditions,
543 				int		 count);
544 static void end_context_rends(_XmStringContext context,
545 			      Boolean          update_context,
546 			      XmStringTag     *rendition,
547 			      int	       count);
548 static XFontStruct * GetFont(XmRenderTable rt,
549 			     _XmStringEntry entry);
550 static _XmStringCache CacheGet(_XmStringEntry entry,
551 			       int type,
552 			       int create,
553 			       XtPointer match_value);
554 static _XmStringEntry EntryCvtToOpt(_XmStringEntry entry);
555 static _XmStringEntry EntryCvtToUnopt(_XmStringEntry entry);
556 
557 static XmString StringTabCreate(void);
558 static XmString StringEmptyCreate(void);
559 
560 static int _get_generate_parse_table (XmParseTable *gen_table);
561 
562 /********    End Static Function Declarations    ********/
563 
564 
565 static struct __Xmlocale locale;
566 static char **_tag_cache;
567 static int    _cache_count = 0;
568 
569 /*
570  * Determines whether this string has a short or long length field
571  */
572 static Boolean
_is_short_length(unsigned char * p)573 _is_short_length(
574         unsigned char *p )
575 {
576 
577   unsigned char *uchar_p = (unsigned char *) p;
578 
579   uchar_p += ASNHEADERLEN;
580 
581   if (*uchar_p & (char)CSLONGBIT)
582     return (FALSE);
583   else return (TRUE);
584 }
585 
586 /*
587  * Routine that writes a long length field
588  */
589 static void
_write_long_length(unsigned char * p,unsigned int length)590 _write_long_length(
591         unsigned char *p,
592 #if NeedWidePrototypes
593         unsigned int length )
594 #else
595         unsigned short length )
596 #endif /* NeedWidePrototypes */
597 {
598 
599   unsigned char   * uchar_p = (unsigned char *) p;
600 
601   /*
602    * flag the long version
603    */
604   *uchar_p = CSLONGLEN1;
605   uchar_p++;
606 
607   /*
608    * need to pull off the high 8 bits
609    */
610 
611   *uchar_p = (unsigned char) (length >> 8);
612   uchar_p++;
613   *uchar_p = (unsigned char) (length & 0xff);
614 
615 }
616 
617 
618 /*
619  * Private routines for manipulating the ASN.1 header of external
620  * compound strings.
621  */
622 static unsigned char *
_write_header(unsigned char * p,unsigned int length)623 _write_header(
624         unsigned char *p,
625 #if NeedWidePrototypes
626         unsigned int length )
627 #else
628         unsigned short length )
629 #endif /* NeedWidePrototypes */
630 {
631 
632   unsigned char * uchar_p = p;
633   int     headlen;
634 
635   /* write the header in. */
636 
637   headlen = ASNHEADERLEN;
638   memcpy( uchar_p, ASNHeader, ASNHEADERLEN);
639   uchar_p += ASNHEADERLEN;
640 
641   /* short or long length value? */
642 
643   if (length > MAXSHORTVALUE)
644     {
645       _write_long_length(uchar_p, length);
646       headlen += CSLONGLEN;
647     }
648   else {
649     /* Short version */
650     *uchar_p = (unsigned char) length;
651     headlen += CSSHORTLEN;
652   }
653   return (p + headlen);
654 }
655 
656 /*
657  * extracts the ASN.1 header from the external compound string.
658  */
659 static unsigned char *
_read_header(unsigned char * p)660 _read_header(
661         unsigned char *p )
662 {
663   /*
664    * Read past the ASN.1 header; get the first length byte and see if this
665    * is a one or three byte length.
666    */
667 
668   if (_is_short_length(p))
669     return (p + ASNHEADERLEN + CSSHORTLEN);
670   else
671     return (p + ASNHEADERLEN + CSLONGLEN);
672 }
673 
674 /*
675  * reads the length the ASN.1 header of an external
676  * compound string.
677  */
678 static unsigned short
_read_header_length(unsigned char * p)679 _read_header_length(
680         unsigned char *p )
681 {
682   /*
683    * Get the first length byte and see if this
684    * is a one or three byte length.
685    */
686 
687   if (_is_short_length(p))
688     return (ASNHEADERLEN + CSSHORTLEN);
689   else
690     return (ASNHEADERLEN + CSLONGLEN);
691 
692 }
693 
694 /*
695  * calculates the length of the external compound string, excluding the
696  * ASN.1 header.
697  */
698 static unsigned short
_read_string_length(unsigned char * p)699 _read_string_length(
700         unsigned char *p )
701 {
702 
703   unsigned char * uchar_p = (unsigned char *) p;
704   unsigned short totallen = 0;
705 
706   /*
707    * Read past the ASN.1 header; get the first length byte and see if this
708    * is a one or three byte length.
709    */
710 
711   uchar_p += ASNHEADERLEN;
712 
713   if (_is_short_length(p))
714     {
715       totallen += (unsigned short) *uchar_p;
716     }
717   else {
718     unsigned short i;
719 
720     uchar_p++;
721     i = ((unsigned short) *uchar_p) << 8;
722     uchar_p++;
723     i |= ((unsigned short) *uchar_p); /* Mask on the low byte */
724     totallen += i;
725   }
726   return (totallen);
727 }
728 
729 /*
730  * calculates length of component marked by a tag-length-value triple.
731  */
732 static unsigned short
_read_asn1_length(unsigned char * p)733 _read_asn1_length(
734         unsigned char *p )
735 {
736   unsigned char * uchar_p = (unsigned char *) p;
737   unsigned short totallen = 0;
738 
739   /*
740    * Read past the tag; get the first length byte and see if this
741    * is a one or three byte length.
742    */
743 
744   uchar_p += ASNTAG;
745 
746   if (_is_asn1_long(p))
747     {
748       unsigned short i;
749 
750       uchar_p++;
751       i = ((unsigned short) *uchar_p) << 8;
752       uchar_p++;
753       i |= ((unsigned short) *uchar_p); /* Mask on the low byte */
754       totallen += i;
755     }
756   else
757     {
758       totallen += (unsigned short) *uchar_p;
759     }
760   return (totallen);
761 }
762 
763 /*
764  * determines length of ASN.1 length field of component of external
765  * compound string.
766  */
767 static unsigned short
_read_length(unsigned char * p)768 _read_length(
769         unsigned char *p )
770 {
771   /*
772    * Read past the tag field; get the first length byte and see if this
773    * is a one or three byte length.
774    */
775   if (_is_asn1_long(p))
776     return ((unsigned short)(ASNTAG + CSLONGLEN));
777   else
778     return ((unsigned short)(ASNTAG + CSSHORTLEN));
779 }
780 
781 /*
782  * Private routines for reading/writing the individual compound string
783  * components
784  */
785 static unsigned char *
_write_component(unsigned char * p,unsigned int tag,unsigned int length,unsigned char * value,int move_by_length)786 _write_component(
787         unsigned char *p,
788 #if NeedWidePrototypes
789         unsigned int tag,
790         unsigned int length,
791 #else
792         unsigned char tag,
793         unsigned short length,
794 #endif /* NeedWidePrototypes */
795         unsigned char *value,
796 #if NeedWidePrototypes
797         int move_by_length )
798 #else
799         Boolean move_by_length )
800 #endif /* NeedWidePrototypes */
801 {
802   unsigned char * uchar_p = p;
803 
804   *uchar_p = tag;		/* stuff tag */
805   uchar_p += ASNTAG;
806 
807   /* short or long length value? */
808   if (length > MAXSHORTVALUE)
809     {
810       _write_long_length(uchar_p, length);
811       uchar_p += CSLONGLEN;
812     }
813   else {
814     /* Short version */
815     *uchar_p = (unsigned char) length;
816     uchar_p += CSSHORTLEN;
817   }
818 
819   if (value != (unsigned char *) NULL)
820     memcpy((char *)uchar_p, (char *)value, (size_t)length);
821 
822   if (move_by_length)
823     return (uchar_p + length);
824   else
825     return (uchar_p);
826 }
827 
828 static unsigned char *
_read_component(unsigned char * p,unsigned char * tag,unsigned short * length,unsigned char * value)829 _read_component(
830         unsigned char *p,
831         unsigned char *tag,
832         unsigned short *length,
833         unsigned char *value)
834 {
835   unsigned char * uchar_p = (unsigned char *) p;
836 
837   *tag = *uchar_p;		/* read tag */
838 
839   *length = _read_asn1_length(p);
840 
841   uchar_p += _read_length(p);	/* move to value */
842   if (value != NULL) memcpy(value, uchar_p, *length);
843 
844   return (uchar_p + *length);
845 
846 }
847 
848 /* Create a new XmString */
849 XmString
XmStringCreate(char * text,XmStringTag tag)850 XmStringCreate(
851         char *text,
852         XmStringTag tag )
853 {
854   XmString ret_val;
855 
856   _XmProcessLock();
857   ret_val = _XmStringNCreate (text, tag, -1);
858   _XmProcessUnlock();
859   return ret_val;
860 }
861 
862 /* Create a new XmString */
863 XmString
_XmStringNCreate(char * text,XmStringTag tag,int len)864 _XmStringNCreate(char *text,
865 		XmStringTag tag,
866 		int len)
867 {
868   XmString		str;
869   char     		*curtag = NULL;
870   int      		t_length;
871   unsigned int 		tag_index = 0;
872   _XmString		opt_str;
873   XmTextType            type = XmCHARSET_TEXT;
874 
875   if (!text) return ((XmString) NULL);
876   if (!tag) return ((XmString) NULL);
877 
878   t_length = ((len >= 0) ? len : strlen (text));
879 
880   if ((tag == XmFONTLIST_DEFAULT_TAG) ||
881       (strcmp(tag, XmFONTLIST_DEFAULT_TAG) == 0))
882     {
883       curtag = tag;
884       type = XmMULTIBYTE_TEXT;
885     }
886   else {
887     if ((strcmp(tag, XmSTRING_DEFAULT_CHARSET) == 0))
888       curtag = _XmStringGetCurrentCharset();
889     else curtag = tag;
890   }
891 
892   tag_index = _XmStringIndexCacheTag(curtag, XmSTRING_TAG_STRLEN);
893 
894   if ((tag_index < TAG_INDEX_UNSET) &&
895       (t_length < (1 << BYTE_COUNT_BITS)))
896     /* Create optimized string. */
897     {
898       _XmStrCreate(opt_str, XmSTRING_OPTIMIZED, t_length);
899       _XmStrTagIndex(opt_str) = tag_index;
900       _XmStrTextType(opt_str) = type;
901       memcpy(_XmStrText(opt_str), text, t_length);
902 
903       return(opt_str);
904     }
905   else /* Non-optimized */
906     {
907       _XmStringUnoptSegRec 	seg;
908       _XmStrCreate(str, XmSTRING_MULTIPLE_ENTRY, 0);
909 
910       _XmEntryInit((_XmStringEntry)&seg, XmSTRING_ENTRY_UNOPTIMIZED);
911 
912       _XmUnoptSegTag(&seg) = _XmStringCacheTag(curtag, XmSTRING_TAG_STRLEN);
913 
914       _XmEntryTextTypeSet(&seg, type);
915       _XmEntryTextSet((_XmStringEntry)&seg, text);
916       _XmUnoptSegByteCount(&seg) = t_length;
917 
918       _XmStringSegmentNew(str, 0, (_XmStringEntry)&seg, True);
919       return(str);
920     }
921 }
922 
923 /*
924  * Convenience routine creating localized XmString from NULL terminated string.
925  */
926 XmString
XmStringCreateLocalized(String text)927 XmStringCreateLocalized(
928         String text )
929 {
930   return (XmStringGenerate(text, NULL, XmCHARSET_TEXT, NULL));
931 }
932 
933 /* Create an optimized _XmString with only direction set. */
934 XmString
XmStringDirectionCreate(int direction)935 XmStringDirectionCreate(
936 #if NeedWidePrototypes
937         int direction )
938 #else
939         XmStringDirection direction )
940 #endif /* NeedWidePrototypes */
941 {
942   /* Maintain a static cache of the common results. */
943   static XmConst XmStringDirection dir_index[] =
944     {
945       XmSTRING_DIRECTION_L_TO_R, XmSTRING_DIRECTION_R_TO_L,
946       XmSTRING_DIRECTION_UNSET, XmSTRING_DIRECTION_DEFAULT
947     };
948   static _XmString cache_str[] = { NULL, NULL, NULL, NULL };
949 
950   int index;
951   _XmString opt_str = NULL;
952 
953   _XmProcessLock();
954   /* Find the static cache index and string for this direction. */
955   assert(XtNumber(dir_index) == XtNumber(cache_str));
956   for (index = 0; index < XtNumber(dir_index); index++)
957     if (dir_index[index] == direction)
958       {
959 	opt_str = cache_str[index];
960 	break;
961       }
962 
963   /* Create the return string if necessary and this is a known direction. */
964   if (!opt_str && (index < XtNumber(dir_index)))
965     {
966       _XmStrCreate(opt_str, XmSTRING_OPTIMIZED, 0);
967       _XmStrDirection(opt_str) = direction;
968 
969       cache_str[index] = opt_str;
970     }
971 
972   /* Try to copy a cached string by incrementing its reference count. */
973   if ((index < XtNumber(dir_index)) &&
974       (_XmStrRefCountInc(opt_str) == 0))
975     {
976       _XmStrRefCountDec(opt_str);	/* Undo previous increment. */
977       XmStringFree(opt_str);		/* Release our cached copy. */
978       cache_str[index] = NULL;
979       opt_str = XmStringDirectionCreate(direction);
980       _XmProcessUnlock();
981       return (XmString) opt_str;
982     }
983 
984   _XmProcessUnlock();
985   return (XmString) opt_str;
986 }
987 
988 /* Create an empty non-optimized _XmString containing a single newline */
989 XmString
XmStringSeparatorCreate(void)990 XmStringSeparatorCreate( void )
991 {
992   static _XmString str = NULL;
993   XmString ret_val;
994 
995   _XmProcessLock();
996   if (!str)
997     {
998       int i;
999 
1000       _XmStrCreate(str, XmSTRING_MULTIPLE_ENTRY, 0);
1001 
1002       _XmStrImplicitLine(str) = True;
1003       _XmStrEntry(str) = (_XmStringEntry *)XtMalloc(2*sizeof(_XmStringEntry));
1004       _XmStrEntryCount(str) = 2;
1005       for (i = 0; i < 2; i++) {
1006 	_XmEntryCreate(_XmStrEntry(str)[i], XmSTRING_ENTRY_OPTIMIZED);
1007       }
1008     }
1009 
1010   /* If the reference count gets too big free the old string. */
1011   if (_XmStrRefCountInc(str) == 0)
1012     {
1013       _XmStrRefCountDec(str);	/* Undo previous increment. */
1014       XmStringFree(str);	/* Release our cached copy. */
1015       str = NULL;
1016       ret_val = XmStringSeparatorCreate();
1017       _XmProcessUnlock();
1018       return ret_val;
1019     }
1020 
1021   ret_val = Clone(str, _XmStrEntryCountGet(str)); /* ??? */
1022   _XmProcessUnlock();
1023   return (XmString)ret_val;
1024 }
1025 
1026 /* Create an empty optimized _XmString containing a single tab. */
1027 static XmString
StringTabCreate(void)1028 StringTabCreate( void )
1029 {
1030   static _XmString opt_str = NULL;
1031 
1032   if (!opt_str)
1033     {
1034       _XmStrCreate(opt_str, XmSTRING_OPTIMIZED, 0);
1035       _XmStrTabs(opt_str) = 1;
1036     }
1037 
1038   /* If the reference count gets too big free the old string. */
1039   if (_XmStrRefCountInc(opt_str) == 0)
1040     {
1041       _XmStrRefCountDec(opt_str); /* Undo previous increment. */
1042       XmStringFree(opt_str);     /* Release our cached copy. */
1043       opt_str = NULL;
1044       return StringTabCreate();
1045     }
1046 
1047   return (XmString)opt_str;
1048 }
1049 
1050 /* Create an empty optimized _XmString. */
1051 static XmString
StringEmptyCreate(void)1052 StringEmptyCreate( void )
1053 {
1054   static _XmString opt_str = NULL;
1055 
1056   if (!opt_str)
1057     {
1058       _XmStrCreate(opt_str, XmSTRING_OPTIMIZED, 0);
1059     }
1060 
1061   /* If the reference count gets too big free the old string. */
1062   if (_XmStrRefCountInc(opt_str) == 0)
1063     {
1064       _XmStrRefCountDec(opt_str); /* Undo previous increment. */
1065       XmStringFree(opt_str);     /* Release our cached copy. */
1066       opt_str = NULL;
1067       return StringEmptyCreate();
1068     }
1069 
1070   return (XmString)opt_str;
1071 }
1072 
1073 /*
1074  * this set provides access to the internal components of XmStrings
1075  */
1076 
1077 /*
1078  * set up the read-out context
1079  */
1080 Boolean
XmStringInitContext(XmStringContext * context,XmString string)1081 XmStringInitContext(
1082         XmStringContext *context,
1083         XmString string )
1084 {
1085   XmStringContext  	ct;
1086 
1087   _XmProcessLock();
1088   /* Initialize the out parameters. */
1089   if (context)	*context = NULL;
1090 
1091   /* make sure there is something in the string.  we are
1092      going to assume a good string in the get next routine
1093      */
1094   if (!(string && context)) {
1095 	_XmProcessUnlock();
1096 	return (FALSE);
1097   }
1098 
1099   ct = (XmStringContext) XtMalloc(sizeof(_XmStringContextRec));
1100   _XmStringContextReInit(ct, string);
1101 
1102   *context = ct;
1103   _XmProcessUnlock();
1104   return (TRUE);
1105 }
1106 
1107 /*
1108  * free the read-out context
1109  */
1110 void
XmStringFreeContext(_XmStringContext context)1111 XmStringFreeContext(
1112         _XmStringContext context )
1113 {
1114   _XmProcessLock();
1115   if (context)
1116     {
1117       _XmStringContextFree(context);
1118       XtFree((char *) context);
1119     }
1120   _XmProcessUnlock();
1121 }
1122 
1123 /*
1124  * this set is the TCS font list handling stuff
1125  */
1126 XmStringTag
_XmStringIndexGetTag(int index)1127 _XmStringIndexGetTag(int index)
1128 {
1129   XmStringTag ret_val;
1130   _XmProcessLock();
1131   if (index > _cache_count) {
1132     _XmProcessUnlock();
1133     return NULL;
1134   }
1135   ret_val = _tag_cache[index];
1136   _XmProcessUnlock();
1137   return ret_val;
1138 }
1139 
1140 int
_XmStringIndexCacheTag(XmStringTag tag,int length)1141 _XmStringIndexCacheTag(XmStringTag tag,
1142 		       int length )
1143 {
1144   char *a;
1145   register int i;
1146 
1147   /* Initialize cache with XmFONTLIST_DEFAULT_TAG, _MOTIF_DEFAULT_LOCALE, and
1148      locale.tag if necessary, to keep indices low. */
1149 
1150   _XmProcessLock();
1151   if (_cache_count == 0)
1152     {
1153       _tag_cache = (char **)XtMalloc(sizeof(char **) * 3);
1154 
1155       _tag_cache[_cache_count] = XmFONTLIST_DEFAULT_TAG;
1156       _cache_count++;
1157       _tag_cache[_cache_count] = _MOTIF_DEFAULT_LOCALE;
1158       _cache_count++;
1159       _tag_cache[_cache_count] = _XmStringGetCurrentCharset();
1160       _cache_count++;
1161     }
1162 
1163   /* Look for an existing cache entry. */
1164   for (i = 0; i < _cache_count; i++)
1165     {
1166       if (((tag == _tag_cache[i]) ||
1167 	   ((length != XmSTRING_TAG_STRLEN) &&
1168 	    (strncmp(tag, _tag_cache[i], length) == 0)) ||
1169 	   ((length == XmSTRING_TAG_STRLEN) &&
1170 	    (strcmp(tag, _tag_cache[i]) == 0))) &&
1171 	  ((length == XmSTRING_TAG_STRLEN) || (_tag_cache[i][length] == '\0')))
1172 	{
1173 	  _XmProcessUnlock();
1174 	  return( i) ;
1175 	}
1176     }
1177 
1178   /* Add this entry to the cache. */
1179   if (length == XmSTRING_TAG_STRLEN) length = strlen(tag);
1180 
1181   _tag_cache = (char **) XtRealloc ((char *) _tag_cache,
1182 				    sizeof (char **) * (_cache_count + 1));
1183 
1184   a = XtMalloc (length + 1);
1185   memcpy(a, tag, length);
1186   a[length] = '\0';
1187 
1188   _tag_cache[_cache_count] = a;
1189   _cache_count++;
1190 
1191   _XmProcessUnlock();
1192   return(i) ;
1193 }
1194 
1195 XmStringTag
_XmStringCacheTag(XmStringTag tag,int length)1196 _XmStringCacheTag(XmStringTag tag,
1197 		  int length )
1198 {
1199   int tag_index ;
1200   XmStringTag ret_val;
1201 
1202   _XmProcessLock();
1203   if (tag == NULL) {
1204       _XmProcessUnlock();
1205       return NULL;
1206   }
1207   tag_index = _XmStringIndexCacheTag( tag, length) ;
1208   ret_val = _tag_cache[tag_index] ;
1209   _XmProcessUnlock();
1210   return ret_val;
1211 }
1212 
1213 static Boolean
RenditionsCompatible(_XmStringEntry seg1,_XmStringEntry seg2)1214 RenditionsCompatible(_XmStringEntry seg1,
1215 		     _XmStringEntry seg2)
1216 {
1217   int		i;
1218   XmStringTag	*begin1, *begin2, *end1, *end2;
1219   short		bcnt1, bcnt2, ecnt1, ecnt2, diff;
1220 
1221   _XmProcessLock();
1222   bcnt1 = _XmEntryRendBeginCountGet(seg1);
1223   bcnt2 = _XmEntryRendBeginCountGet(seg2);
1224   ecnt1 = _XmEntryRendEndCountGet(seg1);
1225   ecnt2 = _XmEntryRendEndCountGet(seg2);
1226   begin1 = _XmEntryRendCountedBegins(seg1, bcnt1);
1227   begin2 = _XmEntryRendCountedBegins(seg2, bcnt2);
1228   end1 = _XmEntryRendCountedEnds(seg1, ecnt1);
1229   end2 = _XmEntryRendCountedEnds(seg2, ecnt2);
1230   _XmProcessUnlock();
1231 
1232   /* if seg1 is optimized, we are very limited in what renditions will be
1233      compatible, since there is only one rend_index. */
1234   if (_XmEntryOptimized(seg1) &&
1235       (((ecnt1 != 0) && (bcnt2 != 0)) ||
1236        ((bcnt1 > 0) && (bcnt2 > 0)) ||
1237        ((ecnt1 > 0) && (ecnt2 > 0)) ||
1238        ((bcnt1 > 0) && (ecnt2 > 0) && (begin1[0] != end2[0]))))
1239     return (FALSE);
1240 
1241   if ((_XmEntryByteCountGet(seg1) == 0) && (ecnt1 == 0))
1242     return(TRUE);
1243 
1244   if ((_XmEntryByteCountGet(seg2) == 0) && (bcnt2 == 0))
1245     return(TRUE);
1246 
1247   if ((ecnt1 == 0) && (bcnt2 == 0)) return(TRUE);
1248 
1249   return(FALSE);
1250 }
1251 
1252 static void
MergeEnds(_XmStringEntry a,_XmStringEntry b)1253 MergeEnds(_XmStringEntry a,
1254 	  _XmStringEntry b)
1255 {
1256   int		i;
1257   short		a_count, b_count;
1258 
1259   a_count = _XmEntryRendEndCountGet(a);
1260   b_count = _XmEntryRendEndCountGet(b);
1261 
1262   if ((a_count == 0) && (b_count == 0)) return;
1263 
1264   if (_XmEntryOptimized(a)) {
1265     if (a_count == 0 && b_count == 1)
1266       {
1267 	_XmEntryRendIndex(a) = _XmEntryOptimized(b) ? _XmEntryRendIndex(b) :
1268 	  _XmStringIndexCacheTag(_XmEntryRendEndGet(b, 0),
1269 				 XmSTRING_TAG_STRLEN);
1270       	_XmEntryRendEndCountSet(a, 1);
1271       }
1272     return;
1273   }
1274 
1275   _XmUnoptSegRendEnds(a) =
1276     (XmStringTag *)XtRealloc((char *)_XmUnoptSegRendEnds(a),
1277 			     (sizeof(XmStringTag) *
1278 			      (a_count + b_count)));
1279 
1280   for (i = 0; i < b_count; i++)
1281       _XmUnoptSegRendEnds(a)[(a_count + i)] = _XmEntryRendEndGet(b, i);
1282 
1283   _XmEntryRendEndCountSet(a, (a_count + b_count));
1284 }
1285 
1286 static void
MergeBegins(_XmStringEntry a,_XmStringEntry b)1287 MergeBegins(_XmStringEntry a,
1288 	    _XmStringEntry b)
1289 {
1290   XmStringTag 	*b_begin;
1291   short		a_b_cnt;
1292   short		b_b_cnt;
1293   int		i;
1294 
1295   a_b_cnt = _XmEntryRendBeginCountGet(a);
1296   b_b_cnt = _XmEntryRendBeginCountGet(b);
1297   b_begin = _XmEntryRendCountedBegins(b, b_b_cnt);
1298 
1299   if ((a_b_cnt == 0) && (b_b_cnt == 0)) return;
1300 
1301   if (_XmEntryOptimized(a)) {
1302     if (a_b_cnt == 0 && b_b_cnt == 1)
1303       {
1304 	_XmEntryRendIndex(a) = _XmEntryOptimized(b) ? _XmEntryRendIndex(b) :
1305 	  _XmStringIndexCacheTag(b_begin[0], XmSTRING_TAG_STRLEN);
1306       	_XmEntryRendBeginCountSet(a, 1);
1307       }
1308     return;
1309   }
1310 
1311   _XmUnoptSegRendBegins(a) =
1312     (XmStringTag *)XtRealloc((char *)_XmUnoptSegRendBegins(a),
1313 			     sizeof(XmStringTag) * (a_b_cnt + b_b_cnt));
1314 
1315   for (i = 0; i < b_b_cnt; i++)
1316       _XmUnoptSegRendBegins(a)[(a_b_cnt + i)] = _XmEntryRendBeginGet(b, i);
1317 
1318   _XmEntryRendBeginCountSet(a, (a_b_cnt + b_b_cnt));
1319 }
1320 
1321 /*
1322  * general external TCS utilties
1323  */
1324 
1325 static Boolean
IsUnopt(_XmString str,int lines)1326 IsUnopt(_XmString str, int lines)
1327 {
1328   _XmStringEntry line;
1329 
1330   if (lines > 0)
1331     {
1332       line = _XmStrEntry(str)[0];
1333 
1334       if ((_XmEntrySegmentCountGet(line) > 0) &&
1335 	  (_XmEntryType(_XmEntrySegmentGet(line)[0]) !=
1336 	   XmSTRING_ENTRY_OPTIMIZED))
1337 	return True;
1338     }
1339   return False;
1340 }
1341 
1342 static _XmStringEntry
Unoptimize(_XmStringEntry entry,int free)1343 Unoptimize(_XmStringEntry entry, int free)
1344 {
1345   _XmStringEntry new_entry = NULL;
1346   _XmStringNREntry tmp_seg;
1347   int j;
1348 
1349   if (entry == NULL)
1350     return NULL;
1351 
1352   if (_XmEntryType(entry) == XmSTRING_ENTRY_OPTIMIZED) {
1353     new_entry = EntryCvtToUnopt(entry);
1354     if (free)
1355       _XmStringEntryFree(entry);
1356   } else if (_XmEntryMultiple(entry)) {
1357     if (free) {
1358       for (j = 0; j < _XmEntrySegmentCount(entry); j++) {
1359 	tmp_seg = _XmEntrySegment(entry)[j];
1360 	if (_XmEntryType(tmp_seg) == XmSTRING_ENTRY_OPTIMIZED) {
1361 	  _XmEntrySegment(entry)[j] =
1362 	    (_XmStringNREntry)EntryCvtToUnopt((_XmStringEntry)tmp_seg);
1363 	  _XmStringEntryFree((_XmStringEntry)tmp_seg);
1364 	}
1365       }
1366       new_entry = entry;
1367     } else {
1368       _XmEntryCreate(new_entry, XmSTRING_ENTRY_ARRAY);
1369       _XmEntrySegmentCount(new_entry) = _XmEntrySegmentCount(entry);
1370       _XmEntrySoftNewlineSet(new_entry, _XmEntrySoftNewlineGet(entry));
1371       _XmEntrySegment(new_entry) =
1372 	(_XmStringNREntry *)XtMalloc(_XmEntrySegmentCount(entry) *
1373 				     sizeof(_XmStringNREntry));
1374       for (j = 0; j < _XmEntrySegmentCount(entry); j++) {
1375 	tmp_seg = _XmEntrySegment(entry)[j];
1376 	if (_XmEntryType(tmp_seg) == XmSTRING_ENTRY_OPTIMIZED)
1377 	  _XmEntrySegment(new_entry)[j] =
1378 	    (_XmStringNREntry)EntryCvtToUnopt((_XmStringEntry)tmp_seg);
1379 	else
1380 	  _XmEntrySegment(new_entry)[j] =
1381 	    (_XmStringNREntry)_XmStringEntryCopy((_XmStringEntry)tmp_seg);
1382       }
1383     }
1384   } else {
1385     if (free)
1386       new_entry = entry;
1387     else
1388       new_entry = _XmStringEntryCopy(entry);
1389   }
1390   return new_entry;
1391 }
1392 
1393 
1394 XmString
XmStringConcat(XmString a,XmString b)1395 XmStringConcat(XmString a,
1396 	       XmString b )
1397 {
1398   return XmStringConcatAndFree (XmStringCopy(a), XmStringCopy(b));
1399 }
1400 
1401 XmString
XmStringConcatAndFree(XmString a,XmString b)1402 XmStringConcatAndFree(XmString a,
1403 		      XmString b)
1404 {
1405   _XmString 		opt_str;
1406   unsigned int 		a_len, b_len, a_lc, b_lc, a_sc, b_sc, lc;
1407   unsigned int 		a_index, b_index, a_rend_index, b_rend_index;
1408   unsigned int 		a_tabs, b_tabs;
1409   XmTextType            a_type, b_type;
1410   XmString 		a_str, b_str;
1411   _XmStringMultiRec     b_tmp;
1412   _XmStringEntry 	a_line, b_line, tmp_line, *segs=NULL;
1413   _XmStringNREntry 	a_last, b_seg = NULL, tmp_seg;
1414   String		a_tag;
1415   String		b_tag;
1416   int 			i, j;
1417   int			merged = 0;
1418   XmStringDirection	last = XmSTRING_DIRECTION_UNSET;
1419   Boolean		modify_a, modify_b, free_b;
1420   Boolean               a_needs_unopt=False, b_needs_unopt=False;
1421   _XmStringArraySegRec	array_seg;
1422 
1423   _XmProcessLock();
1424   if (a == NULL)
1425   {
1426     _XmProcessUnlock();
1427     return b;
1428   }
1429   if (b == NULL)
1430   {
1431     _XmProcessUnlock();
1432     return a;
1433   }
1434 
1435   if ((_XmStrOptimized(a) && _XmStrOptimized(b)))
1436     {
1437       /* Both optimized */
1438       a_len = _XmStrByteCount(a);
1439       b_len = _XmStrByteCount(b);
1440 
1441       a_index = _XmStrTagIndex(a);
1442       b_index = _XmStrTagIndex(b);
1443 
1444       a_rend_index = _XmStrRendIndex(a);
1445       b_rend_index = _XmStrRendIndex(b);
1446 
1447       a_type = (XmTextType) _XmStrTextType(a);
1448       b_type = (XmTextType) _XmStrTextType(b);
1449 
1450       a_tabs = _XmStrTabs(a);
1451       b_tabs = _XmStrTabs(b);
1452 
1453       if (((a_index == b_index) ||
1454 	   (a_index == TAG_INDEX_UNSET) ||
1455 	   (b_index == TAG_INDEX_UNSET)) &&
1456 	  RenditionsCompatible((_XmStringEntry)a,
1457 			       (_XmStringEntry)b) &&
1458 	  ((_XmStrDirection(a) == _XmStrDirection(b)) ||
1459 	   (_XmStrDirection(b) == XmSTRING_DIRECTION_UNSET) ||
1460 	   ((_XmStrDirection(a) == XmSTRING_DIRECTION_UNSET) &&
1461 	    (a_len == 0))) &&
1462 	  (a_type == b_type || a_type == XmNO_TEXT || b_type == XmNO_TEXT) &&
1463 	  ((a_len + b_len) < (1 << BYTE_COUNT_BITS)) &&
1464 	  ((_XmStrText(a) && b_tabs==0) ||
1465 	   (!_XmStrText(a) && a_tabs+b_tabs <= 3)))
1466 	{
1467 	  /* Compatible strings.  Make an optimized string. */
1468 	  if ((b_len == 0) && (_XmStrRefCountGet(a) == 1))
1469 	    opt_str = (_XmString) a;
1470 	  else if ((a_len == 0) && (_XmStrRefCountGet(b) == 1))
1471 	    opt_str = (_XmString) b;
1472 	  else
1473 	    _XmStrCreate(opt_str, XmSTRING_OPTIMIZED, a_len + b_len);
1474 
1475 	  _XmStrByteCount((_XmString)opt_str) = a_len + b_len;
1476 	  _XmStrTextType((_XmString)opt_str) =
1477 	    (a_type == XmNO_TEXT) ? b_type : a_type;
1478 	  _XmStrTagIndex((_XmString)opt_str) =
1479 	    (a_index == TAG_INDEX_UNSET) ? b_index : a_index;
1480 	  _XmStrRendIndex((_XmString)opt_str) =
1481 	    (a_rend_index == REND_INDEX_UNSET) ? b_rend_index : a_rend_index;
1482 
1483 	  /* Push begin and end state. */
1484 	  _XmStrRendBegin((_XmString)opt_str) =
1485 	    (_XmStrRendBegin(a) ? _XmStrRendBegin(a) : _XmStrRendBegin(b));
1486 	  _XmStrRendEnd((_XmString)opt_str) =
1487 	    (_XmStrRendEnd(b) ? _XmStrRendEnd(b) : _XmStrRendEnd(a));
1488 
1489 	  _XmStrDirection((_XmString)opt_str) =
1490 	    (_XmStrDirection(a) == XmSTRING_DIRECTION_UNSET) ?
1491 	      _XmStrDirection(b) : _XmStrDirection(a);
1492 	  _XmStrTabs((_XmString)opt_str) = a_tabs+b_tabs;
1493 
1494 	  if (a_len && (opt_str != a))
1495 	    memcpy(_XmStrText((_XmString)opt_str), _XmStrText(a), a_len);
1496 	  if (b_len && (opt_str != b))
1497 	    memcpy((_XmStrText((_XmString)opt_str) + a_len),
1498 		   _XmStrText(b), b_len);
1499 
1500 	  if (opt_str != a)
1501 	    XmStringFree(a);
1502 	  if (opt_str != b)
1503 	    XmStringFree(b);
1504 	  _XmProcessUnlock();
1505 	  return (XmString)opt_str;
1506 	}
1507     }
1508 
1509   /* Concatenate non-optimized versions */
1510   a_lc = _XmStrEntryCountGet(a);
1511   b_lc = _XmStrEntryCountGet(b);
1512 
1513   if (_XmStrAddNewline(a)) {
1514     if (_XmStrAddNewline(b) && b_lc > 0)
1515       lc = a_lc + b_lc - 1;
1516     else
1517       lc = a_lc;
1518   } else {
1519     if (_XmStrAddNewline(b))
1520       lc = b_lc ? b_lc : 1;
1521     else
1522       lc = a_lc + b_lc;
1523   }
1524 
1525   modify_a = !_XmStrOptimized(a) && (_XmStrRefCountGet(a) == 1);
1526   if (modify_a)
1527     {
1528       a_str = a;
1529       if (a_lc > 1 && !_XmStrAddNewline(a) && _XmStrAddNewline(b)) {
1530 	segs = _XmStrEntry(a_str);
1531 	_XmStrEntry(a_str) = NULL;
1532       }
1533       _XmStrEntry(a_str) = (_XmStringEntry *)
1534 	XtRealloc((char*) _XmStrEntry(a_str),
1535 		  sizeof(_XmStringEntry) * lc);
1536       for (i = (segs ? 0 : a_lc); i < lc; i++)
1537 	_XmStrEntry(a_str)[i] = NULL;
1538     }
1539   else if (_XmStrOptimized(a))
1540     {
1541       a_str = _XmStringOptToNonOpt((_XmStringOpt)a);
1542       if (a_lc > 1 && !_XmStrAddNewline(a) && _XmStrAddNewline(b)) {
1543 	segs = _XmStrEntry(a_str);
1544 	_XmStrEntry(a_str) = NULL;
1545       }
1546       _XmStrEntry(a_str) = (_XmStringEntry *)
1547 	XtRealloc((char*) _XmStrEntry(a_str),
1548 		  sizeof(_XmStringEntry) * lc);
1549       for (i = (segs ? 0 : a_lc); i < lc; i++)
1550 	_XmStrEntry(a_str)[i] = NULL;
1551     }
1552   else {
1553     if (a_lc > 1 && !_XmStrAddNewline(a) && _XmStrAddNewline(b)) {
1554       segs = _XmStrEntry(a);
1555       _XmStrEntry(a) = NULL;
1556       _XmStrEntryCount(a) = 0;
1557     }
1558     a_str = Clone(a, lc);
1559     if (a_lc > 1 && !_XmStrAddNewline(a) && _XmStrAddNewline(b)) {
1560       _XmStrEntry(a) = segs;
1561       _XmStrEntryCount(a) = a_lc;
1562       if (segs) {
1563 	segs = (_XmStringEntry *)XtMalloc(a_lc * sizeof(_XmStringEntry));
1564 	for (i = 0; i < a_lc; i++)
1565 	  segs[i] = _XmStringEntryCopy(_XmStrEntry(a)[i]);
1566       }
1567     }
1568   }
1569 
1570   if (segs) {
1571     /* need to move a:s segments down one level */
1572     _XmStringEntry line;
1573 
1574     _XmEntryCreate(line, XmSTRING_ENTRY_ARRAY);
1575     _XmEntrySegmentCount(line) = a_lc;
1576     _XmEntrySegment(line) = (_XmStringNREntry *)segs;
1577     _XmStrEntry(a_str)[0] = line;
1578     _XmStrImplicitLine(a_str) = True;
1579     a_lc = 1;
1580   }
1581 
1582   modify_b = !_XmStrOptimized(b) && (_XmStrRefCountGet(b) == 1);
1583   free_b = True;
1584   if (modify_b)
1585     b_str = b;
1586   else if (_XmStrOptimized(b)) {
1587 #ifndef _XmDEBUG_XMSTRING_MEM
1588     /* This won't work in that case -
1589        _XmStrMalloc adds bytes at the beginning */
1590     if (_XmStrRefCountGet(b) == 1) {
1591       /*
1592        * An optimized XmString looks very much like an
1593        * optimized segment. In this case we can use the
1594        * optimized XmString as the segment with a little
1595        * of poking around in the last byte of the header.
1596        * This saves us from allocating a new string, which
1597        * will get free:d anyway.
1598        */
1599       b_str = (XmString)&b_tmp;
1600       _XmStrInit(b_str, XmSTRING_MULTIPLE_ENTRY);
1601       _XmStrEntryCount(b_str) = 1;
1602       _XmStrRefCountSet(b, 0);
1603       _XmEntryTabsSet(b, _XmStrTabs(b));
1604       _XmEntryImm(b) = 1;
1605       if (_XmStrText(b) != (char *)_XmEntryTextGet((_XmStringEntry)b)) {
1606 	/* If the XtPointer in the union in the
1607 	 * optimized segment leads to padding in the structure
1608 	 * between the header and the text data
1609 	 * (it will on some 64-bit architectures) we have
1610 	 * to move the text data, since the optimized
1611 	 * string does not have this padding.
1612 	 */
1613 	unsigned int size = sizeof(_XmStringOptSegRec);
1614 	if (_XmStrByteCount(b) > sizeof(XtPointer))
1615 	  size += _XmStrByteCount(b) - sizeof(XtPointer);
1616 	b = (XmString)XtRealloc((char *)b, size);
1617 	memmove(_XmEntryTextGet((_XmStringEntry)b),
1618 		_XmStrText(b),
1619 		_XmStrByteCount(b));
1620       }
1621       _XmStrEntry(b_str) = (_XmStringEntry *)&b;
1622       free_b = False;
1623     } else {
1624 #endif
1625       b_str = _XmStringOptToNonOpt((_XmStringOpt)b);
1626       XmStringFree(b);
1627 #ifndef _XmDEBUG_XMSTRING_MEM
1628     }
1629 #endif
1630     modify_b = TRUE;
1631   } else
1632     b_str = b;
1633 
1634   assert((a != b) || (!modify_a && !modify_b));
1635 
1636   /* convert a to unopt segs if necessary */
1637   a_needs_unopt = IsUnopt(a_str, a_lc);
1638 
1639   if (!a_needs_unopt) {
1640     b_needs_unopt = IsUnopt(b_str, _XmStrEntryCount(b_str));
1641 
1642     if (b_needs_unopt)
1643       for (i = 0; i < a_lc; i++)
1644 	_XmStrEntry(a_str)[i] = Unoptimize(_XmStrEntry(a_str)[i], True);
1645   }
1646 
1647   _XmStrEntryCount(a_str) = lc;
1648 
1649   _XmStrImplicitLine(a_str) =
1650     _XmStrImplicitLine(a_str) || _XmStrImplicitLine(b_str);
1651 
1652   /* Add first line of b_str to last line of a_str */
1653   a_line = _XmStrEntry(a_str)[a_lc - 1];
1654   if (_XmStrImplicitLine(b_str))
1655     {
1656       b_line = _XmStrEntry(b_str)[0];
1657     }
1658   else
1659     {
1660       _XmEntryType(&array_seg) = XmSTRING_ENTRY_ARRAY;
1661       _XmEntrySegmentCount(&array_seg) = _XmStrEntryCount(b_str);
1662       _XmEntrySegment(&array_seg) = (_XmStringNREntry *)_XmStrEntry(b_str);
1663       b_line = (_XmStringEntry)&array_seg;
1664       b_lc = 1;
1665     }
1666 
1667   a_sc = _XmEntrySegmentCountGet(a_line);
1668   b_sc = _XmEntrySegmentCountGet(b_line);
1669 
1670   if ((a_sc != 0) && (b_sc != 0))
1671     {
1672       /* Need to combine last segment of a with first of b if compatible. */
1673       a_last = _XmEntrySegmentGet(a_line)[a_sc - 1];
1674       b_seg = _XmEntrySegmentGet(b_line)[0];
1675       a_len = _XmEntryByteCountGet((_XmStringEntry)a_last);
1676       b_len = _XmEntryByteCountGet((_XmStringEntry)b_seg);
1677 
1678       /* Remember last direction set. */
1679       last = _XmEntryDirectionGet((_XmStringEntry)a_last);
1680 
1681       a_tag = _XmEntryTag((_XmStringEntry)a_last);
1682       b_tag = _XmEntryTag((_XmStringEntry)b_seg);
1683 
1684       a_type = (XmTextType) _XmEntryTextTypeGet((_XmStringEntry)a_last);
1685       b_type = (XmTextType) _XmEntryTextTypeGet((_XmStringEntry)b_seg);
1686 
1687       a_tabs = _XmEntryTabsGet((_XmStringEntry)a_last);
1688       b_tabs = _XmEntryTabsGet((_XmStringEntry)b_seg);
1689 
1690       merged = 0;
1691 
1692       if (((a_tag == b_tag) ||
1693 	   (a_tag == NULL) || (b_tag == NULL)) &&
1694 	  RenditionsCompatible((_XmStringEntry)a_last,
1695 			       (_XmStringEntry)b_seg) &&
1696 	  (a_type == b_type || a_type == XmNO_TEXT || b_type == XmNO_TEXT) &&
1697 	  ((last == _XmEntryDirectionGet((_XmStringEntry)b_seg)) ||
1698 	   (_XmEntryDirectionGet((_XmStringEntry)b_seg) ==
1699 	    XmSTRING_DIRECTION_UNSET) ||
1700 	   ((last == XmSTRING_DIRECTION_UNSET) &&
1701 	    (a_len == 0))) &&
1702 	  !_XmEntryPopGet((_XmStringEntry)a_last) &&
1703 	  !_XmEntryPushGet((_XmStringEntry)b_seg) &&
1704 	  (((a_len != 0) && b_tabs==0) ||
1705 	   ((a_len == 0) && a_tabs+b_tabs <= 7)))
1706 	{
1707 	  if (b_len) {
1708 	    if ((_XmEntryType(a_last) == XmSTRING_ENTRY_OPTIMIZED) &&
1709 		_XmEntryImm(a_last)) {
1710 	      unsigned int size = sizeof(_XmStringOptSegRec);
1711 	      if (a_len + b_len > sizeof(XtPointer))
1712 		size += a_len + b_len - sizeof(XtPointer);
1713 	      if (a_line == (_XmStringEntry)a_last) {
1714 		a_last = (_XmStringNREntry)XtRealloc((char *)a_last, size);
1715 		_XmStrEntry(a_str)[a_lc - 1] = a_line = (_XmStringEntry)a_last;
1716 	      } else
1717 		_XmEntrySegmentGet(a_line)[a_sc-1] = a_last =
1718 		  (_XmStringNREntry)XtRealloc((char *)a_last, size);
1719 	    } else {
1720 	      _XmEntryTextSet((_XmStringEntry)a_last,
1721 			      XtRealloc((char *)
1722 				       _XmEntryTextGet((_XmStringEntry)a_last),
1723 				       a_len + b_len));
1724 	    }
1725 	  }
1726 	  if (_XmEntryOptimized(a_last))
1727 	    _XmEntryTagIndex(a_last) =
1728 	      ((a_tag == NULL) ?
1729 	       (b_tag == NULL ?
1730 		TAG_INDEX_UNSET :
1731 		_XmStringIndexCacheTag(b_tag, XmSTRING_TAG_STRLEN)) :
1732 	       _XmEntryTagIndex(a_last));
1733 	  else
1734 	    _XmUnoptSegTag(a_last) = (a_tag == NULL) ? b_tag : a_tag;
1735 
1736 	  /* Fixup rendition begins and ends */
1737 	  if (a_len == 0)
1738 	    MergeBegins((_XmStringEntry)a_last, (_XmStringEntry)b_seg);
1739 
1740 	  if (_XmEntryRendEnds((_XmStringEntry)a_last) == NULL) {
1741 	    if (_XmEntryOptimized(a_last) &&
1742 		_XmEntryRendEndCountGet((_XmStringEntry)b_seg) > 0) {
1743 	      b_tag = _XmEntryRendEndGet((_XmStringEntry)b_seg, 0);
1744 	      _XmEntryRendIndex(a_last) =
1745 		_XmStringIndexCacheTag(b_tag, XmSTRING_TAG_STRLEN);
1746 	    }
1747 	    if (!_XmEntryOptimized(a_last) &&
1748 		(_XmEntryRendEndCountGet((_XmStringEntry)b_seg) != 0))
1749             {
1750 	      if (_XmEntryOptimized(b_seg))
1751               {
1752 		_XmUnoptSegRendEnds(a_last) =
1753 		  (XmStringTag *)XtMalloc(sizeof(XmStringTag));
1754 		_XmUnoptSegRendEnds(a_last)[0] =
1755 		  _XmEntryRendEndGet((_XmStringEntry)b_seg, 0);
1756 	      } else if (modify_b)
1757               {
1758 		_XmUnoptSegRendEnds(a_last) = _XmUnoptSegRendEnds(b_seg);
1759 	      } else
1760               {
1761 		int end_count = _XmEntryRendEndCountGet((_XmStringEntry)b_seg);
1762 		int k;
1763 		_XmUnoptSegRendEnds(a_last) =
1764 		  (XmStringTag *)XtMalloc(end_count * sizeof(XmStringTag));
1765 		for (k = 0; k < end_count; k++)
1766 		  _XmUnoptSegRendEnds(a_last)[k] =
1767 		    _XmUnoptSegRendEnds(b_seg)[k];
1768 	      }
1769           }
1770 	    _XmEntryRendEndCountSet
1771 	      (a_last, _XmEntryRendEndCountGet((_XmStringEntry)b_seg));
1772 	  } else
1773 	    MergeEnds((_XmStringEntry)a_last, (_XmStringEntry)b_seg);
1774 
1775 	  _XmEntryTextTypeSet(a_last, (a_type == XmNO_TEXT) ? b_type : a_type);
1776 	  memcpy(((char *)_XmEntryTextGet((_XmStringEntry)a_last)) + a_len,
1777 		 _XmEntryTextGet((_XmStringEntry)b_seg), b_len);
1778 
1779 	  _XmEntryByteCountSet(a_last, a_len + b_len);
1780 
1781 	  _XmEntryTabsSet(a_last, a_tabs+b_tabs);
1782 	  if (last == XmSTRING_DIRECTION_UNSET)
1783 	    _XmEntryDirectionSet((_XmStringEntry)a_last,
1784 				 _XmEntryDirectionGet((_XmStringEntry)b_seg));
1785 	  _XmEntryPopSet(a_last, _XmEntryPopGet((_XmStringEntry)b_seg));
1786 
1787 	  if (modify_b) {
1788 	    /* Free leftover bits of b_seg */
1789 	    if (_XmEntryUnoptimized(b_seg)) {
1790 	      if (_XmEntryOptimized(a_last) ||
1791 		  (_XmUnoptSegRendBegins(a_last) !=
1792 		   _XmUnoptSegRendBegins(b_seg)))
1793 		XtFree((char *)_XmUnoptSegRendBegins(b_seg));
1794 
1795 	      if (_XmEntryOptimized(a_last) ||
1796 		  (_XmUnoptSegRendEnds(a_last) != _XmUnoptSegRendEnds(b_seg)))
1797 		XtFree((char *)_XmUnoptSegRendEnds(b_seg));
1798 	    }
1799 	    if ( ! ((_XmEntryType(b_seg) == XmSTRING_ENTRY_OPTIMIZED) &&
1800 		    _XmEntryImm(b_seg)))
1801 	      XtFree((char*)_XmEntryTextGet((_XmStringEntry)b_seg));
1802 	    XtFree((char *)b_seg);
1803 	  }
1804 
1805 	  merged = 1;
1806 	}
1807     }
1808   else /* Need to figure out last direction set. */
1809     {
1810       for (i = a_lc; i > 0; i--) {
1811 	tmp_line = _XmStrEntry(a_str)[i - 1];
1812 	for (j = _XmEntrySegmentCountGet(tmp_line); j > 0; j--) {
1813 	  tmp_seg = _XmEntrySegmentGet(tmp_line)[j - 1];
1814 	  if (_XmEntryDirectionGet((_XmStringEntry)tmp_seg) !=
1815 	      XmSTRING_DIRECTION_UNSET) {
1816 	    last = _XmEntryDirectionGet((_XmStringEntry)tmp_seg);
1817 	    break;
1818 	  }
1819 	}
1820 	if (last != XmSTRING_DIRECTION_UNSET) break;
1821       }
1822     }
1823 
1824   if (merged && !_XmStrImplicitLine(a_str))
1825     _XmStrEntryCount(a_str)--;
1826 
1827   if (b_sc - merged > 0 && _XmStrImplicitLine(a_str)) {
1828     Boolean free_b_line = (modify_b && _XmEntryMultiple(b_line) &&
1829 			   ((_XmStringEntry)b_seg != b_line));
1830 
1831     if (_XmEntryMultiple(a_line)) {
1832       _XmEntrySegment(a_line) =
1833 	(_XmStringNREntry *)XtRealloc((char *)_XmEntrySegment(a_line),
1834 				      sizeof(_XmStringNREntry) *
1835 				      (a_sc + b_sc - merged));
1836       _XmEntrySegmentCount(a_line) = a_sc + b_sc - merged;
1837     } else {
1838       _XmEntryCreate(a_line, XmSTRING_ENTRY_ARRAY);
1839       _XmEntrySegmentCount(a_line) = a_sc + b_sc - merged;
1840       _XmEntrySegment(a_line) =
1841 	(_XmStringNREntry *)XtMalloc(sizeof(_XmStringNREntry) *
1842 				     (a_sc + b_sc - merged));
1843       _XmEntrySegment(a_line)[0] =
1844 	(_XmStringNREntry)_XmStrEntry(a_str)[a_lc - 1];
1845       _XmStrEntry(a_str)[a_lc - 1] = a_line;
1846       _XmStrImplicitLine(a_str) = True;
1847     }
1848 
1849     for (i = 0; i < (b_sc - merged); i++)
1850       {
1851 	b_seg = _XmEntrySegmentGet(b_line)[i + merged];
1852 	if (a_needs_unopt && !b_needs_unopt)
1853 	  b_seg = (_XmStringNREntry)Unoptimize((_XmStringEntry)b_seg,modify_b);
1854 	else if (!modify_b)
1855 	  b_seg = (_XmStringNREntry)_XmStringEntryCopy((_XmStringEntry)b_seg);
1856 
1857 	if (_XmEntryDirectionGet((_XmStringEntry)b_seg) ==
1858 	    XmSTRING_DIRECTION_UNSET)
1859 	  _XmEntryDirectionSet((_XmStringEntry)b_seg, last);
1860 	else last = _XmEntryDirectionGet((_XmStringEntry)b_seg);
1861 	_XmEntrySegment(a_line)[i + a_sc] = b_seg;
1862       }
1863 
1864     if (free_b_line) {
1865       if (_XmEntrySegment(b_line) != (_XmStringNREntry *)&b &&
1866 	  _XmEntrySegment(b_line) != (_XmStringNREntry *)_XmStrEntry(b_str))
1867 	XtFree((char *)_XmEntrySegment(b_line));
1868       if (b_line != (_XmStringEntry)&array_seg) XtFree((char *)b_line);
1869     }
1870   } else if (b_sc - merged > 0 && !_XmStrImplicitLine(a_str)) {
1871     for (i = 0; i < (b_sc - merged); i++)
1872       {
1873 	b_line = _XmStrEntry(b_str)[i + merged];
1874 	if (a_needs_unopt && !b_needs_unopt)
1875 	  _XmStrEntry(a_str)[a_lc] = Unoptimize(b_line, modify_b);
1876 	else if (modify_b)
1877 	  _XmStrEntry(a_str)[a_lc] = b_line;
1878 	else
1879 	  _XmStrEntry(a_str)[a_lc] = _XmStringEntryCopy(b_line);
1880 	a_lc++;
1881       }
1882   }
1883 
1884   /* Add rest of b's lines to a */
1885   for (i = 0; i < (b_lc - 1); i++)
1886     {
1887       b_line = _XmStrEntry(b_str)[i + 1];
1888       if (a_needs_unopt && !b_needs_unopt)
1889 	b_line = Unoptimize(b_line, modify_b);
1890       else if (!modify_b)
1891 	b_line = _XmStringEntryCopy(b_line);
1892 
1893       b_sc = _XmEntrySegmentCountGet(b_line);
1894 
1895       for (j = 0; j < b_sc; j++)
1896 	{
1897 	  b_seg = _XmEntrySegmentGet(b_line)[j];
1898 
1899 	  if (_XmEntryDirectionGet((_XmStringEntry)b_seg) ==
1900 	      XmSTRING_DIRECTION_UNSET)
1901 	    _XmEntryDirectionSet((_XmStringEntry)b_seg, last);
1902 	  else break;
1903 	}
1904 
1905       _XmStrEntry(a_str)[i + a_lc] = b_line;
1906     }
1907 
1908   if (modify_b && free_b) {
1909     /* Free leftover bits of b_str. */
1910     XtFree((char *)_XmStrEntry(b_str));
1911     _XmStrFree ((char *)b_str);
1912   }
1913 
1914   /* Set layout cache dirty */
1915   if (a_str && _XmStrEntryCount(a_str) > 0 ) {
1916     tmp_line = _XmStrEntry(a_str)[0];
1917     if (tmp_line && _XmEntrySegmentCountGet(tmp_line) > 0) {
1918       _XmStringCache cache;
1919 
1920       tmp_seg = _XmEntrySegmentGet(tmp_line)[0];
1921       for (cache = _XmStringCacheGet(_XmEntryCacheGet((_XmStringEntry)tmp_seg),
1922 				     _XmSCANNING_CACHE);
1923 	   cache;
1924 	   cache = _XmStringCacheGet(cache->next, _XmSCANNING_CACHE))
1925 	_XmCacheDirty(cache) = True;
1926     }
1927   }
1928 
1929   if (!modify_a)
1930     XmStringFree(a);
1931   if (!modify_b)
1932     XmStringFree(b);
1933 
1934   _XmProcessUnlock();
1935   return (XmString)a_str;
1936 }
1937 
1938 /************************************************************************
1939  *									*
1940  * XmStringCompare - compare two strings.  				*
1941  *									*
1942  * Returns TRUE if the strings are equal, FALSE o.w.			*
1943  *									*
1944  ************************************************************************/
1945 Boolean
XmStringCompare(XmString a,XmString b)1946 XmStringCompare(
1947         XmString a,
1948         XmString b )
1949 {
1950   _XmProcessLock();
1951   if ((a == NULL) && (b == NULL)) {
1952 	_XmProcessUnlock();
1953 	return TRUE;
1954   }
1955   if ((a == NULL) || (b == NULL)) {
1956 	_XmProcessUnlock();
1957 	return FALSE;
1958   }
1959 
1960   if (_XmStrOptimized(a) && _XmStrOptimized(b)) {
1961     if (!((_XmStrTagGet(a) == _XmStrTagGet(b)) ||
1962 	  (_XmStrTagGet(a) == NULL) ||
1963 	  (_XmStrTagGet(b) == NULL) ||
1964 	  ((strcmp(_XmStringIndexGetTag(_XmStrTagIndex(a)), XmFONTLIST_DEFAULT_TAG) == 0) &&
1965 	   _XmStringIsCurrentCharset(_XmStrTagGet(b))) ||
1966 	  ((strcmp(_XmStringIndexGetTag(_XmStrTagIndex(b)), XmFONTLIST_DEFAULT_TAG) == 0) &&
1967 	   _XmStringIsCurrentCharset(_XmStrTagGet(a))))) {
1968       _XmProcessUnlock();
1969       return (FALSE);
1970     }
1971     if (_XmStrByteCount(a) != _XmStrByteCount(b)) {
1972       _XmProcessUnlock();
1973       return (FALSE);
1974     }
1975     if ((_XmStrDirection(a) != _XmStrDirection(b)) &&
1976 	(((_XmStrDirection(a) == XmSTRING_DIRECTION_UNSET) &&
1977 	  (_XmStrDirection(b) != XmSTRING_DIRECTION_L_TO_R)) ||
1978 	 ((_XmStrDirection(b) == XmSTRING_DIRECTION_UNSET) &&
1979 	  (_XmStrDirection(a) != XmSTRING_DIRECTION_L_TO_R)))) {
1980       _XmProcessUnlock();
1981       return (FALSE);
1982     }
1983     if (strncmp(_XmStrText(a), _XmStrText(b), _XmStrByteCount(a)) != 0) {
1984       _XmProcessUnlock();
1985       return (FALSE);
1986     }
1987   } else {
1988     int i, j;
1989     _XmStringEntry *entry_a;
1990     _XmStringEntry *entry_b;
1991     XmString a_unopt = NULL;
1992     XmString b_unopt = NULL;
1993 
1994     if (_XmStrEntryCountGet(a) != _XmStrEntryCountGet(b)) {
1995       _XmProcessUnlock();
1996       return (FALSE);
1997     }
1998 
1999     if (_XmStrOptimized(a)) {
2000       a_unopt = _XmStringOptToNonOpt((_XmStringOpt)a);
2001       entry_a = _XmStrEntry(a_unopt);
2002     } else {
2003       entry_a = _XmStrEntry(a);
2004     }
2005 
2006     if (_XmStrOptimized(b)) {
2007       b_unopt = _XmStringOptToNonOpt((_XmStringOpt)b);
2008       entry_b = _XmStrEntry(b_unopt);
2009     } else {
2010       entry_b = _XmStrEntry(b);
2011     }
2012 
2013     for (i = 0; i < _XmStrEntryCountGet(a); i++) {
2014       if (_XmEntryMultiple(entry_a[i]) && _XmEntryMultiple(entry_b[i])) {
2015 	if (_XmEntrySegmentCount(entry_a[i]) !=
2016 	    _XmEntrySegmentCount(entry_b[i])) {
2017 	  if (a_unopt) XmStringFree(a_unopt);
2018 	  if (b_unopt) XmStringFree(b_unopt);
2019 	  _XmProcessUnlock();
2020 	  return (FALSE);
2021 	}
2022 
2023 	for (j=0; j<_XmEntrySegmentCount(entry_a[i]); j++) {
2024 	  _XmStringNREntry a_seg = _XmEntrySegment(entry_a[i])[j];
2025 	  _XmStringNREntry b_seg = _XmEntrySegment(entry_b[i])[j];
2026 	  unsigned int len;
2027 	  XmStringTag a_tag = _XmEntryTag((_XmStringEntry)a_seg);
2028 	  XmStringTag b_tag = _XmEntryTag((_XmStringEntry)b_seg);
2029 
2030 	  if (!((a_tag == b_tag) ||
2031 		(a_tag == NULL) ||
2032 		(b_tag == NULL) ||
2033 		((strcmp(a_tag, XmFONTLIST_DEFAULT_TAG) == 0) &&
2034 		 _XmStringIsCurrentCharset(b_tag)) ||
2035 		((strcmp(b_tag, XmFONTLIST_DEFAULT_TAG) == 0) &&
2036 		 _XmStringIsCurrentCharset(a_tag)))) {
2037 	        if (a_unopt) XmStringFree(a_unopt);
2038 	        if (b_unopt) XmStringFree(b_unopt);
2039 	        _XmProcessUnlock();
2040 		return (FALSE);
2041 	  }
2042 
2043 	  len = _XmEntryByteCountGet((_XmStringEntry)a_seg);
2044 	  if (len != _XmEntryByteCountGet((_XmStringEntry)b_seg)) {
2045 	    if (a_unopt) XmStringFree(a_unopt);
2046 	    if (b_unopt) XmStringFree(b_unopt);
2047 	    _XmProcessUnlock();
2048 	    return (FALSE);
2049 	  }
2050 
2051 	  {
2052 	    unsigned int a_dir = _XmEntryDirectionGet((_XmStringEntry)a_seg);
2053 	    unsigned int b_dir = _XmEntryDirectionGet((_XmStringEntry)b_seg);
2054 	    if ((a_dir != b_dir) &&
2055 		(((a_dir == XmSTRING_DIRECTION_UNSET) &&
2056 		  (b_dir != XmSTRING_DIRECTION_L_TO_R)) ||
2057 		 ((b_dir == XmSTRING_DIRECTION_UNSET) &&
2058 		  (a_dir != XmSTRING_DIRECTION_L_TO_R)))) {
2059 	      if (a_unopt) XmStringFree(a_unopt);
2060 	      if (b_unopt) XmStringFree(b_unopt);
2061 	      _XmProcessUnlock();
2062 	      return (FALSE);
2063 	    }
2064 	  }
2065 
2066 	  if (strncmp ((char*)_XmEntryTextGet((_XmStringEntry)a_seg),
2067 		       (char*)_XmEntryTextGet((_XmStringEntry)b_seg),
2068 		       len) != 0) {
2069 	    if (a_unopt) XmStringFree(a_unopt);
2070 	    if (b_unopt) XmStringFree(b_unopt);
2071 	    _XmProcessUnlock();
2072 	    return (FALSE);
2073 	  }
2074 	}
2075       } else if (!_XmEntryMultiple(entry_a[i]) &&
2076 		 !_XmEntryMultiple(entry_b[i])) {
2077 	unsigned int len;
2078 
2079 	if (!((_XmEntryTag(entry_a[i]) == _XmEntryTag(entry_b[i])) ||
2080 	      (_XmEntryTag(entry_a[i]) == NULL) ||
2081 	      (_XmEntryTag(entry_b[i]) == NULL) ||
2082 	      ((strcmp(_XmEntryTag(entry_a[i]),
2083 		       XmFONTLIST_DEFAULT_TAG) == 0) &&
2084 	       _XmStringIsCurrentCharset(_XmEntryTag(entry_b[i]))) ||
2085 	      ((strcmp(_XmEntryTag(entry_b[i]),
2086 		       XmFONTLIST_DEFAULT_TAG) == 0) &&
2087 	       _XmStringIsCurrentCharset(_XmEntryTag(entry_a[i])))))
2088 	{
2089 	  if (a_unopt) XmStringFree(a_unopt);
2090 	  if (b_unopt) XmStringFree(b_unopt);
2091 	  _XmProcessUnlock();
2092 	  return (FALSE);
2093 	}
2094 
2095 	len = _XmEntryByteCountGet(entry_a[i]);
2096 	if (len != _XmEntryByteCountGet(entry_b[i])) {
2097 	  if (a_unopt) XmStringFree(a_unopt);
2098 	  if (b_unopt) XmStringFree(b_unopt);
2099 	  _XmProcessUnlock();
2100 	  return (FALSE);
2101 	}
2102 
2103 	if ((_XmEntryDirectionGet(entry_a[i])  !=
2104 	     _XmEntryDirectionGet(entry_b[i]))         &&
2105 	    (((_XmEntryDirectionGet(entry_a[i]) ==
2106 	       XmSTRING_DIRECTION_UNSET) &&
2107 	      (_XmEntryDirectionGet(entry_b[i]) !=
2108 	       XmSTRING_DIRECTION_L_TO_R))           ||
2109 	     ((_XmEntryDirectionGet(entry_b[i]) ==
2110 	       XmSTRING_DIRECTION_UNSET) &&
2111 	      (_XmEntryDirectionGet(entry_a[i]) !=
2112 	       XmSTRING_DIRECTION_L_TO_R)))) {
2113 	  if (a_unopt) XmStringFree(a_unopt);
2114 	  if (b_unopt) XmStringFree(b_unopt);
2115 	  _XmProcessUnlock();
2116 	  return (FALSE);
2117 	}
2118 
2119 	if (strncmp ((char*) _XmEntryTextGet(entry_a[i]),
2120 		     (char*) _XmEntryTextGet(entry_b[i]),
2121 		     len) != 0) {
2122 	  if (a_unopt) XmStringFree(a_unopt);
2123 	  if (b_unopt) XmStringFree(b_unopt);
2124 	  _XmProcessUnlock();
2125 	  return (FALSE);
2126 	}
2127       } else {
2128         if (a_unopt) XmStringFree(a_unopt);
2129 	if (b_unopt) XmStringFree(b_unopt);
2130 	_XmProcessUnlock();
2131 	return (FALSE);
2132       }
2133     }
2134     if (a_unopt) XmStringFree(a_unopt);
2135     if (b_unopt) XmStringFree(b_unopt);
2136   }
2137   _XmProcessUnlock();
2138   return (TRUE);
2139 }
2140 
2141 int
XmStringLength(XmString string)2142 XmStringLength(
2143         XmString string )
2144 {
2145   unsigned int	len;
2146 
2147   if (!string) return (0);
2148   if (!XmeStringIsValid(string)) return (0);
2149 
2150   len = XmCvtXmStringToByteStream(string, NULL);
2151 
2152   return((int)len);
2153 }
2154 
2155 /************************************************************************
2156  *                                                                      *
2157  * XmeStringIsXmString - returns TRUE if the parameter is an XmString.   *
2158  *                                                                      *
2159  ************************************************************************/
2160 Boolean
XmeStringIsValid(XmString string)2161 XmeStringIsValid(
2162         XmString string )
2163 {
2164   if (string == NULL) return(FALSE);
2165   return(TRUE);
2166 }
2167 
2168 /*
2169  * determines from ASN.1 header whether this is an ASN.1 conformant
2170  * external compound string.  Returns T or F.
2171  */
2172 static Boolean
_is_asn1(unsigned char * string)2173 _is_asn1( unsigned char *string )
2174 {
2175   unsigned char *uchar_p = string;
2176 
2177   /*  Compare the ASN.1 header. */
2178   return (strncmp ((char *)uchar_p, (char *)ASNHeader, ASNHEADERLEN) == 0);
2179 }
2180 
2181 /*
2182  * optimized internal TCS structure handling routines
2183  */
2184 /*
2185  * find the ascender for the given optimized line
2186  */
2187 static Dimension
OptLineAscender(XmRenderTable f,_XmStringOpt opt)2188 OptLineAscender(
2189         XmRenderTable f,
2190         _XmStringOpt opt )
2191 {
2192   Dimension width, height, ascent, descent;
2193 
2194   OptLineMetrics(f, (_XmString)opt, NULL, NULL,
2195 		 &width, &height, &ascent, &descent);
2196 
2197   return(ascent);
2198 }
2199 
2200 int
_XmConvertFactor(unsigned char units,float * factor)2201 _XmConvertFactor(unsigned char units,
2202 	      float *factor)
2203 {
2204   switch (units)
2205     {
2206     case XmINCHES:
2207       *factor = 1000.0;
2208       return(Xm1000TH_INCHES);
2209     case XmCENTIMETERS:
2210       *factor = 1000.0;
2211       return(Xm100TH_MILLIMETERS);
2212     case XmMILLIMETERS:
2213       *factor = 100.0;
2214       return(Xm100TH_MILLIMETERS);
2215     case XmPOINTS:
2216       *factor = 100.0;
2217       return(Xm100TH_POINTS);
2218     case XmFONT_UNITS:
2219       *factor = 100.0;
2220       return(Xm100TH_FONT_UNITS);
2221     default:
2222       *factor = 1.0;
2223       return(units);
2224     }
2225 }
2226 
2227 static int
TabVal(Display * d,Screen ** pscreen,Window w,XmTab tab)2228 TabVal(Display *d,
2229        Screen **pscreen,
2230        Window w,
2231        XmTab tab)
2232 {
2233   int	fromType;
2234   int	intValue;
2235   float	multiplier, convertValue;
2236 
2237   fromType = _XmConvertFactor(_XmTabUnits(tab), &multiplier);
2238 
2239   convertValue = multiplier * _XmTabValue(tab);
2240 
2241   /* error */
2242   if (((convertValue < 0.0) ? -convertValue : convertValue) > (float)INT_MAX)
2243     return(0);
2244 
2245   convertValue += (convertValue > 0.0) ? 0.5 : -0.5;
2246   intValue = convertValue;
2247 
2248   /*
2249    * The pscreen storage should be pushed higher; we may still make
2250    * several round trips to the server to draw a single string???
2251    */
2252   /* All we really want is the screen, but we may only have a drawable. */
2253   assert(w || *pscreen);
2254   if (*pscreen == NULL)
2255     {
2256       Widget widget = XtWindowToWidget(d, w);
2257 
2258       /* If this drawable is really a widget Xt will have cached it. */
2259       if (widget)
2260 	*pscreen = XtScreenOfObject(widget);
2261       else
2262 	{
2263 	  /* Give up and ask the server. */
2264 	  XWindowAttributes attr;
2265 	  XGetWindowAttributes(d, w, &attr);
2266 	  *pscreen = attr.screen;
2267 	}
2268     }
2269 
2270   return _XmConvertUnits(*pscreen, XmHORIZONTAL, fromType, intValue, XmPIXELS);
2271 }
2272 
2273 
2274 /*
2275  * Find width, height, ascent and descent for the given optimized line.
2276  */
2277 static void
OptLineMetrics(XmRenderTable r,_XmString opt,XmRendition * rend_io,XmRendition base_rend,Dimension * width,Dimension * height,Dimension * ascent,Dimension * descent)2278 OptLineMetrics(XmRenderTable 	r,
2279 	       _XmString 	opt,
2280 	       XmRendition *rend_io,
2281 	       XmRendition base_rend,
2282 	       Dimension *width,
2283 	       Dimension *height,
2284 	       Dimension *ascent,
2285 	       Dimension *descent)
2286 {
2287   short	                rend_index;
2288   XmRendition		rend = NULL;
2289   XmStringTag		tags[1];
2290   Display              *d;
2291   Screen	       *screen;
2292   int			prev_val, val, i, ref_cnt, rt_ref_cnt;
2293   XmTabList		tl = NULL;
2294   XmTab			tab;
2295   unsigned short	tab_cnt;
2296   Dimension             tab_w = 0;
2297   _XmRendition		rend_int;
2298 
2299   /* compute rendition */
2300   /* Find font as per I 198. */
2301   /* 1. Find font from rendition tags. */
2302   /* 2. Find font from locale/charset tag. */
2303   if (base_rend == NULL)
2304     {
2305       if (_XmStrRendBegin(opt))
2306 	rend = _XmRenderTableFindRendition(r, _XmStrRendTagGet(opt),
2307 					   TRUE, FALSE, TRUE, &rend_index);
2308 
2309       if ((rend == NULL) ||
2310           (_XmRendFont(rend) == NULL && _XmRendXftFont(rend) == NULL))
2311 	rend = _XmRenderTableFindRendition(r, _XmStrTagGet(opt),
2312 					   TRUE, FALSE, TRUE, &rend_index);
2313     }
2314   else
2315     {
2316       if (_XmStrRendBegin(opt))
2317 	{
2318 	  tags[0] = _XmStrRendTagGet(opt);
2319 
2320 	  rend = _XmRenditionMerge(_XmRendDisplay(base_rend), rend_io,
2321 				   base_rend, r, _XmStrTagGet(opt), tags, 1,
2322 				   FALSE);
2323 	}
2324       else
2325 	{
2326 	  rend = _XmRenditionMerge(_XmRendDisplay(base_rend), rend_io,
2327 				   base_rend, r, _XmStrTagGet(opt), NULL, 0,
2328 				   FALSE);
2329 	}
2330     }
2331 
2332   /* 3. Default rendition. */
2333   if ((rend == NULL) ||
2334       (_XmRendFont(rend) == NULL && _XmRendXftFont(rend) == NULL))
2335     {
2336       tags[0] = ((_XmStrTextType(opt) == XmCHARSET_TEXT) ?
2337 		 XmFONTLIST_DEFAULT_TAG :
2338 		 _MOTIF_DEFAULT_LOCALE);
2339 
2340       rend = _XmRenderTableFindRendition(r, tags[0],
2341 					 TRUE, FALSE, FALSE, NULL);
2342       if ((rend != NULL) &&
2343           (_XmRendFont(rend) == NULL) && (_XmRendXftFont(rend) == NULL) &&
2344 	  (((base_rend != NULL) && (_XmRendDisplay(base_rend) != NULL)) ||
2345 	   (_XmRendDisplay(rend) != NULL)))
2346 	/* Call noFontCallback. */
2347 	{
2348 	  XmDisplay			dsp;
2349 	  XmDisplayCallbackStruct	cb;
2350 
2351 	  rt_ref_cnt = _XmRTRefcount(r);
2352 	  rend = _XmRTRenditions(r)[0];
2353 	  rend_int = *rend;
2354 	  ref_cnt = _XmRendRefcount(rend);
2355 
2356 	  if ((base_rend != NULL) && (_XmRendDisplay(base_rend) != NULL))
2357 	    dsp = (XmDisplay)XmGetXmDisplay(_XmRendDisplay(base_rend));
2358 	  else dsp = (XmDisplay)XmGetXmDisplay(_XmRendDisplay(rend));
2359 
2360 	  cb.reason = XmCR_NO_FONT;
2361 	  cb.event = NULL;
2362 	  cb.rendition = rend;
2363 	  cb.font_name = XmS;
2364 
2365 	  XtCallCallbackList((Widget)dsp, dsp->display.noFontCallback, &cb);
2366 
2367 	  if (rend_int != *rend)		  /* Changed in callback. */
2368 	    {
2369 	      /* Need to split ref counts. */
2370 	      _XmRendRefcount(&rend_int) = ref_cnt - rt_ref_cnt;
2371 	      _XmRendRefcount(rend) = rt_ref_cnt;
2372 	    }
2373 
2374 	  if (_XmRendFont(rend) == NULL && _XmRendXftFont(rend) == NULL)
2375 	    rend = NULL;
2376 	}
2377 
2378       /* 4a. Take the first one */
2379       if ((rend == NULL) &&
2380 	  ((_XmStrTextType(opt) == XmCHARSET_TEXT) ||
2381 	    ((_XmStrTextType(opt) == XmMULTIBYTE_TEXT) &&
2382 	     (_XmStrTagGet(opt) == XmFONTLIST_DEFAULT_TAG))) &&
2383 	  (r != NULL) && (_XmRTCount(r) > 0))
2384 	_XmRenderTableFindFirstFont(r, &rend_index, &rend);
2385 
2386       if ((rend != NULL) &&
2387           (_XmRendFont(rend) == NULL && _XmRendXftFont(rend) == NULL) &&
2388 	  (((base_rend != NULL) && (_XmRendDisplay(base_rend) != NULL)) ||
2389 	   (_XmRendDisplay(rend) != NULL)))
2390 	/* Call noFontCallback. */
2391 	{
2392 	  XmDisplay			dsp;
2393 	  XmDisplayCallbackStruct	cb;
2394 
2395 	  rt_ref_cnt = _XmRTRefcount(r);
2396 	  rend = _XmRTRenditions(r)[0];
2397 	  rend_int = *rend;
2398 	  ref_cnt = _XmRendRefcount(rend);
2399 
2400 	  if ((base_rend != NULL) && (_XmRendDisplay(base_rend) != NULL))
2401 	    dsp = (XmDisplay)XmGetXmDisplay(_XmRendDisplay(base_rend));
2402 	  else dsp = (XmDisplay)XmGetXmDisplay(_XmRendDisplay(rend));
2403 
2404 	  cb.reason = XmCR_NO_FONT;
2405 	  cb.event = NULL;
2406 	  cb.rendition = rend;
2407 	  cb.font_name = XmS;
2408 
2409 	  XtCallCallbackList((Widget)dsp, dsp->display.noFontCallback, &cb);
2410 
2411 	  if (rend_int != *rend)		  /* Changed in callback. */
2412 	    {
2413 	      /* Need to split ref counts. */
2414 	      _XmRendRefcount(&rend_int) = ref_cnt - rt_ref_cnt;
2415 	      _XmRendRefcount(rend) = rt_ref_cnt;
2416 	    }
2417 
2418 	  if (_XmRendFont(rend) == NULL && _XmRendXftFont(rend) == NULL)
2419 	    rend = NULL;
2420 	}
2421 
2422       /* 4b/5a. Emit warning and don't render. */
2423       if ((rend == NULL) ||
2424           (_XmRendFont(rend) == NULL && _XmRendXftFont(rend) == NULL))
2425 	{
2426 	  /* Don't emit warning if no tags, e.g. just a dir component. */
2427 	  if (_XmStrRendBegin(opt) ||
2428 	      (_XmStrTagGet(opt) != NULL))
2429 	    XmeWarning(NULL, NO_FONT_MSG);
2430 	  if ((base_rend != NULL) && (rend_io == NULL))
2431 	    XmRenditionFree(rend);
2432 	  rend = NULL;
2433 	  return;
2434 	}
2435       else if (rend_io != NULL)
2436 	{
2437 	  _XmRendFont(*rend_io) = _XmRendFont(rend);
2438 #ifdef USE_XFT
2439 	  _XmRendXftFont(*rend_io) = _XmRendXftFont(rend);
2440 #endif
2441 	  _XmRendFontName(*rend_io) = _XmRendFontName(rend);
2442 	  _XmRendFontType(*rend_io) = _XmRendFontType(rend);
2443 	}
2444     }
2445 
2446   /* Use the raster extent for a single line. */
2447   if (rend != NULL)
2448     ComputeMetrics(rend,
2449 		   (XtPointer)_XmStrText(opt),
2450 		   _XmStrByteCount(opt), (XmTextType) _XmStrTextType(opt),
2451 		   XmSTRING_SINGLE_SEG, width, height, ascent, descent,
2452 #ifdef UTF8_SUPPORTED
2453                    (_XmStrTextType(opt) == XmCHARSET_TEXT ||
2454                     _XmStrTextType(opt) == XmMULTIBYTE_TEXT) &&
2455                    ((_XmStrTagGet(opt) == XmFONTLIST_DEFAULT_TAG
2456                      && _XmStringIsCurrentCharset("UTF-8"))
2457                     || (_XmStrTagGet(opt)
2458 		     && strcmp(_XmStringIndexGetTag(_XmStrTagIndex(opt)), "UTF-8") == 0))
2459 #else
2460                    False
2461 #endif
2462 		    );
2463 
2464   if (rend != NULL) tl = _XmRendTabs(rend);
2465   d = (_XmRTDisplay(r) == NULL) ? _XmGetDefaultDisplay() : _XmRTDisplay(r);
2466   screen = XtScreenOfObject(XmGetXmDisplay(d));
2467 
2468   tab = ((tl == NULL) || ((long)tl == XmAS_IS)) ? NULL : _XmTabLStart(tl);
2469 
2470   prev_val = 0;
2471   tab_cnt = 0;
2472 
2473   /* If this string is tabbed, set width accordingly. */
2474   if ((tab != NULL) &&
2475       (_XmStrTabs(opt) != 0) &&
2476       (tab_cnt < _XmTabLCount(tl)))
2477     {
2478       for (i = 0;
2479 	   (i < _XmStrTabs(opt)) && (tab_cnt < _XmTabLCount(tl));
2480 	   tab = _XmTabNext(tab), tab_cnt++, i++)
2481 	{
2482 	  val = TabVal(d, &screen, None, tab);
2483 	  if (_XmTabModel(tab) == XmABSOLUTE)
2484 	    {
2485 	      tab_w = val;
2486 	      prev_val = val;
2487 	    }
2488 	  else				  /* XmRELATIVE */
2489 	    {
2490 	      tab_w = prev_val + val;
2491 	      prev_val += val;
2492 	    }
2493 	}
2494     }
2495 
2496   (*width) += tab_w;
2497   if ((base_rend != NULL) && (rend_io == NULL)) XmRenditionFree(rend);
2498 }
2499 
2500 /*
2501  * internal TCS structure handling routines
2502  */
2503 
2504 
2505 /*
2506  * find biggest ascender and descender and width and height in this line
2507  */
2508 static void
LineMetrics(_XmStringEntry line,XmRenderTable r,XmRendition * rend_io,XmRendition base,XmDirection prim_dir,Dimension * width,Dimension * height,Dimension * ascender,Dimension * descender)2509 LineMetrics(_XmStringEntry line,
2510 	    XmRenderTable r,
2511 	    XmRendition *rend_io,
2512 	    XmRendition base,
2513 	    XmDirection prim_dir,
2514 	    Dimension *width,
2515 	    Dimension *height,
2516 	    Dimension *ascender,
2517 	    Dimension *descender)
2518 {
2519   int 			i, seg_index = 0;
2520   Dimension w, tab_w = 0, h, max_h = 0, asc, max_asc = 0, dsc, max_dsc = 0;
2521   Display		*d;
2522   Screen		*screen;
2523   int			prev_val, val;
2524   XmTabList		tl = NULL;
2525   XmTab			tab;
2526   unsigned short	tab_cnt;
2527   _XmStringNREntry	seg, peek_seg;
2528   XmDirection 		lay_dir = 0;
2529   Boolean		set_direction = FALSE;
2530 
2531   d = _XmRendDisplay(*rend_io);
2532   screen = XtScreenOfObject(XmGetXmDisplay(d));
2533 
2534   seg = _XmEntrySegmentGet(line)[seg_index];
2535 
2536   if (_XmEntryType(seg) != XmSTRING_ENTRY_OPTIMIZED)
2537     {
2538       lay_dir = _XmEntryLayoutGet(seg, prim_dir);
2539 
2540       if (XmDirectionMatch(lay_dir, XmLEFT_TO_RIGHT))
2541 	{
2542 	  while (_XmEntryLeftGet(seg, prim_dir) != NULL)
2543 	    seg = (_XmStringNREntry)_XmEntryLeftGet(seg, prim_dir);
2544 	  peek_seg = (_XmStringNREntry)_XmEntryRightGet(seg, prim_dir);
2545 	}
2546       else
2547 	{
2548 	  while (_XmEntryRightGet(seg, prim_dir) != NULL)
2549 	    seg = (_XmStringNREntry)_XmEntryRightGet(seg, prim_dir);
2550 	  peek_seg = (_XmStringNREntry)_XmEntryLeftGet(seg, prim_dir);
2551 	}
2552     }
2553   else
2554     {
2555       peek_seg = ((seg_index + 1) < _XmEntrySegmentCountGet(line) ?
2556 		  _XmEntrySegmentGet(line)[seg_index + 1] :
2557 		  NULL);
2558     }
2559 
2560   if (_XmEntryDirectionGet((_XmStringEntry)seg) == XmSTRING_DIRECTION_UNSET)
2561     {
2562       _XmEntryDirectionSet((_XmStringEntry)seg,
2563 			   XmDirectionToStringDirection(prim_dir));
2564       set_direction = True;
2565     }
2566 
2567   if (peek_seg != NULL)
2568     (void)SpecifiedSegmentExtents((_XmStringEntry)seg, r, rend_io, base,
2569 				  XmSTRING_FIRST_SEG, &w, &h, &asc, &dsc);
2570   else (void)SpecifiedSegmentExtents((_XmStringEntry)seg, r, rend_io, base,
2571 				     XmSTRING_SINGLE_SEG, &w, &h, &asc, &dsc);
2572 
2573   if (*rend_io != NULL) tl = _XmRendTabs(*rend_io);
2574 
2575   tab = ((tl == NULL) || ((long)tl == XmAS_IS)) ? NULL : _XmTabLStart(tl);
2576 
2577   prev_val = 0;
2578   tab_cnt = 0;
2579 
2580   while (seg != NULL)
2581     {
2582       /* If this segment is tabbed, set width accordingly. */
2583 	if ((tab != NULL) &&
2584 	    (_XmEntryTabsGet((_XmStringEntry)seg) != 0) &&
2585 	    (tab_cnt < _XmTabLCount(tl)))
2586 	  {
2587 	    for (i = 0;
2588 		 (i < _XmEntryTabsGet((_XmStringEntry)seg)) &&
2589 		 (tab_cnt < _XmTabLCount(tl));
2590 		 i++, tab = _XmTabNext(tab), tab_cnt++)
2591 	      {
2592 		val = TabVal(d, &screen, None, tab);
2593 		if (_XmTabModel(tab) == XmABSOLUTE)
2594 		  tab_w = MAX(tab_w, val);
2595 		else				  /* XmRELATIVE */
2596 		  tab_w = MAX(tab_w, prev_val + val);
2597 
2598 		prev_val = tab_w;
2599 	      }
2600 	  }
2601 
2602 	tab_w += w;
2603 	if (h > max_h) max_h = h;
2604 	if (asc > max_asc) max_asc = asc;
2605 	if (dsc >max_dsc) max_dsc = dsc;
2606 
2607 	if (set_direction)
2608 	  {
2609 	    _XmEntryDirectionSet((_XmStringEntry)seg,
2610 				 XmSTRING_DIRECTION_UNSET);
2611 	    set_direction = False;
2612 	  }
2613 
2614 	if (_XmEntryType(seg) != XmSTRING_ENTRY_OPTIMIZED)
2615 	  {
2616 	    if (XmDirectionMatch(lay_dir, XmLEFT_TO_RIGHT))
2617 	      {
2618 		seg = (_XmStringNREntry)_XmEntryRightGet(seg, prim_dir);
2619 		peek_seg = (_XmStringNREntry)_XmEntryRightGet(seg, prim_dir);
2620 	      }
2621 	    else
2622 	      {
2623 		seg = (_XmStringNREntry)_XmEntryLeftGet(seg, prim_dir);
2624 		peek_seg = (_XmStringNREntry)_XmEntryLeftGet(seg, prim_dir);
2625 	      }
2626 	  }
2627 	else {
2628 	  seg_index++;
2629 	  seg = (seg_index < _XmEntrySegmentCountGet(line) ?
2630 		 _XmEntrySegmentGet(line)[seg_index] :
2631 		 NULL);
2632 	  peek_seg = ((seg_index + 1) < _XmEntrySegmentCountGet(line) ?
2633 		      _XmEntrySegmentGet(line)[seg_index + 1] :
2634 		      NULL);
2635 	}
2636 	if (seg != NULL)
2637 	  {
2638 	    if (_XmEntryDirectionGet((_XmStringEntry)seg) ==
2639 		XmSTRING_DIRECTION_UNSET)
2640 	      {
2641 		_XmEntryDirectionSet((_XmStringEntry)seg,
2642 				     XmDirectionToStringDirection(prim_dir));
2643 		set_direction = True;
2644 	      }
2645 	    if (peek_seg != NULL)
2646 	      (void)SpecifiedSegmentExtents((_XmStringEntry)seg, r, rend_io, base,
2647 					    XmSTRING_MIDDLE_SEG,
2648 					    &w, &h, &asc, &dsc);
2649 	    else (void)SpecifiedSegmentExtents((_XmStringEntry)seg, r, rend_io, base,
2650 					       XmSTRING_LAST_SEG,
2651 					       &w, &h, &asc, &dsc);
2652 	  }
2653       }
2654 
2655   *width = tab_w;
2656   if (max_h > 0) *height = max_h;
2657   if (max_asc > 0) *ascender = max_asc;
2658   if (max_dsc > 0) *descender = max_dsc;
2659 }
2660 
2661 static XFontStruct *
GetFont(XmRenderTable rt,_XmStringEntry entry)2662 GetFont(XmRenderTable rt,
2663 	_XmStringEntry entry)
2664 {
2665   XmRendition rend = NULL;
2666   short	 indx = -1;
2667   Cardinal	n;
2668   Arg		args[2];
2669   XmFontType	type;
2670   XtPointer	font;
2671 
2672   rend = _XmEntryRenditionGet(entry, rt);
2673   if (rend == NULL)
2674     (void)_XmRenderTableFindFallback(rt, _XmEntryTag(entry), TRUE, &indx, &rend);
2675 
2676   if (rend != NULL) {
2677     n = 0;
2678     XtSetArg(args[n], XmNfontType, &type); n++;
2679     XtSetArg(args[n], XmNfont, &font); n++;
2680     XmRenditionRetrieve(rend, args, n);
2681 
2682     if (type == XmFONT_IS_FONT)
2683       return (XFontStruct *)font;
2684     else
2685       return (XFontStruct *)NULL;
2686   }
2687   return (XFontStruct *)NULL;
2688 }
2689 
2690 
2691 unsigned char
_XmStringCharacterCount(XtPointer text,XmTextType text_type,int byte_count,XFontStruct * font)2692 _XmStringCharacterCount(XtPointer text,
2693 			XmTextType text_type,
2694 			int byte_count,
2695 			XFontStruct *font)
2696 {
2697   if (text == NULL)
2698     return 0;
2699   if (byte_count == 0)
2700     byte_count = strlen((char *)text);
2701 
2702   switch (text_type)
2703     {
2704     case XmCHARSET_TEXT:
2705       {
2706 	if (font && two_byte_font(font))
2707 	  return (byte_count/2);
2708 	else
2709 	  return byte_count;
2710       }
2711     case XmMULTIBYTE_TEXT:
2712       {
2713 	char *s = (char *) text;
2714 	if (MB_CUR_MAX == 1)
2715 	  return byte_count;
2716 	else {
2717 	  int cnt = 0;
2718 	  int len;
2719 #ifndef NO_MULTIBYTE
2720 	  while (byte_count > 0 && (len = mblen(s, MB_CUR_MAX)) > 0) {
2721 	    cnt++;
2722 	    s += len;
2723 	    byte_count -= len;
2724 	  }
2725 #else
2726 	  while (byte_count > 0 && *s) {
2727 	    cnt++;
2728 	    s++;
2729 	    byte_count--;
2730 	  }
2731 #endif
2732 	  return cnt;
2733 	}
2734       }
2735     case XmWIDECHAR_TEXT:
2736       {
2737 	wchar_t *wcs = (wchar_t *)text;
2738 	int cnt = 0;
2739 	while (byte_count > 0 && wcs[cnt]) {
2740 	  cnt++;
2741 	  byte_count -= sizeof(wchar_t);
2742 	}
2743 	return cnt;
2744       }
2745     default:
2746       return byte_count;
2747     }
2748 }
2749 
2750 unsigned char
_XmEntryCharCountGet(_XmStringEntry entry,XmRenderTable rt)2751 _XmEntryCharCountGet(_XmStringEntry entry,
2752 		     XmRenderTable rt)
2753 {
2754   unsigned int len;
2755 
2756   if (_XmEntryOptimized(entry)) {
2757     if ((len = _XmEntryByteCountGet(entry)) == 0) {
2758       return 0;
2759     } else {
2760       return _XmStringCharacterCount((char *)_XmEntryTextGet(entry),
2761 				     (XmTextType) _XmEntryTextTypeGet(entry),
2762 				     len,
2763 				     GetFont(rt, entry));
2764     }
2765   }
2766   if (_XmEntryUnoptimized(entry))  {
2767     if (((_XmStringUnoptSeg)entry)->char_count == 0 &&
2768 	(len = _XmEntryByteCountGet(entry)) != 0) {
2769       ((_XmStringUnoptSeg)entry)->char_count =
2770 	_XmStringCharacterCount((char *)_XmEntryTextGet(entry),
2771 				(XmTextType) _XmEntryTextTypeGet(entry),
2772 				len,
2773 				GetFont(rt, entry));
2774     }
2775     return ((_XmStringUnoptSeg)entry)->char_count;
2776   }
2777   return(0);
2778 }
2779 
2780 
2781 _XmStringCache
_XmStringCacheGet(_XmStringCache caches,int type)2782 _XmStringCacheGet(_XmStringCache caches,
2783 		  int type)
2784 {
2785   _XmStringCache cache = caches;
2786 
2787   while (cache && cache->cache_type != type)
2788     cache = cache->next;
2789 
2790   return cache;
2791 }
2792 
2793 
2794 void
_XmStringCacheFree(_XmStringCache caches)2795 _XmStringCacheFree(_XmStringCache caches)
2796 {
2797   _XmStringCache prev = NULL, current = caches;
2798 
2799   while (current) {
2800     prev = current;
2801     current = current->next;
2802     if (prev)
2803       {
2804 	if (prev->cache_type == _XmRENDERING_CACHE &&
2805 	    ((_XmStringRenderingCache)prev)->rendition != NULL)
2806 	  XmRenditionFree(((_XmStringRenderingCache)prev)->rendition);
2807 
2808 	XtFree((char *)prev);
2809       }
2810   }
2811 }
2812 
2813 
2814 static _XmStringCache
CacheGet(_XmStringEntry entry,int type,int create,XtPointer match_value)2815 CacheGet(_XmStringEntry entry,
2816          int type,
2817          int create,
2818          XtPointer match_value)
2819 {
2820   _XmStringCache cache;
2821 
2822   if (!entry || !_XmEntryUnoptimized(entry))
2823     return NULL;
2824 
2825   switch (type)
2826     {
2827     case _XmSCANNING_CACHE:
2828       {
2829         XmDirection  d;
2830 
2831 	d = (XmDirection)(long)match_value;
2832 
2833         if (d) {
2834           cache = _XmEntryCacheGet(entry);
2835           while (cache &&
2836                  !(cache->cache_type == type &&
2837                    (XmDirectionMatch(((_XmStringScanningCache)cache)->prim_dir,
2838                                      d))))
2839             cache = cache->next;
2840           if (!cache && create) {
2841             cache = (_XmStringCache)XtCalloc(1, sizeof(_XmStringScanningRec));
2842             cache->cache_type = type;
2843             cache->dirty = True;
2844             cache->next = _XmEntryCacheGet(entry);
2845             _XmEntryCacheSet(entry, cache);
2846             ((_XmStringScanningCache)cache)->prim_dir = d;
2847           }
2848         } else
2849           cache = NULL;
2850       }
2851       break;
2852     case _XmRENDERING_CACHE:
2853       {
2854         XmRenderTable rt;
2855 
2856 	rt = (XmRenderTable)match_value;
2857 
2858         if (rt) {
2859           cache = _XmEntryCacheGet(entry);
2860           while (cache &&
2861                  !(cache->cache_type == type &&
2862                    ((_XmStringRenderingCache)cache)->rt == rt))
2863             cache = cache->next;
2864           if (!cache && create) {
2865             cache = (_XmStringCache)XtCalloc(1, sizeof(_XmStringRenderingRec));
2866             cache->cache_type = type;
2867             cache->dirty = True;
2868             cache->next = _XmEntryCacheGet(entry);
2869             _XmEntryCacheSet(entry, cache);
2870             ((_XmStringRenderingCache)cache)->rt = rt;
2871           }
2872         } else
2873           cache = NULL;
2874       }
2875       break;
2876     default:
2877       cache = NULL;
2878       break;
2879     }
2880   return cache;
2881 }
2882 
2883 
2884 XtPointer
_XmScanningCacheGet(_XmStringNREntry entry,int d,int field)2885 _XmScanningCacheGet(_XmStringNREntry entry,
2886 #if NeedWidePrototypes
2887 		    int d,
2888 #else
2889 		    XmDirection d,
2890 #endif /* NeedWidePrototypes */
2891 		    int field)
2892 {
2893   _XmStringScanningCache cache;
2894 
2895   cache = (_XmStringScanningCache)CacheGet((_XmStringEntry)entry,
2896 					   _XmSCANNING_CACHE, False,
2897 					   (XtPointer)(long)d);
2898   if (!cache)
2899     {
2900       if (entry && _XmEntryUnoptimized(entry) && (field == _XmCACHE_DIRTY))
2901 	return (XtPointer)True;
2902       else
2903 	return NULL;
2904     }
2905 
2906   switch (field)
2907     {
2908     case _XmCACHE_DIRTY:
2909       return (XtPointer)(long)cache->header.dirty;
2910     case _XmCACHE_SCAN_LEFT:
2911       return (XtPointer)cache->left;
2912     case _XmCACHE_SCAN_RIGHT:
2913       return (XtPointer)cache->right;
2914     case _XmCACHE_SCAN_LAYOUT:
2915       return (XtPointer)(long)cache->layout_direction;
2916     case _XmCACHE_SCAN_DEPTH:
2917       return (XtPointer)(long)cache->depth;
2918     default:
2919       return NULL;
2920     }
2921 }
2922 
2923 
2924 void
_XmScanningCacheSet(_XmStringNREntry entry,int d,int field,XtPointer value)2925 _XmScanningCacheSet(_XmStringNREntry entry,
2926 #if NeedWidePrototypes
2927 		    int d,
2928 #else
2929 		    XmDirection d,
2930 #endif /* NeedWidePrototypes */
2931 		    int field,
2932 		    XtPointer value)
2933 {
2934   _XmStringScanningCache cache;
2935 
2936   cache = (_XmStringScanningCache)CacheGet((_XmStringEntry)entry,
2937 					   _XmSCANNING_CACHE, True,
2938 					   (XtPointer)(long)d);
2939   if (!cache)
2940     return;
2941 
2942   switch (field)
2943     {
2944     case _XmCACHE_DIRTY:
2945       cache->header.dirty = (Boolean)(long)value;
2946       break;
2947     case _XmCACHE_SCAN_LEFT:
2948       cache->left = (_XmStringEntry)value;
2949       break;
2950     case _XmCACHE_SCAN_RIGHT:
2951       cache->right = (_XmStringEntry)value;
2952       break;
2953     case _XmCACHE_SCAN_LAYOUT:
2954       cache->layout_direction = (XmDirection)(long)value;
2955       break;
2956     case _XmCACHE_SCAN_DEPTH:
2957       cache->depth = (unsigned short)(long)value;
2958       break;
2959     }
2960 }
2961 
2962 
2963 XtPointer
_XmRenderCacheGet(_XmStringEntry entry,XmRenderTable rt,int field)2964 _XmRenderCacheGet(_XmStringEntry entry,
2965 		  XmRenderTable rt,
2966 		  int field)
2967 {
2968   _XmStringRenderingCache cache;
2969 
2970   cache = (_XmStringRenderingCache)CacheGet(entry, _XmRENDERING_CACHE, False,
2971 					    (XtPointer)rt);
2972   if (!cache)
2973     {
2974       if (entry && _XmEntryUnoptimized(entry) && (field == _XmCACHE_DIRTY))
2975 	return (XtPointer)True;
2976       else
2977 	return NULL;
2978     }
2979 
2980   switch (field)
2981     {
2982     case _XmCACHE_DIRTY:
2983       return (XtPointer)(long)cache->header.dirty;
2984     case _XmCACHE_RENDER_X:
2985       return (XtPointer)(long)cache->x;
2986     case _XmCACHE_RENDER_Y:
2987       return (XtPointer)(long)cache->y;
2988     case _XmCACHE_RENDER_WIDTH:
2989       return (XtPointer)(long)cache->width;
2990     case _XmCACHE_RENDER_HEIGHT:
2991       return (XtPointer)(long)cache->height;
2992     case _XmCACHE_RENDER_BASELINE:
2993       return (XtPointer)(long)cache->baseline;
2994     case _XmCACHE_RENDER_ASCENT:
2995       return (XtPointer)(long)cache->ascent;
2996     case _XmCACHE_RENDER_DESCENT:
2997       return (XtPointer)(long)cache->descent;
2998     case _XmCACHE_RENDER_RENDITION:
2999       return (XtPointer)cache->rendition;
3000     case _XmCACHE_RENDER_PREV_TABS:
3001       return (XtPointer)(long)cache->prev_tabs;
3002     default:
3003       return NULL;
3004     }
3005 }
3006 
3007 
3008 void
_XmRenderCacheSet(_XmStringEntry entry,XmRenderTable rt,int field,XtPointer value)3009 _XmRenderCacheSet(_XmStringEntry entry,
3010 		  XmRenderTable rt,
3011 		  int field,
3012 		  XtPointer value)
3013 {
3014   _XmStringRenderingCache cache;
3015 
3016   cache = (_XmStringRenderingCache)CacheGet(entry, _XmRENDERING_CACHE, True,
3017 					    (XtPointer)rt);
3018   if (!cache)
3019     return;
3020 
3021   switch (field)
3022     {
3023     case _XmCACHE_DIRTY:
3024       cache->header.dirty = (Boolean)(long)value;
3025       break;
3026     case _XmCACHE_RENDER_X:
3027       cache->x = (int)(long)value;
3028       break;
3029     case _XmCACHE_RENDER_Y:
3030       cache->y = (int)(long)value;
3031       break;
3032     case _XmCACHE_RENDER_WIDTH:
3033       cache->width = (int)(long)value;
3034       break;
3035     case _XmCACHE_RENDER_HEIGHT:
3036       cache->height = (int)(long)value;
3037       break;
3038     case _XmCACHE_RENDER_BASELINE:
3039       cache->baseline = (int)(long)value;
3040       break;
3041     case _XmCACHE_RENDER_ASCENT:
3042       cache->ascent = (int)(long)value;
3043       break;
3044     case _XmCACHE_RENDER_DESCENT:
3045       cache->descent = (int)(long)value;
3046       break;
3047     case _XmCACHE_RENDER_RENDITION:
3048       if (cache->rendition != NULL) XmRenditionFree(cache->rendition);
3049       cache->rendition = (XmRendition)value;
3050       break;
3051     case _XmCACHE_RENDER_PREV_TABS:
3052       cache->prev_tabs = (char)(long)value;
3053       break;
3054     }
3055 }
3056 
3057 
3058 /*
3059  * find width of widest line in XmString
3060  */
3061 Dimension
XmStringWidth(XmRenderTable rendertable,XmString string)3062 XmStringWidth(
3063         XmRenderTable rendertable,
3064         XmString string )
3065 {
3066   Dimension width, height;
3067   XmStringExtent(rendertable, string, &width, &height);
3068   return(width);
3069 }
3070 
3071 /*
3072  * find total height of an XmString
3073  */
3074 Dimension
XmStringHeight(XmRenderTable rendertable,XmString string)3075 XmStringHeight(
3076         XmRenderTable rendertable,
3077         XmString string )
3078 {
3079   Dimension width, height;
3080   XmStringExtent(rendertable, string, &width, &height);
3081   return(height);
3082 }
3083 
3084 /*
3085  * find the rectangle which will enclose the text
3086  */
3087 void
XmStringExtent(XmRenderTable rendertable,XmString string,Dimension * width,Dimension * height)3088 XmStringExtent(
3089         XmRenderTable rendertable,
3090         XmString string,
3091         Dimension *width,
3092         Dimension *height )
3093 {
3094   Dimension cur_width = 0, max_width = 0;
3095   Dimension cur_height = 0, line_height = 0;
3096   Dimension asc, dsc;
3097   int j;
3098   Display *d;
3099   XtAppContext app = NULL;
3100 
3101   *width = 0, *height = 0;
3102 
3103   if ((rendertable == NULL) || (string == NULL)) return;
3104 
3105 #ifdef XTHREADS
3106   if (_XmRTDisplay(rendertable))
3107     app = XtDisplayToApplicationContext(_XmRTDisplay(rendertable));
3108   if (app)
3109   {
3110       _XmAppLock(app);
3111   }
3112   else
3113   {
3114       _XmProcessLock();
3115   }
3116 #endif
3117   if (_XmStrOptimized(string))
3118     OptLineMetrics(rendertable, string, NULL, NULL, width, height, NULL, NULL);
3119   else
3120     {
3121       _XmRenditionRec	scratch;
3122       _XmRendition	tmp;
3123       XmRendition	rend;
3124       _XmStringArraySegRec array_seg;
3125 
3126       bzero((char*) &scratch, sizeof(_XmRenditionRec));
3127       tmp = &scratch;
3128       rend = &tmp;
3129 
3130       /* Initialize for tabs. */
3131       d = (_XmRTDisplay(rendertable) == NULL) ?
3132 	_XmGetDefaultDisplay()
3133 	  : _XmRTDisplay(rendertable);
3134 
3135       _XmRendDisplay(rend) = d;
3136 
3137       _XmStringLayout(string, XmLEFT_TO_RIGHT);
3138 
3139       for (j = 0; j < _XmStrLineCountGet(string); j++)
3140 	{
3141 	  _XmStringEntry line;
3142 
3143 	  if (_XmStrImplicitLine(string))
3144 	    line = _XmStrEntry(string)[j];
3145 	  else {
3146 	    _XmEntryType(&array_seg) = XmSTRING_ENTRY_ARRAY;
3147 	    _XmEntrySegmentCount(&array_seg) = _XmStrEntryCount(string);
3148 	    _XmEntrySegment(&array_seg) =
3149 	      (_XmStringNREntry *)_XmStrEntry(string);
3150 	    line = (_XmStringEntry)&array_seg;
3151 	  }
3152 
3153 	  LineMetrics(line, rendertable, &rend, NULL, XmLEFT_TO_RIGHT,
3154 		      &cur_width, &cur_height, &asc, &dsc);
3155 
3156 	  /* Returned height for empty lines is zero, so go
3157 	     with previous in that case. */
3158 	  if (cur_height != 0) line_height = cur_height;
3159 
3160 	  *height += line_height;
3161 
3162 	  if (cur_width > max_width) max_width = cur_width;
3163 	}
3164       *width = max_width;
3165       if (_XmRendTags(rend) != NULL)
3166 	XtFree((char *)_XmRendTags(rend));
3167     }
3168 #ifdef XTHREADS
3169   if (app)
3170   {
3171      _XmAppUnlock(app);
3172   }
3173   else
3174   {
3175      _XmProcessUnlock();
3176   }
3177 #endif
3178 }
3179 
3180 Boolean
XmStringEmpty(XmString string)3181 XmStringEmpty(
3182         XmString string )
3183 {
3184   int i, j;
3185 
3186   _XmProcessLock();
3187   if (!string) {
3188     _XmProcessUnlock();
3189     return (TRUE);
3190   }
3191 
3192   if (_XmStrOptimized(string)) {
3193     if (_XmStrByteCount(string) > 0) {
3194       _XmProcessUnlock();
3195       return FALSE;
3196     }
3197   } else {
3198     _XmStringEntry  *entry = _XmStrEntry(string);
3199 
3200     for (i = 0; i < _XmStrEntryCount(string); i++) {
3201       if (_XmEntryMultiple(entry[i])) {
3202 	int segcount = _XmEntrySegmentCount(entry[i]);
3203 	for (j = 0; j < segcount; j++) {
3204 	  _XmStringNREntry seg = _XmEntrySegment(entry[i])[j];
3205 	  if (_XmEntryByteCountGet((_XmStringEntry)seg) > 0) {
3206 	    _XmProcessUnlock();
3207 	    return (FALSE);
3208 	  }
3209 	}
3210       } else {
3211 	if (_XmEntryByteCountGet(entry[i]) > 0) {
3212 	  _XmProcessUnlock();
3213 	  return (FALSE);
3214 	}
3215       }
3216     }
3217   }
3218   _XmProcessUnlock();
3219   return (TRUE);
3220 }
3221 
3222 Boolean
XmStringIsVoid(XmString string)3223 XmStringIsVoid(XmString string)
3224 {
3225   XmStringComponentType	type;
3226   _XmStringContextRec	stack_context;
3227   unsigned int	len;
3228   XtPointer	val;
3229 
3230   _XmProcessLock();
3231   if (!string) {
3232      _XmProcessUnlock();
3233      return (TRUE);
3234   }
3235 
3236   _XmStringContextReInit(&stack_context, string);
3237 
3238   while ((type = XmeStringGetComponent(&stack_context, TRUE, FALSE,
3239 				       &len, &val)) !=
3240 	 XmSTRING_COMPONENT_END)
3241     {
3242       switch(type)
3243 	{
3244 	case XmSTRING_COMPONENT_TAB:
3245 	case XmSTRING_COMPONENT_TEXT:
3246 	case XmSTRING_COMPONENT_LOCALE_TEXT:
3247 	case XmSTRING_COMPONENT_WIDECHAR_TEXT:
3248 	case XmSTRING_COMPONENT_SEPARATOR:
3249 	  _XmStringContextFree(&stack_context);
3250 	  _XmProcessUnlock();
3251 	  return(FALSE);
3252 
3253 	default:
3254 	  break;
3255 	}
3256     }
3257 
3258   _XmStringContextFree(&stack_context);
3259   _XmProcessUnlock();
3260   return(TRUE);
3261 }
3262 
3263 /****************************************************************
3264  * EntryCvtToOpt:
3265  *
3266  * Converts a single segment to a single Opt segment.
3267  * Returns NULL if no conversion could be done.
3268  *
3269  ****************************************************************/
3270 static _XmStringEntry
EntryCvtToOpt(_XmStringEntry entry)3271 EntryCvtToOpt(_XmStringEntry entry)
3272 {
3273   char *text;
3274   _XmStringEntry new_entry;
3275 
3276   if (!entry)
3277     return NULL;
3278 
3279   /* Array segment */
3280   if (_XmEntryMultiple(entry))
3281     return NULL;
3282 
3283   /* Unoptimized, convert if possible */
3284   if (_XmEntryUnoptimized(entry)) {
3285     if (_XmEntryPushGet(entry) ||
3286 	_XmEntryPopGet(entry) ||
3287 	_XmUnoptSegRendBeginCount(entry) > 1 ||
3288 	_XmUnoptSegRendEndCount(entry) > 1 ||
3289 	_XmEntryTabsGet(entry) > 7 ||
3290 	_XmEntryByteCountGet(entry) > 255 ||
3291 	(_XmUnoptSegRendBeginCount(entry) &&
3292 	 _XmStringIndexCacheTag(_XmEntryRendBeginGet(entry, 0),
3293 				XmSTRING_TAG_STRLEN) >= REND_INDEX_MAX) ||
3294 	(_XmUnoptSegRendEndCount(entry) &&
3295 	 _XmStringIndexCacheTag(_XmEntryRendEndGet(entry, 0),
3296 				XmSTRING_TAG_STRLEN) >= REND_INDEX_MAX) ||
3297 	(_XmUnoptSegRendBeginCount(entry) && _XmUnoptSegRendEndCount(entry) &&
3298 	 _XmEntryRendEndGet(entry, 0) != _XmEntryRendBeginGet(entry, 0)) ||
3299 	(_XmUnoptSegTag(entry) &&
3300 	 _XmStringIndexCacheTag(_XmUnoptSegTag(entry), XmSTRING_TAG_STRLEN) >=
3301 	 TAG_INDEX_MAX))
3302       return NULL;
3303 
3304     new_entry = (_XmStringEntry)XtCalloc(1, sizeof(_XmStringOptSegRec));
3305     _XmEntryType(new_entry) = XmSTRING_ENTRY_OPTIMIZED;
3306     _XmEntryImm(new_entry) = 0;
3307     _XmEntryTextTypeSet(new_entry, (XmTextType) _XmEntryTextTypeGet(entry));
3308     _XmEntryTagIndex(new_entry) =
3309       (_XmUnoptSegTag(entry) ?
3310        _XmStringIndexCacheTag(_XmUnoptSegTag(entry), XmSTRING_TAG_STRLEN)
3311        : TAG_INDEX_UNSET);
3312     _XmEntryByteCountSet(new_entry, _XmUnoptSegByteCount(entry));
3313     _XmEntryRendIndex(new_entry) =
3314       (_XmUnoptSegRendBeginCount(entry) ?
3315        _XmStringIndexCacheTag(_XmEntryRendBeginGet(entry, 0),
3316 			      XmSTRING_TAG_STRLEN)
3317        : (_XmUnoptSegRendEndCount(entry) ?
3318 	  _XmStringIndexCacheTag(_XmEntryRendEndGet(entry, 0),
3319 				 XmSTRING_TAG_STRLEN)
3320 	  : REND_INDEX_UNSET));
3321     _XmEntryRendBeginCountSet(new_entry, _XmUnoptSegRendBeginCount(entry));
3322     _XmEntryRendEndCountSet(new_entry, _XmUnoptSegRendEndCount(entry));
3323     _XmEntryTabsSet(new_entry, _XmEntryTabsGet(entry));
3324     _XmEntryDirectionSet(new_entry, _XmEntryDirectionGet(entry));
3325     _XmEntryFlippedSet(new_entry, _XmEntryFlippedGet(entry));
3326     _XmEntryPermSet(new_entry, _XmEntryPermGet(entry));
3327     _XmEntrySoftNewlineSet(new_entry, _XmEntrySoftNewlineGet(entry));
3328     if (_XmEntryPermGet(entry))
3329       _XmEntryTextSet(new_entry, _XmEntryTextGet(entry));
3330     else {
3331       unsigned int len = _XmEntryByteCountGet(entry);
3332       text = (char *)XtMalloc(len);
3333       memcpy(text, _XmEntryTextGet(entry), len);
3334       _XmEntryTextSet(new_entry, text);
3335     }
3336     return new_entry;
3337   }
3338   /* If we were already opt., return a copy */
3339   return _XmStringEntryCopy(entry);
3340 }
3341 
3342 
3343 
3344 /****************************************************************
3345  * EntryCvtToUnOpt:
3346  *
3347  * Converts a single segment to a single UnOpt segment.
3348  * Returns NULL if no conversion could be done (only for Array segs)
3349  *
3350  ****************************************************************/
3351 static _XmStringEntry
EntryCvtToUnopt(_XmStringEntry entry)3352 EntryCvtToUnopt(_XmStringEntry entry)
3353 {
3354   char *text;
3355   _XmStringEntry new_entry;
3356   unsigned int len;
3357 
3358   if (!entry)
3359     return NULL;
3360 
3361   /* Array segment */
3362   if (_XmEntryMultiple(entry))
3363     return NULL;
3364 
3365   /* Unoptimized, return copy */
3366   if (_XmEntryUnoptimized(entry))
3367     return _XmStringEntryCopy(entry);
3368 
3369   /* Optimized: convert */
3370   len = _XmEntryByteCountGet(entry);
3371   new_entry = (_XmStringEntry)XtCalloc(1, sizeof(_XmStringUnoptSegRec));
3372   _XmEntryType(new_entry) = XmSTRING_ENTRY_UNOPTIMIZED;
3373   _XmEntryTextTypeSet(new_entry, (XmTextType) _XmEntryTextTypeGet(entry));
3374   _XmUnoptSegTag(new_entry) = _XmEntryTag(entry);
3375   _XmUnoptSegByteCount(new_entry) = len;
3376   _XmUnoptSegRendBeginCount(new_entry) = _XmEntryRendBeginCountGet(entry);
3377   _XmUnoptSegRendEndCount(new_entry) = _XmEntryRendEndCountGet(entry);
3378   if (_XmEntryRendBeginCountGet(entry)) {
3379     _XmUnoptSegRendBegins(new_entry) =
3380       (XmStringTag *)XtMalloc(sizeof(XmStringTag));
3381     _XmUnoptSegRendBegins(new_entry)[0] = _XmEntryRendBeginGet(entry, 0);
3382   }
3383   if (_XmEntryRendEndCountGet(entry)) {
3384     _XmUnoptSegRendEnds(new_entry) =
3385       (XmStringTag *)XtMalloc(sizeof(XmStringTag));
3386     _XmUnoptSegRendEnds(new_entry)[0] = _XmEntryRendEndGet(entry, 0);
3387   }
3388   _XmEntryTabsSet(new_entry, _XmEntryTabsGet(entry));
3389   _XmEntryDirectionSet(new_entry, _XmEntryDirectionGet(entry));
3390   _XmEntryFlippedSet(new_entry, _XmEntryFlippedGet(entry));
3391   _XmEntryPermSet(new_entry, _XmEntryPermGet(entry));
3392   _XmEntrySoftNewlineSet(new_entry, _XmEntrySoftNewlineGet(entry));
3393   _XmEntryPushSet(new_entry, _XmEntryPushGet(entry));
3394   _XmEntryPopSet(new_entry, _XmEntryPopGet(entry));
3395   if (_XmEntryPermGet(entry))
3396     _XmEntryTextSet(new_entry, _XmEntryTextGet(entry));
3397   else if (len>0) {
3398     text = (char *)XtMalloc(len);
3399     memcpy(text, _XmEntryTextGet(entry), len);
3400     _XmEntryTextSet(new_entry, text);
3401   }
3402   else
3403     _XmEntryTextSet(new_entry, NULL);
3404   return new_entry;
3405 }
3406 
3407 
3408 
3409 /* Convert an optimized _XmString to an equivalent non-optimized _XmString */
3410 _XmString
_XmStringOptToNonOpt(_XmStringOpt string)3411 _XmStringOptToNonOpt(_XmStringOpt string)
3412 {
3413   _XmString str;
3414   _XmStringOptSegRec seg;
3415 
3416   _XmStrCreate(str, XmSTRING_MULTIPLE_ENTRY, 0);
3417   _XmEntryInit((_XmStringEntry)&seg, XmSTRING_ENTRY_OPTIMIZED);
3418 
3419   _XmEntryTagIndex(&seg) = _XmStrTagIndex((_XmString)string);
3420   _XmEntryRendIndex(&seg) = _XmStrRendIndex((_XmString)string);
3421   _XmEntryRendBeginCountSet(&seg, _XmStrRendBegin((_XmString)string));
3422   _XmEntryRendEndCountSet(&seg, _XmStrRendEnd((_XmString)string));
3423   _XmEntryTextTypeSet(&seg, (XmTextType) _XmStrTextType((_XmString)string));
3424   _XmEntryByteCountSet(&seg, _XmStrByteCount((_XmString)string));
3425   _XmEntryDirectionSet((_XmStringEntry)&seg,
3426 		       _XmStrDirection((_XmString)string));
3427   _XmEntryTabsSet(&seg, _XmStrTabs((_XmString)string));
3428   _XmEntryFlippedSet(&seg, _XmStrFlipped((_XmString)string));
3429   _XmEntryTextSet((_XmStringEntry)&seg, _XmStrText((_XmString)string));
3430 
3431   _XmStringSegmentNew(str, 0, (_XmStringEntry)&seg, True);
3432 
3433   return(str);
3434 }
3435 
3436 /*
3437  * figure out if there is sub string match, and if so the begining
3438  * and end of the match section in pixels.  Don't touch anything if
3439  * there is no match
3440  */
3441 static void
SubStringPosition(int one_byte,XmRenderTable rt,XmRendition entry,_XmStringEntry seg,_XmStringEntry under_seg,int x,Dimension * under_begin,Dimension * under_end)3442 SubStringPosition(
3443 #if NeedWidePrototypes
3444         int one_byte,
3445 #else
3446         Boolean one_byte,
3447 #endif /* NeedWidePrototypes */
3448 	XmRenderTable rt,
3449 	XmRendition entry,
3450         _XmStringEntry seg,
3451         _XmStringEntry under_seg,
3452 #if NeedWidePrototypes
3453         int x,
3454 #else
3455         Position x,
3456 #endif /* NeedWidePrototypes */
3457         Dimension *under_begin,
3458         Dimension *under_end )
3459 {
3460   char *a = (char*) _XmEntryTextGet(seg);
3461   char *b = (char*) _XmEntryTextGet(under_seg);
3462   char *seg_tag = _XmEntryTag(seg);
3463   int i, j, k, begin, max, width;
3464   unsigned int seg_len, under_seg_len;
3465   Boolean fail;
3466 
3467   /* Metro Link fix: _XmEntryTag(seg) can be NULL, but the original Motif
3468    * code never checked for that.  We check, and if it is NULL, we treat
3469    * it as if it was set to XmFONTLIST_DEFAULT_TAG. */
3470 
3471   if (seg_tag == NULL)
3472     seg_tag = XmFONTLIST_DEFAULT_TAG;
3473 
3474   if (!((seg_tag == _XmEntryTag(under_seg)) ||
3475 	((strcmp(seg_tag, XmFONTLIST_DEFAULT_TAG) == 0) &&
3476 	 _XmStringIsCurrentCharset(_XmEntryTag(under_seg))) ||
3477 	((strcmp(_XmEntryTag(under_seg), XmFONTLIST_DEFAULT_TAG) == 0) &&
3478 	 _XmStringIsCurrentCharset(seg_tag))))
3479     return;
3480 
3481   seg_len = _XmEntryByteCountGet(seg);
3482   under_seg_len = _XmEntryByteCountGet(under_seg);
3483   if (seg_len < under_seg_len)
3484     return;
3485 
3486   max = (seg_len - under_seg_len);
3487 
3488   if (_XmRendFontType(entry) == XmFONT_IS_FONT
3489       || _XmRendFontType(entry) == XmFONT_IS_XFT) {
3490     XFontStruct *font_struct = (XFontStruct *)_XmRendFont(entry);
3491 
3492     if (one_byte) {
3493       for (i = 0; i <= max; i++) {
3494 	fail = FALSE;
3495 	begin = i;
3496 
3497 	for (j = 0; j < under_seg_len; j++) {
3498 	  if (a[i+j] != b[j]) {
3499 	    fail = TRUE;
3500 	    break;
3501 	  }
3502 	}
3503 	if ( ! fail) {    /* found it */
3504 	  if (begin == 0)
3505 	    *under_begin = x;
3506 	  else
3507 	    if (_XmRendFontType(entry) == XmFONT_IS_FONT)
3508 	      *under_begin = x + abs(XTextWidth (font_struct, a, begin));
3509 #ifdef USE_XFT
3510 	    else {
3511 	      XGlyphInfo ext;
3512 	      XftTextExtentsUtf8(_XmRendDisplay(entry), _XmRendXftFont(entry),
3513 	                      (FcChar8*)a, begin, &ext);
3514 	      *under_begin = x + ext.xOff;
3515 	    }
3516 #endif
3517 
3518 	  width = _XmEntryWidthGet((_XmStringEntry)under_seg, rt);
3519 
3520 	  if (width == 0) {
3521 	    if (_XmRendFontType(entry) == XmFONT_IS_FONT)
3522 	      width = abs(XTextWidth(font_struct, b, under_seg_len));
3523 #ifdef USE_XFT
3524 	    else {
3525 	      XGlyphInfo ext;
3526 	      XftTextExtentsUtf8(_XmRendDisplay(entry), _XmRendXftFont(entry),
3527 	                      (FcChar8*)b, under_seg_len, &ext);
3528 	      width = ext.xOff;
3529 	    }
3530 #endif
3531 	    _XmEntryWidthSet((_XmStringEntry)under_seg, rt, width);
3532 	  }
3533 
3534 	  *under_end = *under_begin + width;
3535 
3536 	  return;
3537 	}
3538       }
3539     } else {
3540       /*
3541        * If either string isn't even byte length, it can't be
3542        * two bytes/char.
3543        */
3544 
3545       if (((seg_len % 2) != 0) || ((under_seg_len % 2) != 0))
3546 	return;
3547 
3548       /*
3549        * search for the substring
3550        */
3551 
3552       for (i = 0; i <= max; i+=2) {
3553 	fail = FALSE;
3554 	begin = i;
3555 
3556 	for (j = 0; j < under_seg_len; j+=2) {
3557 	  if ((a[i+j] != b[j]) || (a[i+j+1] != b[j+1])) {
3558 	    fail = TRUE;
3559 	    break;
3560 	  }
3561 	}
3562 	if ( ! fail) {    /* found it */
3563 	  if (begin == 0)
3564 	    *under_begin = x;
3565 	  else
3566 	    if (_XmRendFontType(entry) == XmFONT_IS_FONT)
3567 	      *under_begin =
3568 	        x + abs(XTextWidth16 (font_struct, (XChar2b *) a, begin/2));
3569 #ifdef USE_XFT
3570 	    else {
3571 	      XGlyphInfo ext;
3572 	      XftTextExtents16(_XmRendDisplay(entry), _XmRendXftFont(entry),
3573 	                      (FcChar16*)a, begin, &ext);
3574 	      *under_begin = x + ext.xOff;
3575 	    }
3576 #endif
3577 
3578 	  width = _XmEntryWidthGet((_XmStringEntry)under_seg, rt);
3579 
3580 	  if (width == 0) {
3581 	    if (_XmRendFontType(entry) == XmFONT_IS_FONT)
3582 	      width = abs(XTextWidth16(font_struct, (XChar2b *) b,
3583 				       under_seg_len/2));
3584 #ifdef USE_XFT
3585 	    else {
3586 	      XGlyphInfo ext;
3587 	      XftTextExtents16(_XmRendDisplay(entry), _XmRendXftFont(entry),
3588 	                      (FcChar16*)b, under_seg_len, &ext);
3589 	      width = ext.xOff;
3590 	    }
3591 #endif
3592 	    _XmEntryWidthSet((_XmStringEntry)under_seg, rt, width);
3593 	  }
3594 
3595 	  *under_end = *under_begin + width;
3596 	  return;
3597 	}
3598       }
3599     }
3600   } else {
3601     XFontSet font_set = (XFontSet)_XmRendFont(entry);
3602     XmTextType type = (XmTextType) _XmEntryTextTypeGet(under_seg);
3603     int len_a, len_a1, len_b;
3604 
3605     for (i = 0; i <= max; i += len_a) {
3606       fail = FALSE;
3607       begin = i;
3608 
3609       if (type == XmWIDECHAR_TEXT) {
3610 	len_a = sizeof(wchar_t);
3611 
3612 	for (j = 0; j < under_seg_len; j += sizeof(wchar_t))
3613 	  if (((wchar_t *)a)[(i+j)/len_a] != ((wchar_t *)b)[j/len_a]) {
3614 	    fail = TRUE;
3615 	    break;
3616 	  }
3617       } else {
3618 #ifndef NO_MULTIBYTE
3619 	len_a = mblen(&a[i], MB_CUR_MAX);
3620 #else
3621 	len_a = a[i] ? 1 : 0;
3622 #endif
3623 	if (len_a < 1) return;
3624 	len_a1 = len_a;
3625 
3626 	for (j = 0; j < under_seg_len; j += len_b) {
3627 #ifndef NO_MULTIBYTE
3628 	  len_b = mblen(&b[j], MB_CUR_MAX);
3629 #else
3630 	  len_b = b[j] ? 1 : 0;
3631 #endif
3632 	  if (len_b < 1) return;
3633 
3634 	  if (len_b == len_a1) {
3635 	    for (k = 0; k < len_b; k++) {
3636 	      if (a[i+j+k] != b[j+k]) {
3637 		fail = TRUE;
3638 		break;
3639 	      }
3640 	    }
3641 	    if (fail == TRUE) break;
3642 	  } else {
3643 	    fail = TRUE;
3644 	    break;
3645 	  }
3646 	}
3647       }
3648 
3649       if (!fail) {          /* found it */
3650 #ifdef UTF8_SUPPORTED
3651         Boolean utf8 = ((_XmEntryTextTypeGet(seg) == XmCHARSET_TEXT) &&
3652               (((_XmEntryTag((_XmStringEntry)seg) ==
3653                  XmFONTLIST_DEFAULT_TAG) &&
3654                 _XmStringIsCurrentCharset("UTF-8")) ||
3655                (strcmp(seg_tag, "UTF-8") == 0)));
3656 #else
3657         Boolean utf8 = False;
3658 #endif
3659 	if (begin == 0)
3660 	  *under_begin = x;
3661 	else if (type == XmWIDECHAR_TEXT) {
3662 	  *under_begin =
3663 	    x + abs(XwcTextEscapement(font_set, (wchar_t *)a,
3664 				      begin/sizeof(wchar_t)));
3665         } else {
3666 #ifdef UTF8_SUPPORTED
3667             if (utf8)
3668                 *under_begin =
3669                     x + abs(Xutf8TextEscapement(font_set, a, begin));
3670             else
3671 #endif
3672                 *under_begin =
3673                     x + abs(XmbTextEscapement(font_set, a, begin));
3674         }
3675 
3676 	width = _XmEntryWidthGet((_XmStringEntry)under_seg, rt);
3677 
3678 	if (width == 0) {
3679 #ifdef UTF8_SUPPORTED
3680 	  width = (type == XmWIDECHAR_TEXT)
3681 	    ? abs(XwcTextEscapement(font_set, (wchar_t *)b,
3682 				  under_seg_len / sizeof(wchar_t)))
3683 	    : (utf8
3684                     ? abs(Xutf8TextEscapement(font_set, b, under_seg_len))
3685                     : abs(XmbTextEscapement(font_set, b, under_seg_len)));
3686 #else
3687 	  width = (type == XmWIDECHAR_TEXT)
3688 	    ? abs(XwcTextEscapement(font_set, (wchar_t *)b,
3689 				  under_seg_len / sizeof(wchar_t)))
3690 	    : abs(XmbTextEscapement(font_set, b, under_seg_len));
3691 #endif
3692 	  _XmEntryWidthSet((_XmStringEntry)under_seg, rt, width);
3693 	}
3694 
3695 	*under_end = *under_begin + width;
3696 
3697 	return;
3698       }
3699     }
3700   }
3701 }
3702 
3703 /*ARGSUSED*/
3704 extern void
_XmStringDrawLining(Display * d,Drawable w,Position x,Position y,Dimension width,Dimension height,Dimension descender,XmRendition rend,Pixel select_color,XmHighlightMode mode,Boolean colors_set)3705 _XmStringDrawLining(Display *d,
3706 		    Drawable w,
3707 		    Position x,
3708 		    Position y,
3709 		    Dimension width,
3710 		    Dimension height,
3711 		    Dimension descender,
3712 		    XmRendition rend,
3713 		    Pixel select_color,	/* unused */
3714 		    XmHighlightMode mode,
3715 		    Boolean colors_set)
3716 {
3717   GC			gc;
3718   XGCValues 		xgcv;
3719   Pixel			fg, bg, old_fg, old_bg;
3720   unsigned char		under, thru;
3721   XGCValues 		current_gcv;
3722   int			style, old_style=LineSolid, cur_style=LineSolid;
3723 
3724   old_fg = old_bg = XmUNSPECIFIED_PIXEL;
3725 
3726   _XmRendDisplay(rend) = d;
3727 
3728   gc = _XmRendGC(rend);
3729 
3730   fg = _XmRendFG(rend);
3731   bg = _XmRendBG(rend);
3732 
3733   under = _XmRendUnderlineType(rend);
3734   thru = _XmRendStrikethruType(rend);
3735 
3736   if (!colors_set)
3737     {
3738       if (fg != XmUNSPECIFIED_PIXEL)
3739 	{
3740 	  XGetGCValues(d, gc, GCForeground, &current_gcv);
3741 	  if (current_gcv.foreground != fg)
3742 	    {
3743 	      old_fg = current_gcv.foreground;
3744 	      xgcv.foreground = fg;
3745 	      XChangeGC(d, gc, GCForeground, &xgcv);
3746 	    }
3747 	}
3748 
3749       if (bg != XmUNSPECIFIED_PIXEL)
3750 	{
3751 	  XGetGCValues(d, gc, GCBackground, &current_gcv);
3752 	  if (current_gcv.background != bg)
3753 	    {
3754 	      old_bg = current_gcv.background;
3755 	      xgcv.background = bg;
3756 	      XChangeGC(d, gc, GCBackground, &xgcv);
3757 	    }
3758 	}
3759     }
3760 
3761   if (mode == XmHIGHLIGHT_SECONDARY_SELECTED)
3762     {
3763       /* Draw lines */
3764       XGetGCValues(d, gc, GCLineStyle, &current_gcv);
3765       old_style = current_gcv.line_style;
3766 
3767       style = LineSolid;
3768 
3769       if (old_style != style)
3770 	{
3771 	  cur_style = xgcv.line_style = style;
3772 	  XChangeGC(d, gc, GCLineStyle, &xgcv);
3773 	}
3774 
3775       XDrawLine (d, w, gc,
3776 		 x, y + SINGLE_OFFSET,
3777 		 x + width - 1, y + SINGLE_OFFSET);
3778     }
3779   else
3780     {
3781       XGetGCValues(d, gc, GCLineStyle, &current_gcv);
3782       cur_style = old_style = current_gcv.line_style;
3783 
3784       if ((under != XmAS_IS) && (under != XmNO_LINE))
3785 	{
3786 	  if ((under == XmSINGLE_DASHED_LINE) ||
3787 	      (under == XmDOUBLE_DASHED_LINE))
3788 	    style = LineDoubleDash;
3789 	  else style = LineSolid;
3790 
3791 	  if (cur_style != style)
3792 	    {
3793 	      cur_style = xgcv.line_style = style;
3794 	      XChangeGC(d, gc, GCLineStyle, &xgcv);
3795 	    }
3796 
3797 	  if ((under == XmSINGLE_LINE) ||
3798 	      (under == XmSINGLE_DASHED_LINE))
3799 	    {
3800 	      XDrawLine(d, w, gc,
3801 			x, y + SINGLE_OFFSET,
3802 			(x + width - 1), y + SINGLE_OFFSET);
3803 	    }
3804 	  else if ((under == XmDOUBLE_LINE) ||
3805 		   (under == XmDOUBLE_DASHED_LINE))
3806 	    {
3807 	      XSegment	segs[2];
3808 
3809 	      segs[0].x1 = segs[1].x1 = x;
3810 	      segs[0].x2 = segs[1].x2 = x + width - 1;
3811 	      segs[0].y1 = segs[0].y2 = y;
3812 	      segs[1].y1 = segs[1].y2 = y + DOUBLE_OFFSET;
3813 
3814 	      XDrawSegments(d, w, gc, segs, 2);
3815 	    }
3816 	}
3817 
3818       if ((thru != XmAS_IS) && (thru != XmNO_LINE))
3819 	{
3820 	  if ((thru == XmSINGLE_DASHED_LINE) ||
3821 	      (thru == XmDOUBLE_DASHED_LINE))
3822 	    style = LineDoubleDash;
3823 	  else style = LineSolid;
3824 
3825 	  if (cur_style != style)
3826 	    {
3827 	      cur_style = xgcv.line_style = style;
3828 	      XChangeGC(d, gc, GCLineStyle, &xgcv);
3829 	    }
3830 
3831 	  if ((thru == XmSINGLE_LINE) ||
3832 	      (thru == XmSINGLE_DASHED_LINE))
3833 	    {
3834 	      XDrawLine(d, w, gc,
3835 			x, (y + descender - height/2 - 1),
3836 			(x + width - 1), (y + descender - height/2 - 1));
3837 	    }
3838 	  else if ((thru == XmDOUBLE_LINE) ||
3839 		   (thru == XmDOUBLE_DASHED_LINE))
3840 	    {
3841 	      XSegment	segs[2];
3842 
3843 	      segs[0].x1 = segs[1].x1 = x;
3844 	      segs[0].x2 = segs[1].x2 = x + width - 1;
3845 	      segs[0].y1 = segs[0].y2 = (y + descender - height/2) - 2;
3846 	      segs[1].y1 = segs[1].y2 = (y + descender - height/2) + 1;
3847 
3848 	      XDrawSegments(d, w, gc, segs, 2);
3849 	    }
3850 	}
3851     }
3852 
3853   if ((cur_style != old_style) &&
3854       ((old_style == LineSolid) || (old_style == LineOnOffDash) ||
3855        (old_style == LineDoubleDash)))
3856     {
3857       xgcv.line_style = old_style;
3858       XChangeGC(d, gc, GCLineStyle, &xgcv);
3859     }
3860 
3861   if (!colors_set)
3862     {
3863       if (old_fg != XmUNSPECIFIED_PIXEL)
3864 	{
3865 	  xgcv.foreground = old_fg;
3866 	  XChangeGC(d, gc, GCForeground, &xgcv);
3867 	}
3868 
3869       if (old_bg != XmUNSPECIFIED_PIXEL)
3870 	{
3871 	  xgcv.background = old_bg;
3872 	  XChangeGC(d, gc, GCBackground, &xgcv);
3873 	}
3874     }
3875 }
3876 
3877 extern void
_XmStringDrawSegment(Display * d,Drawable w,int x,int y,int width,int height,_XmStringNREntry seg,XmRendition rend,XmRenderTable rendertable,int image,XmString * underline,unsigned int descender)3878 _XmStringDrawSegment(Display *d,
3879 		     Drawable w,
3880 #if NeedWidePrototypes
3881 		     int x,
3882 		     int y,
3883 		     int width,
3884 		     int height,
3885 #else
3886 		     Position x,
3887 		     Position y,
3888 		     Dimension width,
3889 		     Dimension height,
3890 #endif /* NeedWidePrototypes */
3891 		     _XmStringNREntry seg,
3892 		     XmRendition rend,
3893 		     XmRenderTable rendertable,
3894 #if NeedWidePrototypes
3895 		     int image,
3896 #else
3897 		     Boolean image,
3898 #endif /* NeedWidePrototypes */
3899 		     XmString *underline,
3900 #if NeedWidePrototypes
3901 		     unsigned int descender
3902 #else
3903 		     Dimension descender
3904 #endif /* NeedWidePrototypes */
3905 		     )
3906 {
3907   Boolean 		text16 = False, multibyte, widechar, utf8;
3908   Font    		oldfont = (Font) 0;
3909   GC			gc;
3910   XGCValues 		xgcv;
3911   char 			*draw_text;       /* text to be drawn -
3912 					     flipped in RtoL mode */
3913   char  		flip_char[100];	  /* but simple */
3914   char 			*flip_char_extra = NULL;
3915   Pixel			fg, bg, old_fg, old_bg;
3916   XGCValues 		current_gcv;
3917   Dimension		under_begin, under_end;
3918   unsigned int		seg_len;
3919   int			font_type;
3920   int			text_type;
3921 
3922   old_fg = old_bg = XmUNSPECIFIED_PIXEL;
3923 
3924   _XmRendDisplay(rend) = d;
3925   font_type = _XmRendFontType(rend);
3926   text_type = _XmEntryTextTypeGet((_XmStringEntry)seg);
3927 
3928   seg_len = _XmEntryByteCountGet((_XmStringEntry)seg);
3929   if (seg_len  > 0)
3930     {
3931       multibyte = (((text_type ==  XmMULTIBYTE_TEXT) ||
3932 		    (text_type == XmCHARSET_TEXT)) &&
3933 		   (font_type == XmFONT_IS_FONTSET));
3934 
3935       widechar = ((text_type == XmWIDECHAR_TEXT) &&
3936 		  (font_type == XmFONT_IS_FONTSET));
3937 
3938 #ifdef UTF8_SUPPORTED
3939       utf8 = ((text_type == XmMULTIBYTE_TEXT || text_type == XmCHARSET_TEXT) &&
3940 		   (font_type == XmFONT_IS_FONTSET ||
3941 		    font_type == XmFONT_IS_XFT ||
3942 		    (font_type == XmFONT_IS_FONT
3943 		     && _XmIsISO10646(d, _XmRendFont(rend)))) &&
3944               (((_XmEntryTag((_XmStringEntry)seg) == XmFONTLIST_DEFAULT_TAG &&
3945                 (_XmStringIsCurrentCharset("UTF-8"))) ||
3946                ((_XmEntryTagIndex(seg) != TAG_INDEX_UNSET
3947 	       && strcmp(_XmEntryTag((_XmStringEntry)seg), "UTF-8") == 0)))));
3948 #else
3949       utf8 = False;
3950 #endif
3951       gc = _XmRendGC(rend);
3952 
3953       fg = _XmRendFG(rend);
3954       bg = _XmRendBG(rend);
3955 
3956 
3957       if (fg != XmUNSPECIFIED_PIXEL)
3958 	{
3959 	  XGetGCValues(d, gc, GCForeground, &current_gcv);
3960 	  if (current_gcv.foreground != fg)
3961 	    {
3962 	      old_fg = current_gcv.foreground;
3963 	      xgcv.foreground = fg;
3964 	      XChangeGC(d, gc, GCForeground, &xgcv);
3965 	    }
3966 	}
3967 
3968       if (bg != XmUNSPECIFIED_PIXEL)
3969 	{
3970 	  XGetGCValues(d, gc, GCBackground, &current_gcv);
3971 	  if (current_gcv.background != bg)
3972 	    {
3973 	      old_bg = current_gcv.background;
3974 	      xgcv.background = bg;
3975 	      XChangeGC(d, gc, GCBackground, &xgcv);
3976 	    }
3977 	}
3978 
3979       if (!multibyte && !widechar && _XmRendFontType(rend) != XmFONT_IS_XFT)
3980 	{
3981 	  XFontStruct *f = (XFontStruct *)_XmRendFont(rend);
3982 
3983 	  /* If we don't have a font, don't render. */
3984 	  if (f == NULL)
3985 	      return;
3986 
3987 	  text16 = two_byte_font(f);
3988 
3989 	  XGetGCValues(d, gc, GCFont, &current_gcv) ;
3990 
3991 	  xgcv.font = f->fid;			  /* get segment font */
3992 
3993 	  if (current_gcv.font != xgcv.font)	  /* not right one */
3994 	    {					  /* change it */
3995 	      oldfont = current_gcv.font;
3996 	      XChangeGC(d, gc, GCFont, &xgcv);
3997 	    }
3998 	}
3999 
4000       if (_XmEntryDirectionGet((_XmStringEntry)seg) ==
4001 	  XmSTRING_DIRECTION_R_TO_L)
4002 	{
4003 	  /* Flip the bytes. */
4004 	  char *p = flip_char, *q;
4005 	  char *ltor_text;
4006 	  int i, j;
4007 	  if (seg_len > 100)
4008 	    p = flip_char_extra = (char *) ALLOCATE_LOCAL(seg_len);
4009 
4010 	  draw_text = p;
4011 	  ltor_text = (char *)_XmEntryTextGet((_XmStringEntry)seg);
4012 
4013 	  if (multibyte)	/* Have to flip a mb character at time. */
4014 	    {
4015 	      int   len;
4016 
4017 	      q = ltor_text;
4018 	      p += seg_len;
4019 	      for (i = 0; i < seg_len; i += len)
4020 		{
4021 #ifndef NO_MULTIBYTE
4022 		  len = mblen(q, MB_CUR_MAX);
4023 #else
4024 		  len = *q ? 1 : 0;
4025 #endif
4026 		  if (len < 1) /* Something went wrong, just return for now. */
4027 		    return;
4028 
4029 		  p -= len;
4030 		  for (j = 0; j < len; j++)
4031 		    {
4032 		      p[j] = q[j];
4033 		    }
4034 		  q += len;
4035 		}
4036 	    }
4037 	  else if (!text16)
4038 	    {
4039 	      q = (ltor_text + seg_len - 1);
4040 	      for (i = 0; i < seg_len; i++)
4041 		*p++ = *q--;
4042 	    }
4043 	  else
4044 	    /* Have to flip two at a time, maintaining their order. */
4045 	    {
4046 	      char tmp;
4047 
4048 	      q = (ltor_text + seg_len - 1);
4049 	      for (i = 0; i < Half(seg_len); i++)
4050 		{
4051 		  tmp = *q--;
4052 		  *p++ = *q--;
4053 		  *p++ = tmp;
4054 		}
4055 	    }
4056 	} else /* LtoR */ {
4057 	  draw_text = (char *)_XmEntryTextGet((_XmStringEntry)seg);
4058 	}
4059 
4060       if (*underline != (_XmString)NULL)
4061 	{
4062 	  under_begin = under_end = 0;
4063 	  if (_XmStrOptimized(*underline))
4064 	    {
4065 	      /*
4066 	       * This is an optimized string; coerce underline to segment
4067 	       * and call the sub-string search routine.
4068 	       */
4069 	      Boolean			imm;
4070 	      _XmStringOptSegRec	under_seg;
4071 
4072 	      if (_XmStrText(*underline) !=
4073 		  (char *)_XmEntryTextGet((_XmStringEntry)*underline))
4074 		/* If XtPointer in union in optimized segment leads to
4075 		 * padding in struct between header and text data
4076 		 * (on some 64-bit architectures) we have to move
4077 		 * text data, since optimized string does not have padding.
4078 		 */
4079 		{
4080 		  bzero((char*)&under_seg, sizeof(_XmStringOptSegRec));
4081 		  _XmEntryType(&under_seg) = XmSTRING_ENTRY_OPTIMIZED;
4082 		  _XmEntryTagIndex(&under_seg) = _XmStrTagIndex(*underline);
4083 		  _XmEntryByteCountSet(&under_seg, _XmStrByteCount(*underline));
4084 		  _XmEntryTextTypeSet(&under_seg,
4085 				      (XmTextType)_XmStrTextType(*underline));
4086 		  _XmEntryTextSet((_XmStringEntry)&under_seg,
4087 				  (char *)_XmStrText(*underline));
4088 
4089 		  SubStringPosition((!text16), rendertable, rend,
4090 				    (_XmStringEntry)seg,
4091 				    (_XmStringEntry)&under_seg, x,
4092 				    &under_begin, &under_end);
4093 		}
4094 	      else
4095 		{
4096 		  imm = _XmEntryImm((_XmStringEntry)*underline);
4097 		  _XmEntryImm((_XmStringEntry)*underline) = TRUE;
4098 		  SubStringPosition((!text16), rendertable, rend,
4099 				    (_XmStringEntry)seg,
4100 				    (_XmStringEntry)*underline, x,
4101 				    &under_begin, &under_end);
4102 		  _XmEntryImm((_XmStringEntry)*underline) = imm;
4103 		}
4104 	    }
4105 	  else {
4106 	    _XmStringEntry line;
4107 	    line = _XmStrEntry(*underline)[0];
4108 
4109 	    if ((_XmStrEntryCount(*underline) > 0) &&
4110 		(_XmEntrySegmentCountGet(line) > 0))
4111 	      {
4112 		_XmStringNREntry under_seg;
4113 
4114 		under_seg = (_XmStringNREntry)_XmEntrySegmentGet(line)[0];
4115 
4116 		SubStringPosition((!text16), rendertable, rend,
4117 				  (_XmStringEntry)seg,
4118 				  (_XmStringEntry)under_seg, x,
4119 				  &under_begin, &under_end);
4120 	      }
4121 	  }
4122 	}
4123 
4124 #ifdef USE_XFT
4125       if (_XmRendFontType(rend) == XmFONT_IS_XFT)
4126         {
4127 	    _XmXftDrawString(d, w, rend, 1, x, y, draw_text, seg_len, image);
4128         }
4129       else /* TODO: fix indentation */
4130 #endif
4131         {
4132       if (image)
4133 	{
4134 	  if (text16)
4135 	    if (utf8)
4136 	    {
4137 		size_t  ucs_str_len;
4138 		XChar2b *ucs_str;
4139 
4140 		/* TODO: it is very unoptimized convert the same sting
4141 		 * twice - for getting extents and drawing */
4142 		ucs_str = _XmUtf8ToUcs2(draw_text, seg_len, &ucs_str_len);
4143 		XDrawImageString16(d, w, gc, x, y, ucs_str, ucs_str_len);
4144 		XFree(ucs_str);
4145 	    } else
4146 	        XDrawImageString16(d, w, gc, x, y, (XChar2b*)draw_text,
4147 			       Half(seg_len));
4148 #ifdef UTF8_SUPPORTED
4149           else if (utf8)
4150             Xutf8DrawImageString(d, w, (XFontSet)_XmRendFont(rend), gc, x, y,
4151                                  draw_text, seg_len);
4152 #endif
4153 	  else if (multibyte)
4154 	    XmbDrawImageString (d, w, (XFontSet)_XmRendFont(rend), gc, x, y,
4155 				draw_text, seg_len);
4156 	  else if (widechar)
4157 	    XwcDrawImageString (d, w, (XFontSet)_XmRendFont(rend),
4158 				gc, x, y, (wchar_t *) draw_text,
4159 				(seg_len / sizeof(wchar_t)));
4160 	  else
4161 	    XDrawImageString (d, w, gc, x, y, draw_text, seg_len);
4162 	}
4163       else
4164 	{
4165 	  if (text16)
4166 	  {
4167 	    if (utf8)
4168 	    {
4169 		size_t  ucs_str_len;
4170 		XChar2b *ucs_str;
4171 
4172 		/* TODO: it is very unoptimized convert the same sting
4173 		 * twice - for getting extents and drawing */
4174 		ucs_str = _XmUtf8ToUcs2(draw_text, seg_len, &ucs_str_len);
4175 		XDrawString16(d, w, gc, x, y, ucs_str, ucs_str_len);
4176 		XFree(ucs_str);
4177 	    } else
4178 		    XDrawString16 (d, w, gc, x, y, (XChar2b *)draw_text,
4179 				    Half(seg_len));
4180 	  }
4181 #ifdef UTF8_SUPPORTED
4182           else if (utf8)
4183 	    Xutf8DrawString(d, w, (XFontSet)_XmRendFont(rend), gc, x, y,
4184                             draw_text, seg_len);
4185 #endif
4186 	  else if (multibyte)
4187 	    XmbDrawString (d, w, (XFontSet)_XmRendFont(rend), gc, x, y,
4188 			   draw_text, seg_len);
4189 	  else if (widechar)
4190 	    XwcDrawString (d, w, (XFontSet)_XmRendFont(rend),
4191 			   gc, x, y, (wchar_t *) draw_text,
4192 			   (seg_len / sizeof(wchar_t)));
4193 	  else
4194 	    XDrawString(d, w, gc, x, y, draw_text, seg_len);
4195 	}
4196 	}
4197 
4198       /* Draw lines */
4199       if ((*underline != NULL) && (under_begin != under_end))
4200 	{
4201 	  *underline = (_XmString) NULL;	  /* only once */
4202 
4203 	  XDrawLine (d, w, gc,
4204 		     under_begin, (y + descender),
4205 		     under_end, (y + descender));
4206 	}
4207 
4208       _XmStringDrawLining(d, w, x, y, width, height, descender,
4209 			  rend, XmUNSPECIFIED_PIXEL, XmHIGHLIGHT_NORMAL, TRUE);
4210 
4211       if (((Font)0 != oldfont) &&		  /* if font was changed */
4212 	  ((Font)~0 != oldfont))		  /* put it back */
4213 	{
4214 	  xgcv.font = oldfont;
4215 	  XChangeGC (d, gc, GCFont, &xgcv);
4216 	}
4217 
4218       if (old_fg != XmUNSPECIFIED_PIXEL)
4219 	{
4220 	  xgcv.foreground = old_fg;
4221 	  XChangeGC(d, gc, GCForeground, &xgcv);
4222 	}
4223 
4224       if (old_bg != XmUNSPECIFIED_PIXEL)
4225 	{
4226 	  xgcv.background = old_bg;
4227 	  XChangeGC(d, gc, GCBackground, &xgcv);
4228 	}
4229 
4230       if (flip_char_extra != NULL)
4231 	{
4232 	  DEALLOCATE_LOCAL(flip_char_extra);
4233 	}
4234     }
4235 }
4236 
4237 /****************************************************************
4238  * recursive_layout:
4239  *    This (partly) recursive function sets up the left/right
4240  *    pointers for segments to ensure that segments will be
4241  *    laid out in the correct order
4242  ****************************************************************/
4243 static void
recursive_layout(_XmString string,int * line_index,int * seg_index,int direction,int p_direction,int depth)4244 recursive_layout(_XmString string,
4245 		 int *line_index,
4246 		 int *seg_index,
4247 #if NeedWidePrototypes
4248 		 int direction,
4249 		 int p_direction,
4250 #else
4251 		 XmDirection direction,
4252 		 XmDirection p_direction,
4253 #endif
4254 		 int depth)
4255 {
4256   _XmStringEntry        line;
4257   _XmStringNREntry 	seg, seg2;
4258   _XmStringNREntry 	last;
4259   XmDirection           pop_dir = 0;
4260   int                   pop_index = -1;
4261   int                   nseg, nline;
4262   int                   push_line;
4263 
4264   if (*line_index >= (nline = _XmStrLineCountGet(string)))
4265     return;
4266 
4267   if (_XmStrImplicitLine(string)) {
4268     line = _XmStrEntry(string)[*line_index];
4269     nseg = _XmEntrySegmentCountGet(line);
4270   } else
4271     nseg = _XmStrEntryCount(string);
4272 
4273   if (*seg_index >= nseg) {
4274     (*line_index)++;
4275     (*seg_index) = 0;
4276     if (*line_index >= nline)
4277       return;
4278   }
4279 
4280   if (*seg_index > 0)
4281     if (_XmStrImplicitLine(string))
4282       last = _XmEntrySegmentGet(line)[*seg_index-1];
4283     else
4284       last = (_XmStringNREntry)_XmStrEntry(string)[*seg_index-1];
4285   else
4286     last = NULL;
4287 
4288   while (*line_index < nline) {
4289     if (_XmStrImplicitLine(string)) {
4290       line = _XmStrEntry(string)[*line_index];
4291       nseg = _XmEntrySegmentCountGet(line);
4292     } else
4293       nseg = _XmStrEntryCount(string);
4294 
4295     while (*seg_index < nseg) {
4296 
4297       if (_XmStrImplicitLine(string))
4298 	seg = _XmEntrySegmentGet(line)[*seg_index];
4299       else
4300 	seg = (_XmStringNREntry)_XmStrEntry(string)[*seg_index];
4301 
4302       if (_XmEntryPushGet((_XmStringEntry)seg) &&
4303 	  !_XmEntryPopGet((_XmStringEntry)seg)) {
4304 	push_line = *line_index;
4305 	(*seg_index)++;
4306 	_XmEntryLayoutSet(seg, p_direction,
4307 			  (long)_XmEntryPushGet((_XmStringEntry)seg));
4308 	_XmEntryLayoutDepthSet(seg, p_direction, (long)++depth);
4309 	recursive_layout(string, line_index, seg_index,
4310 			 _XmEntryPushGet((_XmStringEntry)seg),
4311 			 p_direction, depth);
4312 
4313 	if (XmDirectionMatch(_XmEntryPushGet((_XmStringEntry)seg),direction)) {
4314 	  /* False push - treat as normal case */
4315 	  if (XmDirectionMatch(_XmEntryPushGet((_XmStringEntry)seg),
4316 			       XmLEFT_TO_RIGHT)) {
4317 	    if (last) {
4318 	      _XmEntryRightSet(last, p_direction, seg);
4319 	      _XmEntryLeftSet(seg, p_direction, last);
4320 	      _XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False);
4321 	    }
4322 	  } else
4323 	    if (last) {
4324 	      _XmEntryLeftSet(last, p_direction, seg);
4325 	      _XmEntryRightSet(seg, p_direction, last);
4326 	      _XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False);
4327 	    }
4328 	  if (_XmStrImplicitLine(string)) {
4329 	    if (*line_index < nline) {
4330 	      line = _XmStrEntry(string)[*line_index];
4331 	      nseg = _XmEntrySegmentCountGet(line);
4332 	      last = _XmEntrySegmentGet(line)[*seg_index];
4333 	    } else {
4334 	      line = NULL;
4335 	      nseg = 0;
4336 	      last = NULL;
4337 	    }
4338 	  } else {
4339 	    nseg = _XmStrEntryCount(string);
4340 	    last = (_XmStringNREntry)_XmStrEntry(string)[*seg_index];
4341 	  }
4342 	} else if (*line_index == push_line) {
4343 	  /* connect segment before push with pop segment
4344 	   */
4345 	  if (_XmStrImplicitLine(string))
4346 	    seg2 = _XmEntrySegmentGet(line)[*seg_index];
4347 	  else
4348 	    seg2 = (_XmStringNREntry)_XmStrEntry(string)[*seg_index];
4349 	  if (XmDirectionMatch(_XmEntryPushGet((_XmStringEntry)seg),
4350 			       XmLEFT_TO_RIGHT)) {
4351 	    if (last) {
4352 	      _XmEntryLeftSet(last, p_direction, seg2);
4353 	      _XmEntryRightSet(seg2, p_direction, last);
4354 	      _XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False);
4355 	      _XmEntryDirtySet(seg2, _XmSCANNING_CACHE, p_direction, False);
4356 	    }
4357 	  } else {
4358 	    if (last){
4359 	      _XmEntryRightSet(last, p_direction, seg2);
4360 	      _XmEntryLeftSet(seg2, p_direction, last);
4361 	      _XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False);
4362 	      _XmEntryDirtySet(seg2, _XmSCANNING_CACHE, p_direction, False);
4363 	    }
4364 	  }
4365 	  last = seg;
4366 	} else {
4367 	  /* pop is on a different line
4368 	   */
4369 	  if (last && nseg > 0) {
4370 	    /* connect last segment on line with the one before push
4371 	     */
4372 	    _XmStringNREntry conn_seg;
4373 	    if (_XmStrImplicitLine(string))
4374 	      conn_seg = _XmEntrySegmentGet(line)[nseg-1];
4375 	    else
4376 	      conn_seg = (_XmStringNREntry)_XmStrEntry(string)[nseg-1];
4377 	    if (XmDirectionMatch(_XmEntryPushGet((_XmStringEntry)seg),
4378 				 XmLEFT_TO_RIGHT)) {
4379 	      while (_XmEntryRightGet(conn_seg,  p_direction))
4380 		conn_seg =
4381 		  (_XmStringNREntry)_XmEntryRightGet(conn_seg, p_direction);
4382 	      _XmEntryLeftSet(last, p_direction, conn_seg);
4383 	      _XmEntryRightSet(conn_seg, p_direction, last);
4384 	      _XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False);
4385 	      _XmEntryDirtySet(conn_seg, _XmSCANNING_CACHE,
4386 			       p_direction, False);
4387 	    } else {
4388 	      while (_XmEntryLeftGet(conn_seg, p_direction))
4389 		conn_seg =
4390 		  (_XmStringNREntry)_XmEntryLeftGet(conn_seg, p_direction);
4391 	      _XmEntryRightSet(last, p_direction, conn_seg);
4392 	      _XmEntryLeftSet(conn_seg, p_direction, last);
4393 	      _XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False);
4394 	      _XmEntryDirtySet(conn_seg, _XmSCANNING_CACHE,
4395 			       p_direction, False);
4396 	    }
4397 	    last = NULL;
4398 	  }
4399 	  if (_XmStrImplicitLine(string)) {
4400 	    if (*line_index < nline) {
4401 	      line = _XmStrEntry(string)[*line_index];
4402 	      nseg = _XmEntrySegmentCountGet(line);
4403 	    } else {
4404 	      line = NULL;
4405 	      nseg = 0;
4406 	    }
4407 	  } else if (*line_index > 0)
4408 	    {
4409 	      line = NULL;
4410 	      nseg = 0;
4411 	    }
4412 	  else
4413 	    nseg = _XmStrEntryCount(string);
4414 	  /* save these things till we return from this level
4415 	   */
4416 	  pop_index = *seg_index;
4417 	  pop_dir = _XmEntryPushGet((_XmStringEntry)seg);
4418 	}
4419 	(*seg_index)++;
4420       } else if (!_XmEntryPushGet((_XmStringEntry)seg) &&
4421 		 _XmEntryPopGet((_XmStringEntry)seg)) {
4422 	/* attach this segment to the previous one */
4423 	if (last) {
4424 	  if (XmDirectionMatch(direction, XmLEFT_TO_RIGHT)) {
4425 	    _XmEntryLeftSet(seg, p_direction, last);
4426 	    _XmEntryRightSet(last, p_direction, seg);
4427 	  } else {
4428 	    _XmEntryRightSet(seg, p_direction, last);
4429 	    _XmEntryLeftSet(last, p_direction, seg);
4430 	  }
4431 	  _XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False);
4432 	}
4433 	_XmEntryLayoutSet(seg, p_direction, (long)direction);
4434 	_XmEntryLayoutDepthSet(seg, p_direction, (long)depth);
4435 	/* If we had a pop with its matching push on another line,
4436 	   now we know what will be adjacent to it in the layout
4437 	   If we popped from left-to-right, we will attach the leftmost
4438 	   segment in the previous level with the rightmost segment in
4439 	   the current level. Vice versa for right-to-left.
4440 	   */
4441 	if (pop_index >= 0 && pop_index != *seg_index) {
4442 	  if (_XmStrImplicitLine(string))
4443 	    last = _XmEntrySegmentGet(line)[pop_index];
4444 	  else
4445 	    last = (_XmStringNREntry)_XmStrEntry(string)[pop_index];
4446 	  if (XmDirectionMatch(pop_dir, XmLEFT_TO_RIGHT)) {
4447 	    while (_XmEntryLeftGet(last, p_direction))
4448 	      last = (_XmStringNREntry)_XmEntryLeftGet(last, p_direction);
4449 	    while (_XmEntryRightGet(seg, p_direction))
4450 	      seg = (_XmStringNREntry)_XmEntryRightGet(seg, p_direction);
4451 	    _XmEntryRightSet(seg, p_direction, last);
4452 	    _XmEntryLeftSet(last, p_direction, seg);
4453 	    _XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False);
4454 	    _XmEntryDirtySet(seg, _XmSCANNING_CACHE, p_direction, False);
4455 	  } else {
4456 	    while (_XmEntryRightGet(last, p_direction))
4457 	      last = (_XmStringNREntry)_XmEntryRightGet(last, p_direction);
4458 	    while (_XmEntryLeftGet(seg, p_direction))
4459 	      seg = (_XmStringNREntry)_XmEntryLeftGet(seg, p_direction);
4460 	    _XmEntryLeftSet(seg, p_direction, last);
4461 	    _XmEntryRightSet(last, p_direction, seg);
4462 	    _XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False);
4463 	    _XmEntryDirtySet(seg, _XmSCANNING_CACHE, p_direction, False);
4464 	  }
4465 	}
4466 	return;
4467       } else {
4468 	/* Default: No push/pop or push, pop in same segment */
4469 	/* set up connection */
4470 	if (last) {
4471 	  if (XmDirectionMatch(direction, XmLEFT_TO_RIGHT)) {
4472 	    _XmEntryLeftSet(seg, p_direction, last);
4473 	    _XmEntryRightSet(last, p_direction, seg);
4474 	  } else {
4475 	    _XmEntryRightSet(seg, p_direction, last);
4476 	    _XmEntryLeftSet(last, p_direction, seg);
4477 	  }
4478 	  _XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False);
4479 	}
4480 	last = seg;
4481 	_XmEntryLayoutSet(seg, p_direction, (long)direction);
4482 	_XmEntryLayoutDepthSet(seg, p_direction, (long)depth);
4483 	(*seg_index)++;
4484       }
4485     }
4486     /* If we had a pop with its matching push on another line,
4487        now we know what will be adjacent to it in the layout,
4488        namely the last segment on this line.
4489        */
4490     if (pop_index >= 0 && last) {
4491       if (pop_index != *seg_index-1)  {
4492 	if (_XmStrImplicitLine(string))
4493 	  seg2 = _XmEntrySegmentGet(line)[pop_index];
4494 	else
4495 	  seg2 = (_XmStringNREntry)_XmStrEntry(string)[pop_index];
4496 	if (XmDirectionMatch(pop_dir, XmLEFT_TO_RIGHT)) {
4497 	  _XmEntryRightSet(seg2, p_direction, last);
4498 	  _XmEntryLeftSet(last, p_direction, seg2);
4499 	} else {
4500 	  _XmEntryLeftSet(seg2, p_direction, last);
4501 	  _XmEntryRightSet(last, p_direction, seg2);
4502 	}
4503 	_XmEntryDirtySet(last, _XmSCANNING_CACHE, p_direction, False);
4504 	_XmEntryDirtySet(seg2, _XmSCANNING_CACHE, p_direction, False);
4505       }
4506       pop_index = -1;
4507     }
4508     (*line_index)++;
4509     (*seg_index) = 0;
4510     last = NULL;
4511   }
4512 }
4513 
4514 
4515 void
_XmStringLayout(_XmString string,int direction)4516 _XmStringLayout(_XmString string,
4517 #if NeedWidePrototypes
4518 		int direction)
4519 #else
4520                 XmDirection direction)
4521 #endif
4522 {
4523   int seg_index=0, line_index=0;
4524   _XmStringEntry        line;
4525   _XmStringNREntry 	seg;
4526   Boolean needs_recompute = False;
4527 
4528   if (!_XmStrMultiple(string))
4529     return;
4530 
4531   if (_XmStrEntryCount(string)) {
4532     line = _XmStrEntry(string)[0];
4533     if (_XmEntrySegmentCountGet(line)) {
4534       seg = _XmEntrySegmentGet(line)[0];
4535       needs_recompute = _XmEntryDirtyGet(seg, _XmSCANNING_CACHE, direction);
4536     }
4537   }
4538 
4539   if (!needs_recompute)
4540     return;
4541 
4542   while (line_index < _XmStrEntryCount(string)) {
4543     line = _XmStrEntry(string)[line_index];
4544     while (seg_index < _XmEntrySegmentCountGet(line)) {
4545       seg = _XmEntrySegmentGet(line)[seg_index];
4546       if (_XmEntrySegmentCountGet(line) > 1) {
4547 	_XmEntryDirtySet(seg, _XmSCANNING_CACHE, direction, True);
4548 	_XmEntryLeftSet(seg, direction, NULL);
4549 	_XmEntryRightSet(seg, direction, NULL);
4550       }
4551       seg_index++;
4552     }
4553     seg_index = 0;
4554     line_index++;
4555   }
4556 
4557   line_index = seg_index = 0;
4558   recursive_layout(string, &line_index, &seg_index,
4559 		   direction, direction, 0);
4560 
4561   /* if there are pops w/o matching pushes, ignore them */
4562   while (line_index < _XmStrLineCountGet(string) &&
4563 	 seg_index < _XmEntrySegmentCountGet(_XmStrEntry(string)[line_index]))
4564     {
4565       line = _XmStrEntry(string)[line_index];
4566       seg = _XmEntrySegmentGet(line)[seg_index];
4567       _XmEntryPopSet(seg, False);
4568       recursive_layout(string, &line_index, &seg_index,
4569 		       direction, direction, 0);
4570       _XmEntryPopSet(seg, True);
4571     }
4572 }
4573 
4574 /****************************************************************
4575  *  What's the layout direction at the end of the line?
4576  ****************************************************************/
4577 static void
last_direction(_XmStringEntry line,int * index,XmDirection * direction)4578 last_direction(_XmStringEntry line,
4579 	       int *index,
4580 	       XmDirection *direction)
4581 {
4582   _XmStringNREntry      seg;
4583   XmDirection         sub_dir = *direction;
4584 
4585   while (*index < _XmEntrySegmentCountGet(line))
4586     {
4587       seg = _XmEntrySegmentGet(line)[*index];
4588       if (_XmEntryPushGet((_XmStringEntry)seg) &&
4589 	  !_XmEntryPopGet((_XmStringEntry)seg)) {
4590         sub_dir = _XmEntryPushGet((_XmStringEntry)seg);
4591         (*index)++;
4592         last_direction(line, index, &sub_dir);
4593         if (*index < _XmEntrySegmentCountGet(line))
4594           sub_dir = *direction;
4595         (*index)++;
4596       } else if (!_XmEntryPushGet((_XmStringEntry)seg) &&
4597 		 _XmEntryPopGet((_XmStringEntry)seg))
4598          return;
4599       else
4600         (*index)++;
4601     }
4602   *direction = sub_dir;
4603 }
4604 
4605 /*
4606  * Draw a single internal TCS line
4607  */
4608 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,int image,_XmString * underline,int descender,int opt,int opt_width,int opt_height)4609 DrawLine(
4610 	 Display *d,
4611 	 Window w,
4612 	 Screen **pscreen,
4613 	 int x,
4614 	 int y,
4615 	 _XmStringEntry line,
4616 	 XmRendition *scr_rend,
4617 	 XmRendition base,
4618 	 XmRenderTable rendertable,
4619 	 XmDirection prim_dir,
4620 #if NeedWidePrototypes
4621 	 int image,
4622 #else
4623 	 Boolean image,
4624 #endif /* NeedWidePrototypes */
4625 	 _XmString *underline,
4626 #if NeedWidePrototypes
4627 	 int descender,
4628 	 int opt,
4629 	 int opt_width,
4630 	 int opt_height
4631 #else
4632 	 Dimension descender,
4633 	 Boolean opt,
4634 	 Dimension opt_width,
4635 	 Dimension opt_height
4636 #endif /* NeedWidePrototypes */
4637 	 )
4638 {
4639   int				i, prev_val, val, offset;
4640   XmTabList			tl = NULL;
4641   XmTab				tab;
4642   unsigned short		tab_cnt;
4643 
4644   /* Absolute tabs use this as left margin */
4645   offset = x;
4646 
4647   if (opt)
4648     {
4649       /*
4650        * This is optimized; build an optimized segment and call the drawing
4651        * routine.
4652        */
4653       _XmStringOptSegRec	segm;
4654       _XmString 		optline = (_XmString)line;
4655 
4656       _XmEntryInit((_XmStringEntry)&segm, XmSTRING_ENTRY_OPTIMIZED);
4657 
4658       _XmEntryTagIndex(&segm) = _XmStrTagIndex(optline);
4659 
4660       _XmEntryByteCountSet(&segm, _XmStrByteCount(optline));
4661       _XmEntryTextTypeSet(&segm,
4662 			  (XmTextType) _XmStrTextType(optline));
4663       _XmEntryTextSet((_XmStringEntry)&segm, _XmStrText(optline));
4664        if (_XmStrDirection(optline) != XmSTRING_DIRECTION_UNSET)
4665 	 _XmEntryDirectionSet((_XmStringEntry)&segm, _XmStrDirection(optline));
4666        else
4667 	 _XmEntryDirectionSet((_XmStringEntry)&segm,
4668 			      XmDirectionToStringDirection(prim_dir));
4669 
4670       if (_XmStrRendBegin(optline))
4671 	  _XmEntryRendIndex(&segm) = _XmStrRendIndex(optline);
4672 
4673       if (*scr_rend != NULL) tl = _XmRendTabs(*scr_rend);
4674 
4675       tab = (tl == NULL) ? NULL : _XmTabLStart(tl);
4676 
4677       prev_val = x;
4678       tab_cnt = 0;
4679 
4680       if ((tab != NULL) &&
4681 	  (_XmEntryTabsGet((_XmStringEntry)&segm) != 0) &&
4682 	  (tab_cnt < _XmTabLCount(tl)) &&
4683 	  _XmEntryDirectionGet((_XmStringEntry)&segm) !=
4684 	  XmSTRING_DIRECTION_R_TO_L)
4685 	{
4686 	  for (i = 0;
4687 	       (i < _XmEntryTabsGet((_XmStringEntry)&segm)) &&
4688 	       (tab_cnt < _XmTabLCount(tl));
4689 	       i++, tab = _XmTabNext(tab), tab_cnt++)
4690 	    {
4691 	      val = TabVal(d, pscreen, w, tab);
4692 	      if (_XmTabModel(tab) == XmABSOLUTE)
4693 		{
4694 		  x = val + offset;
4695 		  prev_val = x;
4696 		}
4697 	      else				  /* XmRELATIVE */
4698 		{
4699 		  x = prev_val + val;
4700 		  prev_val += val;
4701 		}
4702 	    }
4703 	}
4704 
4705       _XmStringDrawSegment(d, w, x, y, opt_width, opt_height,
4706 			   (_XmStringNREntry)&segm, *scr_rend, rendertable,
4707 			   image, underline, descender);
4708     }
4709   else {
4710     _XmStringNREntry 	seg;
4711     int			seg_index = 0;
4712     Boolean		ok;
4713     Dimension		width, height;
4714     Boolean             set_direction = False;
4715     XmDirection         lay_dir = prim_dir; /* layout direction of this line */
4716 
4717     seg = _XmEntrySegmentGet(line)[seg_index];
4718 
4719     if (_XmEntryType(seg) != XmSTRING_ENTRY_OPTIMIZED) {
4720       lay_dir = _XmEntryLayoutGet(seg, prim_dir);
4721     }
4722 
4723     if (XmDirectionMatch(lay_dir, XmLEFT_TO_RIGHT)) {
4724 
4725       if (_XmEntryType(seg) != XmSTRING_ENTRY_OPTIMIZED) {
4726 	while (_XmEntryLeftGet(seg, prim_dir) != NULL)
4727 	  seg = (_XmStringNREntry)_XmEntryLeftGet(seg, prim_dir);
4728       }
4729 
4730       if (_XmEntryDirectionGet((_XmStringEntry)seg) ==
4731 	  XmSTRING_DIRECTION_UNSET) {
4732 	_XmEntryDirectionSet((_XmStringEntry)seg,
4733 			     XmDirectionToStringDirection(prim_dir));
4734 	set_direction = True;
4735       }
4736 
4737       ok = SpecifiedSegmentExtents((_XmStringEntry)seg, rendertable, scr_rend,
4738 				   base, XmSTRING_MIDDLE_SEG,
4739 				   &width, &height, NULL, NULL);
4740 
4741       if (*scr_rend != NULL) tl = _XmRendTabs(*scr_rend);
4742 
4743       tab = (tl == NULL) ? NULL : _XmTabLStart(tl);
4744 
4745       prev_val = x;
4746       tab_cnt = 0;
4747 
4748       while (seg != NULL)
4749 	{
4750 	  /* If this segment is tabbed, set x accordingly. */
4751 	  if ((tab != NULL) &&
4752 	      (_XmEntryTabsGet((_XmStringEntry)seg) != 0) &&
4753 	      (tab_cnt < _XmTabLCount(tl)))
4754 	    {
4755 	      int start_x = x;
4756 
4757 	      for (i = 0;
4758 		   (i < _XmEntryTabsGet((_XmStringEntry)seg)) &&
4759 		   (tab_cnt < _XmTabLCount(tl));
4760 		   i++, tab = _XmTabNext(tab), tab_cnt++)
4761 		{
4762 		  val = TabVal(d, pscreen, w, tab);
4763 
4764 		  if (_XmTabModel(tab) == XmABSOLUTE)
4765 		    x = MAX(x, (val + offset));
4766 		  else				  /* XmRELATIVE */
4767 		    x = MAX(x, prev_val + val);
4768 
4769 		  prev_val = x;
4770 		}
4771 
4772 	      _XmStringDrawLining(d, w, start_x, y,
4773 				  (x - start_x), height, descender,
4774 				  *scr_rend, XmUNSPECIFIED_PIXEL,
4775 				  XmHIGHLIGHT_NORMAL, FALSE);
4776 	    }
4777 
4778 	  if (ok)
4779 	    _XmStringDrawSegment(d, w, x, y, width, height, seg, *scr_rend,
4780 				 rendertable, image, underline, descender);
4781 
4782 	  x += width;
4783 
4784 	  if (set_direction) {
4785 	    _XmEntryDirectionSet((_XmStringEntry)seg,
4786 				 XmSTRING_DIRECTION_UNSET);
4787 	    set_direction = False;
4788 	  }
4789 
4790 	  if (_XmEntryType(seg) != XmSTRING_ENTRY_OPTIMIZED) {
4791 	    seg = (_XmStringNREntry)_XmEntryRightGet(seg, prim_dir);
4792 	  } else {
4793 	    seg_index++;
4794 	    seg = (seg_index < _XmEntrySegmentCountGet(line) ?
4795 		   _XmEntrySegmentGet(line)[seg_index] :
4796 		   NULL);
4797 	  }
4798 	  if (seg != NULL) {
4799 	    if (_XmEntryDirectionGet((_XmStringEntry)seg) ==
4800 		XmSTRING_DIRECTION_UNSET) {
4801 	      _XmEntryDirectionSet((_XmStringEntry)seg,
4802 				   XmDirectionToStringDirection(prim_dir));
4803 	      set_direction = True;
4804 	    }
4805 	    ok = SpecifiedSegmentExtents((_XmStringEntry)seg, rendertable,
4806 					 scr_rend,
4807 					 base, XmSTRING_MIDDLE_SEG,
4808 					 &width, &height, NULL, NULL);
4809 	  }
4810 	}
4811     } else {
4812       if (_XmEntryType(seg) != XmSTRING_ENTRY_OPTIMIZED) {
4813 	while (_XmEntryRightGet(seg, prim_dir) != NULL)
4814 	  seg = (_XmStringNREntry)_XmEntryRightGet(seg, prim_dir);
4815       }
4816 
4817       if (_XmEntryDirectionGet((_XmStringEntry)seg) ==
4818 	  XmSTRING_DIRECTION_UNSET) {
4819 	_XmEntryDirectionSet((_XmStringEntry)seg,
4820 			     XmDirectionToStringDirection(prim_dir));
4821 	set_direction = True;
4822       }
4823 
4824       ok = SpecifiedSegmentExtents((_XmStringEntry)seg, rendertable, scr_rend,
4825 				   base, XmSTRING_MIDDLE_SEG,
4826 				   &width, &height, NULL, NULL);
4827 
4828       if (*scr_rend != NULL) tl = _XmRendTabs(*scr_rend);
4829 
4830       tab = (tl == NULL) ? NULL : _XmTabLStart(tl);
4831 
4832       x += opt_width;
4833       offset = prev_val = x;
4834       tab_cnt = 0;
4835 
4836       while (seg != NULL)
4837 	{
4838 	  /* If this segment is tabbed, set x accordingly. */
4839 	  if ((tab != NULL) &&
4840 	      (_XmEntryTabsGet((_XmStringEntry)seg) != 0) &&
4841 	      (tab_cnt < _XmTabLCount(tl)))
4842 	    {
4843 	      int start_x = x;
4844 
4845 	      for (i = 0;
4846 		   (i < _XmEntryTabsGet((_XmStringEntry)seg)) &&
4847 		   (tab_cnt < _XmTabLCount(tl));
4848 		   i++, tab = _XmTabNext(tab), tab_cnt++)
4849 		{
4850 		  val = TabVal(d, pscreen, w, tab);
4851 
4852 		  if (_XmTabModel(tab) == XmABSOLUTE)
4853 		    x = MIN(x, offset - val);
4854 		  else				  /* XmRELATIVE */
4855 		    x = MIN(x, prev_val - val);
4856 
4857 		  prev_val = x;
4858 		}
4859 
4860 	      _XmStringDrawLining(d, w, x, y,
4861 				  (start_x - x), height, descender,
4862 				  *scr_rend, XmUNSPECIFIED_PIXEL,
4863 				  XmHIGHLIGHT_NORMAL, FALSE);
4864 	    }
4865 
4866 	  x -= width;
4867 
4868 	  if (ok)
4869 	    _XmStringDrawSegment(d, w, x, y, width, height, seg, *scr_rend,
4870 				 rendertable, image, underline, descender);
4871 
4872 	  if (set_direction) {
4873 	    _XmEntryDirectionSet((_XmStringEntry)seg,
4874 				 XmSTRING_DIRECTION_UNSET);
4875 	    set_direction = False;
4876 	  }
4877 
4878 	  if (_XmEntryType(seg) != XmSTRING_ENTRY_OPTIMIZED) {
4879 	    seg = (_XmStringNREntry)_XmEntryLeftGet(seg, prim_dir);
4880 	  } else {
4881 	    seg_index++;
4882 	    seg = (seg_index < _XmEntrySegmentCountGet(line) ?
4883 		   _XmEntrySegmentGet(line)[seg_index] :
4884 		   NULL);
4885 	  }
4886 	  if (seg != NULL) {
4887 	    if (_XmEntryDirectionGet((_XmStringEntry)seg) ==
4888 		XmSTRING_DIRECTION_UNSET) {
4889 	      _XmEntryDirectionSet((_XmStringEntry)seg,
4890 				   XmDirectionToStringDirection(prim_dir));
4891 	      set_direction = True;
4892 	    }
4893 	    ok = SpecifiedSegmentExtents((_XmStringEntry)seg, rendertable,
4894 					 scr_rend,
4895 					 base, XmSTRING_MIDDLE_SEG,
4896 					 &width, &height, NULL, NULL);
4897 	  }
4898 	}
4899     }
4900   }
4901 }
4902 
4903 /*
4904  * calculate the alignment, position and clipping for the string
4905  */
4906 static void
_calc_align_and_clip(Display * d,Window w,GC gc,Position * x,int y,int width,int line_width,int line_height,unsigned int lay_dir,XRectangle * clip,unsigned int align,int descender,int * restore,XmFontType font_type)4907 _calc_align_and_clip(
4908         Display *d,
4909 	Window w,
4910         GC gc,
4911         Position *x,
4912 #if NeedWidePrototypes
4913         int y,
4914         int width,
4915 #else
4916         Position y,
4917         Dimension width,
4918 #endif /* NeedWidePrototypes */
4919         int line_width,
4920 #ifdef FIX_1488
4921         int line_height,
4922 #endif
4923 #if NeedWidePrototypes
4924         unsigned int lay_dir,
4925 #else
4926         unsigned char lay_dir,
4927 #endif /* NeedWidePrototypes */
4928         XRectangle *clip,
4929 #if NeedWidePrototypes
4930         unsigned int align,
4931 #else
4932         unsigned char align,
4933 #endif /* NeedWidePrototypes */
4934         int descender,
4935         int *restore,
4936 	XmFontType font_type)
4937 {
4938 
4939     Boolean l_to_r = XmDirectionMatch(lay_dir, XmSTRING_DIRECTION_L_TO_R);
4940 
4941 
4942     switch (align)
4943     {
4944     	case XmALIGNMENT_BEGINNING:
4945 	    if ( ! l_to_r) *x += width - line_width;
4946 	    break;
4947 
4948     	case XmALIGNMENT_CENTER:
4949 	    *x += Half (width) - Half (line_width);
4950 	    break;
4951 
4952     	case XmALIGNMENT_END :
4953 	    if (l_to_r)
4954 	    	*x += width - line_width;
4955 	    break;
4956    }
4957 
4958     if ((clip != NULL) && ( ! *restore))
4959 
4960 #ifdef FIX_1488
4961         if (((*x) <= clip->x + clip->width) &&
4962             (clip->x <= (*x) + line_width) &&
4963             (y - line_height + descender <= clip->y + clip->height) &&
4964             (clip->y <= y + descender))
4965 #else
4966 /* BEGIN OSF Fix CR 5106 */
4967         if ((line_width > clip->width) ||
4968 /* END OSF Fix CR 5106 */
4969 	     (y + descender) > (clip->y + clip->height))
4970 #endif
4971 	{
4972 	    *restore = TRUE;
4973 #ifdef USE_XFT
4974             if (font_type == XmFONT_IS_XFT)
4975 	      _XmXftSetClipRectangles(d, w, 0, 0, clip, 1);
4976 #ifndef FIX_1532
4977 	    else
4978 #endif
4979 #endif
4980             XSetClipRectangles (d, gc, 0, 0, clip, 1, YXBanded);
4981 	}
4982 
4983 }
4984 
4985 /*
4986  * draw a complete internal format TCS
4987  */
4988 static void
_draw(Display * d,Window w,XmRenderTable rendertable,_XmString string,GC gc,int x,int y,int width,unsigned int align,unsigned int lay_dir,XRectangle * clip,int image,_XmString underline)4989 _draw(
4990         Display *d,
4991         Window w,
4992         XmRenderTable rendertable,
4993         _XmString string,
4994         GC gc,
4995 #if NeedWidePrototypes
4996         int x,
4997         int y,
4998         int width,
4999         unsigned int align,
5000         unsigned int lay_dir,
5001 #else
5002         Position x,
5003         Position y,
5004         Dimension width,
5005         unsigned char align,
5006         unsigned char lay_dir,
5007 #endif /* NeedWidePrototypes */
5008         XRectangle *clip,
5009 #if NeedWidePrototypes
5010         int image,
5011 #else
5012         Boolean image,
5013 #endif /* NeedWidePrototypes */
5014         _XmString underline )
5015 {
5016   static XmRendition	rend = NULL;
5017 
5018   if (!string) return;
5019 
5020   _XmProcessLock();
5021   if (rend == NULL) rend = XmRenditionCreate(NULL, XmS, NULL, 0);
5022 
5023   _XmRendDisplay(rend) = d;
5024   _XmRendGC(rend) = gc;
5025   _XmRendTags(rend) = NULL;
5026   _XmRendTagCount(rend) = 0;
5027 
5028   _render(d, w, rendertable, rend, string, x, y, width,
5029 	  align, lay_dir, image, underline, clip);
5030   _XmProcessUnlock();
5031 }
5032 
5033 /*
5034  * render a complete internal format TCS
5035  */
5036 static void
_render(Display * d,Drawable w,XmRenderTable rendertable,XmRendition rend,_XmString string,int x,int y,int width,unsigned int align,unsigned int lay_dir,int image,_XmString underline,XRectangle * clip)5037 _render(Display *d,
5038         Drawable w,
5039         XmRenderTable rendertable,
5040 	XmRendition rend,
5041         _XmString string,
5042 #if NeedWidePrototypes
5043         int x,
5044         int y,
5045         int width,
5046         unsigned int align,
5047         unsigned int lay_dir,
5048         int image,
5049 #else
5050         Position x,
5051         Position y,
5052         Dimension width,
5053         unsigned char align,
5054         unsigned char lay_dir,
5055         Boolean image,
5056 #endif /* NeedWidePrototypes */
5057 	_XmString underline,
5058         XRectangle *clip)
5059 {
5060   Position base_x = x, draw_x;
5061   Dimension line_width, line_height, ascender = 0, descender = 0;
5062   _XmStringEntry line;
5063   int i;
5064   int restore_clip = FALSE;
5065   _XmRenditionRec	scratch1, scratch2;
5066   _XmRendition		tmp1, tmp2;
5067   XmRendition		rend1, rend2;
5068   GC			gc;
5069   Screen		*screen = NULL;
5070 
5071   if (!string) return;
5072 
5073   tmp1 = &scratch1;
5074   bzero((char *)tmp1, sizeof(_XmRenditionRec));
5075   rend1 = &tmp1;
5076   tmp2 = &scratch2;
5077   bzero((char *)tmp2, sizeof(_XmRenditionRec));
5078   rend2 = &tmp2;
5079 
5080   _XmRendDisplay(rend1) = _XmRendDisplay(rend2) = d;
5081   gc = _XmRendGC(rend1) = _XmRendGC(rend2) = _XmRendGC(rend);
5082   _XmRendTags(rend1) = _XmRendTags(rend2) = NULL;
5083   _XmRendTagCount(rend1) = _XmRendTagCount(rend2) = 0;
5084 
5085   if (lay_dir <= 1) /* got passed XmStringDirection value */
5086     lay_dir = XmStringDirectionToDirection(lay_dir);
5087 
5088   if (_XmStrOptimized(string))
5089     {
5090       OptLineMetrics(rendertable, string, &rend2, rend,
5091 		     &line_width, &line_height, &ascender, &descender);
5092 	y += ascender;
5093 
5094         if (line_width != 0)
5095           {
5096             draw_x = base_x ; /* most left position */
5097             _calc_align_and_clip( d, w, gc, &draw_x, y, width, line_width,
5098 #ifdef FIX_1488
5099                                 line_height, lay_dir, clip, align, descender,
5100 #else
5101                                 lay_dir, clip, align, descender,
5102 #endif
5103 #ifdef FIX_1521
5104                                 &restore_clip, _XmRendFontType(rend2));
5105 #else
5106                                 &restore_clip, _XmRendFontType(rend));
5107 #endif
5108 
5109             DrawLine(d, w, &screen, draw_x, y, (_XmStringEntry)string,
5110 		     &rend2, rend, rendertable, lay_dir, image,
5111 		     &underline, descender, TRUE, line_width, line_height);
5112           }
5113         y += descender ;      /* go to bottom of this line */
5114       }
5115   else {
5116     XmDirection 		direction = lay_dir;
5117     int 			val;
5118     _XmStringArraySegRec	array_seg;
5119 
5120     _XmStringLayout(string, lay_dir);
5121 
5122     for (i = 0; i < _XmStrLineCountGet(string); i++)
5123       {
5124 	if (_XmStrImplicitLine(string))
5125 	  {
5126 	    line = _XmStrEntry(string)[i];
5127 	  }
5128 	else
5129 	  {
5130 	    _XmEntryType(&array_seg) = XmSTRING_ENTRY_ARRAY;
5131 	    _XmEntrySegmentCount(&array_seg) = _XmStrEntryCount(string);
5132 	    _XmEntrySegment(&array_seg) = (_XmStringNREntry *)_XmStrEntry(string);
5133 	    line = (_XmStringEntry)&array_seg;
5134 	  }
5135 
5136 	/* width, height, ascent, descent of this line */
5137 #ifdef FIX_1521
5138 	LineMetrics(line, rendertable, &rend1, rend, lay_dir,
5139 #else
5140 	LineMetrics(line, rendertable, &rend2, rend, lay_dir,
5141 #endif
5142 		    &line_width, &line_height, &ascender, &descender);
5143 
5144 	y += ascender;
5145 
5146 	if (line_width != 0)
5147 	  {
5148 	    draw_x = base_x;			  /* most left position */
5149 
5150 	    _calc_align_and_clip(d, w, gc, &draw_x, y, width, line_width,
5151 #ifdef FIX_1488
5152 	            line_height, direction, clip, align, descender,
5153 #else
5154 				 direction, clip, align, descender,
5155 #endif
5156 #ifdef FIX_1521
5157 				 &restore_clip, _XmRendFontType(rend1));
5158 #else
5159 				 &restore_clip, _XmRendFontType(rend));
5160 #endif
5161 
5162 	    DrawLine(d, w, &screen, draw_x, y, line, &rend1, rend,
5163 		     rendertable, lay_dir, image, &underline,
5164 		     descender, FALSE, line_width, line_height);
5165 	    val = 0;
5166 	    last_direction((_XmStringEntry)line, &val, &direction);
5167 	    if (val < _XmEntrySegmentCountGet(line))
5168 	      /* found an 'unmatched' pop */
5169 	      direction = lay_dir;
5170 	  }
5171 
5172 	y += descender;			  /* go to bottom of this line */
5173       }
5174   }
5175   if (restore_clip) {
5176 #ifdef FIX_1521
5177 #ifdef USE_XFT
5178 	  if (_XmRendFontType((_XmStrOptimized(string)) ? rend2 : rend1) == XmFONT_IS_XFT) {
5179 		  XftDraw *draw = _XmXftDrawCreate(d, w);
5180 		  XftDrawSetClip(draw, NULL);
5181 	  } else
5182 #endif
5183 #endif
5184 		  XSetClipMask (d, gc, None);
5185   }
5186 
5187   if (_XmRendTags(rend1) != NULL) XtFree((char *)_XmRendTags(rend1));
5188   if (_XmRendTags(rend2) != NULL) XtFree((char *)_XmRendTags(rend2));
5189 }
5190 
5191 void
_XmStringRender(Display * d,Drawable w,XmRenderTable rendertable,XmRendition rend,_XmString string,int x,int y,int width,unsigned int align,unsigned int lay_dir)5192 _XmStringRender(Display *d,
5193 		Drawable w,
5194 		XmRenderTable rendertable,
5195 		XmRendition rend,
5196 		_XmString string,
5197 #if NeedWidePrototypes
5198 		int x,
5199 		int y,
5200 		int width,
5201 		unsigned int align,
5202 		unsigned int lay_dir
5203 #else
5204 		Position x,
5205 		Position y,
5206 		Dimension width,
5207 		unsigned char align,
5208 		unsigned char lay_dir
5209 #endif						  /* NeedWidePrototypes */
5210 		)
5211 {
5212   _render(d, w, rendertable, rend, string, x, y, width,
5213 	  align, lay_dir, FALSE, NULL, NULL);
5214 }
5215 
5216 /*
5217  * add a new segment to a particular line in an XmString
5218  */
5219 void
_XmStringSegmentNew(_XmString string,int line_index,_XmStringEntry value,int copy)5220 _XmStringSegmentNew(
5221         _XmString string,
5222         int line_index,
5223         _XmStringEntry value,
5224 	int copy)
5225 {
5226     _XmStringEntry line;
5227     _XmStringEntry seg;
5228     int sc;
5229     int lc = _XmStrEntryCount(string);
5230 
5231     if (lc == 0 || lc-1 < line_index) {
5232       _XmStrEntry(string) = (_XmStringEntry *)
5233 	XtRealloc((char *) _XmStrEntry(string),
5234 		  sizeof(_XmStringEntry) * (lc + 1));
5235       _XmStrEntryCount(string)++;
5236       if (line_index > lc) line_index = lc;
5237       if (copy)
5238 	line = _XmStringEntryCopy(value);
5239       else {
5240 	line = value;
5241       }
5242       _XmStrEntry(string)[line_index] = line;
5243     } else {
5244       line  = _XmStrEntry(string)[line_index];
5245       if (!_XmEntryMultiple(line)) {
5246 	/* have to create an array entry */
5247 	sc = 1;
5248 	seg = line;
5249 	_XmEntryCreate(line, XmSTRING_ENTRY_ARRAY);
5250 	_XmEntrySegmentCount(line) = sc;
5251 	_XmEntrySoftNewlineSet(line, _XmEntrySoftNewlineGet(seg));
5252 	_XmEntrySegment(line) = (_XmStringNREntry *)
5253 	  XtMalloc(sizeof(_XmStringEntry) * 2);
5254 	_XmEntrySegment(line)[0] = (_XmStringNREntry)seg;
5255 	_XmStrEntry(string)[line_index] = line;
5256 	_XmStrImplicitLine(string) = True;
5257       } else {
5258 	sc  = _XmEntrySegmentCount(line);
5259 	_XmEntrySegment(line) = (_XmStringNREntry *)
5260 	  XtRealloc((char *) _XmEntrySegment(line),
5261 		    sizeof(_XmStringEntry) * (sc+1));
5262       }
5263       seg = (copy ? _XmStringEntryCopy(value) : value);
5264       _XmEntrySegment(line)[sc] = (_XmStringNREntry)seg;
5265       _XmEntrySegmentCount(line)++;
5266     }
5267 }
5268 
5269 static _XmString
_XmStringOptCreate(unsigned char * c,unsigned char * end,unsigned int textlen,int havetag,unsigned int tag_index)5270 _XmStringOptCreate(
5271         unsigned char *c,
5272         unsigned char *end,
5273 #if NeedWidePrototypes
5274         unsigned int textlen,
5275         int havetag,
5276 #else
5277         unsigned short textlen,
5278         Boolean havetag,
5279 #endif /* NeedWidePrototypes */
5280         unsigned int tag_index )
5281 {
5282   _XmString      string;
5283   char          *tag = NULL;
5284   unsigned short length;
5285 
5286   _XmStrCreate(string, XmSTRING_OPTIMIZED, textlen);
5287   if (havetag)
5288     {
5289       _XmStrTagIndex((_XmString)string) = tag_index ;
5290     }
5291   else
5292     {
5293       tag = XmFONTLIST_DEFAULT_TAG;
5294       _XmStrTagIndex((_XmString)string) =
5295 	_XmStringIndexCacheTag((char *) tag, XmSTRING_TAG_STRLEN);
5296     }
5297 
5298   while (c < end)
5299     {
5300       length = _read_asn1_length (c);
5301 
5302       switch (*c)
5303 	{
5304 	case XmSTRING_COMPONENT_RENDITION_BEGIN:
5305 	  _XmStrRendIndex(string) =
5306 	    _XmStringIndexCacheTag((char *)(c + _asn1_size(length)),
5307 				   (int)length);
5308 	  _XmStrRendBegin(string) = TRUE;
5309 	  break;
5310 
5311         case XmSTRING_COMPONENT_LOCALE:
5312 	  _XmStrTextType((_XmString)string) = XmMULTIBYTE_TEXT;
5313 	  break;
5314 
5315         case XmSTRING_COMPONENT_TAG:
5316 	  _XmStrTextType((_XmString)string) = XmCHARSET_TEXT;
5317 	  break;
5318 
5319 	case XmSTRING_COMPONENT_TAB:
5320 	  _XmStrTabs(string)++;
5321 	  break;
5322 
5323 	case XmSTRING_COMPONENT_DIRECTION:		/* record dir */
5324 	  _XmStrDirection((_XmString) string) =
5325 	    ((XmStringDirection)*(c + _asn1_size(length)));
5326 	  break;
5327 
5328 	case XmSTRING_COMPONENT_TEXT:
5329 	  _XmStrTextType((_XmString)string) = XmCHARSET_TEXT;
5330 	  memcpy(_XmStrText((_XmString)string), (c + _asn1_size(length)),
5331 		 textlen);
5332 	  break;
5333 
5334 	case XmSTRING_COMPONENT_LOCALE_TEXT:
5335 	  _XmStrTextType((_XmString)string) = XmMULTIBYTE_TEXT;
5336 	  memcpy(_XmStrText((_XmString)string), (c + _asn1_size(length)),
5337 		 textlen);
5338 	  break;
5339 
5340 	case XmSTRING_COMPONENT_RENDITION_END:
5341 	  _XmStrRendIndex(string) =
5342 	    _XmStringIndexCacheTag((char *)(c + _asn1_size(length)),
5343 				   (int)length);
5344 	  _XmStrRendEnd(string) = TRUE;
5345 	  break;
5346 
5347 	case XmSTRING_COMPONENT_SEPARATOR:		/* start new line */
5348 	  _XmStrFree ((char *) string);
5349 	  return (NULL);
5350 	  /* break; */
5351 
5352 	default:
5353 	  break;
5354 	}
5355 
5356       c += length + _asn1_size(length);
5357     }
5358 
5359   return((_XmString) string);
5360 }
5361 
5362 static void
finish_segment(_XmString str,_XmStringUnoptSeg seg,int * lc,int * sc,Boolean * unopt,XmStringDirection dir)5363 finish_segment(_XmString str,
5364 	       _XmStringUnoptSeg seg,
5365 	       int *lc,
5366 	       int *sc,
5367 	       Boolean *unopt,
5368 	       XmStringDirection dir)
5369 {
5370   _XmStringEntry opt_seg;
5371 
5372   _XmEntryDirectionSet((_XmStringEntry)seg, dir);
5373 
5374   if (!*unopt &&
5375       (opt_seg = EntryCvtToOpt((_XmStringEntry)seg)))
5376     _XmStringSegmentNew(str, _XmStrImplicitLine(str) ? *lc : *sc,
5377 		opt_seg, False);
5378   else
5379     _XmStringSegmentNew(str, _XmStrImplicitLine(str) ? *lc : *sc,
5380 		(_XmStringEntry)seg, True);
5381   (*sc)++;
5382   *unopt = False;
5383   _XmEntryInit((_XmStringEntry)seg, XmSTRING_ENTRY_UNOPTIMIZED);
5384 }
5385 
5386 
5387 static _XmString
_XmStringNonOptCreate(unsigned char * c,unsigned char * end,int havetag)5388 _XmStringNonOptCreate(
5389         unsigned char *c,
5390         unsigned char *end,
5391 #if NeedWidePrototypes
5392         int havetag )
5393 #else
5394         Boolean havetag )
5395 #endif /* NeedWidePrototypes */
5396 {
5397   int lc, sc;
5398   _XmStringUnoptSegRec seg;
5399   unsigned short length;
5400   _XmString string ;
5401   char *tag = NULL;
5402   Boolean needs_unopt = False;
5403   Boolean txt_seen = False;
5404   Boolean push_seen = False;
5405   Boolean pop_seen = False;
5406   Boolean need_finish = False;
5407   int rend_cnt;
5408   int tab_cnt;
5409   XmTextType prev_type = XmCHARSET_TEXT;
5410   XmStringDirection dir = XmSTRING_DIRECTION_UNSET;
5411 
5412   _XmStrCreate(string, XmSTRING_MULTIPLE_ENTRY, 0);
5413   _XmEntryInit((_XmStringEntry)&seg, XmSTRING_ENTRY_UNOPTIMIZED);
5414 
5415   if (!havetag)
5416     {
5417       tag = XmFONTLIST_DEFAULT_TAG;
5418       _XmUnoptSegTag(&seg) =
5419 	_XmStringCacheTag((char *) (tag), XmSTRING_TAG_STRLEN);
5420     }
5421   _XmEntryDirectionSet((_XmStringEntry)&seg, XmSTRING_DIRECTION_L_TO_R);
5422 
5423   lc = sc = 0;
5424 
5425   while (c < end)
5426     {
5427       length = _read_asn1_length (c);
5428       need_finish = True;
5429 
5430       switch (*c)
5431 	{
5432 	case XmSTRING_COMPONENT_LAYOUT_PUSH:		/* record dir */
5433 	  if ((txt_seen) || (push_seen))
5434 	    {
5435 	      finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir);
5436 	      push_seen = txt_seen = pop_seen = False;
5437 	    }
5438 
5439 	  needs_unopt = True;
5440 	  push_seen = True;
5441 	  _XmEntryPushSet(&seg, (XmDirection)*(c + _asn1_size(length)));
5442 	  break;
5443 
5444 	case XmSTRING_COMPONENT_RENDITION_BEGIN:
5445 	  if (txt_seen)
5446 	    {
5447 	      finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir);
5448 	      push_seen = txt_seen = pop_seen = False;
5449 	    }
5450 
5451 	  rend_cnt = ++(_XmUnoptSegRendBeginCount(&seg));
5452 
5453 	  if (rend_cnt > 1) needs_unopt = True;
5454 
5455 	  _XmUnoptSegRendBegins(&seg) = (XmStringTag *)
5456 	    XtRealloc((char *)_XmUnoptSegRendBegins(&seg), rend_cnt);
5457 
5458 	  _XmUnoptSegRendBegins(&seg)[rend_cnt - 1] =
5459 	    _XmStringCacheTag((char *)(c + _asn1_size(length)),
5460 			      (int)length);
5461 	  break;
5462 
5463         case XmSTRING_COMPONENT_LOCALE:
5464 	  if (txt_seen)
5465 	    {
5466 	      finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir);
5467 	      push_seen = txt_seen = pop_seen = False;
5468 	    }
5469 
5470 	  _XmEntryTextTypeSet(&seg, XmMULTIBYTE_TEXT);
5471 	  prev_type = XmMULTIBYTE_TEXT;
5472 	  _XmUnoptSegTag(&seg) =
5473 	    _XmStringCacheTag((char *)(c+_asn1_size(length)), (int)length);
5474 	  break;
5475 
5476         case XmSTRING_COMPONENT_TAG:
5477 	  if (txt_seen)
5478 	    {
5479 	      finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir);
5480 	      push_seen = txt_seen = pop_seen = False;
5481 	    }
5482 
5483 	  _XmEntryTextTypeSet(&seg, XmCHARSET_TEXT);
5484 	  prev_type = XmCHARSET_TEXT;
5485 	  _XmUnoptSegTag(&seg) =
5486 	    _XmStringCacheTag((char *)(c+_asn1_size(length)), (int)length);
5487 	  break;
5488 
5489 	case XmSTRING_COMPONENT_TAB:
5490 	  if (txt_seen)
5491 	    {
5492 	      finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir);
5493 	      push_seen = txt_seen = pop_seen = False;
5494 	    }
5495 
5496 	  tab_cnt = _XmEntryTabsGet((_XmStringEntry)&seg);
5497 	  if (++tab_cnt > 7) needs_unopt = True;
5498 	  _XmEntryTabsSet(&seg, tab_cnt);
5499 	  break;
5500 
5501 	case XmSTRING_COMPONENT_DIRECTION:		/* record dir */
5502 	  if (txt_seen)
5503 	    {
5504 	      finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir);
5505 	      push_seen = txt_seen = pop_seen = False;
5506 	    }
5507 
5508 	  dir = (XmStringDirection)*(c + _asn1_size(length));
5509 	  break;
5510 
5511 	case XmSTRING_COMPONENT_WIDECHAR_TEXT:
5512 	  if (txt_seen)
5513 	    {
5514 	      finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir);
5515 	      push_seen = txt_seen = pop_seen = False;
5516 	    }
5517 
5518 	  _XmEntryTextTypeSet(&seg, XmWIDECHAR_TEXT);
5519 	  prev_type = XmWIDECHAR_TEXT;
5520 	  /* Fall through */
5521 	case XmSTRING_COMPONENT_LOCALE_TEXT:
5522 	  if (txt_seen)
5523 	    {
5524 	      finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir);
5525 	      push_seen = txt_seen = pop_seen = False;
5526 	    }
5527 
5528 	  /* from above */
5529 	  if (_XmEntryTextTypeGet((_XmStringEntry)&seg) != XmWIDECHAR_TEXT)
5530 	    {
5531 	      _XmEntryTextTypeSet(&seg, XmMULTIBYTE_TEXT);
5532 	      prev_type = XmMULTIBYTE_TEXT;
5533 	    }
5534 	  _XmUnoptSegTag(&seg) =
5535 	    _XmStringCacheTag((char *) XmFONTLIST_DEFAULT_TAG,
5536 			      XmSTRING_TAG_STRLEN);
5537 	  /* Fall through to regular text. */
5538 	case XmSTRING_COMPONENT_TEXT:
5539 	  if (txt_seen)
5540 	    {
5541 	      push_seen = txt_seen = pop_seen = False;
5542 	      finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir);
5543 	    }
5544 
5545 	  if (_XmEntryTextTypeGet((_XmStringEntry)&seg) == XmNO_TEXT)
5546 	    _XmEntryTextTypeSet(&seg, prev_type);
5547 
5548 	  _XmEntryTextSet((_XmStringEntry)&seg, (c + _asn1_size(length)));
5549 	  _XmUnoptSegByteCount(&seg) = length;
5550 
5551 	  txt_seen = True;
5552 	  break;
5553 
5554 	case XmSTRING_COMPONENT_RENDITION_END:
5555 	  txt_seen = True;
5556 
5557 	  rend_cnt = ++(_XmUnoptSegRendEndCount(&seg));
5558 
5559 	  if (rend_cnt > 1) needs_unopt = True;
5560 
5561 	  _XmUnoptSegRendEnds(&seg) = (XmStringTag *)
5562 	    XtRealloc((char *)_XmUnoptSegRendEnds(&seg), rend_cnt);
5563 
5564 	  _XmUnoptSegRendEnds(&seg)[rend_cnt - 1] =
5565 	    _XmStringCacheTag((char *)(c + _asn1_size(length)),
5566 			      (int)length);
5567 	  break;
5568 
5569 	case XmSTRING_COMPONENT_LAYOUT_POP:
5570 	  if (pop_seen)
5571 	    {
5572 	      finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir);
5573 	      push_seen = txt_seen = pop_seen = False;
5574 	    }
5575 
5576 	  needs_unopt = True;
5577 	  txt_seen = True;
5578 	  pop_seen = True;
5579 	  _XmEntryPopSet(&seg, TRUE);
5580 	  break;
5581 
5582 	case XmSTRING_COMPONENT_SEPARATOR:              /* start new line */
5583 	  finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir);
5584 	  need_finish = push_seen = txt_seen = pop_seen = False;
5585 
5586 	  if (!_XmStrImplicitLine(string) && _XmStrEntryCount(string) > 1) {
5587 	    /* need to move segments down one level */
5588 	    _XmStringEntry line;
5589 	    line = (_XmStringEntry)XtMalloc(sizeof(_XmStringArraySegRec));
5590 	    _XmEntryType(line) = XmSTRING_ENTRY_ARRAY;
5591 	    _XmEntrySoftNewlineSet(line, False);
5592 	    _XmEntrySegmentCount(line) = _XmStrEntryCount(string);
5593 	    _XmEntrySegment(line) = (_XmStringNREntry *)_XmStrEntry(string);
5594 	    _XmStrEntry(string) =
5595 	      (_XmStringEntry *)XtMalloc(sizeof(_XmStringEntry));
5596 	    _XmStrEntry(string)[0] = line;
5597 	    _XmStrEntryCount(string) = 1;
5598 	  }
5599 	  _XmStrImplicitLine(string) = True;
5600 	  lc++;
5601 	  break;
5602 
5603 	default:
5604 	  break;
5605 	}
5606 
5607       c += length + _asn1_size(length);
5608     }
5609 
5610   if (need_finish) finish_segment(string, &seg, &lc, &sc, &needs_unopt, dir);
5611 
5612   return(string);
5613 }
5614 
5615 /*
5616  * Converts from ASN.1 formatted byte stream to XmString.
5617  */
5618 /*ARGSUSED*/
5619 XmString
XmCvtByteStreamToXmString(unsigned char * property)5620 XmCvtByteStreamToXmString(unsigned char *property)
5621 {
5622   unsigned char       *c;
5623   unsigned char       *c_opt;
5624   unsigned char       *end;
5625   unsigned short      length;
5626   unsigned short      txtlength;
5627   XmString            string ;
5628   Boolean     	      continue_flag;
5629   Boolean     	      optimized;
5630   Boolean     	      havetag;
5631   Boolean	      begin_seen, end_seen;
5632   Boolean	      txt_seen;
5633   unsigned int 	      tag_index = TAG_INDEX_MAX;
5634   unsigned int 	      begin_index = REND_INDEX_MAX;
5635   unsigned int 	      end_index = REND_INDEX_MAX;
5636   unsigned char	      tab_cnt;
5637 
5638   _XmProcessLock();
5639   if (!property) {
5640       _XmProcessUnlock();
5641       return((XmString) NULL);
5642   }
5643   /* If property isn't an asn.1 conformant string, return NULL. */
5644   if (!_is_asn1(property)) {
5645       _XmProcessUnlock();
5646       return ((XmString) NULL);
5647   }
5648 
5649   c  = (unsigned char *) _read_header((unsigned char *) property);
5650   end = c + _read_string_length ((unsigned char *) property);
5651   if (c >= end) {
5652       _XmProcessUnlock();
5653       return ((_XmString) NULL);
5654   }
5655 
5656   /*
5657    * In order to build an optimized string, we have to see if this one
5658    * qualifies.  Do some preprocessing to see.
5659    * We also need to know if this CS contains a character set component,
5660    * so look for that too.
5661    */
5662 
5663   c_opt = c;
5664   continue_flag = TRUE;
5665   optimized = TRUE;
5666   txtlength = 0;		/* For strings with no text component. */
5667   havetag = FALSE;
5668   end_seen = begin_seen = FALSE;
5669   txt_seen = FALSE;
5670   tab_cnt = 0;
5671 
5672   while (continue_flag)
5673     {
5674       length = _read_asn1_length (c_opt);
5675 
5676       switch (*c_opt)
5677         {
5678 	/* All non-optimized */
5679 	case XmSTRING_COMPONENT_LAYOUT_PUSH:
5680 	case XmSTRING_COMPONENT_LAYOUT_POP:
5681         case XmSTRING_COMPONENT_SEPARATOR: /* start new line */
5682           optimized = FALSE;
5683           break;
5684 
5685 	case XmSTRING_COMPONENT_RENDITION_BEGIN:
5686 	  if (begin_seen || txt_seen)
5687 	    {
5688 	      optimized = FALSE;
5689 	      break;
5690 	    }
5691 	  else
5692 	    {
5693 	      begin_seen = TRUE;
5694 	      begin_index =
5695 		_XmStringIndexCacheTag((char *)(c_opt + _asn1_size(length)),
5696 				       (int)length);
5697 	      if (begin_index >= REND_INDEX_MAX) optimized = FALSE ;
5698 	    }
5699 	  break;
5700 
5701         case XmSTRING_COMPONENT_LOCALE:
5702         case XmSTRING_COMPONENT_TAG:
5703           tag_index = _XmStringIndexCacheTag
5704             ((char *) (c_opt + _asn1_size(length)), (int) length);
5705 
5706           if (txt_seen ||
5707 	      (tag_index >= TAG_INDEX_MAX))
5708 	    optimized = FALSE ;
5709 
5710           havetag = TRUE;
5711           break;
5712 
5713 	case XmSTRING_COMPONENT_TAB:
5714 	  if (++tab_cnt > 3) optimized = FALSE;
5715 	  break;
5716 
5717 	case XmSTRING_COMPONENT_DIRECTION:
5718 	  if (txt_seen) optimized = FALSE;
5719 	  break;
5720 
5721 	case XmSTRING_COMPONENT_WIDECHAR_TEXT:
5722 	  optimized = FALSE;
5723 	  txtlength = length;
5724 	  break;
5725 
5726         case XmSTRING_COMPONENT_LOCALE_TEXT:
5727 	  /* Check the tag. */
5728           tag_index = _XmStringIndexCacheTag((char *)XmFONTLIST_DEFAULT_TAG,
5729 					     XmSTRING_TAG_STRLEN);
5730           havetag = TRUE;
5731 
5732 	  if ((txt_seen) ||
5733 	      (tag_index >= TAG_INDEX_MAX))
5734 	    {
5735 	      optimized = FALSE;
5736 	      break;
5737 	    }
5738 
5739           /* Else fall through to text case. */
5740         case XmSTRING_COMPONENT_TEXT:
5741           if (txt_seen ||
5742 	      (((c_opt + length + _asn1_size(length)) < end) ||
5743 	       (length >= (1 << BYTE_COUNT_BITS))))
5744 	    optimized = FALSE;
5745 
5746 	  txtlength = length;
5747 	  txt_seen = TRUE;
5748 
5749           break;
5750 
5751 	case XmSTRING_COMPONENT_RENDITION_END:
5752 	  if (end_seen)
5753 	    {
5754 	      optimized = FALSE;
5755 	      break;
5756 	    }
5757 	  else
5758 	    {
5759 	      end_seen = TRUE;
5760 	      txt_seen = TRUE;
5761 	      end_index =
5762 		_XmStringIndexCacheTag((char *)(c_opt + _asn1_size(length)),
5763 				       (int)length);
5764 	      if ((end_index >= REND_INDEX_MAX) ||
5765 		  (end_index != begin_index))
5766 		optimized = FALSE;
5767 	    }
5768 	  break;
5769 
5770         default:
5771           break;
5772         }
5773 
5774       c_opt += length + _asn1_size(length);
5775       if ((c_opt >= end) || (!optimized))
5776 	continue_flag = FALSE;
5777     }
5778 
5779   if (optimized) string = (_XmString)
5780     _XmStringOptCreate(c, end, txtlength, havetag, tag_index);
5781   else string = _XmStringNonOptCreate(c, end, havetag);
5782 
5783   _XmProcessUnlock();
5784   return (string);
5785 }
5786 
5787 _XmStringEntry
_XmStringEntryCopy(_XmStringEntry entry)5788 _XmStringEntryCopy(_XmStringEntry entry)
5789 {
5790   int i;
5791   int size;
5792   XtPointer text;
5793   _XmStringEntry new_entry = NULL;
5794   unsigned int entry_len;
5795 
5796   if (!entry)
5797     return NULL;
5798 
5799   entry_len = _XmEntryByteCountGet(entry);
5800 
5801   switch (_XmEntryType(entry)) {
5802   case XmSTRING_ENTRY_OPTIMIZED:
5803     if (_XmEntryImm(entry)) {
5804       if (entry_len > sizeof(XtPointer))
5805 	size = sizeof(_XmStringOptSegRec) + entry_len - sizeof(XtPointer);
5806       else
5807 	size = sizeof(_XmStringOptSegRec);
5808       new_entry = (_XmStringEntry)XtMalloc(size);
5809       memcpy((char *)new_entry, (char *)entry, size);
5810     } else {
5811       new_entry = (_XmStringEntry)XtMalloc(sizeof(_XmStringOptSegRec));
5812       memcpy((char *)new_entry, (char *)entry, sizeof(_XmStringOptSegRec));
5813       if (_XmEntryPermGet(entry)) {
5814 	_XmEntryTextSet(new_entry, _XmEntryTextGet(entry));
5815       } else if (entry_len > 0) {
5816 	text = (XtPointer)XtMalloc(entry_len);
5817 	memcpy((char *)text, (char *)_XmEntryTextGet(entry), entry_len);
5818 	_XmEntryTextSet(new_entry, text);
5819       } else
5820 	_XmEntryTextSet(new_entry, NULL);
5821     }
5822     break;
5823   case XmSTRING_ENTRY_ARRAY:
5824     {
5825       _XmStringNREntry *arr;
5826       new_entry = (_XmStringEntry)XtMalloc(sizeof(_XmStringArraySegRec));
5827       memcpy((char *)new_entry, (char *)entry, sizeof(_XmStringArraySegRec));
5828       if (_XmEntrySegmentCount(entry) > 0) {
5829 	arr = (_XmStringNREntry *)XtMalloc(_XmEntrySegmentCount(entry) *
5830 					   sizeof(_XmStringNREntry));
5831 	for (i = 0; i < _XmEntrySegmentCount(entry); i++)
5832 	  arr[i] = (_XmStringNREntry)
5833 	    _XmStringEntryCopy((_XmStringEntry)_XmEntrySegment(entry)[i]);
5834 	_XmEntrySegment(new_entry) = arr;
5835       } else
5836 	_XmEntrySegment(new_entry) = NULL;
5837     }
5838     break;
5839   case XmSTRING_ENTRY_UNOPTIMIZED:
5840     {
5841       new_entry = (_XmStringEntry)XtMalloc(sizeof(_XmStringUnoptSegRec));
5842       memcpy((char *)new_entry, (char *)entry,
5843 	     sizeof(_XmStringUnoptSegRec));
5844       if (_XmEntryPermGet(entry)) {
5845 	_XmEntryTextSet(new_entry, _XmEntryTextGet(entry));
5846       } else if (entry_len > 0) {
5847 	text = (XtPointer)XtMalloc(entry_len);
5848 	memcpy((char *)text,
5849 	       (char *)_XmEntryTextGet((_XmStringEntry)entry),
5850 	       entry_len);
5851 	_XmEntryTextSet(new_entry, text);
5852       } else
5853 	_XmEntryTextSet(new_entry, NULL);
5854       if (_XmUnoptSegRendBegins(entry)) {
5855 	_XmUnoptSegRendBegins(new_entry) =
5856 	  (XmStringTag *)XtMalloc(_XmUnoptSegRendBeginCount(entry) *
5857 				  sizeof(XmStringTag));
5858 	for (i = 0; i < _XmUnoptSegRendBeginCount(entry); i++)
5859 	  _XmUnoptSegRendBegins(new_entry)[i] =
5860 	    _XmUnoptSegRendBegins(entry)[i];
5861       } else
5862 	_XmUnoptSegRendBegins(new_entry) = NULL;
5863       if (_XmUnoptSegRendEnds(entry)) {
5864 	_XmUnoptSegRendEnds(new_entry) =
5865 	  (XmStringTag *)XtMalloc(_XmUnoptSegRendEndCount(entry) *
5866 				  sizeof(XmStringTag));
5867 	for (i = 0; i < _XmUnoptSegRendEndCount(entry); i++)
5868 	  _XmUnoptSegRendEnds(new_entry)[i] = _XmUnoptSegRendEnds(entry)[i];
5869       } else
5870 	_XmUnoptSegRendEnds(new_entry) = NULL;
5871       _XmEntryCacheSet(new_entry, NULL);
5872     }
5873     break;
5874   }
5875   return(new_entry);
5876 }
5877 
5878 /** Begin macros converted to functions. **/
5879 
5880 XmStringTag
_XmEntryTag(_XmStringEntry entry)5881 _XmEntryTag(_XmStringEntry entry)
5882 {
5883 #if 1
5884   XmStringTag rettag;
5885 
5886   if (_XmEntryOptimized(entry))
5887   {
5888     if (_XmEntryTagIndex(entry) != TAG_INDEX_UNSET)
5889       rettag = _XmStringIndexGetTag(_XmEntryTagIndex(entry));
5890     else
5891       rettag = NULL;
5892   }
5893   else
5894     rettag = _XmUnoptSegTag(entry);
5895 
5896   return rettag;
5897 #else
5898   return (_XmEntryOptimized(entry) ?
5899 	  (_XmEntryTagIndex(entry) != TAG_INDEX_UNSET ?
5900 	   _XmStringIndexGetTag(_XmEntryTagIndex(entry)) : NULL) :
5901 	  _XmUnoptSegTag(entry));
5902 #endif
5903 }
5904 
5905 void
_XmEntryTagSet(_XmStringEntry entry,XmStringTag tag)5906 _XmEntryTagSet(_XmStringEntry entry, XmStringTag tag)
5907 {
5908   if (_XmEntryOptimized(entry))
5909     {
5910       if (tag == NULL)
5911 	_XmEntryTagIndex(entry) = TAG_INDEX_UNSET;
5912       else
5913 	_XmEntryTagIndex(entry) =
5914 	  _XmStringIndexCacheTag(tag, XmSTRING_TAG_STRLEN);
5915     }
5916   else
5917     {
5918       _XmUnoptSegTag(entry) = tag;
5919     }
5920 }
5921 
5922 
5923 XmDirection
_XmEntryPushGet(_XmStringEntry entry)5924 _XmEntryPushGet(_XmStringEntry entry)
5925 {
5926   return (_XmEntryUnoptimized(entry) ?
5927 	  ((_XmStringEntry)(entry))->unopt_single.push_before :
5928 	  False);
5929 }
5930 
5931 unsigned int
_XmEntryByteCountGet(_XmStringEntry entry)5932 _XmEntryByteCountGet(_XmStringEntry entry)
5933 {
5934   switch (_XmEntryType(entry))
5935     {
5936     case XmSTRING_ENTRY_OPTIMIZED:
5937       return ((_XmStringEntry)(entry))->single.byte_count;
5938     case XmSTRING_ENTRY_ARRAY:
5939       return 0;
5940     case XmSTRING_ENTRY_UNOPTIMIZED:
5941       return _XmUnoptSegByteCount(entry);
5942 
5943     default:
5944       assert(FALSE);
5945       return 0;
5946     }
5947 }
5948 
5949 void
_XmEntryTextSet(_XmStringEntry entry,XtPointer val)5950 _XmEntryTextSet(_XmStringEntry entry,
5951 		XtPointer val)
5952 {
5953   (_XmEntryOptimized(entry) ?
5954    (!_XmEntryImm(entry) ?
5955     (((_XmStringOptSeg)(entry))->data.text = val) :
5956     /* This below is potentially dangerous. This function needs a length
5957        parameter, or requires that the byte count is set in the segment.
5958        However, to my knowledge, nobody needs this now. But it needs to
5959        be looked at.. */
5960     strcpy((char *)((_XmStringOptSeg)(entry))->data.chars, (char *)val)) :
5961    (((_XmStringUnoptSeg)(entry))->data.text = val));
5962 }
5963 
5964 XtPointer
_XmEntryTextGet(_XmStringEntry entry)5965 _XmEntryTextGet(_XmStringEntry entry)
5966 {
5967   return(_XmEntryOptimized(entry) ?
5968  	 (!_XmEntryImm(entry) ?
5969  	  ((_XmStringOptSeg)(entry))->data.text :
5970  	  (XtPointer)((_XmStringOptSeg)(entry))->data.chars) :
5971 	 (((_XmStringUnoptSeg)(entry))->data.text));
5972 }
5973 
5974 unsigned int
_XmEntryDirectionGet(_XmStringEntry entry)5975 _XmEntryDirectionGet(_XmStringEntry entry)
5976 {
5977   return(_XmEntryOptimized(entry) ?
5978 	 ((_XmStringEntry)(entry))->single.str_dir :
5979 	 ((_XmStringEntry)(entry))->unopt_single.str_dir);
5980 }
5981 
5982 void
_XmEntryDirectionSet(_XmStringEntry entry,XmDirection val)5983 _XmEntryDirectionSet(_XmStringEntry entry,
5984 		     XmDirection val)
5985 {
5986   (_XmEntryOptimized(entry) ?
5987    (((_XmStringEntry)entry)->single.str_dir = val) :
5988    (((_XmStringEntry)entry)->unopt_single.str_dir = val));
5989 }
5990 
5991 unsigned int
_XmEntryTextTypeGet(_XmStringEntry entry)5992 _XmEntryTextTypeGet(_XmStringEntry entry)
5993 {
5994   return(_XmEntryOptimized(entry) ?
5995 	 ((_XmStringEntry)(entry))->single.text_type :
5996 	 ((_XmStringEntry)(entry))->unopt_single.text_type);
5997 }
5998 
5999 _XmStringCache
_XmEntryCacheGet(_XmStringEntry entry)6000 _XmEntryCacheGet(_XmStringEntry entry)
6001 {
6002   return (_XmEntryUnoptimized(entry) ?
6003 	  ((_XmStringUnoptSeg)(entry))->cache :
6004 	  NULL);
6005 }
6006 
6007 unsigned char
_XmEntryRendEndCountGet(_XmStringEntry entry)6008 _XmEntryRendEndCountGet(_XmStringEntry entry)
6009 {
6010   return(_XmEntryOptimized(entry) ?
6011 	 ((_XmStringEntry)(entry))->single.rend_end :
6012 	 _XmUnoptSegRendEndCount(entry));
6013 }
6014 
6015 unsigned char
_XmEntryRendBeginCountGet(_XmStringEntry entry)6016 _XmEntryRendBeginCountGet(_XmStringEntry entry)
6017 {
6018   return(_XmEntryOptimized(entry) ?
6019 	 ((_XmStringEntry)(entry))->single.rend_begin :
6020 	 _XmUnoptSegRendBeginCount(entry));
6021 }
6022 
6023 Boolean
_XmEntryPopGet(_XmStringEntry entry)6024 _XmEntryPopGet(_XmStringEntry entry)
6025 {
6026   return (_XmEntryUnoptimized(entry) ?
6027 	  ((_XmStringEntry)(entry))->unopt_single.pop_after :
6028 	  False);
6029 }
6030 
6031 XmStringTag
_XmEntryRendEndGet(_XmStringEntry entry,int n)6032 _XmEntryRendEndGet(_XmStringEntry entry,
6033 		   int n)
6034 {
6035   return((_XmEntryRendEndCountGet(entry) > n) ?
6036 	 (_XmEntryOptimized(entry) ?
6037 	  (_XmEntryRendIndex(entry) != REND_INDEX_UNSET ?
6038 	   _XmStringIndexGetTag(_XmEntryRendIndex(entry)) : NULL) :
6039 	  (((_XmStringUnoptSeg)(entry))->rend_end_tags)[n]) :
6040 	 NULL);
6041 }
6042 
6043 XmStringTag
_XmEntryRendBeginGet(_XmStringEntry entry,int n)6044 _XmEntryRendBeginGet(_XmStringEntry entry,
6045 		     int n)
6046 {
6047   return((_XmEntryRendBeginCountGet(entry) > n) ?
6048 	 (_XmEntryOptimized(entry) ?
6049 	  (_XmEntryRendIndex(entry) != REND_INDEX_UNSET ?
6050 	   _XmStringIndexGetTag(_XmEntryRendIndex(entry)) : NULL) :
6051 	  (((_XmStringUnoptSeg)(entry))->rend_begin_tags)[n]) :
6052 	 NULL);
6053 }
6054 
6055 void
_XmEntryRendEndSet(_XmStringEntry entry,XmStringTag tag,int n)6056 _XmEntryRendEndSet(_XmStringEntry entry,
6057 		   XmStringTag tag,
6058 		   int n)
6059 {
6060   int i;
6061 
6062   if (_XmEntryOptimized(entry))
6063     {
6064       if (tag == NULL) {
6065  	if (_XmEntryRendBeginCountGet(entry) == 0)
6066  	  _XmEntryRendIndex(entry) = REND_INDEX_UNSET;
6067       } else {
6068  	_XmEntryRendIndex(entry) = _XmStringIndexCacheTag(tag,
6069 							  XmSTRING_TAG_STRLEN);
6070       }
6071       _XmEntryRendEndCountSet(entry, ((tag == NULL) ? 0 : 1));
6072     }
6073   else
6074     {
6075       if (tag == NULL)
6076   	{
6077  	  if (_XmEntryRendEndCountGet(entry) > n) {
6078 	    for (i = n; i < _XmEntryRendEndCountGet(entry) - 1; i++)
6079  	      _XmUnoptSegRendEnds(entry)[i] = _XmUnoptSegRendEnds(entry)[i+1];
6080 
6081  	    _XmUnoptSegRendEndCount(entry)--;
6082  	    _XmUnoptSegRendEnds(entry)[_XmEntryRendEndCountGet(entry)] = NULL;
6083  	    if (_XmEntryRendEndCountGet(entry) == 0) {
6084  	      XtFree((char *)_XmUnoptSegRendEnds(entry));
6085  	      _XmUnoptSegRendEnds(entry) = NULL;
6086  	    }
6087  	  }
6088   	}
6089       else
6090   	{
6091  	  if (n >= _XmUnoptSegRendEndCount(entry)) {
6092  	    n = _XmUnoptSegRendEndCount(entry);
6093  	    _XmUnoptSegRendEndCount(entry)++;
6094  	    _XmUnoptSegRendEnds(entry) =
6095  	      (XmStringTag *)XtRealloc((char *)_XmUnoptSegRendEnds(entry),
6096  				       _XmUnoptSegRendEndCount(entry) *
6097  				       sizeof(XmStringTag));
6098  	  }
6099   	  _XmUnoptSegRendEnds(entry)[n] = tag;
6100   	}
6101     }
6102 }
6103 
6104 
6105 void
_XmEntryRendBeginSet(_XmStringEntry entry,XmStringTag tag,int n)6106 _XmEntryRendBeginSet(_XmStringEntry entry,
6107  		     XmStringTag tag,
6108  		     int n)
6109 {
6110   int i;
6111 
6112   if (_XmEntryOptimized(entry))
6113     {
6114       if (tag == NULL) {
6115  	if (_XmEntryRendEndCountGet(entry) == 0)
6116  	  _XmEntryRendIndex(entry) = REND_INDEX_UNSET;
6117       } else {
6118  	_XmEntryRendIndex(entry) = _XmStringIndexCacheTag(tag,
6119  							  XmSTRING_TAG_STRLEN);
6120       }
6121       _XmEntryRendBeginCountSet(entry, ((tag == NULL) ? 0 : 1));
6122     }
6123   else
6124     {
6125       if (tag == NULL)
6126   	{
6127  	  if (_XmEntryRendBeginCountGet(entry) > n) {
6128 	    for (i = n; i < _XmEntryRendBeginCountGet(entry) - 1; i++)
6129  	      _XmUnoptSegRendBegins(entry)[i] =
6130 		_XmUnoptSegRendBegins(entry)[i+1];
6131 
6132  	    _XmUnoptSegRendBeginCount(entry)--;
6133  	    _XmUnoptSegRendBegins(entry)[_XmEntryRendBeginCountGet(entry)] =
6134  	      NULL;
6135  	    if (_XmEntryRendBeginCountGet(entry) == 0) {
6136  	      XtFree((char *)_XmUnoptSegRendBegins(entry));
6137  	      _XmUnoptSegRendBegins(entry) = NULL;
6138  	    }
6139  	  }
6140   	}
6141       else
6142   	{
6143  	  if (n >= _XmUnoptSegRendBeginCount(entry)) {
6144  	    n = _XmUnoptSegRendBeginCount(entry);
6145  	    _XmUnoptSegRendBeginCount(entry)++;
6146  	    _XmUnoptSegRendBegins(entry) =
6147  	      (XmStringTag *)XtRealloc((char *)_XmUnoptSegRendBegins(entry),
6148  				       _XmUnoptSegRendBeginCount(entry) *
6149  				       sizeof(XmStringTag));
6150  	  }
6151  	  _XmUnoptSegRendBegins(entry)[n] = tag;
6152   	}
6153     }
6154 }
6155 
6156 unsigned char
_XmEntryTabsGet(_XmStringEntry entry)6157 _XmEntryTabsGet(_XmStringEntry entry)
6158 {
6159   return(_XmEntryOptimized(entry) ?
6160 	 ((_XmStringEntry)(entry))->single.tabs_before :
6161 	 ((_XmStringEntry)(entry))->unopt_single.tabs_before);
6162 }
6163 
6164 /** End macros converted to functions. **/
6165 
6166 void
_XmStringEntryFree(_XmStringEntry entry)6167 _XmStringEntryFree(_XmStringEntry entry)
6168 {
6169   int i;
6170 
6171   if (!entry)
6172     return;
6173 
6174   switch (_XmEntryType(entry)) {
6175   case XmSTRING_ENTRY_OPTIMIZED:
6176     if (!_XmEntryImm(entry) && !_XmEntryPermGet(entry) && _XmEntryTextGet(entry))
6177       XtFree((char *)_XmEntryTextGet(entry));
6178     XtFree((char *)entry);
6179     break;
6180   case XmSTRING_ENTRY_ARRAY:
6181     for (i = 0; i < _XmEntrySegmentCount(entry); i++)
6182       _XmStringEntryFree((_XmStringEntry)_XmEntrySegment(entry)[i]);
6183     if (_XmEntrySegment(entry)) XtFree((char *)_XmEntrySegment(entry));
6184     XtFree((char *)entry);
6185     break;
6186   case XmSTRING_ENTRY_UNOPTIMIZED:
6187     _XmStringCacheFree(_XmEntryCacheGet(entry));
6188     if (_XmUnoptSegRendBegins(entry))
6189       XtFree((char *)_XmUnoptSegRendBegins(entry));
6190     if (_XmUnoptSegRendEnds(entry)) XtFree((char *)_XmUnoptSegRendEnds(entry));
6191     if (_XmEntryTextGet(entry) && !_XmEntryPermGet(entry))
6192       XtFree((char *)_XmEntryTextGet(entry));
6193     XtFree((char *)entry);
6194     break;
6195   }
6196 }
6197 
6198 
6199 /*
6200  * free the XmString internal data structure
6201  */
6202 void
XmStringFree(XmString string)6203 XmStringFree(
6204         XmString string )
6205 {
6206   int i;
6207   int lcount;
6208 
6209   _XmProcessLock();
6210   if (!string) {
6211      _XmProcessUnlock();
6212      return;
6213   }
6214 
6215   /* Decrement refcount.  If not zero, just return. */
6216   if (_XmStrRefCountDec(string) != 0) {
6217      _XmProcessUnlock();
6218      return;
6219   }
6220 
6221   if (!_XmStrOptimized(string))
6222     {
6223       lcount = _XmStrEntryCount(string);
6224       for (i = 0; i < lcount; i++)
6225 	{
6226 	  _XmStringEntryFree(_XmStrEntry(string)[i]);
6227 	}
6228       XtFree((char *)_XmStrEntry(string));
6229     }
6230   _XmStrFree ((char *) string);
6231   _XmProcessUnlock();
6232 }
6233 
6234 static void
ComputeMetrics(XmRendition rend,XtPointer text,unsigned int byte_count,XmTextType type,int which_seg,Dimension * width,Dimension * height,Dimension * ascent,Dimension * descent,Boolean utf8)6235 ComputeMetrics(XmRendition rend,
6236 	       XtPointer text,
6237 	       unsigned int byte_count,
6238 	       XmTextType type,
6239 	       int which_seg,
6240 	       Dimension *width,
6241 	       Dimension *height,
6242 	       Dimension *ascent,
6243 	       Dimension *descent,
6244                Boolean utf8)
6245 {
6246   Dimension	wid, hi;
6247   int		dir, asc, desc;
6248 
6249   wid = 0;
6250   hi = 0;
6251   asc = 0;
6252   desc = 0;
6253 
6254   switch (_XmRendFontType(rend)) {
6255     case XmFONT_IS_FONT:
6256     {
6257       XFontStruct *font_struct = (XFontStruct *)_XmRendFont(rend);
6258       XCharStruct	char_ret;
6259 
6260       if (two_byte_font(font_struct))
6261 	{
6262 #ifdef FIX_1434
6263 	  if (byte_count >= 2 || utf8)
6264 #else
6265 	  if (byte_count >= 2)
6266 #endif
6267 	    {
6268 	      if (utf8)
6269 		{
6270 		  /* TODO: it is very unoptimized convert the same sting
6271 		   * twice - for getting extents and drawing */
6272 		  size_t  str_len = 0;
6273 		  XChar2b *str = _XmUtf8ToUcs2(text, byte_count, &str_len);
6274 
6275 		  XTextExtents16(font_struct, str, str_len,
6276 			     &dir, &asc, &desc, &char_ret);
6277 		} else
6278 	      XTextExtents16(font_struct,
6279 			     (XChar2b *)text, Half(byte_count),
6280 			     &dir, &asc, &desc, &char_ret);
6281 
6282 	      wid = ComputeWidth(which_seg, char_ret);
6283 
6284 	      /* pir 2967 */
6285 	      if (wid == 0)
6286 		wid = Half(byte_count) * (font_struct->max_bounds.width);
6287 	      hi = asc + desc;
6288 	    }
6289 	}
6290       else
6291 	{
6292 	  if (byte_count >= 1)
6293 	    {
6294 	      XTextExtents(font_struct, (char *)text, byte_count,
6295 			   &dir, &asc, &desc, &char_ret);
6296 
6297 	      wid = ComputeWidth(which_seg, char_ret);
6298 
6299 	      /* pir 2967 */
6300 	      if (wid == 0)
6301 		wid = byte_count * (font_struct->max_bounds.width);
6302 	      hi = asc + desc;
6303 	    }
6304 	}
6305     }
6306     break;
6307     case XmFONT_IS_FONTSET:
6308     {
6309       if (byte_count >= 1)
6310 	{
6311 	  XFontSet font_set = (XFontSet)_XmRendFont(rend);
6312 	  XRectangle ink, logical;
6313 
6314 	  if (type == XmWIDECHAR_TEXT)
6315 	    XwcTextExtents(font_set, (wchar_t *)text,
6316 			   byte_count/sizeof(wchar_t),
6317 			   &ink, &logical);
6318 	  else {
6319 #ifdef UTF8_SUPPORTED
6320               if (utf8)
6321                   Xutf8TextExtents(font_set, (char *)text, byte_count,
6322                           &ink, &logical);
6323               else
6324 #endif
6325                   XmbTextExtents(font_set, (char *)text, byte_count,
6326                           &ink, &logical);
6327           }
6328 
6329 	  if (logical.height == 0)
6330 	    {
6331 	      XFontSetExtents *extents = XExtentsOfFontSet(font_set);
6332 	      logical.height = extents->max_logical_extent.height;
6333 	    }
6334 	  wid = logical.width;
6335 	  hi = logical.height;
6336 	  asc = -(logical.y);
6337 	  desc = logical.height + logical.y;
6338 	}
6339     }
6340     break;
6341 #ifdef USE_XFT
6342     case XmFONT_IS_XFT:
6343 	asc = _XmRendXftFont(rend)->ascent;
6344 	desc = _XmRendXftFont(rend)->descent;
6345 	/* FIXME
6346 	 * Following Keith Packard comments it should be
6347 	 *  hi = _XmRendXftFont(rend)->height;
6348 	 * but is looking ascent + descent better. Is it a bug?
6349 	 */
6350 	hi = asc+desc;
6351     {
6352 	XGlyphInfo	info;
6353 	XftTextExtentsUtf8(_XmRendDisplay(rend),
6354 		_XmRendXftFont(rend),
6355 		text, byte_count,
6356 		&info);
6357 	wid = info.xOff;
6358     }
6359 #endif
6360   }
6361 
6362   /* Adjust for underlining. Add one pixel for line and one pixel at bottom so
6363    * that line doesn't bleed into background with select color of
6364    * XmREVERSED_GROUND_COLORS.
6365    */
6366   switch (_XmRendUnderlineType(rend))
6367     {
6368     case XmSINGLE_LINE:
6369     case XmSINGLE_DASHED_LINE:
6370       if (desc < (SINGLE_OFFSET + 2))
6371 	{
6372 	  hi += (SINGLE_OFFSET + 2) - desc;
6373 	  desc = SINGLE_OFFSET + 2;
6374 	}
6375       break;
6376     case XmDOUBLE_LINE:
6377     case XmDOUBLE_DASHED_LINE:
6378       if (desc < (DOUBLE_OFFSET + 2))
6379 	{
6380 	  hi += (DOUBLE_OFFSET + 2) - desc;
6381 	  desc = DOUBLE_OFFSET + 2;
6382 	}
6383       break;
6384     default:
6385       break;
6386     }
6387 
6388   if (width != NULL) *width = wid;
6389   if (height != NULL) *height = hi;
6390   if (ascent != NULL) *ascent = asc;
6391   if (descent != NULL) *descent = desc;
6392 }
6393 
6394 static Dimension
ComputeWidth(unsigned char which,XCharStruct char_ret)6395 ComputeWidth(unsigned char which,
6396 	     XCharStruct char_ret)
6397 {
6398   Dimension wid = 0;
6399   int bearing;
6400 
6401   /* Width of first segment is -leftbearing + width. */
6402   /* Width of last segment is max of width and rightbearing. */
6403   /* Width of single segment is max of width and rightbearing - leftbearing. */
6404   /* Width of all other segments is width. */
6405   switch (which)
6406     {
6407     case XmSTRING_FIRST_SEG:
6408       if (char_ret.lbearing < 0)
6409 	wid = -(char_ret.lbearing);
6410       /* Fall through */
6411     case XmSTRING_MIDDLE_SEG:
6412       wid += char_ret.width;
6413       break;
6414     case XmSTRING_LAST_SEG:
6415       wid = ((char_ret.width > char_ret.rbearing) ?
6416 	     char_ret.width : char_ret.rbearing);
6417       break;
6418     case XmSTRING_SINGLE_SEG:
6419       bearing = char_ret.rbearing - char_ret.lbearing;
6420       wid = (char_ret.width > bearing) ? char_ret.width : bearing;
6421       break;
6422     }
6423   return(wid);
6424 }
6425 
6426 /****************************************************************
6427  *
6428  ****************************************************************/
6429 Boolean
_XmStringSegmentExtents(_XmStringEntry entry,XmRenderTable rendertable,XmRendition * rend_in_out,XmRendition base,Dimension * width,Dimension * height,Dimension * ascent,Dimension * descent)6430 _XmStringSegmentExtents(_XmStringEntry entry,
6431 			XmRenderTable    rendertable,
6432 			XmRendition    * rend_in_out,
6433 			XmRendition	 base,
6434 			Dimension      * width,
6435 			Dimension      * height,
6436 			Dimension      * ascent,
6437 			Dimension      * descent)
6438 {
6439   return(SpecifiedSegmentExtents(entry, rendertable, rend_in_out, base,
6440 				 XmSTRING_MIDDLE_SEG,
6441 				 width, height, ascent, descent));
6442 }
6443 
6444 static Boolean
SpecifiedSegmentExtents(_XmStringEntry entry,XmRenderTable rendertable,XmRendition * rend_in_out,XmRendition base,int which_seg,Dimension * width,Dimension * height,Dimension * ascent,Dimension * descent)6445 SpecifiedSegmentExtents(_XmStringEntry entry,
6446 			XmRenderTable    rendertable,
6447 			XmRendition    * rend_in_out,
6448 			XmRendition	 base,
6449 			int		 which_seg,
6450 			Dimension      * width,
6451 			Dimension      * height,
6452 			Dimension      * ascent,
6453 			Dimension      * descent)
6454 {
6455   unsigned short	count;
6456   XmStringTag		*tags = NULL;
6457   unsigned int		tag_count =0;
6458   Display		*d;
6459   XmStringTag		def_tag;
6460   XmStringTag		entry_tag;
6461   XmRendition		rend, cached_rend = NULL, def_rend;
6462   int			i, j, depth, hits, ref_cnt, rt_ref_cnt;
6463   Dimension		h, w, asc, dsc;
6464   Boolean		can_do = TRUE;
6465   _XmRendition		rend_int;
6466   _XmStringRenderingCache render_cache;
6467 
6468   /* Fetching the cache once and accessing the fields directly saves
6469    * substantial time searching the cache
6470    */
6471   render_cache = (_XmStringRenderingCache)CacheGet(entry, _XmRENDERING_CACHE, False,
6472 						   (XtPointer)rendertable);
6473 
6474   if ((render_cache != NULL) && !render_cache->header.dirty)
6475     {
6476       if (width != NULL)
6477 	*width = (Dimension)render_cache->width;
6478       if (height != NULL)
6479 	*height = (Dimension)render_cache->height;
6480       if (ascent != NULL)
6481 	*ascent = (Dimension)render_cache->ascent;
6482       if (descent != NULL)
6483 	*descent = (Dimension)render_cache->descent;
6484       if (rend_in_out != NULL)
6485 	*rend_in_out = render_cache->rendition;
6486       return True;
6487     } else if (rend_in_out == NULL)
6488       {
6489 	if (render_cache != NULL)
6490 	  cached_rend = render_cache->rendition;
6491 
6492 	if (cached_rend == NULL) return(FALSE);
6493 	else rend_in_out = &cached_rend;
6494       }
6495 
6496   entry_tag = _XmEntryTag(entry);
6497 
6498   if (cached_rend == NULL)			  /* Update *rend_in_out. */
6499     {
6500       /* Add rendition begins */
6501       d = _XmRendDisplay(*rend_in_out);
6502 
6503       /* Prepare tags. */
6504       count = _XmEntryRendBeginCountGet(entry);
6505       tags = _XmRendTags(*rend_in_out);
6506       tag_count = _XmRendTagCount(*rend_in_out);
6507 
6508       /* Update tag stack. */
6509       if (count > 0)
6510 	{
6511 	  tags = (XmStringTag *)XtRealloc((char *)tags,
6512 					  (sizeof(XmStringTag) *
6513 					   (tag_count + count)));
6514 	  for (i = 0; i < count; i++)
6515 	    tags[tag_count + i] = _XmEntryRendBeginGet(entry, i);
6516 
6517 	  tag_count += count;
6518 	}
6519 
6520       /* compute rendition */
6521       /* Find font as per I 198. */
6522       /* 1. Find font from rendition tags. */
6523       /* 2. Find font from locale/charset tag. */
6524       if ((_XmRendTag(*rend_in_out) != entry_tag) ||
6525 	  (count != 0) || _XmRendHadEnds(*rend_in_out))
6526 	{
6527 	  *rend_in_out = _XmRenditionMerge(d, rend_in_out, base, rendertable,
6528 					   entry_tag, tags, tag_count,
6529 					   (render_cache != NULL));
6530 	  _XmRendTag(*rend_in_out) = entry_tag;
6531 	}
6532 
6533       /* 3. Default rendition. */
6534       if (_XmRendFont(*rend_in_out) == NULL &&
6535           _XmRendXftFont(*rend_in_out) == NULL)
6536 	{
6537 	  def_tag = ((_XmEntryTextTypeGet(entry) == XmCHARSET_TEXT) ?
6538 		     XmFONTLIST_DEFAULT_TAG :
6539 		     _MOTIF_DEFAULT_LOCALE);
6540 
6541 	  rend = _XmRenditionMerge(d, rend_in_out, base, rendertable,
6542 				   def_tag, NULL, 0, (render_cache != NULL));
6543 
6544 	  if ((rend != NULL) &&
6545 	      (_XmRendFont(rend) == NULL) && (_XmRendXftFont(rend) == NULL) &&
6546 	      ((def_rend = _XmRenderTableFindRendition(rendertable, def_tag,
6547 						       TRUE, FALSE, FALSE, NULL))
6548 	       != NULL))
6549 	    /* Call noFontCallback. */
6550 	    {
6551 	      XmDisplay			dsp;
6552 	      XmDisplayCallbackStruct	cb;
6553 
6554 	      rt_ref_cnt = _XmRTRefcount(rendertable);
6555 	      def_rend = _XmRTRenditions(rendertable)[0];
6556 	      rend_int = *def_rend;
6557 	      ref_cnt = _XmRendRefcount(def_rend);
6558 
6559 	      dsp = (XmDisplay)XmGetXmDisplay(d);
6560 	      cb.reason = XmCR_NO_FONT;
6561 	      cb.event = NULL;
6562 	      cb.rendition = def_rend;
6563 	      cb.font_name = XmS;
6564 
6565 	      XtCallCallbackList((Widget)dsp, dsp->display.noFontCallback, &cb);
6566 
6567 	      if (rend_int != *def_rend)	  /* Changed in callback. */
6568 		{
6569 		  /* Need to split ref counts. */
6570 		  _XmRendRefcount(&rend_int) = ref_cnt - rt_ref_cnt;
6571 		  _XmRendRefcount(def_rend) = rt_ref_cnt;
6572 		}
6573 
6574 	      if (_XmRendFont(def_rend) != NULL)
6575 		{
6576 		  _XmRendFontType(rend) = _XmRendFontType(def_rend);
6577 		  _XmRendFont(rend) = _XmRendFont(def_rend);
6578 		}
6579 #ifdef USE_XFT
6580               else if (_XmRendXftFont(def_rend) != NULL)
6581 	        {
6582 		  _XmRendFontType(rend) = _XmRendFontType(def_rend);
6583 		  _XmRendXftFont(rend) = _XmRendXftFont(def_rend);
6584 		}
6585 #endif
6586 	      else rend = NULL;
6587 	    }
6588 
6589 	  /* 4a. Take the first one */
6590 	  if ((rend == NULL) &&
6591 	      ((_XmEntryTextTypeGet(entry) == XmCHARSET_TEXT) ||
6592 	       ((_XmEntryTextTypeGet(entry) == XmMULTIBYTE_TEXT) &&
6593 		(entry_tag == XmFONTLIST_DEFAULT_TAG))) &&
6594 	      (rendertable != NULL) && (_XmRTCount(rendertable) > 0))
6595 	    rend = _XmRenditionMerge(d, rend_in_out, base, rendertable,
6596 				     NULL, NULL, 0, (render_cache != NULL));
6597 
6598 	  if ((rend != NULL) &&
6599 	      (_XmRendFont(rend) == NULL) && (_XmRendXftFont(rend) == NULL))
6600 	    /* Call noFontCallback. */
6601 	    {
6602 	      XmDisplay			dsp;
6603 	      XmDisplayCallbackStruct	cb;
6604 
6605 	      rt_ref_cnt = _XmRTRefcount(rendertable);
6606 	      def_rend = _XmRTRenditions(rendertable)[0];
6607 	      rend_int = *def_rend;
6608 	      ref_cnt = _XmRendRefcount(def_rend);
6609 
6610 	      dsp = (XmDisplay)XmGetXmDisplay(d);
6611 	      cb.reason = XmCR_NO_FONT;
6612 	      cb.event = NULL;
6613 	      cb.rendition = def_rend;
6614 	      cb.font_name = XmS;
6615 
6616 	      XtCallCallbackList((Widget)dsp, dsp->display.noFontCallback, &cb);
6617 
6618 	      if (rend_int != *def_rend)	  /* Changed in callback. */
6619 		{
6620 		  /* Need to split ref counts. */
6621 		  _XmRendRefcount(&rend_int) = ref_cnt - rt_ref_cnt;
6622 		  _XmRendRefcount(def_rend) = rt_ref_cnt;
6623 		}
6624 
6625 	      if (_XmRendFont(def_rend) != NULL)
6626 		{
6627 		  _XmRendFontType(rend) = _XmRendFontType(def_rend);
6628 		  _XmRendFont(rend) = _XmRendFont(def_rend);
6629 		}
6630 #ifdef USE_XFT
6631               else if (_XmRendXftFont(def_rend) != NULL)
6632 	        {
6633 		  _XmRendFontType(rend) = _XmRendFontType(def_rend);
6634 		  _XmRendXftFont(rend) = _XmRendXftFont(def_rend);
6635 		}
6636 #endif
6637 	      else rend = NULL;
6638 	    }
6639 
6640 	  /* 4b/5a. Emit warning and don't render. */
6641 	  if ((rend == NULL) ||
6642 	      (_XmRendFont(rend) == NULL && _XmRendXftFont(rend) == NULL))
6643 	    {
6644 	      /* No warning if no tags, e.g. just dir component. */
6645 	      if ((tag_count > 0) || (entry_tag != NULL))
6646 		XmeWarning(NULL, NO_FONT_MSG);
6647 	      if (width != NULL)
6648 		{
6649 		  *width = 0;
6650 		  if (render_cache)
6651 		    render_cache->width = 0;
6652 		}
6653 	      if (height != NULL)
6654 		{
6655 		  *height = 0;
6656 		  if (render_cache)
6657 		    render_cache->height = 0;
6658 		}
6659 	      if (ascent != NULL)
6660 		{
6661 		  *ascent = 0;
6662 		  if (render_cache)
6663 		    render_cache->ascent = 0;
6664 		}
6665 	      if (descent != NULL)
6666 		{
6667 		  *descent = 0;
6668 		  if (render_cache)
6669 		    render_cache->descent = 0;
6670 		}
6671 	      can_do = FALSE;
6672 	    }
6673 	}
6674     }
6675 
6676   if (can_do)
6677     {
6678       /* compute width & height */
6679       ComputeMetrics(*rend_in_out, _XmEntryTextGet(entry),
6680 		     _XmEntryByteCountGet(entry),
6681 		     (XmTextType) _XmEntryTextTypeGet(entry),
6682 		     which_seg, &w, &h, &asc, &dsc,
6683 #ifdef UTF8_SUPPORTED
6684                    _XmEntryType(entry) == XmCHARSET_TEXT &&
6685                    (_XmEntryTag(entry) == XmFONTLIST_DEFAULT_TAG
6686                     && (_XmStringIsCurrentCharset("UTF-8")
6687                     || (_XmEntryTagIndex(entry) !=  TAG_INDEX_UNSET
6688 		    && strcmp(_XmEntryTag(entry), "UTF-8") == 0)))
6689 #else
6690                    False
6691 #endif
6692 		    );
6693 
6694       /* If cache exists, set it. */
6695       if (render_cache != NULL)
6696 	{
6697 	  if (width != NULL) render_cache->width = w;
6698 	  if (height != NULL) render_cache->height = h;
6699 	  if (ascent != NULL) render_cache->ascent = asc;
6700 	  if (descent != NULL) render_cache->descent = dsc;
6701 
6702 	  render_cache->rendition = *rend_in_out;
6703 	  render_cache->header.dirty = False;
6704 	}
6705 
6706       if (width != NULL) *width = w;
6707       if (height != NULL) *height = h;
6708       if (ascent != NULL) *ascent = asc;
6709       if (descent != NULL) *descent = dsc;
6710     }
6711 
6712   if (cached_rend == NULL)			  /* Update *rend_in_out */
6713     {
6714       /* Remove rendition ends. */
6715       count = _XmEntryRendEndCountGet(entry);
6716 
6717       if (count > 0)
6718 	{
6719 	  depth = tag_count;
6720 	  hits = 0;
6721 
6722 	  for (i = 0; i < count; i++)
6723 	    for (j = (tag_count - 1); j >= 0; j--)
6724 	      if (_XmEntryRendEndGet(entry, i) == (tags)[j])
6725 		{
6726 		  tags[j] = NULL;
6727 		  depth = j;
6728 		  hits++;
6729 		  break;
6730 		}
6731 
6732 	  j = depth;
6733 	  for (i = (depth + 1); i < tag_count; i++)
6734 	    if (tags[i] != NULL)
6735 	      {
6736 		tags[j] = tags[i];
6737 		j++;
6738 	      }
6739 
6740 	  if(tags != NULL && tag_count - hits)
6741 	    tags = (XmStringTag *)XtRealloc((char *)tags,
6742 					  (sizeof(XmStringTag) *
6743 					   (tag_count - hits)));
6744 	  tag_count -= hits;
6745 	  _XmRendHadEnds(*rend_in_out) = TRUE;
6746 	}
6747       else
6748 	{
6749 	  _XmRendHadEnds(*rend_in_out) = FALSE;
6750 	}
6751 
6752       _XmRendTagCount(*rend_in_out) = tag_count;
6753       _XmRendTags(*rend_in_out) = tags;
6754     }
6755 
6756   return(can_do);
6757 }
6758 
6759 static void
_parse_locale(char * str,int * indx,int * len)6760 _parse_locale(
6761         char *str,
6762         int *indx,
6763         int *len )
6764 {
6765     char     *temp;
6766     int      start;
6767     int      end;
6768 
6769     /*
6770      *  Set the return variables to zero.  If we find what we're looking
6771      *  for, we reset them.
6772      */
6773 
6774     *indx = 0;
6775     *len = 0;
6776 
6777     /*
6778      *  The format of the locale string is:
6779      *          language[_territory[.codeset]]
6780      */
6781 
6782     temp = str;
6783     end = 0;
6784     while ((temp[end] != '.') && (temp[end] != 0))
6785       end++;
6786 
6787     if (temp[end] == '.')
6788     {
6789         start = end + 1;
6790         *indx = start;
6791 	end = start;
6792         while (temp[end] != 0)
6793 	  end++;
6794         *len = end - start;
6795     }
6796 }
6797 
6798  /* This function returns current default charset being used.  This is */
6799  /* determined from the value of the $LANG environment variable or */
6800  /* XmFALLBACK_CHARSET.  */
6801 char *
_XmStringGetCurrentCharset(void)6802 _XmStringGetCurrentCharset( void )
6803 {
6804     char *str;
6805     char *ptr;
6806     int  chlen;
6807     int  indx;
6808     int  len;
6809     char *ret_val;
6810 
6811     _XmProcessLock();
6812     if (!locale.inited)
6813     {
6814         locale.tag = NULL;
6815         locale.taglen = 0;
6816 
6817         str = (char *)getenv(env_variable);
6818 
6819         if (str)
6820         {
6821            _parse_locale(str, &indx, &chlen);
6822            if (chlen > 0)
6823            {
6824                ptr = &str[indx];
6825 	       len = chlen;
6826            }
6827            else {
6828                len = strlen(XmFALLBACK_CHARSET);
6829                ptr = XmFALLBACK_CHARSET;
6830            }
6831         }
6832         else {
6833 	  len = strlen(XmFALLBACK_CHARSET);
6834 	  ptr = XmFALLBACK_CHARSET;
6835         }
6836         locale.tag = (char *) XtMalloc(len + 1);
6837         strncpy(locale.tag, ptr, len);
6838         locale.tag[len] = '\0';
6839         locale.taglen = len;
6840 
6841 	/* Register XmSTRING_DEFAULT_CHARSET for compound text conversion. */
6842 	XmRegisterSegmentEncoding(XmSTRING_DEFAULT_CHARSET,
6843 				  XmFONTLIST_DEFAULT_TAG);
6844 
6845         locale.inited = TRUE;
6846     }
6847     ret_val = locale.tag;
6848     _XmProcessUnlock();
6849     return (ret_val);
6850 }
6851 
6852  /* This function compares a given charset to the current default charset
6853     being used.  It return TRUE if they match, FALSE otherwise.
6854  */
6855 Boolean
_XmStringIsCurrentCharset(XmStringCharSet c)6856 _XmStringIsCurrentCharset( XmStringCharSet c )
6857 {
6858   return (strcmp(c, _XmStringGetCurrentCharset()) == 0);
6859 }
6860 
6861 /*
6862  * copy a refcounted string
6863  */
6864 XmString
XmStringCopy(XmString string)6865 XmStringCopy(
6866         XmString string )
6867 {
6868   _XmProcessLock();
6869   if (string == NULL) {
6870       _XmProcessUnlock();
6871       return((XmString)NULL);
6872   }
6873 
6874   /* If the refcount wraps around, have to make clone,
6875      otherwise just return. */
6876   if (_XmStrRefCountInc(string) != 0) {
6877     _XmProcessUnlock();
6878     return(string);
6879   }
6880   else
6881     {
6882       XmString ret_val;
6883 
6884       _XmStrRefCountDec(string);
6885       ret_val = Clone(string, _XmStrEntryCountGet(string));
6886       _XmProcessUnlock();
6887       return ret_val;
6888     }
6889 }
6890 
6891 /*
6892  * duplicate structure of an internal string
6893  */
6894 static XmString
Clone(XmString string,int lines)6895 Clone(XmString string,
6896       int lines)
6897 {
6898   XmString new_string;
6899 
6900   if (_XmStrOptimized(string))
6901     {
6902       _XmStringOpt n_o_string =
6903 	(_XmStringOpt) _XmStrMalloc(sizeof(_XmStringOptRec) +
6904 				    _XmStrByteCount(string) -
6905 				    TEXT_BYTES_IN_STRUCT);
6906 
6907       memcpy(n_o_string, string,
6908 	     sizeof(_XmStringOptRec) +
6909 	     _XmStrByteCount(string) -
6910 	     TEXT_BYTES_IN_STRUCT) ;
6911       new_string = (XmString)n_o_string;
6912     }
6913   else
6914     {
6915       int i;
6916       _XmString n_string;
6917 
6918       _XmStrCreate(n_string, XmSTRING_MULTIPLE_ENTRY, 0);
6919 
6920       _XmStrImplicitLine(n_string) = _XmStrImplicitLine(string);
6921 
6922       _XmStrEntryCount(n_string) = _XmStrEntryCount(string);
6923       _XmStrEntry(n_string) = (_XmStringEntry *)
6924 	XtMalloc(sizeof(_XmStringEntry) * lines);
6925 
6926       for (i = 0; i < _XmStrEntryCount(string); i++)
6927 	_XmStrEntry(n_string)[i] = _XmStringEntryCopy(_XmStrEntry(string)[i]);
6928       for (i = _XmStrEntryCount(string); i < lines; i++)
6929 	_XmStrEntry(n_string)[i] = NULL;
6930 
6931       new_string = (XmString)n_string;
6932     }
6933 
6934   _XmStrRefCountSet(new_string, 1);
6935 
6936   return(new_string);
6937 }
6938 
6939 /*
6940  * Given a string in ASN.1 format, return the size of the
6941  * string, including the header.
6942  */
6943 unsigned int
XmStringByteStreamLength(unsigned char * string)6944 XmStringByteStreamLength(unsigned char *string)
6945 {
6946     unsigned int len;
6947 
6948     _XmProcessLock();
6949     len = _read_string_length( string );
6950     len += _calc_header_size(len);
6951     _XmProcessUnlock();
6952     return (len);
6953 }
6954 
6955 /*
6956  * build the ASN.1 format given an XmString.
6957  * This makes a pass to figure out how big it
6958  * needs to be and builds the ASN.1 string in-place.
6959  * If prop_return is NULL, just computes size.
6960  */
6961 unsigned int
XmCvtXmStringToByteStream(XmString string,unsigned char ** prop_return)6962 XmCvtXmStringToByteStream(XmString string,
6963 		  unsigned char **prop_return)
6964 {
6965   /* Using XmeStringGetComponent makes this almost trivial. */
6966   _XmStringContextRec	stack_context;
6967   unsigned int		length;
6968   XtPointer		value;
6969   unsigned int		len;
6970   unsigned int		str_len;
6971   unsigned char		*ext;
6972   XmStringComponentType	tag;
6973 
6974   _XmProcessLock();
6975   if (!string)
6976     {
6977       if (prop_return != NULL) *prop_return = NULL;
6978       _XmProcessUnlock();
6979       return(0);
6980     }
6981 
6982   _XmStringContextReInit(&stack_context, string);
6983 
6984   /* Compute size */
6985   len = 0;
6986   while (XmeStringGetComponent(&stack_context, TRUE, FALSE, &length, &value) !=
6987 	 XmSTRING_COMPONENT_END)
6988     len += _asn1_size(length) + length;
6989 
6990   str_len = len;
6991   len += _calc_header_size(len);
6992 
6993   _XmStringContextFree(&stack_context);
6994 
6995   /* We're just computing size. */
6996   if (prop_return == NULL) {
6997 	 _XmProcessUnlock();
6998 	 return(len);
6999   }
7000 
7001   /* Allocate. */
7002   ext = (unsigned char *)XtMalloc(len);
7003   *prop_return = ext;
7004 
7005   /* Write components. */
7006   ext = _write_header(ext, str_len);
7007 
7008   _XmStringContextReInit(&stack_context, string);
7009 
7010   while ((tag = XmeStringGetComponent(&stack_context, TRUE, FALSE,
7011 				      &length, &value)) !=
7012 	 XmSTRING_COMPONENT_END)
7013     ext = _write_component(ext, tag, length, (unsigned char *)value, TRUE);
7014 
7015   _XmStringContextFree(&stack_context);
7016 
7017   _XmProcessUnlock();
7018   return(len);
7019 }
7020 
7021 Dimension
XmStringBaseline(XmRenderTable rendertable,XmString string)7022 XmStringBaseline(
7023         XmRenderTable rendertable,
7024         XmString string )
7025 {
7026   Dimension 		width, height, asc = 0, desc;
7027   _XmRenditionRec	scratch;
7028   _XmRendition		tmp;
7029   XmRendition		rend;
7030   _XmStringEntry 	line;
7031   _XmStringArraySegRec 	array_seg;
7032   Display		*d;
7033   XtAppContext		app = NULL;
7034 
7035   if ((rendertable == NULL) || (string == NULL)) return(0);
7036 
7037 #ifdef XTHREADS
7038   if (_XmRTDisplay(rendertable))
7039     app = XtDisplayToApplicationContext(_XmRTDisplay(rendertable));
7040   if (app)
7041   {
7042 	_XmAppLock(app);
7043   }
7044   else
7045   {
7046 	_XmProcessLock();
7047   }
7048 #endif
7049   bzero((char*) &scratch, sizeof(_XmRenditionRec));
7050   tmp = &scratch;
7051   rend = &tmp;
7052 
7053   /* Initialize for tabs. */
7054   d = (_XmRTDisplay(rendertable) == NULL) ?
7055     _XmGetDefaultDisplay()
7056       : _XmRTDisplay(rendertable);
7057 
7058   _XmRendDisplay(rend) = d;
7059 
7060   _XmStringLayout(string, XmLEFT_TO_RIGHT);
7061 
7062   if (!_XmStrOptimized(string))
7063     {
7064       if (_XmStrImplicitLine(string))
7065 	line = _XmStrEntry(string)[0];
7066       else {
7067 	_XmEntryType(&array_seg) = XmSTRING_ENTRY_ARRAY;
7068 	_XmEntrySegmentCount(&array_seg) = _XmStrEntryCount(string);
7069 	_XmEntrySegment(&array_seg) =
7070 	  (_XmStringNREntry *)_XmStrEntry(string);
7071 	line = (_XmStringEntry)&array_seg;
7072       }
7073 
7074       LineMetrics(line, rendertable, &rend, NULL, XmLEFT_TO_RIGHT,
7075 		  &width, &height, &asc, &desc);
7076 
7077       if (app)
7078   	{
7079          _XmAppUnlock(app);
7080 	}
7081       else
7082 	{
7083 	 _XmProcessUnlock();
7084 	}
7085       return(asc);
7086     }
7087   else
7088     {
7089       if (app)
7090 	{
7091          _XmAppUnlock(app);
7092 	}
7093       else
7094 	{
7095 	 _XmProcessUnlock();
7096 	}
7097       return (OptLineAscender(rendertable, (_XmStringOpt)string));
7098     }
7099 }
7100 
7101 void
_XmStringGetBaselines(XmRenderTable rendertable,_XmString string,Dimension ** baselines,Cardinal * line_count)7102 _XmStringGetBaselines(XmRenderTable rendertable,
7103 		      _XmString string,
7104 		      Dimension **baselines,
7105 		      Cardinal *line_count)
7106 {
7107   /* Initialize the return values. */
7108   *baselines = NULL;
7109   *line_count = 0;
7110 
7111   if (rendertable && string)
7112     *line_count = XmStringLineCount(string);
7113 
7114   if (*line_count == 1)
7115     {
7116       *baselines = (Dimension*) XtMalloc(*line_count * sizeof(Dimension));
7117       (*baselines)[0] = XmStringBaseline(rendertable, string);
7118     }
7119   else if (*line_count > 1)
7120     {
7121       Cardinal line_num;
7122       Dimension offset;
7123       Dimension prev_height;
7124 
7125       Dimension		   width, height, asc, desc;
7126       _XmRenditionRec	   scratch;
7127       _XmRendition	   tmp = &scratch;
7128       XmRendition	   rend = &tmp;
7129       _XmStringArraySegRec array_seg;
7130 
7131       *baselines = (Dimension*) XtMalloc(*line_count * sizeof(Dimension));
7132 
7133       /* Initialize the scratch rendition for tabs. */
7134       bzero((char*) &scratch, sizeof(_XmRenditionRec));
7135       _XmRendDisplay(rend) =
7136 	((_XmRTDisplay(rendertable) == NULL) ?
7137 	 _XmGetDefaultDisplay() : _XmRTDisplay(rendertable));
7138 
7139       _XmStringLayout(string, XmLEFT_TO_RIGHT);
7140 
7141       offset = prev_height = 0;
7142       for (line_num = 0; line_num < *line_count; line_num++)
7143 	{
7144 	  _XmStringEntry line;
7145 
7146 	  if (_XmStrImplicitLine(string))
7147 	    line = _XmStrEntry(string)[line_num];
7148 	  else {
7149 	    _XmEntryType(&array_seg) = XmSTRING_ENTRY_ARRAY;
7150 	    _XmEntrySegmentCount(&array_seg) = _XmStrEntryCount(string);
7151 	    _XmEntrySegment(&array_seg) =
7152 	      (_XmStringNREntry *)_XmStrEntry(string);
7153 	    line = (_XmStringEntry)&array_seg;
7154 	  }
7155 
7156 	  LineMetrics(line, rendertable, &rend, NULL, XmLEFT_TO_RIGHT,
7157 		      &width, &height, &asc, &desc);
7158 
7159 	  /* Treat empty lines as the same height as the previous line. */
7160 	  if (height)
7161 	    prev_height = height;
7162 
7163 	  (*baselines)[line_num] = offset + asc;
7164 	  offset += prev_height;
7165 	}
7166     }
7167 }
7168 
7169 /*
7170  * count the number of lines in an XmString.
7171  */
7172 int
XmStringLineCount(XmString string)7173 XmStringLineCount(
7174         XmString string )
7175 {
7176   int ret_val;
7177 
7178   _XmProcessLock();
7179   if ((string == NULL)) {
7180 	_XmProcessUnlock();
7181 	return(0);
7182   }
7183 
7184   if (_XmStrOptimized(string)) {
7185     _XmProcessUnlock();
7186     return( 1) ;
7187   }
7188 
7189   ret_val = (int) _XmStrLineCountGet(string) ;
7190   _XmProcessUnlock();
7191   return ret_val;
7192 }
7193 
7194 /*
7195  * drawing routine for external TCS
7196  */
7197 void
XmStringDraw(Display * d,Window w,XmRenderTable rendertable,XmString string,GC gc,int x,int y,int width,unsigned int align,unsigned int lay_dir,XRectangle * clip)7198 XmStringDraw(
7199         Display *d,
7200         Window w,
7201         XmRenderTable rendertable,
7202         XmString string,
7203         GC gc,
7204 #if NeedWidePrototypes
7205         int x,
7206         int y,
7207         int width,
7208         unsigned int align,
7209         unsigned int lay_dir,
7210 #else
7211         Position x,
7212         Position y,
7213         Dimension width,
7214         unsigned char align,
7215         unsigned char lay_dir,
7216 #endif /* NeedWidePrototypes */
7217         XRectangle *clip )
7218 {
7219   _XmDisplayToAppContext(d);
7220   _XmAppLock(app);
7221 
7222   if (string)
7223     _draw (d, w, rendertable, (_XmString)string, gc, x, y, width,
7224 	   align, lay_dir, clip, FALSE, NULL);
7225 
7226   _XmAppUnlock(app);
7227 }
7228 
7229 void
XmStringDrawImage(Display * d,Window w,XmRenderTable rendertable,XmString string,GC gc,int x,int y,int width,unsigned int align,unsigned int lay_dir,XRectangle * clip)7230 XmStringDrawImage(
7231         Display *d,
7232         Window w,
7233         XmRenderTable rendertable,
7234         XmString string,
7235         GC gc,
7236 #if NeedWidePrototypes
7237         int x,
7238         int y,
7239         int width,
7240         unsigned int align,
7241         unsigned int lay_dir,
7242 #else
7243         Position x,
7244         Position y,
7245         Dimension width,
7246         unsigned char align,
7247         unsigned char lay_dir,
7248 #endif /* NeedWidePrototypes */
7249         XRectangle *clip )
7250 {
7251   _XmDisplayToAppContext(d);
7252   _XmAppLock(app);
7253 
7254   if (string)
7255     _draw (d, w, rendertable, (_XmString)string, gc, x, y, width,
7256 	   align, lay_dir, clip, TRUE, NULL);
7257 
7258   _XmAppUnlock(app);
7259 }
7260 
7261 void
XmStringDrawUnderline(Display * d,Window w,XmRenderTable fntlst,XmString str,GC gc,int x,int y,int width,unsigned int align,unsigned int lay_dir,XRectangle * clip,XmString under)7262 XmStringDrawUnderline(
7263         Display *d,
7264         Window w,
7265         XmRenderTable fntlst,
7266         XmString str,
7267         GC gc,
7268 #if NeedWidePrototypes
7269         int x,
7270         int y,
7271         int width,
7272         unsigned int align,
7273         unsigned int lay_dir,
7274 #else
7275         Position x,
7276         Position y,
7277         Dimension width,
7278         unsigned char align,
7279         unsigned char lay_dir,
7280 #endif /* NeedWidePrototypes */
7281         XRectangle *clip,
7282         XmString under )
7283 {
7284   _XmDisplayToAppContext(d);
7285   _XmAppLock(app);
7286   if (str)
7287     _draw (d, w, fntlst, (_XmString)str, gc, x, y, width,
7288 	   align, lay_dir, clip, FALSE, (_XmString)under);
7289 
7290   _XmAppUnlock(app);
7291 }
7292 
7293 
7294 #ifdef _XmDEBUG_XMSTRING
7295 
7296 void
_Xm_dump_stream(unsigned char * cs)7297 _Xm_dump_stream(
7298         unsigned char *cs )
7299 {
7300     unsigned char *c;
7301     unsigned char *end;
7302     int k;
7303 
7304     if (_is_asn1(cs))
7305     {
7306 	printf ("Compound string\n");
7307 	printf ("overall length = %d\n", _read_string_length(cs));
7308 	c = _read_header(cs);
7309     }
7310     else {
7311         printf ("Not a compound string\n");
7312         return;
7313     }
7314 
7315     c = (unsigned char *) cs;
7316     end = c + _read_string_length (c) + _read_header_length(c);
7317 
7318     while (c < end)
7319     {
7320 	unsigned short length = _read_asn1_length (c);
7321 
7322 	switch (*c)
7323 	{
7324 	    case XmSTRING_COMPONENT_CHARSET:
7325 	    case XmSTRING_COMPONENT_LOCALE:
7326                 if (*c ==  XmSTRING_COMPONENT_LOCALE)
7327 		  printf ("\tLocale name component\n");
7328 		else
7329 		  printf ("\tCharacter set component\n");
7330 		printf ("\tlength = %d\n", length);
7331 	  	printf ("\tvalue  = <");
7332 		for (k=0; k<length; k++)
7333 		  printf ("%c", *(c + _asn1_size(length) + k));
7334 		printf (">\n");
7335 		c += length + _asn1_size(length);
7336 		break;
7337 
7338 	    case XmSTRING_COMPONENT_TEXT:
7339             case XmSTRING_COMPONENT_LOCALE_TEXT:
7340                 if (*c ==  XmSTRING_COMPONENT_TEXT)
7341                   printf ("\tText component\n");
7342                 else printf ("\tLocalized text component\n");
7343 
7344 		printf ("\tlength = %d\n", length);
7345 	  	printf ("\tvalue  = <");
7346 		for (k=0; k<length; k++)
7347 		  printf ("%c", *(c + _asn1_size(length) + k));
7348 		printf (">\n");
7349 		c += length + _asn1_size(length);
7350 		break;
7351 
7352             case XmSTRING_COMPONENT_WIDECHAR_TEXT:
7353                 printf ("\tWide char text component\n");
7354 		printf ("\tlength = %d\n", length);
7355 	  	printf ("\tvalue  = <");
7356 		for (k=0; k<length; k++)
7357 		  printf ("%c", *(c + _asn1_size(length) + k));
7358 		printf (">\n");
7359 		c += length + _asn1_size(length);
7360 		break;
7361 
7362 	    case XmSTRING_COMPONENT_DIRECTION:		/* record dir */
7363 		printf ("\tDirection component\n");
7364 		printf ("\tlength = %d\n", length);
7365 	  	printf ("\tvalue  = %d\n", *(c + _asn1_size(length)));
7366 		c += length + _asn1_size(length);
7367 		break;
7368 
7369 	    case XmSTRING_COMPONENT_SEPARATOR:		/* start new line */
7370 		printf ("\tSeparator component\n");
7371 		printf ("\tlength = %d\n", length);
7372 		c += length + _asn1_size(length);
7373 		break;
7374 
7375 	    default:
7376 		printf ("\tUnknown component\n");
7377 		printf ("\tlength = %d\n", length);
7378 	  	printf ("\tvalue  = <");
7379 		for (k=0; k<length; k++)
7380 			printf ("%3d ", (int) *(c + _asn1_size(length) + k));
7381 		printf ("\n");
7382 		c += length + _asn1_size(length);
7383 		break;
7384 	}
7385 
7386 	printf ("\n");
7387 
7388     }
7389 }
7390 
7391 static char*
type_image(XmTextType type)7392 type_image(XmTextType type)
7393 {
7394   switch (type)
7395     {
7396     case XmCHARSET_TEXT:
7397       return "XmCHARSET_TEXT";
7398     case XmMULTIBYTE_TEXT:
7399       return "XmMULTIBYTE_TEXT";
7400     case XmWIDECHAR_TEXT:
7401       return "XmWIDECHAR_TEXT";
7402     case XmNO_TEXT:
7403       return "XmNO_TEXT";
7404     default:
7405       return "unknown";
7406     }
7407 }
7408 
7409 static char*
entry_type_image(int type)7410 entry_type_image(int type)
7411 {
7412   switch (type)
7413     {
7414     case XmSTRING_ENTRY_OPTIMIZED:
7415       return "XmSTRING_ENTRY_OPTIMIZED";
7416     case XmSTRING_ENTRY_ARRAY:
7417       return "XmSTRING_ENTRY_ARRAY";
7418     case XmSTRING_ENTRY_UNOPTIMIZED:
7419       return "XmSTRING_ENTRY_UNOPTIMIZED";
7420     default:
7421       return "unknown";
7422     }
7423 }
7424 
7425 void
_Xm_dump_internal(_XmString string)7426 _Xm_dump_internal(
7427         _XmString string )
7428 {
7429   int i, j, k;
7430 
7431   if (_XmStrOptimized(string))
7432     {
7433       printf ("string with 1 line\n") ;
7434       printf ("\tOptimized string - single segment\n");
7435       printf ("\t    tag type      = %4d\n", _XmStrTextType(string));
7436       printf ("\t    direction     = %4d\n", _XmStrDirection(string));
7437       printf ("\t    tag index     = %4d\n", _XmStrTagIndex(string));
7438       printf ("\t    rend_begin    = %4d\n", _XmStrRendBegin(string));
7439       printf ("\t    rend_end      = %4d\n", _XmStrRendEnd(string));
7440       printf ("\t    rend_index    = %4d <%s>\n", _XmStrRendIndex(string),
7441 	      (_XmStrRendTagGet(string) ?
7442 	       _XmStrRendTagGet(string) : "(unset)"));
7443       printf ("\t    tab_before    = %4d\n", _XmStrTabs(string));
7444       printf ("\t    refcount      = %4d\n", _XmStrRefCountGet(string));
7445       printf ("\t    char count    = %4d\n", _XmStrByteCount(string));
7446       printf ("\t    text          = <");
7447       for (k=0; k<_XmStrByteCount(string); k++)
7448 	printf ("%c", _XmStrText(string)[k]);
7449       printf (">\n");
7450     }
7451 
7452   else {
7453     _XmStringEntry 		line;
7454     int			line_count;
7455     _XmStringEntry 		seg;
7456     int			seg_count;
7457     _XmStringArraySegRec	array_seg;
7458 
7459     line_count = _XmStrLineCountGet(string);
7460 
7461     printf ("string with %d lines\n", line_count);
7462     for (i = 0; i < line_count; i++)
7463       {
7464 	if (_XmStrImplicitLine(string))
7465 	  {
7466 	    line = _XmStrEntry(string)[i];
7467 	  }
7468 	else
7469 	  {
7470 	    _XmEntryType(&array_seg) = XmSTRING_ENTRY_ARRAY;
7471 	    _XmEntrySegmentCount(&array_seg) = _XmStrEntryCount(string);
7472 	    _XmEntrySegment(&array_seg) = (_XmStringNREntry *)_XmStrEntry(string);
7473 	    line = (_XmStringEntry)&array_seg;
7474 	  }
7475 
7476 	if (_XmEntryMultiple(line))
7477 	  seg_count = _XmEntrySegmentCount(line);
7478 	else
7479 	  seg_count = 1;
7480 
7481 	printf ("\tline [%d] has %d segments\n", i, seg_count);
7482 
7483 	for (j = 0; j < seg_count; j++)
7484 	  {
7485 	    if (_XmEntryMultiple(line))
7486 	      seg = (_XmStringEntry)_XmEntrySegment(line)[j];
7487 	    else seg = line;
7488 
7489 	    printf ("\t    segment [%d]\n", j);
7490 	    if (seg == NULL) {
7491               printf ("\t\tNULL?\n");
7492               continue;
7493 	    }
7494 
7495 	    printf ("\t\ttype            = %d (%s)\n",
7496 		    _XmEntryType(seg),
7497 		    entry_type_image(_XmEntryType(seg)));
7498 	    printf ("\t\tpush before     = %d \n", _XmEntryPushGet(seg));
7499 	    printf ("\t\trend_begin_tags = (%d)\n",
7500 		    _XmEntryRendBeginCountGet(seg));
7501 	    for (k=0; k<_XmEntryRendBeginCountGet(seg); k++)
7502 	      printf ("\t\t  %4d <%s>\n",
7503 		      _XmStringIndexCacheTag(_XmEntryRendBeginGet(seg,k),
7504 					     XmSTRING_TAG_STRLEN),
7505 		      _XmEntryRendBeginGet(seg,k));
7506 	    printf ("\t\ttag             = <%s>\n", _XmEntryTag(seg));
7507 	    printf ("\t\ttabs            = %d\n", _XmEntryTabsGet(seg));
7508 	    printf ("\t\tdirection       = %d\n", _XmEntryDirectionGet(seg));
7509 	    printf ("\t\ttext type       = %d (%s)\n",
7510 		    _XmEntryTextTypeGet(seg),
7511 		    type_image(_XmEntryTextTypeGet(seg)));
7512 	    printf ("\t\ttext            = <");
7513 	    for (k=0; k<_XmEntryByteCountGet(seg); k++)
7514 	      printf ("%c", ((char *)_XmEntryTextGet(seg))[k]);
7515 	    printf (">\n");
7516 	    printf ("\t\tbyte count      = %d\n", _XmEntryByteCountGet(seg));
7517 	    printf ("\t\trend_end_tags   = (%d)\n",
7518 		    _XmEntryRendEndCountGet(seg));
7519 	    for (k=0; k<_XmEntryRendEndCountGet(seg); k++)
7520 	      printf ("\t\t  %4d <%s>\n", _XmStringIndexCacheTag(_XmEntryRendEndGet(seg,k), XmSTRING_TAG_STRLEN), _XmEntryRendEndGet(seg,k));
7521 	    printf ("\t\tpop after       = %d \n", _XmEntryPopGet(seg));
7522 	  }
7523       }
7524   }
7525   printf("\n\n");
7526 }
7527 
7528 #endif /* _XmDEBUG_XMSTRING */
7529 
7530 /****************************************************************
7531  * _XmStringGetTextConcat:
7532  * Note: at some point this could be reimplemented as two pass
7533  * process to eliminate calls to XtRealloc.
7534  ****************************************************************/
7535 char *
_XmStringGetTextConcat(XmString string)7536 _XmStringGetTextConcat(
7537         XmString string)
7538 {
7539   _XmStringContextRec stack_context;
7540   XmStringComponentType type ;
7541   unsigned int len ;
7542   XtPointer val ;
7543   size_t OldLen ;
7544   size_t OutLen = 0 ;
7545   char * OutStr = NULL ;
7546 
7547   if (string) {
7548     _XmStringContextReInit(&stack_context, string);
7549 
7550     while((type = XmeStringGetComponent(&stack_context, TRUE, FALSE,
7551 					&len, &val)) !=
7552 	  XmSTRING_COMPONENT_END)
7553       {
7554 	switch( type)
7555 	  {
7556 	  case XmSTRING_COMPONENT_TEXT:
7557 	  case XmSTRING_COMPONENT_LOCALE_TEXT:
7558 	  case XmSTRING_COMPONENT_WIDECHAR_TEXT:
7559 	    OldLen = OutLen;
7560 	    OutLen += len;
7561 	    OutStr = XtRealloc( OutStr, OutLen + 1) ;
7562 	    memcpy( &OutStr[OldLen], (char *)val, len) ;
7563 	    OutStr[OutLen] = '\0';
7564 	    break ;
7565 	  default:
7566 	    break ;
7567 	  }
7568       }
7569 
7570     _XmStringContextFree(&stack_context);
7571   }
7572   return( OutStr) ;
7573 }
7574 
7575 /****************************************************************
7576  * Allocates a copy of the text and character set of the specified XmString
7577  *   if the XmString is composed of a single segment.
7578  * Returns TRUE if str is a single segment, FALSE otherwise.
7579  * If TRUE, pTextOut is valid; if FALSE, pTextOut and pTagOut are NULL.
7580 ****************/
7581 Boolean
_XmStringSingleSegment(XmString str,char ** pTextOut,XmStringTag * pTagOut)7582 _XmStringSingleSegment(
7583         XmString str,
7584         char **pTextOut,
7585         XmStringTag *pTagOut )
7586 {
7587   _XmStringContextRec stack_context ;
7588   Boolean           retVal;
7589   unsigned int	    len;
7590   XtPointer	    val;
7591   XmStringComponentType type;
7592 
7593   /* Initialize the return parameters. */
7594   retVal = FALSE;
7595   *pTextOut = NULL;
7596   *pTagOut = NULL;
7597 
7598   if (str)
7599     {
7600       _XmStringContextReInit(&stack_context, str);
7601 
7602       /** Get the first tag and text. **/
7603       /* Peak ahead and only copy tag or text. */
7604       while ((type = XmeStringGetComponent(&stack_context, FALSE, FALSE,
7605 					   &len, &val)) !=
7606 	     XmSTRING_COMPONENT_END)
7607 	{
7608 	  switch (type)
7609 	    {
7610 	    case XmSTRING_COMPONENT_TAG:
7611 	    case XmSTRING_COMPONENT_LOCALE:
7612 	      XmeStringGetComponent(&stack_context, TRUE, TRUE, &len, &val);
7613 	      XtFree((char *)*pTagOut);
7614 	      *pTagOut = (XmStringTag)val;
7615 	      break;
7616 
7617 	    case XmSTRING_COMPONENT_TEXT:
7618 	    case XmSTRING_COMPONENT_LOCALE_TEXT:
7619 	    case XmSTRING_COMPONENT_WIDECHAR_TEXT:
7620 	      XmeStringGetComponent(&stack_context, TRUE, TRUE, &len, &val);
7621 
7622 	      retVal = TRUE;
7623 	      *pTextOut = (char *)val;
7624 
7625 	      if (type == XmSTRING_COMPONENT_LOCALE_TEXT)
7626 		{
7627 		  XtFree((char *)*pTagOut);
7628 		  *pTagOut = (XmStringTag)XtNewString(XmFONTLIST_DEFAULT_TAG);
7629 		}
7630 
7631 	      /* Make sure there are no more segments. */
7632 	      while ((type = XmeStringGetComponent(&stack_context, TRUE, FALSE,
7633 						   &len, &val)) !=
7634 		     XmSTRING_COMPONENT_END)
7635 		switch (type)
7636 		  {
7637 		  /* These are all okay */
7638 		  case XmSTRING_COMPONENT_RENDITION_END:
7639 		  case XmSTRING_COMPONENT_LAYOUT_POP:
7640 		  case XmSTRING_COMPONENT_SEPARATOR:
7641 		    break;
7642 
7643 		  /* Anything else is a second segment. */
7644 		  default:
7645 		    retVal = FALSE;
7646 		    continue;
7647 		  }
7648 	      continue;
7649 
7650 	    /* Advance the context. */
7651 	    default:
7652 	      XmeStringGetComponent(&stack_context, TRUE, FALSE, &len, &val);
7653 	      break;
7654 	    }
7655 	}
7656 
7657       _XmStringContextFree(&stack_context);
7658     }
7659 
7660   if (!retVal)
7661     {
7662       XtFree(*pTextOut);
7663       XtFree((char *)*pTagOut);
7664       *pTextOut = NULL;
7665       *pTagOut = NULL;
7666     }
7667 
7668   return retVal;
7669 }
7670 
7671 /****************************************************************************
7672  ***									  ***
7673  ***  This next function SUPERCEDES UpdateWMShellTitle() in BulletinB.c!  ***
7674  ***  REMOVE other copy and reuse for 1.2.1!				  ***
7675  ***									  ***
7676  ****************************************************************************/
7677 
7678 #define STRING_CHARSET          "ISO8859-1"
7679 
7680 void
XmeSetWMShellTitle(XmString xmstr,Widget shell)7681 XmeSetWMShellTitle(
7682 	XmString xmstr,
7683 	Widget shell)
7684 {
7685   char *          text = (char*) NULL;
7686   XmStringTag	  tag = (XmStringTag) NULL;
7687   Arg             al[10] ;
7688   Cardinal        ac ;
7689   XrmValue        from ;
7690   Atom            encoding = None;
7691   XrmValue        to ;
7692   _XmWidgetToAppContext(shell);
7693 
7694   _XmAppLock(app);
7695   /* Set WMShell title (if present). */
7696   if(    XtIsWMShell( shell)    )
7697     {
7698       /* Shell is a Window Manager Shell, so set WMShell title
7699        *   from XmNdialogTitle.
7700        */
7701       text = NULL ;
7702       ac = 0 ;
7703       if (_XmStringSingleSegment(xmstr, &text, &tag))
7704 	{
7705 	  if ((tag != NULL) && (strcmp(STRING_CHARSET, tag) == 0))
7706 	    {
7707 	      /* dialog_title is a single segment of charset STRING_CHARSET,
7708 	       *   so use atom of "STRING".  Otherwise, convert to compound
7709 	       *   text and use atom of "COMPOUND_TEXT".
7710 	       */
7711 	      XtFree( (char *) tag) ;
7712 	      encoding = XA_STRING;
7713 	    }
7714 	  else if ((tag != NULL) &&
7715 		   (strcmp(XmFONTLIST_DEFAULT_TAG, tag) == 0))
7716 	    {
7717 	      /* dialog_title locale encoded so use constant of None */
7718 	      XtFree((char *)tag);
7719 	      encoding = None;
7720 	    }
7721 	  else
7722 	    {
7723 	      /* Don't need this, since dialog_title will be converted from
7724 	       *   original XmString to compound text.
7725 	       */
7726 	      if (tag != NULL)
7727 	        XtFree( (char *) tag) ;
7728 	      XtFree( (char *) text) ;
7729 	      text = NULL ;
7730 	    }
7731 	}
7732       if (!text)
7733 	{
7734 	  from.addr = (char *) xmstr;
7735 	  if(    XmCvtXmStringToText( XtDisplay( shell), NULL, NULL,
7736 				     &from, &to, NULL)    )
7737 	    {
7738 	      text = to.addr ;
7739 	      encoding = XInternAtom(XtDisplay(shell), XmSCOMPOUND_TEXT, FALSE);
7740 	    }
7741 	}
7742       if(    text    )
7743         {
7744 	  XtSetArg( al[ac], XtNtitle, text) ;  ++ac ;
7745 	  XtSetArg( al[ac], XtNtitleEncoding, encoding) ; ++ac ;
7746 	  XtSetArg( al[ac], XtNiconName, text) ;  ++ac ;
7747 	  XtSetArg( al[ac], XtNiconNameEncoding, encoding) ; ++ac ;
7748 	  XtSetValues( shell, al, ac) ;
7749 	  XtFree( (char *) text) ;
7750 	}
7751     }
7752     _XmAppUnlock(app);
7753 }
7754 
7755 /*
7756  * XmeGetDirection: An XmParseProc to insert a direction component.
7757  *	Does not consume the triggering character.
7758  */
7759 /*ARGSUSED*/
7760 XmIncludeStatus
XmeGetDirection(XtPointer * in_out,XtPointer text_end,XmTextType type,XmStringTag tag,XmParseMapping entry,int pattern_length,XmString * str_include,XtPointer call_data)7761 XmeGetDirection(XtPointer     *in_out,
7762 		XtPointer      text_end, /* unused */
7763 		XmTextType     type,
7764 		XmStringTag    tag,
7765 		XmParseMapping entry, /* unused */
7766 		int	       pattern_length, /* unused */
7767 		XmString      *str_include,
7768 		XtPointer      call_data) /* unused */
7769 {
7770   XmCharDirectionProc char_proc = _XmOSGetCharDirection;
7771   XmStringDirection dir;
7772   (void) XmOSGetMethod(NULL, XmMCharDirection, (XtPointer *)&char_proc, NULL);
7773 
7774   /* Create a component for the new direction. */
7775   dir = XmDirectionToStringDirection((*char_proc)(*in_out, type, tag));
7776   *str_include = XmStringComponentCreate(XmSTRING_COMPONENT_DIRECTION,
7777 					 sizeof (dir),
7778 					 (XtPointer) &dir);
7779 
7780   /* Don't consume the triggering character. */
7781   return XmINSERT;
7782 }
7783 
7784 /*
7785  * match_pattern: A helper for XmStringParseText.  Determine whether
7786  *	the text matches a XmParseMapping pattern.
7787  */
7788 /*ARGSUSED*/
7789 static Boolean
match_pattern(XtPointer text,XmStringTag tag,XmTextType type,XmParseMapping pattern,int char_len,Boolean dir_change)7790 match_pattern(XtPointer      text,
7791 	      XmStringTag    tag, /* unused */
7792 	      XmTextType     type,
7793 	      XmParseMapping pattern,
7794 	      int	     char_len,
7795 	      Boolean	     dir_change)
7796 {
7797   if (pattern == NULL)
7798     {
7799       return False;
7800     }
7801   else if (pattern->pattern == XmDIRECTION_CHANGE)
7802     {
7803       return dir_change;
7804     }
7805   else if ((pattern->pattern_type == XmWIDECHAR_TEXT) &&
7806 	   (type == XmWIDECHAR_TEXT))
7807     {
7808       /* Compare wchar_t text to wchar_t pattern. */
7809       return (*((wchar_t*) text) == *((wchar_t*) pattern->pattern));
7810     }
7811   else if (type == XmWIDECHAR_TEXT)
7812     {
7813       /* Compare wchar_t text to a mbs pattern. */
7814       char mb_text[MB_LEN_MAX];
7815       wctomb(mb_text, (wchar_t) '\0');
7816       wctomb(mb_text, *((wchar_t*)text));
7817       return !strncmp(mb_text, (char*) pattern->pattern, char_len);
7818     }
7819   else if (pattern->pattern_type == XmWIDECHAR_TEXT)
7820     {
7821       /* Compare mbs text to wchar_t pattern. */
7822       char mb_pattern[MB_LEN_MAX];
7823       wctomb(mb_pattern, (wchar_t) '\0');
7824       wctomb(mb_pattern, *((wchar_t*)pattern->pattern));
7825       return !strncmp((char*) text, mb_pattern, char_len);
7826     }
7827   else if (strlen((char*) pattern->pattern) == char_len)
7828     {
7829       /* The normal case: mbs text and pattern. */
7830       return !strncmp((char*) text, (char*) pattern->pattern, char_len);
7831     }
7832 
7833   return False;
7834 }
7835 
7836 /*
7837  * parse_unmatched: A Helper routine for XmStringParseText.  Produce
7838  *	a component for characters that weren't matched by any pattern.
7839  */
7840 static void
parse_unmatched(XmString * result,char ** ptr,XmTextType text_type,int length)7841 parse_unmatched(XmString  *result,
7842 		char     **ptr,
7843 		XmTextType text_type,
7844 		int        length)
7845 {
7846   /* Insert length bytes from ptr into result, and update ptr. */
7847   XmString tmp_1, tmp_2;
7848   XmStringComponentType ctype;
7849 
7850   /* Do nothing if there are no unmatched bytes. */
7851   if (length <= 0)
7852     return;
7853 
7854   /* Choose a component type. */
7855   switch (text_type)
7856     {
7857     case XmCHARSET_TEXT:
7858       ctype = XmSTRING_COMPONENT_TEXT;
7859       break;
7860     case XmMULTIBYTE_TEXT:
7861       ctype = XmSTRING_COMPONENT_LOCALE_TEXT;
7862       break;
7863     case XmWIDECHAR_TEXT:
7864       ctype = XmSTRING_COMPONENT_WIDECHAR_TEXT;
7865       break;
7866 
7867     default:
7868       return;
7869     }
7870 
7871   /* Can't concat without copying both strings? */
7872   tmp_1 = *result;
7873   tmp_2 = XmStringComponentCreate(ctype, length, (XtPointer) *ptr);
7874   if (tmp_2 == NULL)
7875     return;
7876 
7877   *result = XmStringConcatAndFree(tmp_1, tmp_2);
7878   *ptr += length;
7879 }
7880 
7881 /*
7882  * parse_pattern: A helper routine for XmStringParseText.  Process a
7883  *	pattern that has matched.
7884  */
7885 static Boolean
parse_pattern(XmString * result,char ** ptr,XtPointer text_end,XmStringTag tag,XmTextType type,XmParseMapping pat,int length,XtPointer call_data,Boolean * terminate)7886 parse_pattern(XmString      *result,
7887 	      char         **ptr,
7888 	      XtPointer      text_end,
7889 	      XmStringTag    tag,
7890 	      XmTextType     type,
7891 	      XmParseMapping pat,
7892 	      int            length,
7893 	      XtPointer      call_data,
7894 	      Boolean	    *terminate)
7895 {
7896   /* Process a matched pattern.  Return True if ptr is updated. */
7897   char* orig_ptr = *ptr;
7898   XmIncludeStatus action = pat->include_status;
7899   XmString insertion = NULL;
7900 
7901   /* Compute the action and insertion. */
7902   if (action == XmINVOKE)
7903     {
7904       /* Resolve parse procs. */
7905       if (pat->parse_proc)
7906 	action = (pat->parse_proc) ((XtPointer*) ptr, text_end, type,
7907 				    tag, pat, length, &insertion, call_data);
7908 
7909       /* Recursive parse procs are not supported. */
7910       if (action == XmINVOKE)
7911 	{
7912 	  *ptr = orig_ptr;
7913 	  XmStringFree (insertion);
7914 	  return False;
7915 	}
7916     }
7917   else
7918     {
7919       /* Non-parse_procs always advance the pointer and terminate matching. */
7920       *ptr += length;
7921       insertion = XmStringCopy(pat->substitute);
7922     }
7923 
7924   /* Insert the substitution. */
7925   switch (action)
7926     {
7927     case XmTERMINATE:
7928       *terminate = True;
7929       /* Fall through. */
7930     case XmINSERT:
7931       if (insertion != NULL)
7932 	*result = XmStringConcatAndFree(*result, insertion);
7933       break;
7934 
7935     default:
7936       /* Ignore substitution string. */
7937       XmStringFree(insertion);
7938       break;
7939     }
7940 
7941   /* Advancing the pointer prevents multiple matches. */
7942   return (*ptr != orig_ptr);
7943 }
7944 
7945 XmString
XmStringParseText(XtPointer text,XtPointer * text_end,XmStringTag tag,XmTextType type,XmParseTable parse_table,Cardinal parse_count,XtPointer call_data)7946 XmStringParseText(XtPointer    text,
7947 		  XtPointer   *text_end,
7948 		  XmStringTag  tag,
7949 		  XmTextType   type,
7950 		  XmParseTable parse_table,
7951 		  Cardinal     parse_count,
7952 		  XtPointer    call_data)
7953 {
7954   /* This routine needs to be reentrant so application supplied */
7955   /* XmParseProcs can make recursive calls. */
7956   static XmParseMapping default_dir_pattern = NULL;
7957 
7958   char*			 ptr = (char*) text;
7959   char*			 prev_ptr = ptr;
7960   XtPointer		 end_ptr = (text_end ? *text_end : NULL);
7961   XmString		 result;
7962   Boolean		 has_dir_pattern;
7963   Boolean		 wide_char = False;
7964   Boolean		 advanced;
7965   Boolean		 halt;
7966   unsigned int		 index;
7967   char*			 dir_ptr;
7968   XmStringComponentType  tag_type;
7969   XmInitialDirectionProc init_char_proc = _XmOSGetInitialCharsDirection;
7970 
7971   _XmProcessLock();
7972 
7973   /* Check some error conditions. */
7974   if (parse_count && !parse_table)
7975   {
7976     _XmProcessUnlock();
7977     return NULL;
7978   }
7979   if (!text)
7980   {
7981     _XmProcessUnlock();
7982     return NULL;
7983   }
7984 
7985   /* Validate the tag and set the tag_type. */
7986   switch (type)
7987     {
7988     case XmCHARSET_TEXT:
7989       if (tag == NULL)
7990 	tag = XmFONTLIST_DEFAULT_TAG;
7991       tag_type = XmSTRING_COMPONENT_CHARSET;
7992       break;
7993 
7994     case XmWIDECHAR_TEXT:
7995       wide_char = True;
7996       /* Fall through */
7997 
7998     case XmMULTIBYTE_TEXT:
7999       /* Non-NULL values (except _MOTIF_DEFAULT_LOCALE)
8000          are not accepted in Motif 2.0. */
8001       if ((tag != NULL) && (strcmp(tag, _MOTIF_DEFAULT_LOCALE) != 0))
8002       {
8003 	_XmProcessUnlock();
8004 	return NULL;
8005       }
8006 
8007       if (tag == NULL)
8008 	tag = _MOTIF_DEFAULT_LOCALE;
8009       tag_type = XmSTRING_COMPONENT_LOCALE;
8010       break;
8011 
8012     default:
8013       /* Error: bad text type. */
8014       _XmProcessUnlock();
8015       return NULL;
8016     }
8017 
8018   /* Create an empty segment with the right tag. */
8019   result = XmStringComponentCreate(tag_type, strlen(tag), (XtPointer) tag);
8020 
8021   /* Did the user provide an XmDIRECTION_CHANGE pattern? */
8022   has_dir_pattern = False;
8023   for (index = 0; (index < parse_count) && !has_dir_pattern; index++)
8024     has_dir_pattern = (parse_table[index]->pattern == XmDIRECTION_CHANGE);
8025   if (!has_dir_pattern && !default_dir_pattern)
8026     {
8027       /* Create a default direction pattern. */
8028       Arg args[10];
8029       Cardinal nargs = 0;
8030 
8031       XtSetArg(args[nargs], XmNincludeStatus, XmINVOKE),          nargs++;
8032       XtSetArg(args[nargs], XmNinvokeParseProc, XmeGetDirection), nargs++;
8033       XtSetArg(args[nargs], XmNpattern, XmDIRECTION_CHANGE),	  nargs++;
8034       assert(nargs < XtNumber(args));
8035       default_dir_pattern = XmParseMappingCreate(args, nargs);
8036     }
8037 
8038   /* Process characters until text has been consumed. */
8039   dir_ptr = NULL;
8040   (void) mblen((char*) NULL, MB_CUR_MAX);
8041   (void) XmOSGetMethod(NULL, XmMInitialCharsDirection,
8042 		       (XtPointer *)&init_char_proc, NULL);
8043   halt = (end_ptr && (ptr >= (char*) end_ptr));
8044   while (!halt && (wide_char ? *((wchar_t*) ptr) : *ptr))
8045     {
8046 #ifndef NO_MULTIBYTE
8047       int len = (wide_char ? sizeof(wchar_t) : mblen(ptr, MB_CUR_MAX));
8048 #else
8049       int len = (wide_char ? sizeof(wchar_t) : 1);
8050 #endif
8051       advanced = False;
8052 
8053       /* If we have an invalid character, treat it as a single byte. */
8054       if (len < 0)
8055 	len = 1;
8056 
8057       /* Reset dir_ptr if the input text has changed directions. */
8058       if (ptr > dir_ptr)
8059 	{
8060 	  XmDirection xm_dir;
8061 	  if ((*init_char_proc)((XtPointer) ptr, type, tag, &index, &xm_dir) ==
8062 	      Success)
8063 	    dir_ptr = ptr + index;
8064 	}
8065 
8066       /* Match against an implicit XmDIRECTION_CHANGE pattern. */
8067       if (!has_dir_pattern && (ptr == dir_ptr))
8068 	{
8069 	  parse_unmatched(&result, &prev_ptr, type, ptr - prev_ptr);
8070 	  advanced =
8071 	    parse_pattern(&result, &ptr, end_ptr, tag, type,
8072 			  default_dir_pattern, len, call_data, &halt);
8073 	}
8074 
8075       /* Try to match this character against the patterns. */
8076       for (index = 0; !advanced && !halt && (index < parse_count); index++)
8077 	{
8078 	  XmParseMapping pat = parse_table[index];
8079 	  if (match_pattern(ptr, tag, type, pat, len, (ptr == dir_ptr)))
8080 	    {
8081 	      parse_unmatched(&result, &prev_ptr, type, ptr - prev_ptr);
8082 	      advanced = parse_pattern(&result, &ptr, end_ptr, tag,
8083 				       type, pat, len, call_data, &halt);
8084 #ifdef FIX_1398
8085 	      /* Insert the charset component after pattern insertion */
8086 	      result = XmStringConcatAndFree(result, XmStringComponentCreate(tag_type, strlen(tag), (XtPointer) tag));
8087 #endif
8088 	    }
8089 	}
8090 
8091       /* Match an implicit "self-insert" pattern if all else fails. */
8092       if (!advanced)
8093 	{
8094 	  /* Buffer unmatched characters into one long insertion. */
8095 	  ptr += len;
8096 	}
8097       else
8098 	{
8099 	  /* Discard this character and reset unmatched pointer. */
8100 	  prev_ptr = ptr;
8101 	}
8102 
8103       /* Stop processing at the end of the text. */
8104       halt |= (end_ptr && (ptr >= (char*) end_ptr));
8105     }
8106 
8107   /* Output and trailing unmatched characters. */
8108   parse_unmatched(&result, &prev_ptr, type, ptr - prev_ptr);
8109 
8110   /* Return the true end of parsing if possible. */
8111   if (text_end)
8112     *text_end = (XtPointer) ptr;
8113 
8114   _XmProcessUnlock();
8115   return result;
8116 }
8117 
8118 /*
8119  * check_unparse_models: A helper for XmStringUnparse.  Invoked
8120  *	after a text component is processed, this routine determines
8121  *	whether future non-text and text components will be unparsed.
8122  */
8123 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)8124 check_unparse_models(XmStringContext context,
8125 		     XmStringTag     tag,
8126 		     XmTextType	     tag_type,
8127 		     XmParseModel    parse_model,
8128 		     Boolean	    *prev_text_match,
8129 		     Boolean	    *next_text_match,
8130 		     Boolean	    *non_text_match)
8131 {
8132   /* Scan ahead to see whether the next text segment will match. */
8133   {
8134     /* Peek ahead in the iterator for a real text segment. */
8135     Boolean		  done = False;
8136     _XmStringContextRec   n_context;
8137     XtPointer             n_value;
8138     unsigned int          n_length;
8139     XmStringComponentType n_ctype;
8140 
8141     /* Compute text_match for the next text segment. */
8142     *prev_text_match = *next_text_match;
8143     _XmStringContextCopy(&n_context, context);
8144     while (!done)
8145       {
8146 	n_ctype = XmeStringGetComponent(&n_context, True, False, &n_length, &n_value);
8147 	switch (n_ctype)
8148 	  {
8149 	  case XmSTRING_COMPONENT_TEXT:
8150 	  case XmSTRING_COMPONENT_LOCALE_TEXT:
8151 	  case XmSTRING_COMPONENT_WIDECHAR_TEXT:
8152 	    if (!tag)
8153 	      *next_text_match = True;
8154 	    else if ((tag_type == _XmStrContTagType(&n_context)) &&
8155 		     (!_XmStrContTag(&n_context) ||
8156 		      (tag == _XmStrContTag(&n_context)) ||
8157 		      (strcmp(tag, _XmStrContTag(&n_context)) == 0)))
8158 	      *next_text_match = True;
8159 	    else
8160 	      *next_text_match = False;
8161 	    done = True;
8162 	    break;
8163 
8164 	  case XmSTRING_COMPONENT_END:
8165 	    *next_text_match = False;
8166 	    done = True;
8167 	    break;
8168 	  }
8169       }
8170 
8171     _XmStringContextFree(&n_context);
8172   }
8173 
8174   /* Compute parse_match for components up to the next text segment. */
8175   switch (parse_model)
8176     {
8177     case XmOUTPUT_ALL:
8178       *non_text_match = True;
8179       break;
8180 
8181     case XmOUTPUT_BETWEEN:
8182       *non_text_match = *prev_text_match && *next_text_match;
8183       break;
8184 
8185     case XmOUTPUT_BEGINNING:
8186       *non_text_match = *next_text_match;
8187       break;
8188 
8189     case XmOUTPUT_END:
8190       *non_text_match = *prev_text_match;
8191       break;
8192 
8193     case XmOUTPUT_BOTH:
8194       *non_text_match = *prev_text_match || *next_text_match;
8195       break;
8196 
8197     default:
8198       /* This is an error. */
8199       *non_text_match = False;
8200       break;
8201     }
8202 }
8203 
8204 /*
8205  * unparse_text: A helper for XmStringUnparse.  Output a matched text
8206  *	component.
8207  */
8208 static void
unparse_text(char ** result,int * length,XmTextType output_type,XmStringComponentType c_type,unsigned int c_length,XtPointer c_value)8209 unparse_text(char                **result,
8210 	     int                  *length,
8211 	     XmTextType            output_type,
8212 	     XmStringComponentType c_type,
8213 	     unsigned int	   c_length,
8214 	     XtPointer	           c_value)
8215 {
8216   /* If we have an invalid character, treat it as a single byte. */
8217   if ((int)c_length < 0)
8218     c_length = 1;
8219 
8220   /* Convert c_value to the appropriate type and insert it. */
8221   if ((c_type == XmSTRING_COMPONENT_WIDECHAR_TEXT) ==
8222       (output_type == XmWIDECHAR_TEXT))
8223     {
8224       /* No conversion is necessary. */
8225       *result = XtRealloc(*result, *length + c_length);
8226       memcpy(*result + *length, c_value, c_length);
8227       *length += c_length;
8228     }
8229   else if (output_type != XmWIDECHAR_TEXT)
8230     {
8231       /* Convert c_value to a multibyte string. */
8232       int len;
8233       int max_bytes = c_length * MB_CUR_MAX / sizeof(wchar_t);
8234       wchar_t *null_text = (wchar_t*) XtMalloc(c_length + sizeof(wchar_t));
8235       memcpy(null_text, c_value, c_length);
8236       null_text[c_length / sizeof(wchar_t)] = (wchar_t) '\0';
8237 
8238       *result = XtRealloc(*result, *length + max_bytes);
8239       len = wcstombs(*result + *length, null_text, max_bytes);
8240       if (len > 0)
8241 	*length += len;
8242 
8243       XtFree((char*) null_text);
8244     }
8245   else
8246     {
8247       /* Convert c_value to a widechar string. */
8248       int len;
8249       char *null_text = XtMalloc(c_length + 1);
8250       memcpy(null_text, c_value, c_length);
8251       null_text[c_length] = '\0';
8252 
8253       *result = XtRealloc(*result, *length + c_length * sizeof(wchar_t));
8254       len = mbstowcs((wchar_t*) (*result + *length), null_text, c_length);
8255       if (len > 0)
8256 	*length += len * sizeof(wchar_t);
8257 
8258       XtFree(null_text);
8259     }
8260 }
8261 
8262 /*
8263  * unparse_is_plausible: A helper routine for unparse_components.
8264  *	Decided whether a pattern is even eligible for unparsing.
8265  */
8266 static Boolean
unparse_is_plausible(XmParseMapping pattern)8267 unparse_is_plausible(XmParseMapping pattern)
8268 {
8269   /* Look for a cached result from previous computations. */
8270   switch (pattern->internal_flags)
8271     {
8272     case XmSTRING_UNPARSE_UNKNOWN:
8273       break;
8274 
8275     case XmSTRING_UNPARSE_PLAUSIBLE:
8276       return True;
8277 
8278     case XmSTRING_UNPARSE_IMPLAUSIBLE:
8279       return False;
8280     }
8281 
8282   /* Test the pattern to see if it might ever be unparsed. */
8283   if (/* Filter patterns based on the include status. */
8284       (pattern->include_status == XmINVOKE) ||
8285 
8286       /* Filter patterns based on the substitution. */
8287       (!pattern->substitute) ||
8288 
8289       /* Filter patterns based on the pattern. */
8290       (pattern->pattern == XmDIRECTION_CHANGE))
8291     {
8292       pattern->internal_flags = XmSTRING_UNPARSE_IMPLAUSIBLE;
8293       return False;
8294     }
8295   else
8296     {
8297       /* Give up and compare the segments component by component. */
8298       pattern->internal_flags = XmSTRING_UNPARSE_PLAUSIBLE;
8299       return True;
8300     }
8301 }
8302 
8303 /*
8304  * unparse_components: A helper for XmStringUnparse.  Compare
8305  *	components against the parse table.
8306  */
8307 static void
unparse_components(char ** result,int * length,XmTextType output_type,XmStringContext context,XmParseTable parse_table,Cardinal parse_count)8308 unparse_components(char          **result,
8309 		   int            *length,
8310 		   XmTextType      output_type,
8311 		   XmStringContext context,
8312 		   XmParseTable    parse_table,
8313 		   Cardinal        parse_count)
8314 {
8315   Boolean match = False;
8316   XmParseMapping pat;
8317   int n_pat;
8318   int n_comp;
8319 
8320   /* Compare each pattern component. */
8321   for (n_pat = 0; !match && (n_pat < parse_count); n_pat++)
8322     {
8323       pat = parse_table[n_pat];
8324       if (unparse_is_plausible(pat))
8325 	{
8326 	  _XmStringContextRec   m_context, p_context;
8327 	  XmStringComponentType m_ctype, p_ctype;
8328 	  XtPointer             m_value, p_value;
8329 	  unsigned int          m_length, p_length;
8330 
8331 	  /* Setup master and pattern context iterators. */
8332 	  _XmStringContextCopy(&m_context, context);
8333 	  _XmStringContextReInit(&p_context, pat->substitute);
8334 
8335 	  /* Iterate over each of the strings. */
8336 	  match = True;
8337 	  for (n_comp = 0; match; n_comp++)
8338 	    {
8339 	      /* Get the next component from each source. */
8340 	      m_ctype = XmeStringGetComponent(&m_context, True, False,
8341 				      &m_length, &m_value);
8342 	      p_ctype = XmeStringGetComponent(&p_context, True, False,
8343 				      &p_length, &p_value);
8344 
8345 	      /* It's a match! */
8346 	      if (p_ctype == XmSTRING_COMPONENT_END)
8347 		break;
8348 
8349 	      /* Comparison of text components always fails. */
8350 	      if ((p_ctype == XmSTRING_COMPONENT_TEXT) ||
8351 		  (p_ctype == XmSTRING_COMPONENT_LOCALE_TEXT) ||
8352 		  (p_ctype == XmSTRING_COMPONENT_WIDECHAR_TEXT))
8353 		{
8354 		  pat->internal_flags = XmSTRING_UNPARSE_IMPLAUSIBLE;
8355 		  match = False;
8356 		}
8357 
8358 	      /* Bit-compare components. */
8359 	      else if ((m_ctype != p_ctype) ||
8360 		       (m_length != p_length) ||
8361 		       ((m_value != p_value) &&
8362 			memcmp(m_value, p_value, m_length)))
8363 		match = False;
8364 	    }
8365 
8366 	  /* Should we undo this substitution? */
8367 	  if (match)
8368 	    {
8369 	      /* Output the original pattern. */
8370 	      if (pat->pattern_type == XmWIDECHAR_TEXT)
8371 		unparse_text(result, length, output_type,
8372 			     XmSTRING_COMPONENT_WIDECHAR_TEXT,
8373 			     sizeof(wchar_t), pat->pattern);
8374 	      else
8375 		unparse_text(result, length, output_type,
8376 			     XmSTRING_COMPONENT_TEXT,
8377 #ifndef NO_MULTIBYTE
8378 			     mblen((char*) pat->pattern, MB_CUR_MAX),
8379 #else
8380 			     *((char *) pat->pattern) ? 1: 0,
8381 #endif
8382 			     pat->pattern);
8383 
8384 	      /* Skip all but the last matched component. */
8385 	      while (--n_comp > 0)
8386 		{
8387 		  m_ctype = XmeStringGetComponent(context, True, False,
8388 					  &m_length, &m_value);
8389 		  assert(m_ctype != XmSTRING_COMPONENT_END);
8390 		}
8391 	    }
8392 
8393 	  /* Cleanup. */
8394 	  _XmStringContextFree(&m_context);
8395 	  _XmStringContextFree(&p_context);
8396 	}
8397     }
8398 }
8399 
8400 XtPointer
XmStringUnparse(XmString string,XmStringTag tag,XmTextType tag_type,XmTextType output_type,XmParseTable parse_table,Cardinal parse_count,XmParseModel parse_model)8401 XmStringUnparse(XmString          string,
8402 		XmStringTag       tag,
8403 		XmTextType        tag_type,
8404 		XmTextType        output_type,
8405 		XmParseTable      parse_table,
8406 		Cardinal          parse_count,
8407 		XmParseModel      parse_model)
8408 {
8409   char               *result = NULL;
8410   int		      length = 0;
8411   _XmStringContextRec stack_context;
8412   Boolean             prev_text_match;
8413   Boolean             next_text_match;
8414   Boolean	      non_text_match;
8415   Boolean	      done;
8416 
8417   XmStringComponentType c_type;
8418   unsigned int	        c_length;
8419   XtPointer	        c_value;
8420 
8421   _XmProcessLock();
8422   /* Convert special tags to real values. */
8423   if ((tag_type == XmCHARSET_TEXT) && tag &&
8424       ((tag == XmSTRING_DEFAULT_CHARSET) ||
8425        (strcmp(tag, XmSTRING_DEFAULT_CHARSET) == 0)))
8426     tag = _XmStringGetCurrentCharset();
8427 
8428   /* Process the components of string individually. */
8429   prev_text_match = next_text_match = non_text_match = False;
8430   done = (string == NULL);
8431   if (!done)
8432    {
8433      _XmStringContextReInit(&stack_context, string);
8434      check_unparse_models(&stack_context, tag, tag_type, parse_model,
8435 			  &prev_text_match, &next_text_match, &non_text_match);
8436    }
8437   while (!done)
8438     {
8439       /* Peek at the next component. */
8440       c_type = XmeStringGetComponent(&stack_context, False, False,
8441 				     &c_length, &c_value);
8442       switch (c_type)
8443 	{
8444 	case XmSTRING_COMPONENT_TEXT:
8445 	case XmSTRING_COMPONENT_LOCALE_TEXT:
8446 	case XmSTRING_COMPONENT_WIDECHAR_TEXT:
8447 	  /* Text component matches are computed in advance. */
8448 	  if (next_text_match)
8449 	    unparse_text(&result, &length, output_type,
8450 			 c_type, c_length, c_value);
8451 
8452 	  /* Advance to the next component. */
8453 	  (void) XmeStringGetComponent(&stack_context, True, False,
8454 				       &c_length, &c_value);
8455 
8456 	  /* Update the text match values. */
8457 	  check_unparse_models(&stack_context, tag, tag_type, parse_model,
8458 			       &prev_text_match, &next_text_match,
8459 			       &non_text_match);
8460 	  break;
8461 
8462 	case XmSTRING_COMPONENT_END:
8463 	  done = True;
8464 	  /* We're done after processing this component. */
8465 	default:
8466 	  /* Non-text components are under the control of parse_model. */
8467 	  if (non_text_match)
8468 	    unparse_components(&result, &length, output_type, &stack_context,
8469 			       parse_table, parse_count);
8470 
8471 	  /* Advance to the next component. */
8472 	  if (!done)
8473 	    (void) XmeStringGetComponent(&stack_context, True, False,
8474 					 &c_length, &c_value);
8475 
8476 	  break;
8477 	}
8478     }
8479 
8480   /* Clean up. */
8481   if (string != NULL)
8482    _XmStringContextFree(&stack_context);
8483 
8484   /* Null terminate the result. */
8485   switch(output_type)
8486     {
8487     case XmWIDECHAR_TEXT:
8488       {
8489 	wchar_t zero = 0;
8490 	unparse_text(&result, &length, output_type,
8491 		     XmSTRING_COMPONENT_WIDECHAR_TEXT,
8492 		     sizeof(wchar_t), (XtPointer) &zero);
8493       }
8494       break;
8495 
8496     case XmCHARSET_TEXT:
8497     case XmMULTIBYTE_TEXT:
8498     case XmNO_TEXT:
8499       unparse_text(&result, &length, output_type,
8500 		   XmSTRING_COMPONENT_TEXT, 1, (XtPointer) "");
8501       break;
8502     }
8503 
8504   _XmProcessUnlock();
8505   return (XtPointer) result;
8506 }
8507 
8508 XmString
XmStringComponentCreate(XmStringComponentType c_type,unsigned int length,XtPointer value)8509 XmStringComponentCreate(XmStringComponentType c_type,
8510 			unsigned int          length,
8511 			XtPointer             value)
8512 {
8513   _XmString           str;
8514   _XmStringUnoptSegRec seg;
8515   _XmStringEntry      opt_seg;
8516   _XmStringOptRec     opt;
8517   int                 tag_index = TAG_INDEX_UNSET;
8518   Boolean             optimized = False;
8519   XmStringTag         rend_tags[1];
8520 
8521   _XmProcessLock();
8522   /* We can't do anything if a needed value is missing. */
8523   if ((length > 0) && (value == NULL)) {
8524     _XmProcessUnlock();
8525     return NULL;
8526   }
8527 
8528   /* Initialize the proto-segments */
8529   _XmEntryInit((_XmStringEntry)&seg, XmSTRING_ENTRY_UNOPTIMIZED);
8530   _XmStrInit((_XmString)&opt, XmSTRING_OPTIMIZED);
8531 
8532   /* Modify a proto-segment appropriately or return a special value. */
8533   switch (c_type)
8534     {
8535     case XmSTRING_COMPONENT_CHARSET:
8536       if (!value || (length != strlen((char*) value))) {
8537         _XmProcessUnlock();
8538 	return NULL;
8539       }
8540       if ((value == XmSTRING_DEFAULT_CHARSET) ||
8541 	  (strcmp((char*) value, XmSTRING_DEFAULT_CHARSET) == 0)) {
8542 	value = _XmStringGetCurrentCharset();
8543 	length = strlen((char*) value);
8544       }
8545 
8546       tag_index = _XmStringIndexCacheTag((char*) value, length);
8547       optimized = (tag_index < TAG_INDEX_MAX);
8548       if (optimized) {
8549 	_XmStrTextType((_XmString)&opt) = XmCHARSET_TEXT;
8550 	_XmStrTagIndex((_XmString)&opt) = tag_index;
8551       } else {
8552 	_XmEntryTextTypeSet(&seg, XmCHARSET_TEXT);
8553 	_XmUnoptSegTag(&seg) = _XmStringCacheTag((char*) value, length);
8554       }
8555       break;
8556 
8557     case XmSTRING_COMPONENT_TEXT:
8558       optimized = (length < (1 << BYTE_COUNT_BITS));
8559       if (optimized) {
8560 	_XmStrTextType((_XmString)&opt)  = XmCHARSET_TEXT;
8561 	_XmStrByteCount((_XmString)&opt) = length;
8562       } else {
8563 	_XmEntryTextTypeSet(&seg, XmCHARSET_TEXT);
8564 	if (value != NULL) {
8565 	  _XmEntryTextSet((_XmStringEntry)&seg, value);
8566 	  _XmEntryByteCountSet(&seg, length);
8567 	}
8568       }
8569       break;
8570 
8571     case XmSTRING_COMPONENT_DIRECTION:
8572       if (length != sizeof(XmStringDirection)) {
8573 	_XmProcessUnlock();
8574 	return NULL;
8575       }
8576       _XmProcessUnlock();
8577       return XmStringDirectionCreate(*((XmStringDirection*) value));
8578 
8579     case XmSTRING_COMPONENT_SEPARATOR:
8580       if (value != NULL) {
8581 	_XmProcessUnlock();
8582 	return NULL;
8583       }
8584       _XmProcessUnlock();
8585       return XmStringSeparatorCreate();
8586 
8587     case XmSTRING_COMPONENT_LOCALE_TEXT:
8588       tag_index = _XmStringIndexCacheTag(
8589 				(char*) XmFONTLIST_DEFAULT_TAG,
8590 				XmSTRING_TAG_STRLEN);
8591 
8592       if (length < (1 << BYTE_COUNT_BITS))
8593 	optimized = (tag_index < TAG_INDEX_MAX);
8594 
8595       if (optimized) {
8596 	_XmStrTextType((_XmString)&opt)  = XmMULTIBYTE_TEXT;
8597 	_XmStrTagIndex((_XmString)&opt)  = tag_index;
8598 	_XmStrByteCount((_XmString)&opt) = length;
8599       } else {
8600 	_XmEntryTextTypeSet(&seg, XmMULTIBYTE_TEXT);
8601 	_XmUnoptSegTag(&seg) = _tag_cache[tag_index];
8602 	if (value != NULL) {
8603 	  _XmEntryTextSet((_XmStringEntry)&seg, value);
8604 	  _XmEntryByteCountSet(&seg, length);
8605 	}
8606       }
8607       break;
8608 
8609     case XmSTRING_COMPONENT_LOCALE:
8610       if (!value || (length != strlen((char*) value))) {
8611 	_XmProcessUnlock();
8612 	return NULL;
8613       }
8614       if (strcmp((char*) value, _MOTIF_DEFAULT_LOCALE) != 0) {
8615 	_XmProcessUnlock();
8616 	return NULL;
8617       }
8618 
8619       tag_index = _XmStringIndexCacheTag((char*) value, length);
8620       optimized = (tag_index < TAG_INDEX_MAX);
8621       if (optimized) {
8622 	_XmStrTextType((_XmString)&opt) = XmMULTIBYTE_TEXT;
8623 	_XmStrTagIndex((_XmString)&opt) = tag_index;
8624       } else {
8625 	_XmEntryTextTypeSet(&seg, XmMULTIBYTE_TEXT);
8626 	_XmUnoptSegTag(&seg)  = _XmStringCacheTag((char*) value, length);
8627       }
8628       break;
8629 
8630     case XmSTRING_COMPONENT_WIDECHAR_TEXT:
8631       optimized = (length < (1 << BYTE_COUNT_BITS));
8632       if (optimized) {
8633 	_XmStrTextType((_XmString)&opt)  = XmWIDECHAR_TEXT;
8634 	_XmStrTagIndex((_XmString)&opt)  = tag_index;
8635 	_XmStrByteCount((_XmString)&opt) = length;
8636       } else {
8637 	_XmEntryTextTypeSet(&seg, XmWIDECHAR_TEXT);
8638 	if (value != NULL) {
8639 	  _XmEntryTextSet((_XmStringEntry)&seg, value);
8640 	  _XmEntryByteCountSet(&seg, length);
8641 	}
8642       }
8643       break;
8644 
8645     case XmSTRING_COMPONENT_LAYOUT_POP:
8646       if (value != NULL) {
8647 	_XmProcessUnlock();
8648 	return NULL;
8649       }
8650 
8651       /* There is no optimized representation for layout components? */
8652       optimized = False;
8653       _XmEntryPopSet(&seg, TRUE);
8654       break;
8655 
8656     case XmSTRING_COMPONENT_LAYOUT_PUSH:
8657       if (length != sizeof(XmDirection)) {
8658 	_XmProcessUnlock();
8659 	return NULL;
8660       }
8661 
8662       /* There is no optimized representation for layout components? */
8663       optimized = False;
8664       _XmEntryPushSet(&seg, *((XmDirection *)value));
8665       break;
8666 
8667     case XmSTRING_COMPONENT_RENDITION_BEGIN:
8668       if (!value || (length != strlen((char*)value))) {
8669 	_XmProcessUnlock();
8670 	return NULL;
8671       }
8672 
8673       tag_index = _XmStringIndexCacheTag((char *)value, length);
8674       optimized = (tag_index < REND_INDEX_MAX);
8675       if (optimized)
8676 	{
8677 	  _XmStrRendIndex((_XmString)&opt) = tag_index;
8678 	  _XmStrRendBegin((_XmString)&opt) = TRUE;
8679 	}
8680       else
8681 	{
8682 	  _XmUnoptSegRendBegins(&seg) = rend_tags;
8683 	  rend_tags[0] = _XmStringCacheTag((char *)value, length);
8684 	  _XmUnoptSegRendBeginCount(&seg) = 1;
8685 	}
8686       break;
8687 
8688     case XmSTRING_COMPONENT_RENDITION_END:
8689       if (!value || (length != strlen((char*)value))) {
8690 	_XmProcessUnlock();
8691 	return NULL;
8692       }
8693 
8694       tag_index = _XmStringIndexCacheTag((char *)value, length);
8695       optimized = (tag_index < REND_INDEX_MAX);
8696       if (optimized)
8697 	{
8698 	  _XmStrRendIndex((_XmString)&opt) = tag_index;
8699 	  _XmStrRendEnd((_XmString)&opt) = TRUE;
8700 	}
8701       else
8702 	{
8703 	  _XmUnoptSegRendEnds(&seg) = rend_tags;
8704 	  rend_tags[0] = _XmStringCacheTag((char *)value, length);
8705 	  _XmUnoptSegRendEndCount(&seg) = 1;
8706 	}
8707       break;
8708 
8709     case XmSTRING_COMPONENT_TAB:
8710       {
8711          XmString ret_val;
8712 
8713          if (value != NULL) {
8714 	    _XmProcessUnlock();
8715 	    return NULL;
8716          }
8717          ret_val = StringTabCreate();
8718          _XmProcessUnlock();
8719          return ret_val;
8720        }
8721 
8722     case XmSTRING_COMPONENT_END:
8723       {
8724          XmString ret_val;
8725 
8726          if (value != NULL) {
8727 	    _XmProcessUnlock();
8728 	    return NULL;
8729          }
8730 	 ret_val = StringEmptyCreate();
8731 	 _XmProcessUnlock();
8732 	 return ret_val;
8733       }
8734 
8735     case XmSTRING_COMPONENT_UNKNOWN:
8736     default:
8737       _XmProcessUnlock();
8738       return NULL;
8739     }
8740 
8741   /* Convert one of the proto-segments into a real _XmString. */
8742   if (optimized)
8743     {
8744       /* Convert opt into an optimized XmString. */
8745       str = (_XmString) _XmStrMalloc(sizeof(_XmStringOptRec) +
8746 				     (_XmStrByteCount((_XmString)&opt) ?
8747 				      (_XmStrByteCount((_XmString)&opt) -
8748 				       TEXT_BYTES_IN_STRUCT) :
8749 				      0));
8750 
8751       memcpy(str, &opt, sizeof(_XmStringOptRec) - TEXT_BYTES_IN_STRUCT);
8752       memcpy(_XmStrText(str), value, _XmStrByteCount((_XmString)&opt));
8753 
8754       _XmStrRefCountSet(str, 1);
8755     }
8756   else
8757     {
8758       /* Convert seg into a non-optimized XmString. */
8759       _XmStrCreate(str, XmSTRING_MULTIPLE_ENTRY, 0);
8760 
8761       if ((opt_seg = EntryCvtToOpt((_XmStringEntry)&seg)) != NULL)
8762 	_XmStringSegmentNew(str, 0, opt_seg, False);
8763       else
8764 	_XmStringSegmentNew(str, 0, (_XmStringEntry)&seg, True);
8765     }
8766 
8767   _XmProcessUnlock();
8768   return (XmString) str;
8769 }
8770 
8771 XmStringComponentType
XmStringGetNextTriple(XmStringContext context,unsigned int * length,XtPointer * value)8772 XmStringGetNextTriple(XmStringContext context,
8773 		      unsigned int   *length,
8774 		      XtPointer      *value)
8775 {
8776   return XmeStringGetComponent((_XmStringContext) context, True, True, length, value);
8777 }
8778 
8779 /*
8780  * XmeStringGetComponent: A generalized implementation of XmStringGetNextTriple.
8781  */
8782 XmStringComponentType
XmeStringGetComponent(_XmStringContext context,Boolean update_context,Boolean copy_data,unsigned int * length,XtPointer * value)8783 XmeStringGetComponent(_XmStringContext context,
8784 		      Boolean	       update_context,
8785 		      Boolean	       copy_data,
8786 		      unsigned int    *length,
8787 		      XtPointer       *value)
8788 {
8789   short			   tmp_index;
8790   Boolean		   optimized;
8791   char			   state;
8792   Boolean		   last_seg, last_line;
8793   Boolean                  pop_dir;
8794   XmDirection              push_dir;
8795   XmStringDirection	   dir;
8796   XmStringTag		   tag = NULL;
8797   int			   char_count = 0;
8798   XmTextType		   text_type = 0;
8799   char 		          *seg_text = NULL;
8800   XmStringTag	          *begin_rends = NULL;
8801   short			   begin_count = 0;
8802   XmStringTag	          *end_rends = NULL;
8803   short			   end_count = 0;
8804   unsigned char		   tabs;
8805   _XmString		   opt = NULL;
8806   _XmStringEntry 	   seg = NULL;
8807   _XmStringArraySegRec	   array_seg;
8808   Boolean		   skip;
8809 
8810   _XmProcessLock();
8811   /* Initialize the out parameters. */
8812   if (length)	*length = 0;
8813   if (value)	*value  = NULL;
8814 
8815   /* No NULL pointers allowed. */
8816   if (! (length  && value)) {
8817     _XmProcessUnlock();
8818     return XmSTRING_COMPONENT_END;
8819   }
8820 
8821   /* We may be done already. */
8822   if (_XmStrContError(context)) {
8823     _XmProcessUnlock();
8824     return XmSTRING_COMPONENT_END;
8825   }
8826 
8827   /* Gather the current segment information. */
8828   state = _XmStrContState(context);
8829   optimized = _XmStrContOpt(context);
8830   if (optimized) {
8831     XmStringTag *rend_tag = NULL;
8832 
8833     opt = (_XmString) _XmStrContString(context);
8834 
8835     last_seg    = True;
8836     last_line   = True;
8837     /* Only lookup pop_dir when we need it. */
8838     /* Only lookup push_dir when we need it. */
8839     /* Only lookup dir when we need it. */
8840     /* Only lookup tag when we need it. */
8841     char_count  = _XmStrByteCount(opt);
8842     text_type   = (XmTextType) _XmStrTextType(opt);
8843     seg_text    = _XmStrText(opt);
8844     begin_count = _XmStrRendBegin(opt);
8845     end_count   = _XmStrRendEnd(opt);
8846     if (begin_count || end_count) {
8847       assert(_XmStrRendIndex(opt) != REND_INDEX_UNSET);
8848       rend_tag = _tag_cache + _XmStrRendIndex(opt);
8849     }
8850     begin_rends = (begin_count ? rend_tag : NULL);
8851     end_rends   = (end_count ? rend_tag : NULL);
8852     /* Only lookup tabs when we need it. */
8853   } else {
8854     _XmString str = _XmStrContString(context);
8855     _XmStringEntry line;
8856 
8857     /* If we've run off the end we're done. */
8858     if (_XmStrContCurrLine(context) >= _XmStrLineCountGet(str)) {
8859       if (update_context)
8860 	_XmStrContError(context) = TRUE;
8861       _XmProcessUnlock();
8862       return XmSTRING_COMPONENT_END;
8863     }
8864 
8865     if (_XmStrImplicitLine(str))
8866       {
8867 	line = _XmStrEntry(str)[_XmStrContCurrLine(context)];
8868       }
8869     else
8870       {
8871 	_XmEntryType(&array_seg) = XmSTRING_ENTRY_ARRAY;
8872 	_XmEntrySegmentCount(&array_seg) = _XmStrEntryCount(str);
8873 	_XmEntrySegment(&array_seg) = (_XmStringNREntry *)_XmStrEntry(str);
8874 	line = (_XmStringEntry)&array_seg;
8875       }
8876 
8877     last_line = (_XmStrContCurrLine(context) + 1 >= _XmStrLineCountGet(str));
8878     if (_XmEntryMultiple(line))
8879       last_seg = (_XmStrContCurrSeg(context) + 1 >=_XmEntrySegmentCount(line));
8880     else
8881       last_seg = True;
8882 
8883     if (_XmEntryMultiple(line) && _XmEntrySegmentCount(line) == 0) {
8884       /* Empty lines are separators. */
8885       state = SEP_STATE;
8886 
8887       /* The normal state variables shouldn't be referenced. */
8888     } else {
8889       /* Extract data from a real segment. */
8890       if (_XmEntryMultiple(line))
8891 	seg =
8892 	  (_XmStringEntry)_XmEntrySegment(line)[_XmStrContCurrSeg(context)];
8893       else
8894 	seg = line;
8895 
8896       /* Only lookup pop_dir when we need it. */
8897       /* Only lookup push_dir when we need it. */
8898       /* Only lookup dir when we need it. */
8899       /* Only lookup tag when we need it. */
8900       char_count  = _XmEntryByteCountGet(seg);
8901       text_type   = (XmTextType) _XmEntryTextTypeGet(seg);
8902       seg_text    = (char*) _XmEntryTextGet(seg);
8903       begin_count = _XmEntryRendBeginCountGet(seg);
8904       begin_rends = _XmEntryRendCountedBegins(seg, begin_count);
8905       end_count   = _XmEntryRendEndCountGet(seg);
8906       end_rends   = _XmEntryRendCountedEnds(seg, end_count);
8907       /* Only lookup tabs when we need it. */
8908     }
8909   }
8910 
8911   /* Return the next non-default component. */
8912   switch (state)
8913     {
8914     case PUSH_STATE:
8915       push_dir = (optimized ? 0 : _XmEntryPushGet(seg));
8916       if (push_dir != 0)
8917 	{
8918 	  if (copy_data)
8919 	    {
8920 	      XmDirection* tmp = XtNew(XmDirection);
8921 	      *tmp = push_dir;
8922 	      *value = (XtPointer) tmp;
8923 	      *length = sizeof(XmDirection);
8924 	    }
8925 	  else
8926 	    {
8927 	      _XmStrContTmpDir(context) = push_dir;
8928 	      *value = (XtPointer) &_XmStrContTmpDir(context);
8929 	      *length = sizeof(XmDirection);
8930 	    }
8931 	  if (update_context)
8932 	    {
8933 	      _XmStrContState(context) = BEGIN_REND_STATE;
8934 	      _XmStrContRendIndex(context) = 0;
8935 	    }
8936           _XmProcessUnlock();
8937 	  return XmSTRING_COMPONENT_LAYOUT_PUSH;
8938 	}
8939       /* Fall through if no push components exist. */
8940 
8941     case BEGIN_REND_STATE:
8942       tmp_index = ((_XmStrContState(context) == BEGIN_REND_STATE) ?
8943 		   _XmStrContRendIndex(context) : 0);
8944       if (tmp_index < begin_count)
8945 	{
8946 	  /* Process another rendition start. */
8947 	  if (copy_data)
8948 	    *value = (XtPointer) XtNewString(begin_rends[tmp_index]);
8949 	  else
8950 	    *value = (XtPointer) begin_rends[tmp_index];
8951 	  *length = strlen((char*) *value);
8952 
8953 	  if (update_context)
8954 	    {
8955 	      /* Add this rendition to the list of active renditions. */
8956 	      begin_context_rends(context, update_context,
8957 				  begin_rends + tmp_index, 1);
8958 
8959 	      _XmStrContState(context) = BEGIN_REND_STATE;
8960 	      _XmStrContRendIndex(context) = tmp_index + 1;
8961 	    }
8962 
8963           _XmProcessUnlock();
8964 	  return XmSTRING_COMPONENT_RENDITION_BEGIN;
8965 	}
8966       /* Fall through if there are no more rendition starts. */
8967 
8968     case TAG_STATE:
8969       /* Don't output implicit leading charset component. */
8970       tag = (optimized ? _XmStrTagGet(opt) : _XmEntryTag(seg));
8971       if ((tag == XmSTRING_DEFAULT_CHARSET) ||
8972 	  (tag && !strcmp((char*) tag, XmSTRING_DEFAULT_CHARSET)))
8973 	tag = _XmStringGetCurrentCharset();
8974 
8975       if ((text_type != XmNO_TEXT &&
8976 	   text_type != _XmStrContTagType(context)) ||
8977 	  (tag && (tag != _XmStrContTag(context)) &&
8978 	   (!_XmStrContTag(context) || strcmp(tag, _XmStrContTag(context)))))
8979 	{
8980 	  skip = (tag == NULL);
8981 
8982 	  assert(tag != XmSTRING_DEFAULT_CHARSET);
8983 
8984 	  /* If we have MB text with FONTLIST_DEFAULT_TAG, we really have
8985 	   * oldstyle locale_text so don't output tag component, but set
8986 	   * context if necessary for GetNextSegment. */
8987 	  if ((tag == XmFONTLIST_DEFAULT_TAG) &&
8988 	      (text_type == XmMULTIBYTE_TEXT))
8989 	    {
8990 	      skip = TRUE;
8991 	      _XmStrContTag(context) = tag;
8992 	    }
8993 
8994 	  if (!skip)
8995 	    {
8996 	      /* Tag is changing. */
8997 	      if (copy_data)
8998 		*value = (XtPointer) XtNewString(tag);
8999 	      else
9000 		*value = (XtPointer) tag;
9001 	      *length = strlen(tag);
9002 
9003 	      if (update_context)
9004 		{
9005 		  _XmStrContTag(context)       = tag;
9006 		  _XmStrContTagType(context)   = text_type;
9007 		  _XmStrContState(context)     = TAB_STATE;
9008 		  _XmStrContTabCount(context)  = 0;
9009 		}
9010 
9011 	      _XmProcessUnlock();
9012 	      return ((text_type == XmCHARSET_TEXT) ?
9013 		      XmSTRING_COMPONENT_CHARSET : XmSTRING_COMPONENT_LOCALE);
9014 	    }
9015 	}
9016       /* Fall through if no tag set. */
9017 
9018     case TAB_STATE:
9019       tmp_index = ((_XmStrContState(context) == TAB_STATE) ?
9020 		   _XmStrContTabCount(context) : 0);
9021       tabs = (optimized ? _XmStrTabs(opt) : _XmEntryTabsGet(seg));
9022       if (tmp_index < tabs)
9023 	{
9024 	  /* A Tab precedes this segment. */
9025 	  if (update_context)
9026 	    {
9027 	      _XmStrContState(context) = TAB_STATE;
9028 	      _XmStrContTabCount(context) = tmp_index + 1;
9029 	    }
9030 
9031 	  _XmProcessUnlock();
9032 	  return XmSTRING_COMPONENT_TAB;
9033 	}
9034       /* Fall through if there are no tabs. */
9035 
9036     case DIR_STATE:
9037       dir = (optimized ? _XmStrDirection(opt) : _XmEntryDirectionGet(seg));
9038       if (dir != _XmStrContDir(context))
9039 	{
9040 	  skip = FALSE;
9041 
9042 	  /* Try to resolve unset directions. */
9043 	  if (dir == XmSTRING_DIRECTION_UNSET)
9044 	    {
9045 	      if ((char_count > 0) ||
9046 		  (_XmStrContDir(context) == XmSTRING_DIRECTION_UNSET))
9047 		{
9048 		  XmCharDirectionProc char_proc = _XmOSGetCharDirection;
9049 		  (void)XmOSGetMethod(NULL, XmMCharDirection,
9050 				      (XtPointer *)&char_proc, NULL);
9051 
9052 		  if (state > TAG_STATE)
9053 		    tag = (optimized ? _XmStrTagGet(opt) : _XmEntryTag(seg));
9054 
9055 		  dir = XmDirectionToStringDirection
9056 		    ((*char_proc)(seg_text, text_type, tag));
9057 		}
9058 	      else skip = TRUE;
9059 	    }
9060 
9061 	  if (!skip)
9062 	    {
9063 	      /* Direction is changing. */
9064 	      if (copy_data)
9065 		{
9066 		  XmStringDirection* tmp = XtNew(XmStringDirection);
9067 		  *tmp = dir;
9068 		  *value = (XtPointer) tmp;
9069 		  *length = sizeof(XmStringDirection);
9070 		}
9071 	      else
9072 		{
9073 		  _XmStrContTmpStrDir(context) = dir;
9074 		  *value = (XtPointer) &_XmStrContTmpStrDir(context);
9075 		  *length = sizeof(XmStringDirection);
9076 		}
9077 	      if (update_context)
9078 		{
9079 		  _XmStrContDir(context) = dir;
9080 		  _XmStrContState(context) = TEXT_STATE;
9081 		}
9082 	      _XmProcessUnlock();
9083 	      return XmSTRING_COMPONENT_DIRECTION;
9084 	    }
9085 	}
9086       /* Fall through if no direction set. */
9087 
9088     case TEXT_STATE:
9089       switch (text_type)
9090 	{
9091 	case XmCHARSET_TEXT:
9092 	case XmMULTIBYTE_TEXT:
9093 	case XmWIDECHAR_TEXT:
9094 	  if (copy_data)
9095 	    {
9096 	      char* tmp = XtMalloc(char_count + sizeof(wchar_t));
9097 	      memcpy(tmp, seg_text, char_count);
9098 	      bzero(tmp + char_count, sizeof(wchar_t));
9099 	      *value = (XtPointer) tmp;
9100 	    }
9101 	  else
9102 	    {
9103 	      if (seg_text != NULL) *value = seg_text;
9104 	      else *value = XmS;
9105 	    }
9106 	  *length = char_count;
9107 
9108 	  if (update_context)
9109 	    {
9110 	      _XmStrContState(context) = END_REND_STATE;
9111 	      _XmStrContRendIndex(context) = 0;
9112 	    }
9113 
9114 	  switch (text_type)
9115 	    {
9116 	    case XmCHARSET_TEXT:
9117 	      _XmProcessUnlock();
9118 	      return XmSTRING_COMPONENT_TEXT;
9119 	    case XmMULTIBYTE_TEXT:
9120 	      _XmProcessUnlock();
9121 	      return XmSTRING_COMPONENT_LOCALE_TEXT;
9122 	    case XmWIDECHAR_TEXT:
9123 	      _XmProcessUnlock();
9124 	      return XmSTRING_COMPONENT_WIDECHAR_TEXT;
9125 	    case XmNO_TEXT:
9126 	      assert(FALSE);
9127 	    }
9128 
9129 	case XmNO_TEXT:
9130 	  break;
9131 
9132 	default:
9133 	  /* Something is wrong! */
9134 	  assert(False);
9135 	  if (update_context)
9136 	    _XmStrContError(context) = True;
9137 	  _XmProcessUnlock();
9138 	  return XmSTRING_COMPONENT_END;
9139 	}
9140       /* Fall through if there is no text. */
9141 
9142     case END_REND_STATE:
9143       tmp_index = ((_XmStrContState(context) == END_REND_STATE) ?
9144 		   _XmStrContRendIndex(context) : 0);
9145       if (tmp_index < end_count)
9146 	{
9147 	  /* Process another rendition end. */
9148 	  if (copy_data)
9149 	    *value = (XtPointer) XtNewString(end_rends[tmp_index]);
9150 	  else
9151 	    *value = (XtPointer) end_rends[tmp_index];
9152 	  *length = strlen((char*) *value);
9153 
9154 	  if (update_context)
9155 	    {
9156 	      /* Remove this rendition from the list of active renditions. */
9157 	      end_context_rends(context, update_context,
9158 				end_rends + tmp_index, 1);
9159 
9160 	      _XmStrContState(context) = END_REND_STATE;
9161 	      _XmStrContRendIndex(context) = tmp_index + 1;
9162 	    }
9163 
9164 	  _XmProcessUnlock();
9165 	  return XmSTRING_COMPONENT_RENDITION_END;
9166 	}
9167       /* Fall through if there are no more rendition ends. */
9168 
9169     case POP_STATE:
9170       pop_dir = (optimized ? 0 : _XmEntryPopGet(seg));
9171       if (pop_dir)
9172 	{
9173 	  /* A pop layout direction follows this segment. */
9174 	  if (update_context)
9175 	    _XmStrContState(context) = SEP_STATE;
9176 
9177 	  _XmProcessUnlock();
9178 	  return XmSTRING_COMPONENT_LAYOUT_POP;
9179 	}
9180       /* Fall through if there is no pop layout direction. */
9181 
9182     case SEP_STATE:
9183       /* This is the last possible component for a segment. */
9184       if (last_seg && last_line)
9185 	{
9186 	  /* Separators only appear between lines. */
9187 	  if (update_context)
9188 	    _XmStrContError(context) = True;
9189 
9190 	  _XmProcessUnlock();
9191 	  return XmSTRING_COMPONENT_END;
9192 	}
9193       else if (last_seg && _XmStrImplicitLine(_XmStrContString(context)))
9194 	{
9195 	  /* Advance to the next line. */
9196 	  if (update_context)
9197 	    {
9198 	      _XmStrContState(context) = PUSH_STATE;
9199 	      _XmStrContCurrSeg(context) = 0;
9200 	      _XmStrContCurrLine(context)++;
9201 	    }
9202 
9203 	  _XmProcessUnlock();
9204 	  return XmSTRING_COMPONENT_SEPARATOR;
9205 	}
9206       else
9207 	{
9208 	  /* Try the next segment of this line recursively. */
9209 	  XmStringComponentType answer;
9210 	  char saved_state = _XmStrContState(context);
9211 	  unsigned short saved_seg = _XmStrContCurrSeg(context);
9212 
9213 	  _XmStrContState(context) = PUSH_STATE;
9214 	  _XmStrContCurrSeg(context)++;
9215 
9216 	  answer = XmeStringGetComponent(context, update_context, copy_data,
9217 				 length, value);
9218 
9219 	  if (!update_context)
9220 	    {
9221 	      _XmStrContState(context) = saved_state;
9222 	      _XmStrContCurrSeg(context) = saved_seg;
9223 	    }
9224 	  _XmProcessUnlock();
9225 	  return answer;
9226 	}
9227       /*NOTREACHED*/
9228       assert(False);
9229 
9230     default:
9231       /* An unknown _XmStrContState? */
9232       assert(False);
9233       if (update_context)
9234 	_XmStrContError(context) = True;
9235       _XmProcessUnlock();
9236       return XmSTRING_COMPONENT_END;
9237     }
9238 }
9239 
9240 /*
9241  * _XmStringContextReInit: Initialize an allocated _XmStringContext.
9242  */
9243 void
_XmStringContextReInit(_XmStringContext context,_XmString string)9244 _XmStringContextReInit(_XmStringContext context,
9245 		       _XmString	string)
9246 {
9247   assert(context != NULL);
9248   bzero((char*) context, sizeof(_XmStringContextRec));
9249 
9250   _XmStrContString(context) = string;
9251   _XmStrContOpt(context)    = _XmStrOptimized(string);
9252   _XmStrContDir(context)    = XmSTRING_DIRECTION_UNSET;
9253 }
9254 
9255 /*
9256  * _XmStringContextCopy: Copy allocated _XmStringContexts.  The active
9257  *	rendition list is always copied because expanding it to
9258  *	contain new entries via XtRealloc may free the old pointer.
9259  *	Use _XmStringContextFree() to deallocate storage.
9260  */
9261 void
_XmStringContextCopy(_XmStringContext target,_XmStringContext source)9262 _XmStringContextCopy(_XmStringContext target,
9263 		     _XmStringContext source)
9264 {
9265   int size;
9266   assert(source && target && (source != target));
9267 
9268   /* Copy the normal fields. */
9269   memcpy(target, source, sizeof(_XmStringContextRec));
9270 
9271   /* Copy the active renditions list so we can modify it. */
9272   if (_XmStrContRendCount(target) > 0) {
9273      size = sizeof(XmStringTag) * _XmStrContRendCount(target);
9274      _XmStrContRendTags(target) = (XmStringTag*) XtMalloc(size);
9275      memcpy(_XmStrContRendTags(target), _XmStrContRendTags(source), size);
9276   }
9277 }
9278 
9279 /*
9280  * _XmStringContextFree: Deallocate an _XmStringContext's internal storage.
9281  */
9282 void
_XmStringContextFree(_XmStringContext context)9283 _XmStringContextFree(_XmStringContext context)
9284 {
9285   assert(context);
9286 
9287   /* Free the active rendition list. */
9288   if (_XmStrContRendTags(context)) {
9289      XtFree((char*) _XmStrContRendTags(context));
9290   }
9291   _XmStrContRendTags(context) = NULL;
9292 }
9293 
9294 /*
9295  * begin_context_rends: Update an _XmStringContext to reflect some
9296  *	newly active renditions.
9297  */
9298 static void
begin_context_rends(_XmStringContext context,Boolean update_context,XmStringTag * rends,int count)9299 begin_context_rends(_XmStringContext context,
9300 		    Boolean	     update_context,
9301 		    XmStringTag     *rends,
9302 		    int		     count)
9303 {
9304   /* Append these renditions the context's list of active renditions. */
9305   _XmStrContRendTags(context) = (XmStringTag*)
9306     XtRealloc((char*) _XmStrContRendTags(context),
9307 	      sizeof(XmStringTag) * (_XmStrContRendCount(context) + count));
9308   memcpy(_XmStrContRendTags(context) + _XmStrContRendCount(context),
9309 	 rends,
9310 	 sizeof(XmStringTag) * count);
9311 
9312   /* Update the total number only if we're advancing the context. */
9313   if (update_context)
9314     _XmStrContRendCount(context) += count;
9315 }
9316 
9317 /*
9318  * end_context_rends: Remove some renditions from an _XmStringContext's
9319  *	list of active renditions.
9320  */
9321 static void
end_context_rends(_XmStringContext context,Boolean update_context,XmStringTag * rends,int count)9322 end_context_rends(_XmStringContext context,
9323 		  Boolean	   update_context,
9324 		  XmStringTag     *rends,
9325 		  int		   count)
9326 {
9327   int n_rend, n_tag;
9328   int i;
9329 
9330   /* Check some simple error conditions. */
9331   if (!update_context || (count <= 0))
9332     return;
9333 
9334   /* Remove the last matching instance of each rendition. */
9335   for (n_rend = 0; n_rend < count; n_rend++)
9336     {
9337       /* Renditions are cached, so we can compare pointers. */
9338       n_tag = _XmStrContRendCount(context);
9339       while (--n_tag >= 0)
9340 	if (_XmStrContRendTags(context)[n_tag] == rends[n_rend])
9341 	  {
9342 	    /* Delete rendition n_tag from the context's list. */
9343 	    for (i = n_tag; i < (_XmStrContRendCount(context) - 1); i++)
9344 	      _XmStrContRendTags(context)[i] =
9345 		_XmStrContRendTags(context)[i + 1];
9346 
9347 	    _XmStrContRendCount(context)--;
9348 	  }
9349     }
9350 }
9351 
9352 XmString
XmStringGenerate(XtPointer text,XmStringTag tag,XmTextType type,XmStringTag rendition)9353 XmStringGenerate(XtPointer   text,
9354 		 XmStringTag tag,
9355 		 XmTextType  type,
9356 		 XmStringTag rendition)
9357 {
9358   XmString result;
9359   int table_size;
9360   XmParseTable gen_table;
9361   int i;
9362 
9363   _XmProcessLock();
9364   /*
9365   ** Get the parse table shared by generate and ungenerate.
9366   */
9367   table_size = _get_generate_parse_table (&gen_table);
9368 
9369   /* Parse the text into an XmString. */
9370   result = XmStringParseText
9371     (text, NULL, tag, type, gen_table, table_size, NULL);
9372 
9373   /* If no rendition was supplied return the parsetext result. */
9374   if (rendition == NULL) {
9375     _XmProcessUnlock();
9376     return result;
9377   }
9378 
9379   /* Try to wrap this rendition around an optimized result. */
9380   if (_XmStrOptimized(result) && (_XmStrRendIndex(result) == REND_INDEX_UNSET))
9381     {
9382       unsigned int rend_index;
9383       assert (!_XmStrRendBegin(result) && !_XmStrRendEnd(result));
9384 
9385       rend_index = _XmStringIndexCacheTag((char *)rendition,
9386 					  XmSTRING_TAG_STRLEN);
9387       if (rend_index < REND_INDEX_MAX)
9388 	{
9389 	  _XmStrRendIndex(result) = rend_index;
9390 	  _XmStrRendBegin(result) = _XmStrRendEnd(result) = True;
9391     	  _XmProcessUnlock();
9392 	  return result;
9393 	}
9394     }
9395 
9396   /* Try to wrap this rendition around an unoptimized result. */
9397   if (!_XmStrOptimized(result))
9398     {
9399       /* We only know how to do this if there is at least one segment. */
9400       XmStringTag cached_rend =
9401 	_XmStringCacheTag(rendition, XmSTRING_TAG_STRLEN);
9402       int n_line;
9403       _XmStringEntry line;
9404       _XmStringEntry seg;
9405 
9406       /* Locate the first segment. */
9407       for (n_line = 0; n_line < _XmStrEntryCount(result); n_line++)
9408 	{
9409 	  line = _XmStrEntry(result)[n_line];
9410 	  if (_XmEntrySegmentCountGet(line) > 0)
9411 	    {
9412 	      /* Prepend rendition_begin to the first segment. */
9413 	      if (_XmStrImplicitLine(result))
9414 		seg = (_XmStringEntry)_XmEntrySegmentGet(line)[0];
9415 	      else seg = line;
9416 
9417 	      if (_XmEntryOptimized(seg) &&
9418 		  _XmEntryRendIndex(seg) == REND_INDEX_UNSET) {
9419 		unsigned int rend_index;
9420 		assert (!_XmEntryRendBeginCountGet(seg) &&
9421 			!_XmEntryRendEndCountGet(seg));
9422 
9423 		rend_index = _XmStringIndexCacheTag((char *)rendition,
9424 						    XmSTRING_TAG_STRLEN);
9425 		if (rend_index < REND_INDEX_MAX) {
9426 		  _XmEntryRendIndex(seg) = rend_index;
9427 		  _XmEntryRendBeginCountSet(seg, 1);
9428 		}
9429 	      } else {
9430 		if (_XmEntryOptimized(seg)) {
9431 		  _XmStringEntry new_seg = EntryCvtToUnopt(seg);
9432 		  _XmStringEntryFree(seg);
9433 		  seg = new_seg;
9434 		  if (_XmEntryMultiple(line))
9435 		    _XmEntrySegment(line)[0] = (_XmStringNREntry)seg;
9436 		  else
9437 		    _XmStrEntry(result)[n_line] = seg;
9438 		}
9439 		_XmUnoptSegRendBegins(seg) = (XmStringTag*)
9440 		  XtRealloc((char*) _XmUnoptSegRendBegins(seg),
9441 			    (_XmUnoptSegRendBeginCount(seg) + 1)*
9442 			    sizeof(XmStringTag));
9443 		/* Put rendition first in begins. */
9444 		for (i = 0; i < _XmUnoptSegRendBeginCount(seg); i++)
9445 		  _XmUnoptSegRendBegins(seg)[i + 1] =
9446 		    _XmUnoptSegRendBegins(seg)[i];
9447 		_XmUnoptSegRendBegins(seg)[0] = cached_rend;
9448 		_XmUnoptSegRendBeginCount(seg)++;
9449 	      }
9450 	      break;
9451 	    }
9452 	}
9453       /* Locate the last segment. */
9454       n_line = _XmStrEntryCount(result);
9455       while (--n_line >= 0)
9456 	{
9457 	  line = _XmStrEntry(result)[n_line];
9458 	  if (_XmEntrySegmentCountGet(line) > 0)
9459 	    {
9460 	      /* Append rendition_end to the last segment. */
9461 	      if (_XmStrImplicitLine(result))
9462 		seg = (_XmStringEntry)
9463 		  _XmEntrySegmentGet(line)[_XmEntrySegmentCountGet(line)-1];
9464 	      else seg = line;
9465 
9466 	      if (_XmEntryOptimized(seg))
9467 		{
9468 		  unsigned int rend_index;
9469 		  rend_index = _XmStringIndexCacheTag((char *)rendition,
9470 						      XmSTRING_TAG_STRLEN);
9471 
9472 		  assert ((_XmEntryRendBeginCountGet(seg) <= 1) &&
9473 			  (_XmEntryRendEndCountGet(seg) == 0));
9474 
9475 
9476 
9477 
9478 		if (((_XmEntryRendIndex(seg) == REND_INDEX_UNSET) ||
9479 		     (_XmEntryRendIndex(seg) == rend_index)) &&
9480 		    (rend_index < REND_INDEX_MAX)) {
9481 		  _XmEntryRendIndex(seg) = rend_index;
9482 		  _XmEntryRendEndCountSet(seg, 1);
9483     	  	  _XmProcessUnlock();
9484 		  return result;
9485 		} else {
9486 		  break;
9487 		}
9488 	      } else {
9489 		if (_XmEntryOptimized(seg)) {
9490 		  _XmStringEntry new_seg = EntryCvtToUnopt(seg);
9491 		  if (_XmEntryMultiple(line))
9492 		    _XmEntrySegment(line)[0] = (_XmStringNREntry)new_seg;
9493 		  else
9494 		    _XmStrEntry(result)[n_line] = new_seg;
9495 		  _XmStringEntryFree(seg);
9496 		  seg = new_seg;
9497 		}
9498 		_XmUnoptSegRendEnds(seg) = (XmStringTag*)
9499 		  XtRealloc((char*) _XmUnoptSegRendEnds(seg),
9500 			    (_XmUnoptSegRendEndCount(seg) + 1) *
9501 			    sizeof(XmStringTag));
9502 		_XmUnoptSegRendEnds(seg)[_XmUnoptSegRendEndCount(seg)] =
9503 		  cached_rend;
9504 		_XmUnoptSegRendEndCount(seg)++;
9505 	  	_XmProcessUnlock();
9506 		return result;
9507 	      }
9508 	    }
9509 	}
9510     }
9511 
9512   /* As a last resort merge the rendition components normally. */
9513   {
9514     XmString tmp_1, tmp_2;
9515 
9516     /* Prepend the rendition begin. */
9517     tmp_1 = XmStringComponentCreate(XmSTRING_COMPONENT_RENDITION_BEGIN,
9518 				    strlen(rendition), rendition);
9519     tmp_2 = result;
9520     result = XmStringConcatAndFree(tmp_1, tmp_2);
9521 
9522     /* Append the rendition end. */
9523     tmp_1 = result;
9524     tmp_2 = XmStringComponentCreate(XmSTRING_COMPONENT_RENDITION_END,
9525 				    strlen(rendition), rendition);
9526     result = XmStringConcatAndFree(tmp_1, tmp_2);
9527   }
9528   _XmProcessUnlock();
9529   return result;
9530 }
9531 
9532 XtPointer
_XmStringUngenerate(XmString string,XmStringTag tag,XmTextType tag_type,XmTextType output_type)9533 _XmStringUngenerate(XmString    string,
9534 		    XmStringTag tag,
9535 		    XmTextType  tag_type,
9536 		    XmTextType  output_type)
9537 {
9538   XtPointer result;
9539   int table_size;
9540   XmParseTable gen_table;
9541 
9542   /*
9543   ** Get the parse table shared by generate and ungenerate.
9544   */
9545   table_size = _get_generate_parse_table (&gen_table);
9546 
9547   /* Unparse the XmString into text. */
9548   result = XmStringUnparse
9549     (string, tag, tag_type, output_type, gen_table, table_size, XmOUTPUT_ALL);
9550 
9551   /*
9552   ** It might be useful to figure out rendition here to return the reverse of
9553   ** what came in for XmStringGenerate.  I'm not real sure about how to do that
9554   ** and it isn't necessary for the immediate needs of CSText, so...
9555   ** RJS
9556   */
9557   return result;
9558 
9559 }
9560 
9561 XmParseMapping
XmParseMappingCreate(ArgList arg_list,Cardinal arg_count)9562 XmParseMappingCreate(ArgList  arg_list,
9563 		     Cardinal arg_count)
9564 {
9565   /* Allocate and initialize the return value. */
9566   XmParseMapping result = XtNew(_XmParseMappingRec);
9567   bzero((char*)result, sizeof(_XmParseMappingRec));
9568 
9569   /* Default values are established by bzero().
9570    *
9571    * result->pattern        = XmDIRECTION_CHANGE = NULL;
9572    * result->pattern_type   = XmCHARSET_TEXT;
9573    * result->substitute     = NULL;
9574    * result->parse_proc     = NULL;
9575    * result->client_data    = NULL;
9576    * result->include_status = XmINSERT;
9577    * result->internal_flags = XmSTRING_UNPARSE_UNKNOWN;
9578    */
9579 
9580   /* Insert specified values. */
9581   XmParseMappingSetValues(result, arg_list, arg_count);
9582 
9583   return result;
9584 }
9585 
9586 void
XmParseMappingSetValues(XmParseMapping mapping,ArgList arg_list,Cardinal arg_count)9587 XmParseMappingSetValues(XmParseMapping mapping,
9588 			ArgList        arg_list,
9589 			Cardinal       arg_count)
9590 {
9591   register Cardinal i;
9592   register String arg_name;
9593   Cardinal unknown = 0;
9594 
9595   _XmProcessLock();
9596   /* Do a little error checking. */
9597   if (mapping == NULL) {
9598     _XmProcessUnlock();
9599     return;
9600   }
9601 
9602   /* Modify the specified values. */
9603   for (i = 0; i < arg_count; i++)
9604     {
9605       arg_name = arg_list[i].name;
9606 
9607       if ((arg_name == XmNpattern) ||
9608 	  (strcmp(arg_name, XmNpattern) == 0))
9609 	mapping->pattern = (XtPointer) arg_list[i].value;
9610       else if ((arg_name == XmNpatternType) ||
9611 	       (strcmp(arg_name, XmNpatternType) == 0))
9612 	mapping->pattern_type = (XmTextType) arg_list[i].value;
9613       else if ((arg_name == XmNsubstitute) ||
9614 	       (strcmp(arg_name, XmNsubstitute) == 0))
9615 	mapping->substitute = XmStringCopy((XmString) arg_list[i].value);
9616       else if ((arg_name == XmNinvokeParseProc) ||
9617 	       (strcmp(arg_name, XmNinvokeParseProc) == 0))
9618 	mapping->parse_proc = (XmParseProc) arg_list[i].value;
9619       else if ((arg_name == XmNclientData) ||
9620 	       (strcmp(arg_name, XmNclientData) == 0))
9621 	mapping->client_data = (XtPointer) arg_list[i].value;
9622       else if ((arg_name == XmNincludeStatus) ||
9623 	       (strcmp(arg_name, XmNincludeStatus) == 0))
9624 	mapping->include_status = (XmIncludeStatus) arg_list[i].value;
9625       else
9626 	unknown++;
9627     }
9628 
9629   /* If there were any known values reset internal_flags. */
9630   if (unknown < arg_count)
9631     mapping->internal_flags = XmSTRING_UNPARSE_UNKNOWN;
9632   _XmProcessUnlock();
9633 }
9634 
9635 
9636 
9637 static int
_get_generate_parse_table(XmParseTable * gen_table)9638 _get_generate_parse_table (XmParseTable *gen_table)
9639 /*
9640 **
9641 ** Utility function to build and supply the parse table shared by
9642 ** XmStringGenerate and _XmStringUngenerate.  All of the information about
9643 ** the size and real storage of the table is maintained here.
9644 **
9645 */
9646 {
9647   int table_size = 2;
9648   Arg args[10];
9649   Cardinal nargs;
9650   XmString tmp;
9651   int index = 0;
9652   static XmParseTable table = NULL;
9653 
9654 
9655   _XmProcessLock();
9656   /* Allocate a parse table only if necessary. */
9657   if (table)
9658     {
9659       *gen_table = table;
9660       _XmProcessUnlock();
9661       return table_size;
9662     }
9663   else
9664     {
9665       table = (XmParseTable) XtCalloc (table_size, sizeof(XmParseMapping));
9666       *gen_table = table;
9667     }
9668   _XmProcessUnlock();
9669 
9670   /* Parse tab characters. */
9671   tmp = XmStringComponentCreate(XmSTRING_COMPONENT_TAB, 0, NULL);
9672   nargs = 0;
9673   XtSetArg(args[nargs], XmNincludeStatus, XmINSERT), nargs++;
9674   XtSetArg(args[nargs], XmNsubstitute, tmp), 	 nargs++;
9675   XtSetArg(args[nargs], XmNpattern, "\t"), 		 nargs++;
9676   assert(nargs < XtNumber(args));
9677   _XmProcessLock();
9678   table[index++] = XmParseMappingCreate(args, nargs);
9679   _XmProcessUnlock();
9680   XmStringFree(tmp);
9681 
9682   /* Parse newline characters. */
9683   tmp = XmStringSeparatorCreate();
9684   nargs = 0;
9685   XtSetArg(args[nargs], XmNincludeStatus, XmINSERT), nargs++;
9686   XtSetArg(args[nargs], XmNsubstitute, tmp),	 nargs++;
9687   XtSetArg(args[nargs], XmNpattern, "\n"),		 nargs++;
9688   assert(nargs < XtNumber(args));
9689   _XmProcessLock();
9690   table[index++] = XmParseMappingCreate(args, nargs);
9691   _XmProcessUnlock();
9692 
9693   assert(index == table_size);
9694 
9695   return (table_size);
9696 }
9697 
9698 /* Destructively truncates str to be n bytes or less, insuring that it
9699    remains a legal ASN.1 encoding. */
9700 unsigned char *
_XmStringTruncateASN1(unsigned char * str,int n)9701 _XmStringTruncateASN1(unsigned char *str, int n)
9702 {
9703   unsigned char    *a = str;
9704   unsigned short   used , delta, d1;
9705   unsigned char    *new_c, *a_end;
9706   unsigned char    *ap;
9707   unsigned char	   d2;
9708   short    	   head_size;
9709   int	     	   len, length, header;
9710 
9711   if (a == NULL) return((unsigned char *)NULL);
9712   if (n < ASNHEADERLEN + CSSHORTLEN) return((unsigned char *)NULL);
9713 
9714   head_size = used = _read_header_length(a);
9715   len = _read_string_length(a);
9716 
9717   ap = _read_header(a);
9718 
9719   a_end = ((unsigned char *) a) + len + head_size;
9720 
9721   length = _read_asn1_length(ap);
9722   header = _asn1_size(length);
9723 
9724   /* Read the components adding up their lengths. */
9725   while (((length + header) < (n - used)) && (ap < a_end))
9726     {
9727       new_c = _read_component(ap, &d2, &d1, NULL);
9728 
9729       delta = length + header;
9730       used += delta;
9731       ap = new_c;
9732       length = _read_asn1_length(ap);
9733       header = _asn1_size(length);
9734     }
9735 
9736   if ((head_size == (ASNHEADERLEN + CSLONGLEN)) &&
9737       ((used - head_size) <= MAXSHORTVALUE))
9738     {
9739       /* Have to reallocate string. */
9740       unsigned char	*tmp;
9741       short		diff = (CSLONGLEN - CSSHORTLEN);
9742 
9743       used -= diff;
9744 
9745       tmp = (unsigned char *)XtMalloc(used * sizeof(unsigned char));
9746       memcpy(tmp, (str + diff), used);
9747       XtFree((char *)str);
9748       str = tmp;
9749     }
9750   else
9751     {
9752       str = (unsigned char *)XtRealloc((char *)str, used);
9753     }
9754 
9755   _write_header(str, used);
9756 
9757   return (str);
9758 }
9759 
9760