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  */
24 /*
25  * HISTORY
26  */
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30 
31 
32 #ifdef REV_INFO
33 #ifndef lint
34 static char rcsid[] = "$XConsortium: XmStringSeg.c /main/7 1995/09/19 23:13:59 cde-sun $"
35 #endif
36 #endif
37 
38 #include <Xm/XmosP.h>
39 
40 #include "XmI.h"
41 #include "XmStringI.h"
42 #include "XmRenderTI.h"
43 
44 
45 /*
46  * _XmStringGetSegment: A generalized version of XmStringGetNextSegment.
47  *	Returns char_count, and allows explicit control over peeking
48  *	and copying of data.  Interleaving of calls to _XmStringGetSegment()
49  *	and XmeStringGetComponent() is supported.
50  */
51 Boolean
52 _XmStringGetSegment(_XmStringContext   context,
53 		    Boolean	       update_context,
54 		    Boolean	       copy_data,
55 		    XtPointer         *text,
56 		    XmStringTag       *tag,
57 		    XmTextType        *type,
58 		    XmStringTag      **rendition_tags,
59 		    unsigned int      *tag_count,
60 		    XmStringDirection *direction,
61 		    Boolean           *separator,
62 		    unsigned char     *tabs,
63 		    short             *char_count,
64 		    XmDirection       *push_before,
65 		    Boolean	      *pop_after)
66 {
67   XmStringTag*   	perm_rends = NULL;
68   _XmStringContextRec	local_context_data;
69   _XmStringContext	local_context = context;
70   Boolean		result = FALSE;
71   Boolean 		done;
72   Boolean		new_renditions;
73   XmStringComponentType ctype;
74   unsigned int 		len;
75   XtPointer 		val;
76 
77   /* Initialize the out parameters */
78   if (text)           *text           = NULL;
79   if (tag)            *tag            = NULL;
80   if (type)           *type           = XmCHARSET_TEXT;
81   if (rendition_tags) *rendition_tags = NULL;
82   if (tag_count)      *tag_count      = 0;
83   if (direction)      *direction      = _XmStrContDir(context);	/* for BC */
84   if (separator)      *separator      = False;
85   if (tabs)           *tabs           = 0;
86   if (char_count)     *char_count     = 0;
87   if (push_before)    *push_before    = 0;
88   if (pop_after)      *pop_after      = False;
89 
90   /* No NULL pointers allowed. */
91   if (! (context && text && tag && type && rendition_tags && tag_count
92 	 && direction && separator && tabs && char_count && push_before
93 	 && pop_after))
94     return False;
95 
96   if (_XmStrContError(context))
97     return False;
98 
99   /* Setup a writable context. */
100   if (!update_context)
101     {
102       local_context = &local_context_data;
103       _XmStringContextCopy(local_context, context);
104     }
105 
106   /* N.B.: This code relies on the order of components from XmeStringGetComponent()! */
107   done = new_renditions = FALSE;
108   while (!done)
109     {
110       /* Peek at components before consuming them. */
111       ctype = XmeStringGetComponent(local_context, FALSE, FALSE, &len, &val);
112       switch (ctype)
113 	{
114 	case XmSTRING_COMPONENT_LAYOUT_PUSH:
115 	  if (*tabs || *text)
116 	    done = TRUE;
117 	  else
118 	    *push_before = *((XmDirection *) val);
119 	  break;
120 
121 	case XmSTRING_COMPONENT_RENDITION_BEGIN:
122 	  if (*text)
123 	    done = TRUE;
124 	  else if (*tabs)
125 	    new_renditions = TRUE;
126 	  break;
127 
128 	case XmSTRING_COMPONENT_CHARSET:
129 	case XmSTRING_COMPONENT_LOCALE:
130 	  if (*text)
131 	    done = TRUE;
132 	  else
133 	    *tag = (XmStringTag) val;
134 	  break;
135 
136 	case XmSTRING_COMPONENT_TAB:
137 	  if (*text)
138 	    done = TRUE;
139 	  else
140 	    {
141 	      /* Save the renditions now. */
142 	      if ((*tag_count == 0) && _XmStrContRendCount(local_context))
143 		{
144 		  *tag_count = _XmStrContRendCount(local_context);
145 		  if (copy_data)
146 		    {
147 		      int tmp;
148 		      *rendition_tags = (XmStringTag *)
149 			XtMalloc(sizeof(XmStringTag) * *tag_count);
150 		      for (tmp = 0; tmp < *tag_count; tmp++)
151 			(*rendition_tags)[tmp] =
152 			  XtNewString(_XmStrContRendTags(local_context)[tmp]);
153 		    }
154 		  else
155 		    {
156 		      perm_rends = (XmStringTag *)
157 			XtMalloc(sizeof(XmStringTag) * *tag_count);
158 		      memcpy((char*) perm_rends,
159 			     _XmStrContRendTags(local_context),
160 			     sizeof(XmStringTag) * *tag_count);
161 		      *rendition_tags = perm_rends;
162 		    }
163 		}
164 
165 	      /* Return at the end of this line. */
166 	      (*tabs)++;
167 	      result = TRUE;
168 	    }
169 	  break;
170 
171 	case XmSTRING_COMPONENT_DIRECTION:
172 	  if (*text)
173 	    done = TRUE;
174 	  else
175 	    *direction = *((XmStringDirection *) val);
176 	  break;
177 
178 	case XmSTRING_COMPONENT_TEXT:
179 	case XmSTRING_COMPONENT_LOCALE_TEXT:
180 	case XmSTRING_COMPONENT_WIDECHAR_TEXT:
181 	  if (*text)
182 	    done = TRUE;
183 	  else if (*tabs && new_renditions)
184 	    {
185 	      /* Tabs had a different set of renditions than the text, */
186 	      /* so we can't return both tabs and text at once. */
187 	      done = TRUE;
188 	    }
189 	  else
190 	    {
191 	      *char_count = len;
192 	      *text = val;
193 
194 	      if (ctype == XmSTRING_COMPONENT_TEXT)
195 		*type = XmCHARSET_TEXT;
196 	      else if (ctype == XmSTRING_COMPONENT_LOCALE_TEXT)
197 		*type = XmMULTIBYTE_TEXT;
198 	      else if (ctype == XmSTRING_COMPONENT_WIDECHAR_TEXT)
199 		*type = XmWIDECHAR_TEXT;
200 	      else
201 		{ assert(FALSE); }
202 
203 	      /* Force a tag for backward compatibility with Motif 1.2 */
204 	      if (! *tag)
205 		*tag = _XmStrContTag(local_context);
206 
207 	      result = TRUE;
208 
209 	      /* Save the renditions now. */
210 	      if ((*tag_count == 0) && _XmStrContRendCount(local_context))
211 		{
212 		  *tag_count = _XmStrContRendCount(local_context);
213 		  if (copy_data)
214 		    {
215 		      int tmp;
216 		      *rendition_tags = (XmStringTag*)
217 			XtMalloc(sizeof(XmStringTag) * *tag_count);
218 		      for (tmp = 0; tmp < *tag_count; tmp++)
219 			(*rendition_tags)[tmp] =
220 			  XtNewString(_XmStrContRendTags(local_context)[tmp]);
221 		    }
222 		  else
223 		    {
224 		      perm_rends = (XmStringTag *)
225 			XtMalloc(sizeof(XmStringTag) * *tag_count);
226 		      memcpy((char*) perm_rends,
227 			     _XmStrContRendTags(local_context),
228 			     sizeof(XmStringTag) * *tag_count);
229 		      *rendition_tags = perm_rends;
230 		    }
231 		}
232 	    }
233 	  break;
234 
235 	case XmSTRING_COMPONENT_RENDITION_END:
236 	  break;
237 
238 	case XmSTRING_COMPONENT_LAYOUT_POP:
239 	  if (*tabs || *text)
240 	    {
241 	      /* We're almost done, so record this pop. */
242 	      *pop_after = TRUE;
243 	    }
244 	  else
245 	    {
246 	      /* We're ignoring this pop, so discard any recorded push. */
247 	      *push_before = 0;
248 	    }
249 	  break;
250 
251 	case XmSTRING_COMPONENT_SEPARATOR:
252 	  if (*tabs || *text)
253 	    {
254 	      *separator = TRUE;
255 	      done = TRUE;
256 	    }
257 	  break;
258 
259 	case XmSTRING_COMPONENT_END:
260 	default:
261 	  done = TRUE;
262 	  break;
263 	}
264 
265       /* Consume the component if we aren't done. */
266       if (!done)
267 	(void) XmeStringGetComponent(local_context, TRUE, FALSE, &len, &val);
268     }
269 
270   if (copy_data && result)
271     {
272       /* Copy the tag. */
273       if (*tag)
274 	*tag = XtNewString(*tag);
275 
276       /* Copy the text. */
277       if (*text)
278 	{
279 	  char *tmp = XtMalloc(*char_count + sizeof(wchar_t));
280 	  memcpy(tmp, *text, *char_count);
281 	  bzero(tmp + *char_count, sizeof(wchar_t));
282 
283 	  *text = (XtPointer) tmp;
284 	}
285     }
286 
287   /* Free the local context. */
288   if (local_context == &local_context_data)
289     _XmStringContextFree(local_context);
290 
291   return result;
292 }
293 
294 Boolean
_XmStringGetNextSegment(_XmStringContext context,XmStringTag * tag,XmStringDirection * direction,char ** text,short * char_count,Boolean * separator)295 _XmStringGetNextSegment(
296         _XmStringContext context,
297         XmStringTag *tag,
298         XmStringDirection *direction,
299         char **text,
300         short *char_count,
301         Boolean *separator )
302 {
303   Boolean       result;
304   XmTextType    type;
305   XmStringTag * rendition_tags;
306   unsigned int  tag_count;
307   unsigned char tabs;
308   XmDirection   push_before;
309   Boolean	pop_after;
310 
311   /* Get all the fields and discard the ones we don't want. */
312   result = _XmStringGetSegment(context, True, True, (XtPointer*) text, tag,
313 		       &type, &rendition_tags, &tag_count, direction,
314 		       separator, &tabs, char_count, &push_before, &pop_after);
315   if (result) {
316     if (rendition_tags)
317       {
318 	while (tag_count-- > 0)
319 	  XtFree((char*) rendition_tags[tag_count]);
320 	XtFree((char*) rendition_tags);
321       }
322 
323     if (type == XmWIDECHAR_TEXT && *text) {
324       /* must convert (this should be done in segment's locale instead) */
325       int len;
326       wchar_t *wtext = (wchar_t *)(*text);
327 
328       /* should be enough */
329       len = ((*char_count)*MB_CUR_MAX)/sizeof(wchar_t);
330 
331       *text = (char *)XtMalloc(len+1);
332       *char_count = wcstombs(*text, wtext, len);
333       if ((*char_count) == (size_t)-1) {
334 	result = False;
335 	XtFree(*text); *text = NULL;
336 	XtFree((char *)*tag); *tag = NULL;
337       } else
338 	(*text)[*char_count] = '\0';
339       XtFree((char *)wtext);
340     }
341   }
342 
343   return result;
344 }
345 
346 /*
347  * fetch the next 'segment' of the external TCS
348  */
349 Boolean
XmStringGetNextSegment(XmStringContext context,char ** text,XmStringTag * tag,XmStringDirection * direction,Boolean * separator)350 XmStringGetNextSegment(XmStringContext context,
351 		       char **text,
352 		       XmStringTag *tag,
353 		       XmStringDirection *direction,
354 		       Boolean *separator )
355 {
356   short char_count;
357   Boolean ret_val;
358 
359   _XmProcessLock();
360   ret_val = _XmStringGetNextSegment((_XmStringContext)context,
361 		 tag, direction, text, &char_count, separator);
362   _XmProcessUnlock();
363   return ret_val;
364 }
365