--- src/Label.c.orig 2013-09-07 23:57:54.000000000 -0400 +++ src/Label.c 2014-10-10 18:58:25.661747784 -0400 @@ -89,6 +89,15 @@ static void SetTextWidthAndHeight(LabelWidget); /* + * Label text is stored as a char*, but in fact points to double-byte + * Unicode characters when encoding property is set to Char2b. In + * this case we cannot use normal string manipulation functions. + */ +static size_t XawLabelStringLength(LabelWidget, char*); +static char* XawLabelNewString(LabelWidget, char*); +static char* XawLabelCharIndex(LabelWidget, char*, char); + +/* * Initialization */ #define offset(field) XtOffsetOf(LabelRec, field) @@ -274,6 +283,110 @@ NULL, 0, XtCacheNone, NULL); } +#define IS_CHAR(p, c) ((p)->byte1 == 0 && (p)->byte2 == c) +#define IS_NOT_CHAR(p, c) !IS_CHAR(p, c) +#define IS_NUL(p) IS_CHAR(p, 0) +#define IS_NOT_NUL(p) !IS_NUL(p) + +#define AT_EOL(lw, lbl) \ + (lw->label.encoding == XawTextEncodingChar2b && \ + IS_NUL((XChar2b *) lbl) || \ + lw->label.encoding != XawTextEncodingChar2b && \ + (*lbl) == '\0') + +#define NOT_AT_EOL(lw, lbl) !AT_EOL(lw, lbl) + +#define MOVE_FORWARD(lw, lbl, nl) \ + do { \ + if (lw->label.encoding == XawTextEncodingChar2b) \ + lbl = (char*) (((XChar2b *) nl) + 1); \ + else \ + lbl = nl + 1; \ + } while (0); + +/* + * Allocates a new string. + */ +static char* +XawLabelNewString(LabelWidget lw, char* string) +{ + char *p; + + if (string == NULL) + return NULL; + + if (lw->label.encoding == XawTextEncodingChar2b) { + XChar2b *ptr; + size_t n; + + n = XawLabelStringLength(lw, string) + sizeof(XChar2b); + ptr = (XChar2b*) XtMalloc(n); + if (ptr == NULL) + return NULL; + + p = (char*) memmove(ptr, string, n); + } + else + p = XtNewString(string); + + return p; +} + +/* + * Returns a number of bytes in a string. + */ +static size_t +XawLabelStringLength(LabelWidget lw, char* string) +{ + size_t n = 0; + + if (string == NULL) + return 0; + + if (lw->label.encoding == XawTextEncodingChar2b) { + XChar2b *ptr = (XChar2b*) string; + + while (ptr != NULL && IS_NOT_NUL(ptr)) { + ptr++; + n += sizeof(XChar2b); + } + } + else + n = strlen(string); + + return n; +} + +/* + * Returns an index of the character in the string, or NULL if not + * found. + */ +static char* +XawLabelCharIndex(LabelWidget lw, char* string, char c) +{ + char *p; + + if (string == NULL) + return NULL; + + if (lw->label.encoding == XawTextEncodingChar2b) { + XChar2b *ptr = (XChar2b*) string; + + while (ptr != NULL && IS_NOT_NUL(ptr) && IS_NOT_CHAR(ptr, c)) { + ptr++; + } + + if (ptr == NULL || IS_NUL(ptr)) + return NULL; + + p = (char*) ptr; + } + else + p = index(string, c); + + return p; +} + /* * Calculate width and height of displayed text in pixels */ @@ -305,29 +418,30 @@ lw->label.label_len = 0; lw->label.label_width = 0; } - else if ((nl = index(lw->label.label, '\n')) != NULL) { + else if ((nl = XawLabelCharIndex(lw, lw->label.label, '\n')) != NULL) { char *label; lw->label.label_len = MULTI_LINE_LABEL; lw->label.label_width = 0; - for (label = lw->label.label; nl != NULL; nl = index(label, '\n')) { + for (label = lw->label.label; nl != NULL; + nl = XawLabelCharIndex(lw, label, '\n')) { int width = XmbTextEscapement(fset, label, (int)(nl - label)); if (width > (int)lw->label.label_width) lw->label.label_width = width; - label = nl + 1; - if (*label) + MOVE_FORWARD(lw, label, nl); + if (NOT_AT_EOL(lw, label)) lw->label.label_height += ext->max_ink_extent.height; } - if (*label) { - int width = XmbTextEscapement(fset, label, strlen(label)); + if (NOT_AT_EOL(lw, label)) { + int width = XmbTextEscapement(fset, label, XawLabelStringLength(lw, label)); if (width > (int)lw->label.label_width) lw->label.label_width = width; } } else { - lw->label.label_len = strlen(lw->label.label); + lw->label.label_len = XawLabelStringLength(lw, lw->label.label); lw->label.label_width = XmbTextEscapement(fset, lw->label.label, lw->label.label_len); } @@ -338,39 +452,42 @@ lw->label.label_len = 0; lw->label.label_width = 0; } - else if ((nl = index(lw->label.label, '\n')) != NULL) { + else if ((nl = XawLabelCharIndex(lw, lw->label.label, '\n')) != NULL) { char *label; lw->label.label_len = MULTI_LINE_LABEL; lw->label.label_width = 0; - for (label = lw->label.label; nl != NULL; nl = index(label, '\n')) { + for (label = lw->label.label; nl != NULL; + nl = XawLabelCharIndex(lw, label, '\n')) { int width; - if (lw->label.encoding) + if (lw->label.encoding == XawTextEncodingChar2b) width = XTextWidth16(fs, (XChar2b *)label, (int)(nl - label) / 2); else width = XTextWidth(fs, label, (int)(nl - label)); if (width > (int)lw->label.label_width) lw->label.label_width = width; - label = nl + 1; - if (*label) + MOVE_FORWARD(lw, label, nl); + if (NOT_AT_EOL(lw, label)) lw->label.label_height += fs->max_bounds.ascent + fs->max_bounds.descent; } - if (*label) { - int width = XTextWidth(fs, label, strlen(label)); + if (NOT_AT_EOL(lw, label)) { + int width; - if (lw->label.encoding) - width = XTextWidth16(fs, (XChar2b *)label, strlen(label) / 2); + if (lw->label.encoding == XawTextEncodingChar2b) + width = XTextWidth16(fs, (XChar2b *)label, + XawLabelStringLength(lw, label) / 2); else - width = XTextWidth(fs, label, strlen(label)); + width = XTextWidth(fs, label, + XawLabelStringLength(lw, label)); if (width > (int) lw->label.label_width) lw->label.label_width = width; } } else { - lw->label.label_len = strlen(lw->label.label); - if (lw->label.encoding) + lw->label.label_len = XawLabelStringLength(lw, lw->label.label); + if (lw->label.encoding == XawTextEncodingChar2b) lw->label.label_width = XTextWidth16(fs, (XChar2b *)lw->label.label, (int)lw->label.label_len / 2); @@ -478,7 +595,7 @@ if (lw->label.label == NULL) lw->label.label = XtNewString(lw->core.name); else - lw->label.label = XtNewString(lw->label.label); + lw->label.label = XawLabelNewString(lw, lw->label.label); GetNormalGC(lw); GetGrayGC(lw); @@ -535,14 +652,14 @@ if (len == MULTI_LINE_LABEL) { char *nl; - while ((nl = index(label, '\n')) != NULL) { + while ((nl = XawLabelCharIndex(w, label, '\n')) != NULL) { XmbDrawString(XtDisplay(w), XtWindow(w), w->label.fontset, gc, w->label.label_x, ksy, label, (int)(nl - label)); ksy += ext->max_ink_extent.height; - label = nl + 1; + MOVE_FORWARD(w, label, nl); } - len = strlen(label); + len = XawLabelStringLength(w, label); } if (len) XmbDrawString(XtDisplay(w), XtWindow(w), w->label.fontset, gc, @@ -552,8 +669,8 @@ if (len == MULTI_LINE_LABEL) { char *nl; - while ((nl = index(label, '\n')) != NULL) { - if (w->label.encoding) + while ((nl = XawLabelCharIndex(w, label, '\n')) != NULL) { + if (w->label.encoding == XawTextEncodingChar2b) XDrawString16(XtDisplay(gw), XtWindow(gw), gc, w->label.label_x, y, (XChar2b *)label, (int)(nl - label) / 2); @@ -562,12 +679,12 @@ w->label.label_x, y, label, (int)(nl - label)); y += w->label.font->max_bounds.ascent + w->label.font->max_bounds.descent; - label = nl + 1; + MOVE_FORWARD(w, label, nl); } - len = strlen(label); + len = XawLabelStringLength(w, label); } if (len) { - if (w->label.encoding) + if (w->label.encoding == XawTextEncodingChar2b) XDrawString16(XtDisplay(gw), XtWindow(gw), gc, w->label.label_x, y, (XChar2b *)label, len / 2); else @@ -678,7 +795,7 @@ XtFree((char *)curlw->label.label); if (newlw->label.label != newlw->core.name) - newlw->label.label = XtNewString(newlw->label.label); + newlw->label.label = XawLabelNewString(newlw, newlw->label.label); was_resized = True; }