/*
* 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 <config.h>
#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 <Xm/XmosP.h>
#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;
}