utils.c (3097B)
1 /* 2 * utils.c - multibyte-string helpers 3 * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #define _XOPEN_SOURCE 20 #include "aconfig.h" 21 #include <limits.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <wchar.h> 25 #include "utils.h" 26 27 /* 28 * mbs_at_width - compute screen position in a string 29 * 30 * For displaying strings on the screen, we have to know how many character 31 * cells are occupied. This function calculates the position in a multibyte 32 * string that is at a desired position. 33 * 34 * Parameters: 35 * s: the string 36 * width: on input, the desired number of character cells; on output, the actual 37 * position, in character cells, of the return value 38 * dir: -1 or 1; in which direction to round if a multi-column character goes 39 * over the desired width 40 * 41 * Return value: 42 * Pointer to the place in the string that is as near the desired width as 43 * possible. If the string is too short, the return value points to the 44 * terminating zero. If the last character is a multi-column character that 45 * goes over the desired width, the return value may be one character cell 46 * earlier or later than desired, depending on the dir parameter. 47 * In any case, the return value points after any zero-width characters that 48 * follow the last character. 49 */ 50 const char *mbs_at_width(const char *s, int *width, int dir) 51 { 52 size_t len; 53 wchar_t wc; 54 int bytes; 55 int width_so_far, w; 56 57 if (*width <= 0) 58 return s; 59 mbtowc(NULL, NULL, 0); /* reset shift state */ 60 len = strlen(s); 61 width_so_far = 0; 62 while (len && (bytes = mbtowc(&wc, s, len)) > 0) { 63 w = wcwidth(wc); 64 if (width_so_far + w > *width && dir < 0) 65 break; 66 if (w >= 0) 67 width_so_far += w; 68 s += bytes; 69 len -= bytes; 70 if (width_so_far >= *width) { 71 while (len && (bytes = mbtowc(&wc, s, len)) > 0) { 72 w = wcwidth(wc); 73 if (w != 0) 74 break; 75 s += bytes; 76 len -= bytes; 77 } 78 break; 79 } 80 } 81 *width = width_so_far; 82 return s; 83 } 84 85 /* 86 * get_mbs_width - compute screen width of a string 87 */ 88 unsigned int get_mbs_width(const char *s) 89 { 90 int width; 91 92 width = INT_MAX; 93 mbs_at_width(s, &width, 1); 94 return width; 95 } 96 97 /* 98 * get_max_mbs_width - get width of longest string in an array 99 */ 100 unsigned int get_max_mbs_width(const char *const *s, unsigned int count) 101 { 102 unsigned int max_width, i, len; 103 104 max_width = 0; 105 for (i = 0; i < count; ++i) { 106 len = get_mbs_width(s[i]); 107 if (len > max_width) 108 max_width = len; 109 } 110 return max_width; 111 }