1 /* $TOG: TxtPropCv.c /main/15 1997/06/18 17:46:05 samborn $ */
2 /*
3 * Motif
4 *
5 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
6 *
7 * These libraries and programs are free software; you can
8 * redistribute them and/or modify them under the terms of the GNU
9 * Lesser General Public License as published by the Free Software
10 * Foundation; either version 2 of the License, or (at your option)
11 * any later version.
12 *
13 * These libraries and programs are distributed in the hope that
14 * they will be useful, but WITHOUT ANY WARRANTY; without even the
15 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 * PURPOSE. See the GNU Lesser General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with these librararies and programs; if not, write
21 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
22 * Floor, Boston, MA 02110-1301 USA
23 *
24 */
25 /*
26 * HISTORY
27 */
28
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32
33
34
35 #include <stdio.h>
36 #ifndef X_NOT_STDC_ENV
37 #include <stdlib.h>
38 #endif
39 #include <string.h>
40 #include <ctype.h>
41 #include <Xm/XmosP.h>
42 #include "XmI.h"
43 #include "XmStringI.h"
44
45
46
47 static Atom
GetLocaleEncodingAtom(Display * dpy)48 GetLocaleEncodingAtom(Display *dpy)
49 {
50 int ret_status = 0;
51 XTextProperty tmp_prop;
52 char * tmp_string = "ABC"; /* these are characters in XPCS, so... safe */
53 Atom encoding;
54
55 tmp_prop.value = NULL; /* just in case X doesn't do it */
56 ret_status = XmbTextListToTextProperty(dpy, &tmp_string, 1,
57 (XICCEncodingStyle)XTextStyle,
58 &tmp_prop);
59 if (ret_status == Success)
60 encoding = tmp_prop.encoding;
61 else
62 encoding = None; /* XmbTextList... should always be able
63 * to convert XPCS characters; but in
64 * case its broken, this prevents a core
65 * dump.
66 */
67 if (tmp_prop.value != NULL) XFree((char *)tmp_prop.value);
68 return(encoding);
69 }
70
71 /************************************************************************
72 *
73 * TextPropertyToSingleTextItem
74 *
75 ************************************************************************/
76
77 static int
TextPropertyToSingleTextItem(Display * display,XTextProperty * text_prop,char ** text_item)78 TextPropertyToSingleTextItem(Display *display, XTextProperty *text_prop,
79 char **text_item)
80 {
81 int result, count;
82 char **textlist;
83
84 result = XmbTextPropertyToTextList(display, text_prop, &textlist,
85 &count);
86 if (result != Success) return(result);
87 if (count == 1)
88 {
89 /* Otherwise just return the first element of the
90 text list */
91 *text_item = XtNewString(textlist[0]);
92 XFreeStringList(textlist);
93 }
94 else if (count > 1)
95 {
96 /* If we got back more than one string, then
97 let's concatenate them all together. */
98 int i, length = 0;
99 char *newstring;
100
101 /* First figure out how big the final string will be */
102 for (i = 0; i < count; ++i)
103 length += strlen(textlist[i]);
104 /* Allocate a buffer and jam all the strings into it */
105 newstring = (char *)XtMalloc(sizeof(char)*(length+1));
106 newstring[0] = '\0';
107 for (i = 0; i < count; ++i)
108 strcat(newstring, textlist[i]);
109 *text_item = newstring;
110 XFreeStringList(textlist);
111 }
112 return(Success);
113 }
114
115 /************************************************************************
116 *
117 * GetTextSegment
118 *
119 * This function gets the next full segment from the given xmstring using
120 * the given xmcontext and tries to extract either locale text or
121 * string text (i.e. ISO8859-1 text) based on the texttype argument.
122 *
123 * This function can return one of three return values:
124 *
125 * _VALID_SEGMENT: we found a segment that we could decompose. The
126 * appropriate text has been stored in the given buffer
127 *
128 * _INVALID_SEGMENT: we could not decompose the segment. The given
129 * buffer does not contain valid data
130 *
131 * _NO_MORE_SEGMENTS: there are no more segments available in the
132 * xmstring using the xmcontext.
133 *
134 ************************************************************************/
135
136 /* Segment type return value */
137 enum { _VALID_SEGMENT, _INVALID_SEGMENT, _NO_MORE_SEGMENTS };
138
139 /* Valid text types */
140 enum { _LOCALE_TEXT, _STRING_TEXT };
141
142 /*ARGSUSED*/
143 static unsigned char
GetTextSegment(Display * display,XmStringContext xmcontext,XmString xmstring,char ** buffer,unsigned char texttype)144 GetTextSegment(Display *display, /* unused */
145 XmStringContext xmcontext,
146 XmString xmstring, /* unused */
147 char **buffer,
148 unsigned char texttype)
149 {
150 XtPointer text;
151 XmStringTag tag, *rendition_tags;
152 XmTextType type;
153 XmStringDirection direction;
154 XmDirection push_before;
155 Boolean separator, pop_after;
156 unsigned int tag_count;
157 unsigned char return_status, tabs;
158 short char_count;
159 char *encoding;
160 int i;
161
162 /* Initialize the locale_buffer just in case we need to return
163 Failure at any point along the way. */
164 *buffer = NULL;
165 return_status = _VALID_SEGMENT;
166
167 /* Decompose the xmstring and handle each segment separately. */
168 if (_XmStringGetSegment(xmcontext, TRUE, FALSE, &text, &tag, &type,
169 &rendition_tags, &tag_count, &direction,
170 &separator, &tabs, &char_count,
171 &push_before, &pop_after))
172 {
173 switch (type)
174 {
175 case XmMULTIBYTE_TEXT:
176 case XmWIDECHAR_TEXT:
177 if (texttype == _LOCALE_TEXT)
178 {
179 /* The text should be already be valid locale text */
180 char *tmp = XtMalloc(char_count + sizeof(wchar_t));
181 memcpy(tmp, text, char_count);
182 bzero(tmp + char_count, sizeof(wchar_t));
183
184 *buffer = tmp;
185 }
186 else if (texttype == _STRING_TEXT)
187 {
188 *buffer = NULL;
189 return(_INVALID_SEGMENT);
190 }
191 break;
192 case XmCHARSET_TEXT:
193 /* "tag" is the charset when type is CHARSET_TEXT */
194 encoding = XmMapSegmentEncoding(tag);
195 if (encoding != NULL)
196 {
197 if (texttype == _LOCALE_TEXT &&
198 (strcmp(encoding, _MOTIF_DEFAULT_LOCALE) == 0 ||
199 strcmp(encoding, XmFONTLIST_DEFAULT_TAG) == 0))
200 /* @@ Is ISO8859-1 valid here? */
201 {
202 /* Given the above charset encodings, the text should
203 already be valid locale text. */
204 char *tmp = XtMalloc(char_count + sizeof(wchar_t));
205 memcpy(tmp, text, char_count);
206 bzero(tmp + char_count, sizeof(wchar_t));
207
208 *buffer = tmp;
209 }
210 else if (texttype == _STRING_TEXT &&
211 (strcmp(encoding, "ISO8859-1") == 0))
212 {
213 /* The text is valid STRING text */
214 char *tmp = XtMalloc(char_count + sizeof(wchar_t));
215 memcpy(tmp, text, char_count);
216 bzero(tmp + char_count, sizeof(wchar_t));
217
218 *buffer = tmp;
219 }
220 else return(_INVALID_SEGMENT);
221 }
222 else return(_INVALID_SEGMENT); /* the encoding was unregistered */
223 break;
224 case XmNO_TEXT:
225 break;
226 }
227 /* Before returning Success, check to see whether we need to
228 prepend any tabs or append any newlines. */
229 if ((return_status == _VALID_SEGMENT) &&
230 (separator == True || tabs != 0))
231 {
232 int newlength;
233 char *newstring;
234
235 newlength =
236 strlen(*buffer) + (separator ? 1 : 0) + tabs;
237 newstring = (char *)XtMalloc(sizeof(char) * (newlength + 1));
238 for (i = 0; i < tabs; i++) newstring[i] = '\t';
239 strcpy(&newstring[i], *buffer);
240 strcat(newstring, "\n");
241 XtFree(*buffer);
242 *buffer = newstring;
243 }
244 return(return_status);
245 }
246 else
247 {
248 /* Return NULL text but a value of Success to designate that
249 there are no more segments to process. */
250 *buffer = NULL;
251 return(_NO_MORE_SEGMENTS);
252 }
253 }
254
255 /************************************************************************
256 *
257 * GetUseableText
258 *
259 * Given an XmString, decompose it into text specified by the texttype
260 * argument. Valid text types are _LOCALE_TEXT for text encoded in the
261 * current locale and _STRING_TEXT for text encoded in ISO8859-1 with
262 * newlines and tabs.
263 *
264 * If the "strict" argument is False, then any compound strings which
265 * have a segment that can not be decomposed as specified will be converted
266 * to compound text and then converted to the appropriate text by using
267 * a series of XmbTextListToTextProperty and XmbTextPropertyToTextList
268 * calls to acchive the conversion.
269 *
270 * If the "strict" argument is True, then all compound strings must be
271 * fully convertible to the specified text type. If one is not in any
272 * way, then XLocaleNotSupported is returned.
273 *
274 ************************************************************************/
275
276 static int
GetUseableText(Display * display,XmString xmstring,char ** buffer,Boolean strict,unsigned char texttype)277 GetUseableText(Display *display, XmString xmstring, char **buffer,
278 Boolean strict, unsigned char texttype)
279 {
280 _XmStringContextRec stack_context;
281 XTextProperty text_prop_return;
282 char *text = NULL, *final_string = NULL, *text_item=NULL, *compound_text;
283 unsigned char return_status;
284 int result, size_so_far = 1; /* initialized for the ending NULL */
285 XICCEncodingStyle encoding_style;
286
287 /* Initialize the buffer in case we have to abort and return
288 failure. */
289 *buffer = NULL;
290 switch(texttype)
291 {
292 case _LOCALE_TEXT:
293 encoding_style = XTextStyle;
294 break;
295 case _STRING_TEXT:
296 encoding_style = XStringStyle;
297 break;
298 default:
299 return(XLocaleNotSupported);
300 }
301
302 /* Decompose the xmstring and handle each segment separately. */
303 _XmStringContextReInit(&stack_context, xmstring);
304
305 /* Get text for each segment of the compound string. Concatenate
306 all the text from the segments together into one string that will
307 be returned in the buffer. */
308 while((return_status =
309 GetTextSegment(display, &stack_context, xmstring,
310 &text, texttype)) == _VALID_SEGMENT)
311 {
312 size_so_far += strlen(text);
313 final_string = (char *)XtRealloc(final_string, size_so_far);
314 final_string[0] = '\0';
315 strcat(final_string, text);
316 XtFree(text);
317 text = NULL;
318 }
319
320 /* If we encountered an invalid segment, then we will throw up our
321 hands and try all over again by converting the compound string to
322 compound text and then converting the compound text to a text
323 property and from a text property back to a text list. This should
324 result in text but with possible loss of information. */
325 if (return_status == _INVALID_SEGMENT)
326 {
327 int txt_len;
328 char *txt_value;
329
330 /* First, free what we've malloc'ed already */
331 if (final_string) XtFree(final_string);
332
333 /* If we are in strict mode, then return XLocaleNotSupported to
334 let the caller know that we could not decompose one of the
335 XmStrings in the context of the current locale */
336 if (strict)
337 {
338 _XmStringContextFree(&stack_context);
339 return(XLocaleNotSupported);
340 }
341
342 /* Now convert the compound string to compound text ... */
343 if ((compound_text = XmCvtXmStringToCT(xmstring))
344 == (char *)NULL)
345 {
346 _XmStringContextFree(&stack_context);
347 return (XLocaleNotSupported);
348 }
349 /* then to a text property in TextStyle encoding ... */
350 txt_len = strlen(compound_text) + 1;
351 txt_value = XtMalloc((txt_len + 1) * sizeof(char));
352 strcpy(txt_value, compound_text);
353 text_prop_return.value = (unsigned char *) txt_value;
354 text_prop_return.value[txt_len] = '\0';
355 text_prop_return.nitems = txt_len;
356 text_prop_return.encoding =
357 XInternAtom(display, XmSCOMPOUND_TEXT, False);
358 text_prop_return.format = 8;
359 XtFree(compound_text);
360 /* then to a text list, which should result in text. */
361 result = TextPropertyToSingleTextItem(display, &text_prop_return,
362 &text_item);
363 if (text_prop_return.value != NULL)
364 XtFree((char *)text_prop_return.value);
365
366 if (result != Success)
367 {
368 _XmStringContextFree(&stack_context);
369 return(result);
370 }
371 final_string = text_item;
372 }
373
374 /* Otherwise, we should have valid text */
375 *buffer = final_string;
376 _XmStringContextFree(&stack_context);
377 return(Success);
378 }
379
380 /************************************************************************
381 *
382 * XmCvtXmStringTableToTextProperty
383 *
384 ************************************************************************/
385 int
XmCvtXmStringTableToTextProperty(Display * display,XmStringTable string_table,int count,XmICCEncodingStyle style,XTextProperty * text_prop_return)386 XmCvtXmStringTableToTextProperty(Display *display,
387 XmStringTable string_table,
388 int count,
389 XmICCEncodingStyle style,
390 XTextProperty *text_prop_return)
391 {
392 char **compound_text, **useable_text, *xm_compound_text, *ptr;
393 unsigned char *ubufptr, *bufptr, texttype =_LOCALE_TEXT , *final_string;
394 int i, result, total_size;
395 Boolean strict = True;
396 Atom encoding = 0;
397 _XmDisplayToAppContext(display);
398
399 _XmAppLock(app);
400 switch (style)
401 {
402 case XmSTYLE_COMPOUND_TEXT:
403 compound_text = (char **)XtMalloc(sizeof(char *) * count);
404 /* Convert each XmString to Compound Text */
405 for (i = 0, total_size = 0; i < count; ++i) {
406 compound_text[i] = XmCvtXmStringToCT(string_table[i]);
407 total_size += (compound_text[i] ? strlen(compound_text[i]) : 0) +1;
408 }
409 /* Generate the resulting XTextProperty value as a set of
410 null-separated compound text elements. A final terminating
411 null is stored at the end of the value field of text_prop_return
412 but is not included in the nitems member. */
413 ptr = xm_compound_text =
414 (char *) XtMalloc(sizeof(char) * (total_size + 1));
415 for (i = 0; i < count; i++)
416 {
417 if (compound_text[i])
418 {
419 strcpy(ptr, compound_text[i]);
420 XtFree(compound_text[i]);
421 }
422 else
423 {
424 *ptr = '\0';
425 }
426 ptr += strlen(ptr) + 1;
427 }
428 *ptr = '\0';
429 XtFree((char *) compound_text);
430 text_prop_return->value = (unsigned char *) xm_compound_text;
431 text_prop_return->encoding =
432 XInternAtom(display, XmSCOMPOUND_TEXT, False);
433 text_prop_return->format = 8;
434 text_prop_return->nitems = total_size;
435 _XmAppUnlock(app);
436 return(Success);
437
438 case XmSTYLE_COMPOUND_STRING:
439 /* First calculate how much space the compound strings will occupy
440 when they are all converted to ASN1 strings. */
441 for (i = 0, total_size = 0; i < count; ++i)
442 total_size += XmCvtXmStringToByteStream(string_table[i],NULL);
443 /* Allocate that amount of space and convert the compound strings
444 to ASN1 strings, putting them directly into the buffer. */
445 text_prop_return->value = ubufptr =
446 (unsigned char *) XtMalloc(sizeof(unsigned char) * total_size);
447 for (i = 0; i < count; ++i)
448 {
449 int size;
450 size = XmCvtXmStringToByteStream(string_table[i],&bufptr);
451 memcpy(ubufptr, bufptr, size);
452 XtFree((char *) bufptr);
453 ubufptr += size;
454 }
455 *(++ubufptr) = '\0';
456 text_prop_return->nitems = total_size;
457 text_prop_return->format = 8;
458 text_prop_return->encoding =
459 XInternAtom(display, XmS_MOTIF_COMPOUND_STRING, False);
460 _XmAppUnlock(app);
461 return(Success);
462
463 case XmSTYLE_LOCALE:
464 case XmSTYLE_TEXT:
465 case XmSTYLE_STRING:
466 case XmSTYLE_STANDARD_ICC_TEXT:
467 /* We do mostly the same thing for these four styles. Do another
468 switch to set up some parameters which will change the behavior
469 slightly depending on which style is being requested. */
470 switch (style) {
471 case XmSTYLE_LOCALE:
472 strict = False;
473 texttype = _LOCALE_TEXT;
474 encoding = GetLocaleEncodingAtom(display);
475 break;
476 case XmSTYLE_TEXT:
477 strict = True;
478 texttype = _LOCALE_TEXT;
479 encoding = GetLocaleEncodingAtom(display);
480 break;
481 case XmSTYLE_STRING:
482 strict = False;
483 texttype = _STRING_TEXT;
484 encoding = XA_STRING;
485 break;
486 case XmSTYLE_STANDARD_ICC_TEXT:
487 strict = True;
488 texttype = _STRING_TEXT;
489 encoding = XA_STRING;
490 break;
491 case XmSTYLE_COMPOUND_TEXT:
492 case XmSTYLE_COMPOUND_STRING:
493 break;
494 }
495 /* Get useable text for each compound string */
496 useable_text = (char **)XtMalloc(sizeof(char *) * count);
497 for (i = 0; i < count; ++i)
498 {
499 result = GetUseableText(display, string_table[i],
500 &useable_text[i], strict, texttype);
501 if (result != Success)
502 {
503 /* Free up what we have so far ... */
504 --i; /* skip the one that failed */
505 while (i >= 0) XtFree(useable_text[i--]);
506 if (strict)
507 {
508 /* If we got back XLocaleNotSupported, then pretend the
509 caller asked for COMPOUND_TEXT style. */
510 if (result == XLocaleNotSupported)
511 {
512 /* Try to do a straight COMPOUND_TEXT conversion
513 and return whatever we got back. */
514 _XmAppUnlock(app);
515 return (XmCvtXmStringTableToTextProperty
516 (display, string_table, count,
517 XmSTYLE_COMPOUND_TEXT, text_prop_return));
518 }
519 else
520 {
521 /* Otherwise, we got back an error we didn't know how
522 to handle. Just return it. */
523 _XmAppUnlock(app);
524 return(result);
525 }
526 }
527 else
528 {
529 /* If we are not being strict, then an error was really
530 an error that we could not handle. */
531 _XmAppUnlock(app);
532 return(result);
533 }
534 }
535 }
536 /* Now take the useable_text array and convert it to one
537 long string with null separated elements. */
538 for (i = 0, total_size = 0; i < count; ++i)
539 total_size += strlen(useable_text[i]) + 1;
540 final_string =
541 (unsigned char *)XtMalloc(sizeof(char) * (total_size + 1));
542 final_string[0] = '\0';
543 bufptr = final_string;
544 for (i = 0; i < count; ++i)
545 {
546 strcpy((char *)bufptr, useable_text[i]);
547 bufptr += strlen(useable_text[i]) + 1;
548 }
549 *bufptr = '\0';
550
551 /* Fill in the text property with the data */
552 text_prop_return->encoding = encoding;
553 text_prop_return->value = final_string;
554 text_prop_return->nitems = total_size;
555 text_prop_return->format = 8;
556
557 /* Clean up and leave town */
558 for (i = 0; i < count; ++i) XtFree(useable_text[i]);
559 XtFree((char *) useable_text);
560 _XmAppUnlock(app);
561 return(Success);
562
563 default:
564 _XmAppUnlock(app);
565 return(XLocaleNotSupported);
566 }
567 }
568
569 /************************************************************************
570 *
571 * XmCvtTextPropertyToXmStringTable
572 *
573 ************************************************************************/
574 int
XmCvtTextPropertyToXmStringTable(Display * display,XTextProperty * text_prop,XmStringTable * string_table_return,int * count_return)575 XmCvtTextPropertyToXmStringTable(Display *display,
576 XTextProperty *text_prop,
577 XmStringTable *string_table_return,
578 int *count_return)
579 {
580 enum { XmACOMPOUND_TEXT, XmA_MOTIF_COMPOUND_STRING,
581 #ifdef UTF8_SUPPORTED
582 XmAUTF8_STRING,
583 #endif
584 NUM_ATOMS };
585 static char* atom_names[] = { XmSCOMPOUND_TEXT, XmS_MOTIF_COMPOUND_STRING,
586 #ifdef UTF8_SUPPORTED
587 XmSUTF8_STRING
588 #endif
589 };
590
591 char **text_list;
592 int i, result, elements = 0;
593 XmStringTable string_table;
594 XmStringTag tag;
595 XmTextType type;
596 Atom LOCALE_ATOM = GetLocaleEncodingAtom(display);
597 Atom atoms[XtNumber(atom_names)];
598 _XmDisplayToAppContext(display);
599
600 assert(XtNumber(atom_names) == NUM_ATOMS);
601 XInternAtoms(display, atom_names, XtNumber(atom_names), False, atoms);
602
603 _XmAppLock(app);
604 if (text_prop->encoding == atoms[XmACOMPOUND_TEXT])
605 {
606 char *ptr;
607
608 /* First found how many XmString we need to allocate. */
609 for (*count_return = 1, i = 0; i < text_prop->nitems; i++)
610 {
611 if (text_prop->value[i] == '\0')
612 (*count_return)++;
613 }
614 string_table =
615 (XmStringTable)XtMalloc(sizeof(XmString) * (*count_return));
616 /* Now convert each compound text to an XmString. */
617 for (i = 0, ptr = (char *)text_prop->value;
618 i < *count_return;
619 i++, ptr += strlen(ptr) + 1)
620 {
621 XmString tempstr;
622 tempstr = XmCvtCTToXmString(ptr);
623 string_table[i] = tempstr;
624 }
625 *string_table_return = string_table;
626
627 _XmAppUnlock(app);
628 return(Success);
629 }
630 else if (text_prop->encoding == atoms[XmA_MOTIF_COMPOUND_STRING])
631 {
632 unsigned char *asn1_head;
633
634 /* First calculate how many elements there are */
635 asn1_head = text_prop->value;
636 for (elements = 0; *asn1_head != '\0'; ++elements)
637 asn1_head += XmStringByteStreamLength(asn1_head);
638
639 /* Now allocate a string table to put them in */
640 string_table = (XmStringTable)XtMalloc(sizeof(XmString) * elements);
641
642 /* Run through again, converting the strings. */
643 asn1_head = text_prop->value;
644 for (elements = 0; *asn1_head != '\0'; ++elements)
645 {
646 string_table[elements] = XmCvtByteStreamToXmString(asn1_head);
647 /* If the string is NULL, then we don't know what to do */
648 if (string_table[elements] == (XmString) NULL)
649 {
650 while (elements > 0) XtFree((char *)string_table[--elements]);
651 XtFree((char *)string_table);
652 _XmAppUnlock(app);
653 return(XConverterNotFound);
654 }
655 /* Find the next asn1 string header */
656 asn1_head += XmStringByteStreamLength(asn1_head);
657 }
658 *string_table_return = string_table;
659 *count_return = elements;
660 _XmAppUnlock(app);
661 return(Success);
662 }
663 else if (text_prop->encoding == LOCALE_ATOM)
664 {
665 tag = _MOTIF_DEFAULT_LOCALE;
666 type = XmMULTIBYTE_TEXT;
667 }
668 else if (text_prop->encoding == XA_STRING)
669 {
670 tag = "ISO8859-1";
671 type = XmCHARSET_TEXT;
672 }
673 #ifdef UTF8_SUPPORTED
674 else if (text_prop->encoding == atoms[XmAUTF8_STRING])
675 {
676 tag = "UTF-8";
677 type = XmCHARSET_TEXT;
678 }
679 #endif
680 else {
681 _XmAppUnlock(app);
682 return(XLocaleNotSupported);
683 }
684
685
686 /* We fell through the else-if's so pull apart the data in the text
687 property and set up a return string table. */
688
689 /* First count up how many string elements there are in the value. */
690 for (i = 0, elements = 1; i < text_prop->nitems - 1; ++i)
691 {
692 /* The text prop value will have two NULL's at the end,
693 one for the end of the last string and one to terminate
694 the entire value. The terminating NULL will be excluded
695 by looping until i == nitems since the terminating NULL
696 is not included in the nitems calculation. */
697 if (text_prop->value[i] == '\0')
698 ++elements;
699 }
700 /* Create an appropriately sized array of xmstrings */
701 string_table =
702 (XmStringTable)XtMalloc(sizeof(XmString) * (elements));
703
704 /* Create XmStrings from each string in the value field */
705 string_table[0] = XmStringGenerate((XtPointer)text_prop->value,
706 tag, type, NULL);
707 for (i = 0, elements = 1; i < text_prop->nitems - 1; ++i)
708 {
709 if (text_prop->value[i] == '\0')
710 string_table[elements++] =
711 XmStringGenerate((XtPointer) &(text_prop->value[i + 1]),
712 tag, type, NULL);
713 }
714 *string_table_return = string_table;
715 *count_return = elements;
716 _XmAppUnlock(app);
717 return(Success);
718 }
719
720