2
* @OPENGROUP_COPYRIGHT@
4
* Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc.
5
* Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group
6
* ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for
7
* the full copyright text.
9
* This software is subject to an open license. It may only be
10
* used on, with or for operating systems which are themselves open
11
* source systems. You must contact The Open Group for a license
12
* allowing distribution and sublicensing of this software on, with,
13
* or for operating systems which are not Open Source programs.
15
* See http://www.opengroup.org/openmotif/license for full
16
* details of the license agreement. Any use, reproduction, or
17
* distribution of the program constitutes recipient's acceptance of
20
* EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
21
* PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
22
* KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
23
* WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
24
* OR FITNESS FOR A PARTICULAR PURPOSE
26
* EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
27
* NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT,
28
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29
* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED
30
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32
* ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
33
* EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
34
* POSSIBILITY OF SUCH DAMAGES.
47
static char rcsid[] = "$TOG: XmStringFunc.c /main/9 1999/10/14 11:20:50 mgreess $"
54
#include "XmStringI.h"
55
#include "XmRenderTI.h"
56
#include "XmTabListI.h"
58
/******** Static Function Declarations ********/
60
static void new_line(_XmString string) ;
62
/******** End Static Function Declarations ********/
66
XmStringPeekNextTriple(XmStringContext context)
71
return XmeStringGetComponent((_XmStringContext) context, False, False, &len, &val);
79
_XmStringContextRec stack_context;
86
_XmStringEntry line, *entry, seg;
87
XmStringComponentType type;
92
if ((string == NULL) || (substring == NULL) || (XmStringEmpty(substring))) {
98
* The substring must be a one line/one segment string.
101
if (_XmStrEntryCountGet(substring) != 1) {
106
if (((entry = _XmStrEntryGet(substring)) != NULL) &&
107
_XmEntrySegmentCountGet(entry[0]) > 1) {
113
* Get the text out of the substring.
116
if (_XmStrOptimized(substring))
118
subchar_count = (short)_XmStrByteCount(substring);
119
subtext = (char *)_XmStrText(substring);
121
else if (_XmStrMultiple(substring))
125
if (_XmEntryMultiple(line))
127
seg = (_XmStringEntry)_XmEntrySegmentGet(line)[0];
129
subchar_count = (short)_XmEntryByteCountGet(seg);
130
subtext = (char*) _XmEntryTextGet(seg);
134
subchar_count = (short)_XmEntryByteCountGet(line);
135
subtext = (char*) _XmEntryTextGet(line);
138
else { /* Oops, some weird string! */
144
if ((subchar_count == 0) || (subtext == NULL)) {
149
/** Find a text component that matches. **/
151
_XmStringContextReInit(&stack_context, string);
152
while ((type = XmeStringGetComponent(&stack_context, TRUE, FALSE,
154
XmSTRING_COMPONENT_END)
158
case XmSTRING_COMPONENT_TEXT:
159
case XmSTRING_COMPONENT_LOCALE_TEXT:
160
case XmSTRING_COMPONENT_WIDECHAR_TEXT:
165
if (char_count >= subchar_count) {
166
max = char_count - subchar_count;
167
for (i = 0; i <= max; i++) {
170
for (j = 0; j < subchar_count; j++) {
171
if (text[i+j] != subtext[j]) {
177
_XmStringContextFree(&stack_context);
188
_XmStringContextFree(&stack_context);
195
XmStringTableParseStringArray(XtPointer *strings,
200
Cardinal parse_count,
207
if ((strings == NULL) || (count == 0)) {
212
strs = (XmStringTable)XtMalloc(count * sizeof(XmString));
214
for (i = 0; i < count; i++)
216
strs[i] = XmStringParseText(strings[i], NULL, tag, type,
217
parse, parse_count, call_data);
225
XmStringTableUnparse(XmStringTable table,
229
XmTextType output_type,
231
Cardinal parse_count,
232
XmParseModel parse_model)
238
if ((table == NULL) || (count == 0)) {
243
strs = (XtPointer *)XtMalloc(count * sizeof(XtPointer));
245
for (i = 0; i < count; i++)
246
strs[i] = XmStringUnparse(table[i], tag, tag_type, output_type,
247
parse, parse_count, parse_model);
253
XmStringTableToXmString(XmStringTable table,
257
/* Note: this is a very expensive way to do this. Fix for Beta */
259
XmString str = NULL, tmp1, tmp2;
264
for (i = 0; i < count; i++)
266
tmp2 = XmStringConcatAndFree(tmp1, XmStringCopy(table[i]));
267
str = XmStringConcatAndFree(tmp2, XmStringCopy(break_comp));
277
XmStringPutRendition(XmString string,
278
XmStringTag rendition)
280
/* Quick and dirty. Fix for beta! */
281
XmString str, tmp1, tmp2;
283
tmp1 = XmStringComponentCreate(XmSTRING_COMPONENT_RENDITION_BEGIN,
284
strlen(rendition), (XtPointer)rendition);
285
tmp2 = XmStringConcatAndFree(tmp1, XmStringCopy(string));
287
tmp1 = XmStringComponentCreate(XmSTRING_COMPONENT_RENDITION_END,
288
strlen(rendition), (XtPointer)rendition);
289
str = XmStringConcatAndFree(tmp2, tmp1);
295
XmParseMappingGetValues(XmParseMapping mapping,
300
register String arg_name;
303
/* Do a little error checking. */
304
if (mapping == NULL) {
309
/* Modify the specified values. */
310
for (i = 0; i < arg_count; i++)
312
arg_name = arg_list[i].name;
314
if ((arg_name == XmNpattern) ||
315
(strcmp(arg_name, XmNpattern) == 0))
316
*((XtPointer*)arg_list[i].value) = mapping->pattern;
317
else if ((arg_name == XmNpatternType) ||
318
(strcmp(arg_name, XmNpatternType) == 0))
319
*((XmTextType*)arg_list[i].value) = mapping->pattern_type;
320
else if ((arg_name == XmNsubstitute) ||
321
(strcmp(arg_name, XmNsubstitute) == 0))
322
*((XmString*)arg_list[i].value) = XmStringCopy(mapping->substitute);
323
else if ((arg_name == XmNinvokeParseProc) ||
324
(strcmp(arg_name, XmNinvokeParseProc) == 0))
325
*((XmParseProc*)arg_list[i].value) = mapping->parse_proc;
326
else if ((arg_name == XmNclientData) ||
327
(strcmp(arg_name, XmNclientData) == 0))
328
*((XtPointer*)arg_list[i].value) = mapping->client_data;
329
else if ((arg_name == XmNincludeStatus) ||
330
(strcmp(arg_name, XmNincludeStatus) == 0))
331
*((XmIncludeStatus*)arg_list[i].value) = mapping->include_status;
337
XmParseMappingFree(XmParseMapping mapping)
342
/* Free copied data. */
343
XmStringFree(mapping->substitute);
345
/* Free the record. */
346
XtFree((char*) mapping);
352
XmParseTableFree(XmParseTable parse_table,
353
Cardinal parse_count)
355
/* Free each entry in the table. */
359
for (i = 0; i < parse_count; i++)
360
XmParseMappingFree(parse_table[i]);
362
/* Free the table itself. */
363
XtFree((char*) parse_table);
368
* XmeGetNextCharacter: An XmParseProc to consume the triggering
369
* character and insert the following character.
373
XmeGetNextCharacter(XtPointer *in_out,
377
XmParseMapping entry, /* unused */
379
XmString *str_include,
380
XtPointer call_data) /* unused */
382
char* ptr = (char*) *in_out;
384
XmStringComponentType comp_type;
385
assert(in_out != NULL);
388
/* Initialize the out parameters */
391
/* Consume the triggering characters. */
392
ptr += pattern_length;
394
/* Select the component type. */
398
if ((tag != NULL) && (strcmp(XmFONTLIST_DEFAULT_TAG, tag) == 0))
399
comp_type = XmSTRING_COMPONENT_LOCALE_TEXT;
401
comp_type = XmSTRING_COMPONENT_TEXT;
402
if ((text_end == NULL) || (ptr < (char*) text_end))
404
len = mblen(ptr, MB_CUR_MAX);
410
case XmMULTIBYTE_TEXT:
411
/* In Motif 2.0 dynamic switching of locales isn't supported. */
412
comp_type = XmSTRING_COMPONENT_LOCALE_TEXT;
413
if ((text_end == NULL) || (ptr < (char*) text_end))
415
len = mblen(ptr, MB_CUR_MAX);
421
case XmWIDECHAR_TEXT:
422
comp_type = XmSTRING_COMPONENT_WIDECHAR_TEXT;
423
if ((text_end == NULL) || (ptr < (char*) text_end))
424
len = sizeof(wchar_t);
428
comp_type = XmSTRING_COMPONENT_UNKNOWN;
432
/* Quit if mblen() failed or if type was unrecognized. */
433
if ((len <= 0) || (comp_type == XmSTRING_COMPONENT_UNKNOWN))
435
*in_out = (XtPointer) ptr;
440
/* Create a component containing the next character. */
441
*str_include = XmStringComponentCreate(comp_type, len, ptr);
443
*in_out = (XtPointer) ptr;
453
int lc = _XmStrEntryCount(string);
456
_XmStrImplicitLine(string) = TRUE;
458
_XmStrEntry(string) = (_XmStringEntry *)
459
XtRealloc((char *) _XmStrEntry(string),
460
sizeof(_XmStringEntry) * (lc + 1));
462
_XmEntryCreate(line, XmSTRING_ENTRY_ARRAY);
463
_XmStrEntry(string)[lc] = line;
465
_XmEntrySegmentCount(line) = 0;
466
_XmEntrySegment(line) = NULL;
468
_XmStrEntryCount(string)++;
472
MakeStrFromSeg(XmStringContext start)
474
_XmStringEntry *line;
475
_XmStringEntry *segs, seg;
478
if (_XmStrContOpt(start)) {
479
_XmStrContError(start) = TRUE;
480
return(XmStringCopy(_XmStrContString(start)));
483
line = _XmStrEntry(_XmStrContString(start));
485
/* Create XmString structure */
486
_XmStrCreate(str, XmSTRING_MULTIPLE_ENTRY, 0);
488
if (_XmEntryMultiple(line[_XmStrContCurrLine(start)])) {
489
segs = (_XmStringEntry*)_XmEntrySegment(line[_XmStrContCurrLine(start)]);
493
if (_XmStrContCurrSeg(start) < _XmEntrySegmentCount(line)) {
494
seg = segs[_XmStrContCurrSeg(start)];
496
_XmStringSegmentNew(str, 0, seg, True);
498
_XmStrContCurrSeg(start)++;
500
_XmStrContDir(start) = _XmEntryDirectionGet(seg);
501
_XmStrContTag(start) = _XmEntryTag(seg);
502
_XmStrContTagType(start) = (XmTextType) _XmEntryTextTypeGet(seg);
505
_XmStrContCurrSeg(start) = 0;
506
_XmStrContCurrLine(start)++;
509
seg = line[_XmStrContCurrLine(start)];
510
_XmStringSegmentNew(str, 0, seg, True);
512
_XmStrContCurrSeg(start) = 0;
513
_XmStrContCurrLine(start)++;
515
_XmStrContDir(start) = _XmEntryDirectionGet(seg);
516
_XmStrContTag(start) = _XmEntryTag(seg);
517
_XmStrContTagType(start) = (XmTextType) _XmEntryTextTypeGet(seg);
519
_XmStrContState(start) = PUSH_STATE;
525
LastSeg(XmStringContext start)
527
_XmStringEntry *line;
529
if (_XmStrContOpt(start))
533
line = _XmStrEntry(_XmStrContString(start));
535
if (_XmEntryMultiple(line[_XmStrContCurrLine(start)]))
536
return(_XmStrContCurrSeg(start) == _XmEntrySegmentCount(line));
542
ContextsMatch(XmStringContext a,
545
if ((_XmStrContCurrLine(a) == _XmStrContCurrLine(b)) &&
546
(_XmStrContCurrSeg(a) == _XmStrContCurrSeg(b)) &&
547
(_XmStrContState(a) == _XmStrContState(b)))
549
if (((_XmStrContState(a) == BEGIN_REND_STATE) ||
550
(_XmStrContState(a) == END_REND_STATE)))
552
if (_XmStrContRendIndex(a) == _XmStrContRendIndex(b))
562
MakeStr(XmStringContext start,
565
/* This is quick and dirty, need to be smarter about it before Beta. */
566
XmStringComponentType type;
572
/* Next component over start until at segment break */
575
while (_XmStrContState(start) != PUSH_STATE)
577
type = XmeStringGetComponent(start, TRUE, FALSE, &len, &val);
579
if (ContextsMatch(start, end)) return(str);
581
str = XmStringConcatAndFree(str,
582
XmStringComponentCreate(type, len, val));
585
/* Next segment over start incrementing until one segment before context */
586
while ((_XmStrContCurrLine(start) < (_XmStrContCurrLine(end) - 1)) ||
587
((_XmStrContCurrLine(start) == _XmStrContCurrLine(end)) &&
588
(_XmStrContCurrSeg(start) < _XmStrContCurrSeg(end))) ||
591
str = XmStringConcatAndFree(str, MakeStrFromSeg(start));
594
/* Next component over start until it matches context */
595
type = XmeStringGetComponent(start, TRUE, FALSE, &len, &val);
596
while (!ContextsMatch(start, end))
598
str = XmStringConcatAndFree(str, XmStringComponentCreate(type, len, val));
599
type = XmeStringGetComponent(start, TRUE, FALSE, &len, &val);
606
XmStringToXmStringTable(XmString string,
607
XmString break_component,
608
XmStringTable *table)
610
/* Note: this is a very expensive way to do this. Fix for Beta */
611
_XmStringContextRec stack_context, stack_start;
612
XmStringComponentType type, b_type;
613
unsigned int len, b_len;
614
XtPointer val, b_val;
618
/* Get triple for first component of break_component */
621
_XmStringContextReInit(&stack_context, break_component);
622
b_type = XmeStringGetComponent(&stack_context, TRUE, FALSE,
624
_XmStringContextFree(&stack_context);
627
/* Nothing to match against. Return complete string. */
631
*table = (XmStringTable)XtMalloc(sizeof(XmString));
632
*table[0] = XmStringCopy(string);
641
if (table != NULL) *table = NULL;
645
_XmStringContextReInit(&stack_context, string);
647
/* Count number of entries for table */
649
while ((type = XmeStringGetComponent(&stack_context, TRUE, FALSE,
651
XmSTRING_COMPONENT_END)
653
if ((type == b_type) && (len == b_len) &&
654
(memcmp(val, b_val, len) == 0))
658
/* Allocate table and insert new strings */
661
*table = (XmStringTable)XtMalloc(count * sizeof(XmString));
663
_XmStringContextReInit(&stack_context, string);
664
_XmStringContextReInit(&stack_start, string);
668
while ((type = XmeStringGetComponent(&stack_context, TRUE, FALSE,
670
XmSTRING_COMPONENT_END)
672
if ((type == b_type) && (len == b_len) &&
673
(memcmp(val, b_val, len) == 0))
675
/* make XmString from start to end */
676
(*table)[i] = MakeStr(&stack_start, &stack_context);
681
_XmStringContextFree(&stack_start);
683
_XmStringContextFree(&stack_context);
692
XmStringTableProposeTablist(XmStringTable strings,
693
Cardinal num_strings,
696
XmOffsetModel offset_model)
699
_XmStringContextRec stack_ctx;
701
XmTab tab, prev, start;
706
_XmRenditionRec scratch;
710
NextTabResult ret_val;
713
if ((strings == NULL) || (num_strings == 0)) {
715
return ((XmTabList)NULL);
718
bzero((char*) &scratch, sizeof(_XmRenditionRec));
722
_XmRendDisplay(rend) = XtDisplayOfObject(widget);
725
XtSetArg(args[n], XmNrenderTable, &rt); n++;
726
XtGetValues(widget, args, n);
728
/* Work around weird bug with XtGetValues. */
730
XtSetArg(args[n], XmNunitType, &units); n++;
731
XtGetValues(widget, args, n);
733
if (rt == NULL) rt = XmeGetDefaultRenderTable(widget, XmTEXT_FONTLIST);
735
tab = XmTabCreate(0.0, units, offset_model, XmALIGNMENT_BEGINNING, ".");
737
tl = XmTabListInsertTabs(NULL, &tab, 1, 0);
741
for (i = 0; i < num_strings; i++)
748
return((XmTabList)NULL);
750
_XmStringContextReInit(&stack_ctx, strings[i]);
752
tab = _XmTabLStart(tl);
755
/* Scan str for tabs, update tl if necessary. */
758
while ((ret_val = _XmStringGetNextTabWidth(&stack_ctx, widget, units,
759
rt, &width, &rend)) !=
762
if (ret_val == XmTAB_NEWLINE)
764
tab = _XmTabLStart(tl);
769
val = width + pad_value;
771
if (j >= _XmTabLCount(tl))
772
/* Need to add a tab */
774
tab = XmTabCreate(0.0, units, offset_model,
775
XmALIGNMENT_BEGINNING, ".");
776
start = _XmTabLStart(tl);
777
prev = _XmTabPrev(start);
779
_XmTabNext(prev) = tab;
780
_XmTabPrev(tab) = prev;
781
_XmTabNext(tab) = start;
782
_XmTabPrev(start) = tab;
787
tab = _XmTabNext(tab);
790
if (val > _XmTabValue(tab)) XmTabSetValue(tab, val);
791
else val = _XmTabValue(tab);
795
_XmStringContextFree(&stack_ctx);
798
if (offset_model == XmABSOLUTE)
800
start = _XmTabLStart(tl);
801
val = _XmTabValue(start);
803
for (tab = _XmTabNext(start); tab != start; tab = _XmTabNext(tab))
805
val += _XmTabValue(tab);
806
XmTabSetValue(tab, val);
815
* Helper function for XmTabList.c
816
* This routine performs successive reads on an XmStringContext
817
* and returns the width (in units of XmNunitType of widget) of
818
* the text segments between the previous and next tab or end of line.
819
* It uses the XmNrenderTable from widget to calculate the width. It
820
* returns XmTAB_EOS if the end of the string has been reached, XmTAB_NEWLINE
821
* if the end of line is reached and XmTAB_NEXT if a tab is encountered.
824
_XmStringGetNextTabWidth(XmStringContext ctx,
832
int toType; /* passed to XmConvertUnits */
833
Dimension w_sum, w_cur;
835
if (_XmStrContError(ctx))
844
/* Big units need to be converted to small ones. */
845
toType = _XmConvertFactor(units, &divisor);
847
/* Calculate the width to the next tab. */
848
if (_XmStrContOpt(ctx))
850
_XmStrContError(ctx) = True;
855
_XmString str = _XmStrContString(ctx);
860
_XmStringArraySegRec array_seg;
862
line_count = _XmStrLineCountGet(str);
864
/* Keep checking lines and segments until we run out or hit a tab. */
865
if (_XmStrContCurrLine(ctx) < line_count)
867
if (_XmStrImplicitLine(str))
869
line = _XmStrEntry(str)[_XmStrContCurrLine(ctx)];
873
_XmEntryType(&array_seg) = XmSTRING_ENTRY_ARRAY;
874
_XmEntrySegmentCount(&array_seg) = _XmStrEntryCount(str);
875
_XmEntrySegment(&array_seg) = (_XmStringNREntry *)_XmStrEntry(str);
876
line = (_XmStringEntry)&array_seg;
879
if (_XmEntryMultiple(line))
880
seg_count = _XmEntrySegmentCount(line);
884
if (seg_count == 0) {
886
_XmStrContCurrLine(ctx)++;
888
return(XmTAB_NEWLINE);
891
while (_XmStrContCurrSeg(ctx) < seg_count)
893
if (_XmEntryMultiple(line))
894
seg = (_XmStringEntry)_XmEntrySegment(line)[_XmStrContCurrSeg(ctx)];
900
if (_XmStrContTabCount(ctx) < _XmEntryTabsGet(seg)) {
901
_XmStrContTabCount(ctx)++;
902
*width = (XmConvertUnits(widget, XmHORIZONTAL,
903
XmPIXELS, w_sum, toType) / divisor);
907
(void)_XmStringSegmentExtents(seg, rt, rend, NULL,
908
&w_cur, NULL, NULL, NULL);
911
_XmStrContCurrSeg(ctx)++;
912
_XmStrContTabCount(ctx) = 0;
915
_XmStrContCurrLine(ctx)++;
916
_XmStrContCurrSeg(ctx) = 0;
917
_XmStrContTabCount(ctx) = 0;
919
return(XmTAB_NEWLINE);
922
_XmStrContError(ctx) = True;