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