/* * Motif * * Copyright (c) 1987-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these librararies and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA * */ /* * HISTORY */ #ifdef HAVE_CONFIG_H #include #endif #ifdef REV_INFO #ifndef lint static char rcsid[] = "$XConsortium: XmStringSeg.c /main/7 1995/09/19 23:13:59 cde-sun $" #endif #endif #include #include "XmI.h" #include "XmStringI.h" #include "XmRenderTI.h" /* * _XmStringGetSegment: A generalized version of XmStringGetNextSegment. * Returns char_count, and allows explicit control over peeking * and copying of data. Interleaving of calls to _XmStringGetSegment() * and XmeStringGetComponent() is supported. */ Boolean _XmStringGetSegment(_XmStringContext context, Boolean update_context, Boolean copy_data, XtPointer *text, XmStringTag *tag, XmTextType *type, XmStringTag **rendition_tags, unsigned int *tag_count, XmStringDirection *direction, Boolean *separator, unsigned char *tabs, short *char_count, XmDirection *push_before, Boolean *pop_after) { XmStringTag* perm_rends = NULL; _XmStringContextRec local_context_data; _XmStringContext local_context = context; Boolean result = FALSE; Boolean done; Boolean new_renditions; XmStringComponentType ctype; unsigned int len; XtPointer val; /* Initialize the out parameters */ if (text) *text = NULL; if (tag) *tag = NULL; if (type) *type = XmCHARSET_TEXT; if (rendition_tags) *rendition_tags = NULL; if (tag_count) *tag_count = 0; if (direction) *direction = _XmStrContDir(context); /* for BC */ if (separator) *separator = False; if (tabs) *tabs = 0; if (char_count) *char_count = 0; if (push_before) *push_before = 0; if (pop_after) *pop_after = False; /* No NULL pointers allowed. */ if (! (context && text && tag && type && rendition_tags && tag_count && direction && separator && tabs && char_count && push_before && pop_after)) return False; if (_XmStrContError(context)) return False; /* Setup a writable context. */ if (!update_context) { local_context = &local_context_data; _XmStringContextCopy(local_context, context); } /* N.B.: This code relies on the order of components from XmeStringGetComponent()! */ done = new_renditions = FALSE; while (!done) { /* Peek at components before consuming them. */ ctype = XmeStringGetComponent(local_context, FALSE, FALSE, &len, &val); switch (ctype) { case XmSTRING_COMPONENT_LAYOUT_PUSH: if (*tabs || *text) done = TRUE; else *push_before = *((XmDirection *) val); break; case XmSTRING_COMPONENT_RENDITION_BEGIN: if (*text) done = TRUE; else if (*tabs) new_renditions = TRUE; break; case XmSTRING_COMPONENT_CHARSET: case XmSTRING_COMPONENT_LOCALE: if (*text) done = TRUE; else *tag = (XmStringTag) val; break; case XmSTRING_COMPONENT_TAB: if (*text) done = TRUE; else { /* Save the renditions now. */ if ((*tag_count == 0) && _XmStrContRendCount(local_context)) { *tag_count = _XmStrContRendCount(local_context); if (copy_data) { int tmp; *rendition_tags = (XmStringTag *) XtMalloc(sizeof(XmStringTag) * *tag_count); for (tmp = 0; tmp < *tag_count; tmp++) (*rendition_tags)[tmp] = XtNewString(_XmStrContRendTags(local_context)[tmp]); } else { perm_rends = (XmStringTag *) XtMalloc(sizeof(XmStringTag) * *tag_count); memcpy((char*) perm_rends, _XmStrContRendTags(local_context), sizeof(XmStringTag) * *tag_count); *rendition_tags = perm_rends; } } /* Return at the end of this line. */ (*tabs)++; result = TRUE; } break; case XmSTRING_COMPONENT_DIRECTION: if (*text) done = TRUE; else *direction = *((XmStringDirection *) val); break; case XmSTRING_COMPONENT_TEXT: case XmSTRING_COMPONENT_LOCALE_TEXT: case XmSTRING_COMPONENT_WIDECHAR_TEXT: if (*text) done = TRUE; else if (*tabs && new_renditions) { /* Tabs had a different set of renditions than the text, */ /* so we can't return both tabs and text at once. */ done = TRUE; } else { *char_count = len; *text = val; if (ctype == XmSTRING_COMPONENT_TEXT) *type = XmCHARSET_TEXT; else if (ctype == XmSTRING_COMPONENT_LOCALE_TEXT) *type = XmMULTIBYTE_TEXT; else if (ctype == XmSTRING_COMPONENT_WIDECHAR_TEXT) *type = XmWIDECHAR_TEXT; else { assert(FALSE); } /* Force a tag for backward compatibility with Motif 1.2 */ if (! *tag) *tag = _XmStrContTag(local_context); result = TRUE; /* Save the renditions now. */ if ((*tag_count == 0) && _XmStrContRendCount(local_context)) { *tag_count = _XmStrContRendCount(local_context); if (copy_data) { int tmp; *rendition_tags = (XmStringTag*) XtMalloc(sizeof(XmStringTag) * *tag_count); for (tmp = 0; tmp < *tag_count; tmp++) (*rendition_tags)[tmp] = XtNewString(_XmStrContRendTags(local_context)[tmp]); } else { perm_rends = (XmStringTag *) XtMalloc(sizeof(XmStringTag) * *tag_count); memcpy((char*) perm_rends, _XmStrContRendTags(local_context), sizeof(XmStringTag) * *tag_count); *rendition_tags = perm_rends; } } } break; case XmSTRING_COMPONENT_RENDITION_END: break; case XmSTRING_COMPONENT_LAYOUT_POP: if (*tabs || *text) { /* We're almost done, so record this pop. */ *pop_after = TRUE; } else { /* We're ignoring this pop, so discard any recorded push. */ *push_before = 0; } break; case XmSTRING_COMPONENT_SEPARATOR: if (*tabs || *text) { *separator = TRUE; done = TRUE; } break; case XmSTRING_COMPONENT_END: default: done = TRUE; break; } /* Consume the component if we aren't done. */ if (!done) (void) XmeStringGetComponent(local_context, TRUE, FALSE, &len, &val); } if (copy_data && result) { /* Copy the tag. */ if (*tag) *tag = XtNewString(*tag); /* Copy the text. */ if (*text) { char *tmp = XtMalloc(*char_count + sizeof(wchar_t)); memcpy(tmp, *text, *char_count); bzero(tmp + *char_count, sizeof(wchar_t)); *text = (XtPointer) tmp; } } /* Free the local context. */ if (local_context == &local_context_data) _XmStringContextFree(local_context); return result; } Boolean _XmStringGetNextSegment( _XmStringContext context, XmStringTag *tag, XmStringDirection *direction, char **text, short *char_count, Boolean *separator ) { Boolean result; XmTextType type; XmStringTag * rendition_tags; unsigned int tag_count; unsigned char tabs; XmDirection push_before; Boolean pop_after; /* Get all the fields and discard the ones we don't want. */ result = _XmStringGetSegment(context, True, True, (XtPointer*) text, tag, &type, &rendition_tags, &tag_count, direction, separator, &tabs, char_count, &push_before, &pop_after); if (result) { if (rendition_tags) { while (tag_count-- > 0) XtFree((char*) rendition_tags[tag_count]); XtFree((char*) rendition_tags); } if (type == XmWIDECHAR_TEXT && *text) { /* must convert (this should be done in segment's locale instead) */ int len; wchar_t *wtext = (wchar_t *)(*text); /* should be enough */ len = ((*char_count)*MB_CUR_MAX)/sizeof(wchar_t); *text = (char *)XtMalloc(len+1); *char_count = wcstombs(*text, wtext, len); if ((*char_count) == (size_t)-1) { result = False; XtFree(*text); *text = NULL; XtFree((char *)*tag); *tag = NULL; } else (*text)[*char_count] = '\0'; XtFree((char *)wtext); } } return result; } /* * fetch the next 'segment' of the external TCS */ Boolean XmStringGetNextSegment(XmStringContext context, char **text, XmStringTag *tag, XmStringDirection *direction, Boolean *separator ) { short char_count; Boolean ret_val; _XmProcessLock(); ret_val = _XmStringGetNextSegment((_XmStringContext)context, tag, direction, text, &char_count, separator); _XmProcessUnlock(); return ret_val; }