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