/* * utils.c - multibyte-string helpers * Copyright (c) Clemens Ladisch * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #define _XOPEN_SOURCE #include "aconfig.h" #include #include #include #include #include "utils.h" /* * mbs_at_width - compute screen position in a string * * For displaying strings on the screen, we have to know how many character * cells are occupied. This function calculates the position in a multibyte * string that is at a desired position. * * Parameters: * s: the string * width: on input, the desired number of character cells; on output, the actual * position, in character cells, of the return value * dir: -1 or 1; in which direction to round if a multi-column character goes * over the desired width * * Return value: * Pointer to the place in the string that is as near the desired width as * possible. If the string is too short, the return value points to the * terminating zero. If the last character is a multi-column character that * goes over the desired width, the return value may be one character cell * earlier or later than desired, depending on the dir parameter. * In any case, the return value points after any zero-width characters that * follow the last character. */ const char *mbs_at_width(const char *s, int *width, int dir) { size_t len; wchar_t wc; int bytes; int width_so_far, w; if (*width <= 0) return s; mbtowc(NULL, NULL, 0); /* reset shift state */ len = strlen(s); width_so_far = 0; while (len && (bytes = mbtowc(&wc, s, len)) > 0) { w = wcwidth(wc); if (width_so_far + w > *width && dir < 0) break; if (w >= 0) width_so_far += w; s += bytes; len -= bytes; if (width_so_far >= *width) { while (len && (bytes = mbtowc(&wc, s, len)) > 0) { w = wcwidth(wc); if (w != 0) break; s += bytes; len -= bytes; } break; } } *width = width_so_far; return s; } /* * get_mbs_width - compute screen width of a string */ unsigned int get_mbs_width(const char *s) { int width; width = INT_MAX; mbs_at_width(s, &width, 1); return width; } /* * get_max_mbs_width - get width of longest string in an array */ unsigned int get_max_mbs_width(const char *const *s, unsigned int count) { unsigned int max_width, i, len; max_width = 0; for (i = 0; i < count; ++i) { len = get_mbs_width(s[i]); if (len > max_width) max_width = len; } return max_width; }