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#ifndef _XOPEN_SOURCE 20#define _XOPEN_SOURCE 21#endif 22#include "aconfig.h" 23#include <limits.h> 24#include <stdlib.h> 25#include <string.h> 26#include <wchar.h> 27#include <errno.h> 28#include <stdio.h> 29#include "utils.h" 30#include "mem.h" 31 32/* 33 * mbs_at_width - compute screen position in a string 34 * 35 * For displaying strings on the screen, we have to know how many character 36 * cells are occupied. This function calculates the position in a multibyte 37 * string that is at a desired position. 38 * 39 * Parameters: 40 * s: the string 41 * width: on input, the desired number of character cells; on output, the actual 42 * position, in character cells, of the return value 43 * dir: -1 or 1; in which direction to round if a multi-column character goes 44 * over the desired width 45 * 46 * Return value: 47 * Pointer to the place in the string that is as near the desired width as 48 * possible. If the string is too short, the return value points to the 49 * terminating zero. If the last character is a multi-column character that 50 * goes over the desired width, the return value may be one character cell 51 * earlier or later than desired, depending on the dir parameter. 52 * In any case, the return value points after any zero-width characters that 53 * follow the last character. 54 */ 55const char *mbs_at_width(const char *s, int *width, int dir) 56{ 57 size_t len; 58 wchar_t wc; 59 int bytes; 60 int width_so_far, w; 61 62 if (*width <= 0) 63 return s; 64 mbtowc(NULL, NULL, 0); /* reset shift state */ 65 len = strlen(s); 66 width_so_far = 0; 67 while (len && (bytes = mbtowc(&wc, s, len)) > 0) { 68 w = wcwidth(wc); 69 if (width_so_far + w > *width && dir < 0) 70 break; 71 if (w >= 0) 72 width_so_far += w; 73 s += bytes; 74 len -= bytes; 75 if (width_so_far >= *width) { 76 while (len && (bytes = mbtowc(&wc, s, len)) > 0) { 77 w = wcwidth(wc); 78 if (w != 0) 79 break; 80 s += bytes; 81 len -= bytes; 82 } 83 break; 84 } 85 } 86 *width = width_so_far; 87 return s; 88} 89 90/* 91 * get_mbs_width - compute screen width of a string 92 */ 93unsigned int get_mbs_width(const char *s) 94{ 95 int width; 96 97 width = INT_MAX; 98 mbs_at_width(s, &width, 1); 99 return width; 100} 101 102/* 103 * get_max_mbs_width - get width of longest string in an array 104 */ 105unsigned int get_max_mbs_width(const char *const *s, unsigned int count) 106{ 107 unsigned int max_width, i, len; 108 109 max_width = 0; 110 for (i = 0; i < count; ++i) { 111 len = get_mbs_width(s[i]); 112 if (len > max_width) 113 max_width = len; 114 } 115 return max_width; 116} 117 118#define MAX_FILE_SIZE 1048576 119char *read_file(const char *file_name, unsigned int *file_size) 120{ 121 FILE *f; 122 int err; 123 char *buf; 124 unsigned int allocated = 2048; 125 unsigned int bytes_read; 126 127 f = fopen(file_name, "r"); 128 if (!f) { 129 err = errno; 130 errno = err; 131 return NULL; 132 } 133 *file_size = 0; 134 buf = NULL; 135 do { 136 allocated *= 2; 137 buf = crealloc(buf, allocated); 138 bytes_read = fread(buf + *file_size, 1, allocated - *file_size, f); 139 *file_size += bytes_read; 140 } while (*file_size == allocated && allocated < MAX_FILE_SIZE); 141 fclose(f); 142 if (*file_size > 0 && buf[*file_size - 1] != '\n' && *file_size < allocated) { 143 buf[*file_size] = '\n'; 144 ++*file_size; 145 } 146 return buf; 147} 148 149