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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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