14c8945a0SNathan Whitehorn /* 22a3e3873SBaptiste Daroussin * $Id: inputstr.c,v 1.72 2012/12/30 22:11:37 tom Exp $ 34c8945a0SNathan Whitehorn * 44c8945a0SNathan Whitehorn * inputstr.c -- functions for input/display of a string 54c8945a0SNathan Whitehorn * 62a3e3873SBaptiste Daroussin * Copyright 2000-2011,2012 Thomas E. Dickey 74c8945a0SNathan Whitehorn * 84c8945a0SNathan Whitehorn * This program is free software; you can redistribute it and/or modify 94c8945a0SNathan Whitehorn * it under the terms of the GNU Lesser General Public License, version 2.1 104c8945a0SNathan Whitehorn * as published by the Free Software Foundation. 114c8945a0SNathan Whitehorn * 124c8945a0SNathan Whitehorn * This program is distributed in the hope that it will be useful, but 134c8945a0SNathan Whitehorn * WITHOUT ANY WARRANTY; without even the implied warranty of 144c8945a0SNathan Whitehorn * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 154c8945a0SNathan Whitehorn * Lesser General Public License for more details. 164c8945a0SNathan Whitehorn * 174c8945a0SNathan Whitehorn * You should have received a copy of the GNU Lesser General Public 184c8945a0SNathan Whitehorn * License along with this program; if not, write to 194c8945a0SNathan Whitehorn * Free Software Foundation, Inc. 204c8945a0SNathan Whitehorn * 51 Franklin St., Fifth Floor 214c8945a0SNathan Whitehorn * Boston, MA 02110, USA. 224c8945a0SNathan Whitehorn */ 234c8945a0SNathan Whitehorn 244c8945a0SNathan Whitehorn #include <dialog.h> 254c8945a0SNathan Whitehorn #include <dlg_keys.h> 264c8945a0SNathan Whitehorn 274c8945a0SNathan Whitehorn #include <errno.h> 284c8945a0SNathan Whitehorn 294c8945a0SNathan Whitehorn #ifdef HAVE_SETLOCALE 304c8945a0SNathan Whitehorn #include <locale.h> 314c8945a0SNathan Whitehorn #endif 324c8945a0SNathan Whitehorn 334c8945a0SNathan Whitehorn #if defined(HAVE_SEARCH_H) && defined(HAVE_TSEARCH) 344c8945a0SNathan Whitehorn #include <search.h> 354c8945a0SNathan Whitehorn #else 364c8945a0SNathan Whitehorn #undef HAVE_TSEARCH 374c8945a0SNathan Whitehorn #endif 384c8945a0SNathan Whitehorn 394c8945a0SNathan Whitehorn #ifdef NEED_WCHAR_H 404c8945a0SNathan Whitehorn #include <wchar.h> 414c8945a0SNathan Whitehorn #endif 424c8945a0SNathan Whitehorn 434c8945a0SNathan Whitehorn #if defined(USE_WIDE_CURSES) 444c8945a0SNathan Whitehorn #define USE_CACHING 1 454c8945a0SNathan Whitehorn #elif defined(HAVE_XDIALOG) 464c8945a0SNathan Whitehorn #define USE_CACHING 1 /* editbox really needs caching! */ 474c8945a0SNathan Whitehorn #else 484c8945a0SNathan Whitehorn #define USE_CACHING 0 494c8945a0SNathan Whitehorn #endif 504c8945a0SNathan Whitehorn 514c8945a0SNathan Whitehorn typedef struct _cache { 524c8945a0SNathan Whitehorn struct _cache *next; 534c8945a0SNathan Whitehorn #if USE_CACHING 544c8945a0SNathan Whitehorn struct _cache *cache_at; /* unique: associate caches by CACHE */ 554c8945a0SNathan Whitehorn const char *string_at; /* unique: associate caches by char* */ 564c8945a0SNathan Whitehorn #endif 577a1c0d96SNathan Whitehorn size_t s_len; /* strlen(string) - we add 1 for EOS */ 587a1c0d96SNathan Whitehorn size_t i_len; /* length(list) - we add 1 for EOS */ 594c8945a0SNathan Whitehorn char *string; /* a copy of the last-processed string */ 604c8945a0SNathan Whitehorn int *list; /* indices into the string */ 614c8945a0SNathan Whitehorn } CACHE; 624c8945a0SNathan Whitehorn 634c8945a0SNathan Whitehorn #if USE_CACHING 644c8945a0SNathan Whitehorn #define SAME_CACHE(c,s,l) (c->string != 0 && memcmp(c->string,s,l) == 0) 654c8945a0SNathan Whitehorn 664c8945a0SNathan Whitehorn static CACHE *cache_list; 674c8945a0SNathan Whitehorn 684c8945a0SNathan Whitehorn #ifdef HAVE_TSEARCH 694c8945a0SNathan Whitehorn static void *sorted_cache; 704c8945a0SNathan Whitehorn #endif 714c8945a0SNathan Whitehorn 724c8945a0SNathan Whitehorn #ifdef USE_WIDE_CURSES 734c8945a0SNathan Whitehorn static int 744c8945a0SNathan Whitehorn have_locale(void) 754c8945a0SNathan Whitehorn { 764c8945a0SNathan Whitehorn static int result = -1; 774c8945a0SNathan Whitehorn if (result < 0) { 784c8945a0SNathan Whitehorn char *test = setlocale(LC_ALL, 0); 794c8945a0SNathan Whitehorn if (test == 0 || *test == 0) { 804c8945a0SNathan Whitehorn result = FALSE; 814c8945a0SNathan Whitehorn } else if (strcmp(test, "C") && strcmp(test, "POSIX")) { 824c8945a0SNathan Whitehorn result = TRUE; 834c8945a0SNathan Whitehorn } else { 844c8945a0SNathan Whitehorn result = FALSE; 854c8945a0SNathan Whitehorn } 864c8945a0SNathan Whitehorn } 874c8945a0SNathan Whitehorn return result; 884c8945a0SNathan Whitehorn } 894c8945a0SNathan Whitehorn #endif 904c8945a0SNathan Whitehorn 914c8945a0SNathan Whitehorn #ifdef HAVE_TSEARCH 924c8945a0SNathan Whitehorn static int 934c8945a0SNathan Whitehorn compare_cache(const void *a, const void *b) 944c8945a0SNathan Whitehorn { 954c8945a0SNathan Whitehorn const CACHE *p = (const CACHE *) a; 964c8945a0SNathan Whitehorn const CACHE *q = (const CACHE *) b; 974c8945a0SNathan Whitehorn int result = 0; 987a1c0d96SNathan Whitehorn result = (int) (p->cache_at - q->cache_at); 994c8945a0SNathan Whitehorn if (result == 0) 1007a1c0d96SNathan Whitehorn result = (int) (p->string_at - q->string_at); 1014c8945a0SNathan Whitehorn return result; 1024c8945a0SNathan Whitehorn } 1034c8945a0SNathan Whitehorn #endif 1044c8945a0SNathan Whitehorn 1054c8945a0SNathan Whitehorn static CACHE * 1064c8945a0SNathan Whitehorn find_cache(CACHE * cache, const char *string) 1074c8945a0SNathan Whitehorn { 1084c8945a0SNathan Whitehorn CACHE *p; 1094c8945a0SNathan Whitehorn 1104c8945a0SNathan Whitehorn #ifdef HAVE_TSEARCH 1114c8945a0SNathan Whitehorn void *pp; 1124c8945a0SNathan Whitehorn CACHE find; 1134c8945a0SNathan Whitehorn 1144c8945a0SNathan Whitehorn memset(&find, 0, sizeof(find)); 1154c8945a0SNathan Whitehorn find.cache_at = cache; 1164c8945a0SNathan Whitehorn find.string_at = string; 1174c8945a0SNathan Whitehorn 1184c8945a0SNathan Whitehorn if ((pp = tfind(&find, &sorted_cache, compare_cache)) != 0) { 1194c8945a0SNathan Whitehorn p = *(CACHE **) pp; 1204c8945a0SNathan Whitehorn } else { 1214c8945a0SNathan Whitehorn p = 0; 1224c8945a0SNathan Whitehorn } 1234c8945a0SNathan Whitehorn #else 1244c8945a0SNathan Whitehorn for (p = cache_list; p != 0; p = p->next) { 1254c8945a0SNathan Whitehorn if (p->cache_at == cache 1264c8945a0SNathan Whitehorn && p->string_at == string) { 1274c8945a0SNathan Whitehorn break; 1284c8945a0SNathan Whitehorn } 1294c8945a0SNathan Whitehorn } 1304c8945a0SNathan Whitehorn #endif 1314c8945a0SNathan Whitehorn return p; 1324c8945a0SNathan Whitehorn } 1334c8945a0SNathan Whitehorn 1344c8945a0SNathan Whitehorn static void 1354c8945a0SNathan Whitehorn make_cache(CACHE * cache, const char *string) 1364c8945a0SNathan Whitehorn { 1374c8945a0SNathan Whitehorn CACHE *p; 1384c8945a0SNathan Whitehorn 1394c8945a0SNathan Whitehorn p = dlg_calloc(CACHE, 1); 1404c8945a0SNathan Whitehorn assert_ptr(p, "load_cache"); 1414c8945a0SNathan Whitehorn p->next = cache_list; 1424c8945a0SNathan Whitehorn cache_list = p; 1434c8945a0SNathan Whitehorn 1444c8945a0SNathan Whitehorn p->cache_at = cache; 1454c8945a0SNathan Whitehorn p->string_at = string; 1464c8945a0SNathan Whitehorn 1474c8945a0SNathan Whitehorn *cache = *p; 1484c8945a0SNathan Whitehorn #ifdef HAVE_TSEARCH 1494c8945a0SNathan Whitehorn (void) tsearch(p, &sorted_cache, compare_cache); 1504c8945a0SNathan Whitehorn #endif 1514c8945a0SNathan Whitehorn } 1524c8945a0SNathan Whitehorn 1534c8945a0SNathan Whitehorn static void 1544c8945a0SNathan Whitehorn load_cache(CACHE * cache, const char *string) 1554c8945a0SNathan Whitehorn { 1564c8945a0SNathan Whitehorn CACHE *p; 1574c8945a0SNathan Whitehorn 1584c8945a0SNathan Whitehorn if ((p = find_cache(cache, string)) != 0) { 1594c8945a0SNathan Whitehorn *cache = *p; 1604c8945a0SNathan Whitehorn } else { 1614c8945a0SNathan Whitehorn make_cache(cache, string); 1624c8945a0SNathan Whitehorn } 1634c8945a0SNathan Whitehorn } 1644c8945a0SNathan Whitehorn 1654c8945a0SNathan Whitehorn static void 1664c8945a0SNathan Whitehorn save_cache(CACHE * cache, const char *string) 1674c8945a0SNathan Whitehorn { 1684c8945a0SNathan Whitehorn CACHE *p; 1694c8945a0SNathan Whitehorn 1704c8945a0SNathan Whitehorn if ((p = find_cache(cache, string)) != 0) { 1714c8945a0SNathan Whitehorn CACHE *q = p->next; 1724c8945a0SNathan Whitehorn *p = *cache; 1734c8945a0SNathan Whitehorn p->next = q; 1744c8945a0SNathan Whitehorn } 1754c8945a0SNathan Whitehorn } 1764c8945a0SNathan Whitehorn #else 1774c8945a0SNathan Whitehorn #define SAME_CACHE(c,s,l) (c->string != 0) 1784c8945a0SNathan Whitehorn #define load_cache(cache, string) /* nothing */ 1794c8945a0SNathan Whitehorn #define save_cache(cache, string) /* nothing */ 1804c8945a0SNathan Whitehorn #endif /* USE_WIDE_CURSES */ 1814c8945a0SNathan Whitehorn 1824c8945a0SNathan Whitehorn /* 1834c8945a0SNathan Whitehorn * If the given string has not changed, we do not need to update the index. 1844c8945a0SNathan Whitehorn * If we need to update the index, allocate enough memory for it. 1854c8945a0SNathan Whitehorn */ 1864c8945a0SNathan Whitehorn static bool 1874c8945a0SNathan Whitehorn same_cache2(CACHE * cache, const char *string, unsigned i_len) 1884c8945a0SNathan Whitehorn { 1894c8945a0SNathan Whitehorn unsigned need; 1907a1c0d96SNathan Whitehorn size_t s_len = strlen(string); 1914c8945a0SNathan Whitehorn 1924c8945a0SNathan Whitehorn if (cache->s_len != 0 1934c8945a0SNathan Whitehorn && cache->s_len >= s_len 1944c8945a0SNathan Whitehorn && cache->list != 0 1957a1c0d96SNathan Whitehorn && SAME_CACHE(cache, string, (size_t) s_len)) { 1964c8945a0SNathan Whitehorn return TRUE; 1974c8945a0SNathan Whitehorn } 1984c8945a0SNathan Whitehorn 1994c8945a0SNathan Whitehorn need = (i_len + 1); 2004c8945a0SNathan Whitehorn if (cache->list == 0) { 2014c8945a0SNathan Whitehorn cache->list = dlg_malloc(int, need); 2024c8945a0SNathan Whitehorn } else if (cache->i_len < i_len) { 2034c8945a0SNathan Whitehorn cache->list = dlg_realloc(int, need, cache->list); 2044c8945a0SNathan Whitehorn } 2054c8945a0SNathan Whitehorn cache->i_len = i_len; 2064c8945a0SNathan Whitehorn 2074c8945a0SNathan Whitehorn if (cache->s_len >= s_len && cache->string != 0) { 2084c8945a0SNathan Whitehorn strcpy(cache->string, string); 2094c8945a0SNathan Whitehorn } else { 2104c8945a0SNathan Whitehorn if (cache->string != 0) 2114c8945a0SNathan Whitehorn free(cache->string); 2124c8945a0SNathan Whitehorn cache->string = dlg_strclone(string); 2134c8945a0SNathan Whitehorn } 2144c8945a0SNathan Whitehorn cache->s_len = s_len; 2154c8945a0SNathan Whitehorn 2164c8945a0SNathan Whitehorn return FALSE; 2174c8945a0SNathan Whitehorn } 2184c8945a0SNathan Whitehorn 2194c8945a0SNathan Whitehorn #ifdef USE_WIDE_CURSES 2204c8945a0SNathan Whitehorn /* 2214c8945a0SNathan Whitehorn * Like same_cache2(), but we are only concerned about caching a copy of the 2224c8945a0SNathan Whitehorn * string and its associated length. 2234c8945a0SNathan Whitehorn */ 2244c8945a0SNathan Whitehorn static bool 2257a1c0d96SNathan Whitehorn same_cache1(CACHE * cache, const char *string, size_t i_len) 2264c8945a0SNathan Whitehorn { 2277a1c0d96SNathan Whitehorn size_t s_len = strlen(string); 2284c8945a0SNathan Whitehorn 2294c8945a0SNathan Whitehorn if (cache->s_len == s_len 2307a1c0d96SNathan Whitehorn && SAME_CACHE(cache, string, (size_t) s_len)) { 2314c8945a0SNathan Whitehorn return TRUE; 2324c8945a0SNathan Whitehorn } 2334c8945a0SNathan Whitehorn 2344c8945a0SNathan Whitehorn if (cache->s_len >= s_len && cache->string != 0) { 2354c8945a0SNathan Whitehorn strcpy(cache->string, string); 2364c8945a0SNathan Whitehorn } else { 2374c8945a0SNathan Whitehorn if (cache->string != 0) 2384c8945a0SNathan Whitehorn free(cache->string); 2394c8945a0SNathan Whitehorn cache->string = dlg_strclone(string); 2404c8945a0SNathan Whitehorn } 2414c8945a0SNathan Whitehorn cache->s_len = s_len; 2424c8945a0SNathan Whitehorn cache->i_len = i_len; 2434c8945a0SNathan Whitehorn 2444c8945a0SNathan Whitehorn return FALSE; 2454c8945a0SNathan Whitehorn } 2464c8945a0SNathan Whitehorn #endif /* USE_CACHING */ 2474c8945a0SNathan Whitehorn 2484c8945a0SNathan Whitehorn /* 2494c8945a0SNathan Whitehorn * Counts the number of bytes that make up complete wide-characters, up to byte 2504c8945a0SNathan Whitehorn * 'len'. If there is no locale set, simply return the original length. 2514c8945a0SNathan Whitehorn */ 2524c8945a0SNathan Whitehorn #ifdef USE_WIDE_CURSES 2534c8945a0SNathan Whitehorn static int 2544c8945a0SNathan Whitehorn dlg_count_wcbytes(const char *string, size_t len) 2554c8945a0SNathan Whitehorn { 2564c8945a0SNathan Whitehorn int result; 2574c8945a0SNathan Whitehorn 2584c8945a0SNathan Whitehorn if (have_locale()) { 2594c8945a0SNathan Whitehorn static CACHE cache; 2604c8945a0SNathan Whitehorn 2614c8945a0SNathan Whitehorn load_cache(&cache, string); 2624c8945a0SNathan Whitehorn if (!same_cache1(&cache, string, len)) { 2634c8945a0SNathan Whitehorn while (len != 0) { 2644c8945a0SNathan Whitehorn size_t code = 0; 2654c8945a0SNathan Whitehorn const char *src = cache.string; 2664c8945a0SNathan Whitehorn mbstate_t state; 2674c8945a0SNathan Whitehorn char save = cache.string[len]; 2684c8945a0SNathan Whitehorn 2694c8945a0SNathan Whitehorn cache.string[len] = '\0'; 2704c8945a0SNathan Whitehorn memset(&state, 0, sizeof(state)); 2714c8945a0SNathan Whitehorn code = mbsrtowcs((wchar_t *) 0, &src, len, &state); 2724c8945a0SNathan Whitehorn cache.string[len] = save; 2734c8945a0SNathan Whitehorn if ((int) code >= 0) { 2744c8945a0SNathan Whitehorn break; 2754c8945a0SNathan Whitehorn } 2764c8945a0SNathan Whitehorn --len; 2774c8945a0SNathan Whitehorn } 2784c8945a0SNathan Whitehorn cache.i_len = len; 2794c8945a0SNathan Whitehorn save_cache(&cache, string); 2804c8945a0SNathan Whitehorn } 2814c8945a0SNathan Whitehorn result = (int) cache.i_len; 2824c8945a0SNathan Whitehorn } else { 2834c8945a0SNathan Whitehorn result = (int) len; 2844c8945a0SNathan Whitehorn } 2854c8945a0SNathan Whitehorn return result; 2864c8945a0SNathan Whitehorn } 2874c8945a0SNathan Whitehorn #endif /* USE_WIDE_CURSES */ 2884c8945a0SNathan Whitehorn 2894c8945a0SNathan Whitehorn /* 2904c8945a0SNathan Whitehorn * Counts the number of wide-characters in the string. 2914c8945a0SNathan Whitehorn */ 2924c8945a0SNathan Whitehorn int 2934c8945a0SNathan Whitehorn dlg_count_wchars(const char *string) 2944c8945a0SNathan Whitehorn { 2954c8945a0SNathan Whitehorn int result; 2964c8945a0SNathan Whitehorn 2974c8945a0SNathan Whitehorn #ifdef USE_WIDE_CURSES 2984c8945a0SNathan Whitehorn if (have_locale()) { 2994c8945a0SNathan Whitehorn static CACHE cache; 3004c8945a0SNathan Whitehorn size_t len = strlen(string); 3014c8945a0SNathan Whitehorn 3024c8945a0SNathan Whitehorn load_cache(&cache, string); 3034c8945a0SNathan Whitehorn if (!same_cache1(&cache, string, len)) { 3044c8945a0SNathan Whitehorn const char *src = cache.string; 3054c8945a0SNathan Whitehorn mbstate_t state; 3064c8945a0SNathan Whitehorn int part = dlg_count_wcbytes(cache.string, len); 3074c8945a0SNathan Whitehorn char save = cache.string[part]; 3084c8945a0SNathan Whitehorn size_t code; 3094c8945a0SNathan Whitehorn wchar_t *temp = dlg_calloc(wchar_t, len + 1); 3104c8945a0SNathan Whitehorn 3112a3e3873SBaptiste Daroussin if (temp != 0) { 3124c8945a0SNathan Whitehorn cache.string[part] = '\0'; 3134c8945a0SNathan Whitehorn memset(&state, 0, sizeof(state)); 3144c8945a0SNathan Whitehorn code = mbsrtowcs(temp, &src, (size_t) part, &state); 3154c8945a0SNathan Whitehorn cache.i_len = ((int) code >= 0) ? wcslen(temp) : 0; 3164c8945a0SNathan Whitehorn cache.string[part] = save; 3174c8945a0SNathan Whitehorn free(temp); 3184c8945a0SNathan Whitehorn save_cache(&cache, string); 3192a3e3873SBaptiste Daroussin } else { 3202a3e3873SBaptiste Daroussin cache.i_len = 0; 3212a3e3873SBaptiste Daroussin } 3224c8945a0SNathan Whitehorn } 3234c8945a0SNathan Whitehorn result = (int) cache.i_len; 3244c8945a0SNathan Whitehorn } else 3254c8945a0SNathan Whitehorn #endif /* USE_WIDE_CURSES */ 3264c8945a0SNathan Whitehorn { 3274c8945a0SNathan Whitehorn result = (int) strlen(string); 3284c8945a0SNathan Whitehorn } 3294c8945a0SNathan Whitehorn return result; 3304c8945a0SNathan Whitehorn } 3314c8945a0SNathan Whitehorn 3324c8945a0SNathan Whitehorn /* 3334c8945a0SNathan Whitehorn * Build an index of the wide-characters in the string, so we can easily tell 3344c8945a0SNathan Whitehorn * which byte-offset begins a given wide-character. 3354c8945a0SNathan Whitehorn */ 3364c8945a0SNathan Whitehorn const int * 3374c8945a0SNathan Whitehorn dlg_index_wchars(const char *string) 3384c8945a0SNathan Whitehorn { 3394c8945a0SNathan Whitehorn static CACHE cache; 3404c8945a0SNathan Whitehorn unsigned len = (unsigned) dlg_count_wchars(string); 3414c8945a0SNathan Whitehorn unsigned inx; 3424c8945a0SNathan Whitehorn 3434c8945a0SNathan Whitehorn load_cache(&cache, string); 3444c8945a0SNathan Whitehorn if (!same_cache2(&cache, string, len)) { 3454c8945a0SNathan Whitehorn const char *current = string; 3464c8945a0SNathan Whitehorn 3474c8945a0SNathan Whitehorn cache.list[0] = 0; 3484c8945a0SNathan Whitehorn for (inx = 1; inx <= len; ++inx) { 3494c8945a0SNathan Whitehorn #ifdef USE_WIDE_CURSES 3504c8945a0SNathan Whitehorn if (have_locale()) { 3514c8945a0SNathan Whitehorn mbstate_t state; 3524c8945a0SNathan Whitehorn int width; 3534c8945a0SNathan Whitehorn memset(&state, 0, sizeof(state)); 3544c8945a0SNathan Whitehorn width = (int) mbrlen(current, strlen(current), &state); 3554c8945a0SNathan Whitehorn if (width <= 0) 3564c8945a0SNathan Whitehorn width = 1; /* FIXME: what if we have a control-char? */ 3574c8945a0SNathan Whitehorn current += width; 3584c8945a0SNathan Whitehorn cache.list[inx] = cache.list[inx - 1] + width; 3594c8945a0SNathan Whitehorn } else 3604c8945a0SNathan Whitehorn #endif /* USE_WIDE_CURSES */ 3614c8945a0SNathan Whitehorn { 3624c8945a0SNathan Whitehorn (void) current; 3634c8945a0SNathan Whitehorn cache.list[inx] = (int) inx; 3644c8945a0SNathan Whitehorn } 3654c8945a0SNathan Whitehorn } 3664c8945a0SNathan Whitehorn save_cache(&cache, string); 3674c8945a0SNathan Whitehorn } 3684c8945a0SNathan Whitehorn return cache.list; 3694c8945a0SNathan Whitehorn } 3704c8945a0SNathan Whitehorn 3714c8945a0SNathan Whitehorn /* 3724c8945a0SNathan Whitehorn * Given the character-offset to find in the list, return the corresponding 3734c8945a0SNathan Whitehorn * array index. 3744c8945a0SNathan Whitehorn */ 3754c8945a0SNathan Whitehorn int 3764c8945a0SNathan Whitehorn dlg_find_index(const int *list, int limit, int to_find) 3774c8945a0SNathan Whitehorn { 3784c8945a0SNathan Whitehorn int result; 3794c8945a0SNathan Whitehorn for (result = 0; result <= limit; ++result) { 3804c8945a0SNathan Whitehorn if (to_find == list[result] 3814c8945a0SNathan Whitehorn || result == limit 3822a3e3873SBaptiste Daroussin || ((result < limit) && (to_find < list[result + 1]))) { 3834c8945a0SNathan Whitehorn break; 3844c8945a0SNathan Whitehorn } 3852a3e3873SBaptiste Daroussin } 3864c8945a0SNathan Whitehorn return result; 3874c8945a0SNathan Whitehorn } 3884c8945a0SNathan Whitehorn 3894c8945a0SNathan Whitehorn /* 3904c8945a0SNathan Whitehorn * Build a list of the display-columns for the given string's characters. 3914c8945a0SNathan Whitehorn */ 3924c8945a0SNathan Whitehorn const int * 3934c8945a0SNathan Whitehorn dlg_index_columns(const char *string) 3944c8945a0SNathan Whitehorn { 3954c8945a0SNathan Whitehorn static CACHE cache; 3964c8945a0SNathan Whitehorn unsigned len = (unsigned) dlg_count_wchars(string); 3974c8945a0SNathan Whitehorn unsigned inx; 3984c8945a0SNathan Whitehorn 3994c8945a0SNathan Whitehorn load_cache(&cache, string); 4004c8945a0SNathan Whitehorn if (!same_cache2(&cache, string, len)) { 4014c8945a0SNathan Whitehorn cache.list[0] = 0; 4024c8945a0SNathan Whitehorn #ifdef USE_WIDE_CURSES 4034c8945a0SNathan Whitehorn if (have_locale()) { 4044c8945a0SNathan Whitehorn size_t num_bytes = strlen(string); 4054c8945a0SNathan Whitehorn const int *inx_wchars = dlg_index_wchars(string); 4064c8945a0SNathan Whitehorn mbstate_t state; 4074c8945a0SNathan Whitehorn 4084c8945a0SNathan Whitehorn for (inx = 0; inx < len; ++inx) { 4094c8945a0SNathan Whitehorn wchar_t temp[2]; 4104c8945a0SNathan Whitehorn size_t check; 4114c8945a0SNathan Whitehorn int result; 4124c8945a0SNathan Whitehorn 4134c8945a0SNathan Whitehorn if (string[inx_wchars[inx]] == TAB) { 4144c8945a0SNathan Whitehorn result = ((cache.list[inx] | 7) + 1) - cache.list[inx]; 4154c8945a0SNathan Whitehorn } else { 4164c8945a0SNathan Whitehorn memset(&state, 0, sizeof(state)); 4174c8945a0SNathan Whitehorn memset(temp, 0, sizeof(temp)); 4184c8945a0SNathan Whitehorn check = mbrtowc(temp, 4194c8945a0SNathan Whitehorn string + inx_wchars[inx], 4204c8945a0SNathan Whitehorn num_bytes - (size_t) inx_wchars[inx], 4214c8945a0SNathan Whitehorn &state); 4224c8945a0SNathan Whitehorn if ((int) check <= 0) { 4234c8945a0SNathan Whitehorn result = 1; 4244c8945a0SNathan Whitehorn } else { 4254c8945a0SNathan Whitehorn result = wcwidth(temp[0]); 4264c8945a0SNathan Whitehorn } 4274c8945a0SNathan Whitehorn if (result < 0) { 4287a1c0d96SNathan Whitehorn const wchar_t *printable; 4297a1c0d96SNathan Whitehorn cchar_t temp2, *temp2p = &temp2; 4307a1c0d96SNathan Whitehorn setcchar(temp2p, temp, 0, 0, 0); 4317a1c0d96SNathan Whitehorn printable = wunctrl(temp2p); 4324c8945a0SNathan Whitehorn result = printable ? (int) wcslen(printable) : 1; 4334c8945a0SNathan Whitehorn } 4344c8945a0SNathan Whitehorn } 4354c8945a0SNathan Whitehorn cache.list[inx + 1] = result; 4364c8945a0SNathan Whitehorn if (inx != 0) 4374c8945a0SNathan Whitehorn cache.list[inx + 1] += cache.list[inx]; 4384c8945a0SNathan Whitehorn } 4394c8945a0SNathan Whitehorn } else 4404c8945a0SNathan Whitehorn #endif /* USE_WIDE_CURSES */ 4414c8945a0SNathan Whitehorn { 4424c8945a0SNathan Whitehorn for (inx = 0; inx < len; ++inx) { 4434c8945a0SNathan Whitehorn chtype ch = UCH(string[inx]); 4444c8945a0SNathan Whitehorn 4454c8945a0SNathan Whitehorn if (ch == TAB) 4464c8945a0SNathan Whitehorn cache.list[inx + 1] = 4474c8945a0SNathan Whitehorn ((cache.list[inx] | 7) + 1) - cache.list[inx]; 4484c8945a0SNathan Whitehorn else if (isprint(ch)) 4494c8945a0SNathan Whitehorn cache.list[inx + 1] = 1; 4504c8945a0SNathan Whitehorn else { 4514c8945a0SNathan Whitehorn const char *printable; 4524c8945a0SNathan Whitehorn printable = unctrl(ch); 4534c8945a0SNathan Whitehorn cache.list[inx + 1] = (printable 4544c8945a0SNathan Whitehorn ? (int) strlen(printable) 4554c8945a0SNathan Whitehorn : 1); 4564c8945a0SNathan Whitehorn } 4574c8945a0SNathan Whitehorn if (inx != 0) 4584c8945a0SNathan Whitehorn cache.list[inx + 1] += cache.list[inx]; 4594c8945a0SNathan Whitehorn } 4604c8945a0SNathan Whitehorn } 4614c8945a0SNathan Whitehorn save_cache(&cache, string); 4624c8945a0SNathan Whitehorn } 4634c8945a0SNathan Whitehorn return cache.list; 4644c8945a0SNathan Whitehorn } 4654c8945a0SNathan Whitehorn 4664c8945a0SNathan Whitehorn /* 4674c8945a0SNathan Whitehorn * Returns the number of columns used for a string. That happens to be the 4684c8945a0SNathan Whitehorn * end-value of the cols[] array. 4694c8945a0SNathan Whitehorn */ 4704c8945a0SNathan Whitehorn int 4714c8945a0SNathan Whitehorn dlg_count_columns(const char *string) 4724c8945a0SNathan Whitehorn { 4734c8945a0SNathan Whitehorn int result = 0; 4744c8945a0SNathan Whitehorn int limit = dlg_count_wchars(string); 4754c8945a0SNathan Whitehorn if (limit > 0) { 4764c8945a0SNathan Whitehorn const int *cols = dlg_index_columns(string); 4774c8945a0SNathan Whitehorn result = cols[limit]; 4784c8945a0SNathan Whitehorn } else { 4794c8945a0SNathan Whitehorn result = (int) strlen(string); 4804c8945a0SNathan Whitehorn } 4814c8945a0SNathan Whitehorn return result; 4824c8945a0SNathan Whitehorn } 4834c8945a0SNathan Whitehorn 4844c8945a0SNathan Whitehorn /* 4854c8945a0SNathan Whitehorn * Given a column limit, count the number of wide characters that can fit 4864c8945a0SNathan Whitehorn * into that limit. The offset is used to skip over a leading character 4874c8945a0SNathan Whitehorn * that was already written. 4884c8945a0SNathan Whitehorn */ 4894c8945a0SNathan Whitehorn int 4904c8945a0SNathan Whitehorn dlg_limit_columns(const char *string, int limit, int offset) 4914c8945a0SNathan Whitehorn { 4924c8945a0SNathan Whitehorn const int *cols = dlg_index_columns(string); 4934c8945a0SNathan Whitehorn int result = dlg_count_wchars(string); 4944c8945a0SNathan Whitehorn 4954c8945a0SNathan Whitehorn while (result > 0 && (cols[result] - cols[offset]) > limit) 4964c8945a0SNathan Whitehorn --result; 4974c8945a0SNathan Whitehorn return result; 4984c8945a0SNathan Whitehorn } 4994c8945a0SNathan Whitehorn 5004c8945a0SNathan Whitehorn /* 5014c8945a0SNathan Whitehorn * Updates the string and character-offset, given various editing characters 5024c8945a0SNathan Whitehorn * or literal characters which are inserted at the character-offset. 5034c8945a0SNathan Whitehorn */ 5044c8945a0SNathan Whitehorn bool 5054c8945a0SNathan Whitehorn dlg_edit_string(char *string, int *chr_offset, int key, int fkey, bool force) 5064c8945a0SNathan Whitehorn { 5074c8945a0SNathan Whitehorn int i; 5084c8945a0SNathan Whitehorn int len = (int) strlen(string); 5094c8945a0SNathan Whitehorn int limit = dlg_count_wchars(string); 5104c8945a0SNathan Whitehorn const int *indx = dlg_index_wchars(string); 5114c8945a0SNathan Whitehorn int offset = dlg_find_index(indx, limit, *chr_offset); 5124c8945a0SNathan Whitehorn int max_len = dlg_max_input(MAX_LEN); 5134c8945a0SNathan Whitehorn bool edit = TRUE; 5144c8945a0SNathan Whitehorn 5154c8945a0SNathan Whitehorn /* transform editing characters into equivalent function-keys */ 5164c8945a0SNathan Whitehorn if (!fkey) { 5174c8945a0SNathan Whitehorn fkey = TRUE; /* assume we transform */ 5184c8945a0SNathan Whitehorn switch (key) { 5194c8945a0SNathan Whitehorn case 0: 5204c8945a0SNathan Whitehorn break; 5214c8945a0SNathan Whitehorn case ESC: 5224c8945a0SNathan Whitehorn case TAB: 5234c8945a0SNathan Whitehorn fkey = FALSE; /* this is used for navigation */ 5244c8945a0SNathan Whitehorn break; 5254c8945a0SNathan Whitehorn default: 5264c8945a0SNathan Whitehorn fkey = FALSE; /* ...no, we did not transform */ 5274c8945a0SNathan Whitehorn break; 5284c8945a0SNathan Whitehorn } 5294c8945a0SNathan Whitehorn } 5304c8945a0SNathan Whitehorn 5314c8945a0SNathan Whitehorn if (fkey) { 5324c8945a0SNathan Whitehorn switch (key) { 5334c8945a0SNathan Whitehorn case 0: /* special case for loop entry */ 5344c8945a0SNathan Whitehorn edit = force; 5354c8945a0SNathan Whitehorn break; 5364c8945a0SNathan Whitehorn case DLGK_GRID_LEFT: 5372a3e3873SBaptiste Daroussin if (*chr_offset && offset > 0) 5384c8945a0SNathan Whitehorn *chr_offset = indx[offset - 1]; 5394c8945a0SNathan Whitehorn break; 5404c8945a0SNathan Whitehorn case DLGK_GRID_RIGHT: 5414c8945a0SNathan Whitehorn if (offset < limit) 5424c8945a0SNathan Whitehorn *chr_offset = indx[offset + 1]; 5434c8945a0SNathan Whitehorn break; 5444c8945a0SNathan Whitehorn case DLGK_BEGIN: 5454c8945a0SNathan Whitehorn if (*chr_offset) 5464c8945a0SNathan Whitehorn *chr_offset = 0; 5474c8945a0SNathan Whitehorn break; 5484c8945a0SNathan Whitehorn case DLGK_FINAL: 5494c8945a0SNathan Whitehorn if (offset < limit) 5504c8945a0SNathan Whitehorn *chr_offset = indx[limit]; 5514c8945a0SNathan Whitehorn break; 5524c8945a0SNathan Whitehorn case DLGK_DELETE_LEFT: 5534c8945a0SNathan Whitehorn if (offset) { 5544c8945a0SNathan Whitehorn int gap = indx[offset] - indx[offset - 1]; 5554c8945a0SNathan Whitehorn *chr_offset = indx[offset - 1]; 5564c8945a0SNathan Whitehorn if (gap > 0) { 5574c8945a0SNathan Whitehorn for (i = *chr_offset; 5584c8945a0SNathan Whitehorn (string[i] = string[i + gap]) != '\0'; 5594c8945a0SNathan Whitehorn i++) { 5604c8945a0SNathan Whitehorn ; 5614c8945a0SNathan Whitehorn } 5624c8945a0SNathan Whitehorn } 5634c8945a0SNathan Whitehorn } 5644c8945a0SNathan Whitehorn break; 5654c8945a0SNathan Whitehorn case DLGK_DELETE_RIGHT: 5664c8945a0SNathan Whitehorn if (limit) { 5674c8945a0SNathan Whitehorn if (--limit == 0) { 5684c8945a0SNathan Whitehorn string[*chr_offset = 0] = '\0'; 5694c8945a0SNathan Whitehorn } else { 5704c8945a0SNathan Whitehorn int gap = ((offset <= limit) 5714c8945a0SNathan Whitehorn ? (indx[offset + 1] - indx[offset]) 5724c8945a0SNathan Whitehorn : 0); 5734c8945a0SNathan Whitehorn if (gap > 0) { 5744c8945a0SNathan Whitehorn for (i = indx[offset]; 5754c8945a0SNathan Whitehorn (string[i] = string[i + gap]) != '\0'; 5764c8945a0SNathan Whitehorn i++) { 5774c8945a0SNathan Whitehorn ; 5784c8945a0SNathan Whitehorn } 5794c8945a0SNathan Whitehorn } else if (offset > 0) { 5804c8945a0SNathan Whitehorn string[indx[offset - 1]] = '\0'; 5814c8945a0SNathan Whitehorn } 5824c8945a0SNathan Whitehorn if (*chr_offset > indx[limit]) 5834c8945a0SNathan Whitehorn *chr_offset = indx[limit]; 5844c8945a0SNathan Whitehorn } 5854c8945a0SNathan Whitehorn } 5864c8945a0SNathan Whitehorn break; 5874c8945a0SNathan Whitehorn case DLGK_DELETE_ALL: 5884c8945a0SNathan Whitehorn string[*chr_offset = 0] = '\0'; 5894c8945a0SNathan Whitehorn break; 5904c8945a0SNathan Whitehorn case DLGK_ENTER: 5914c8945a0SNathan Whitehorn edit = 0; 5924c8945a0SNathan Whitehorn break; 5934c8945a0SNathan Whitehorn #ifdef KEY_RESIZE 5944c8945a0SNathan Whitehorn case KEY_RESIZE: 5954c8945a0SNathan Whitehorn edit = 0; 5964c8945a0SNathan Whitehorn break; 5974c8945a0SNathan Whitehorn #endif 5984c8945a0SNathan Whitehorn case DLGK_GRID_UP: 5994c8945a0SNathan Whitehorn case DLGK_GRID_DOWN: 6004c8945a0SNathan Whitehorn case DLGK_FIELD_NEXT: 6014c8945a0SNathan Whitehorn case DLGK_FIELD_PREV: 6024c8945a0SNathan Whitehorn edit = 0; 6034c8945a0SNathan Whitehorn break; 6044c8945a0SNathan Whitehorn case ERR: 6054c8945a0SNathan Whitehorn edit = 0; 6064c8945a0SNathan Whitehorn break; 6074c8945a0SNathan Whitehorn default: 6084c8945a0SNathan Whitehorn beep(); 6094c8945a0SNathan Whitehorn break; 6104c8945a0SNathan Whitehorn } 6114c8945a0SNathan Whitehorn } else { 6124c8945a0SNathan Whitehorn if (key == ESC || key == ERR) { 6134c8945a0SNathan Whitehorn edit = 0; 6144c8945a0SNathan Whitehorn } else { 6154c8945a0SNathan Whitehorn if (len < max_len) { 6164c8945a0SNathan Whitehorn for (i = ++len; i > *chr_offset; i--) 6174c8945a0SNathan Whitehorn string[i] = string[i - 1]; 6184c8945a0SNathan Whitehorn string[*chr_offset] = (char) key; 6194c8945a0SNathan Whitehorn *chr_offset += 1; 6204c8945a0SNathan Whitehorn } else { 6214c8945a0SNathan Whitehorn (void) beep(); 6224c8945a0SNathan Whitehorn } 6234c8945a0SNathan Whitehorn } 6244c8945a0SNathan Whitehorn } 6254c8945a0SNathan Whitehorn return edit; 6264c8945a0SNathan Whitehorn } 6274c8945a0SNathan Whitehorn 6284c8945a0SNathan Whitehorn static void 6294c8945a0SNathan Whitehorn compute_edit_offset(const char *string, 6304c8945a0SNathan Whitehorn int chr_offset, 6314c8945a0SNathan Whitehorn int x_last, 6324c8945a0SNathan Whitehorn int *p_dpy_column, 6334c8945a0SNathan Whitehorn int *p_scroll_amt) 6344c8945a0SNathan Whitehorn { 6354c8945a0SNathan Whitehorn const int *cols = dlg_index_columns(string); 6364c8945a0SNathan Whitehorn const int *indx = dlg_index_wchars(string); 6374c8945a0SNathan Whitehorn int limit = dlg_count_wchars(string); 6384c8945a0SNathan Whitehorn int offset = dlg_find_index(indx, limit, chr_offset); 6394c8945a0SNathan Whitehorn int offset2; 6404c8945a0SNathan Whitehorn int dpy_column; 6414c8945a0SNathan Whitehorn int n; 6424c8945a0SNathan Whitehorn 6434c8945a0SNathan Whitehorn for (n = offset2 = 0; n <= offset; ++n) { 6444c8945a0SNathan Whitehorn if ((cols[offset] - cols[n]) < x_last 6454c8945a0SNathan Whitehorn && (offset == limit || (cols[offset + 1] - cols[n]) < x_last)) { 6464c8945a0SNathan Whitehorn offset2 = n; 6474c8945a0SNathan Whitehorn break; 6484c8945a0SNathan Whitehorn } 6494c8945a0SNathan Whitehorn } 6504c8945a0SNathan Whitehorn 6514c8945a0SNathan Whitehorn dpy_column = cols[offset] - cols[offset2]; 6524c8945a0SNathan Whitehorn 6534c8945a0SNathan Whitehorn if (p_dpy_column != 0) 6544c8945a0SNathan Whitehorn *p_dpy_column = dpy_column; 6554c8945a0SNathan Whitehorn if (p_scroll_amt != 0) 6564c8945a0SNathan Whitehorn *p_scroll_amt = offset2; 6574c8945a0SNathan Whitehorn } 6584c8945a0SNathan Whitehorn 6594c8945a0SNathan Whitehorn /* 6604c8945a0SNathan Whitehorn * Given the character-offset in the string, returns the display-offset where 6614c8945a0SNathan Whitehorn * we will position the cursor. 6624c8945a0SNathan Whitehorn */ 6634c8945a0SNathan Whitehorn int 6644c8945a0SNathan Whitehorn dlg_edit_offset(char *string, int chr_offset, int x_last) 6654c8945a0SNathan Whitehorn { 6664c8945a0SNathan Whitehorn int result; 6674c8945a0SNathan Whitehorn 6684c8945a0SNathan Whitehorn compute_edit_offset(string, chr_offset, x_last, &result, 0); 6694c8945a0SNathan Whitehorn 6704c8945a0SNathan Whitehorn return result; 6714c8945a0SNathan Whitehorn } 6724c8945a0SNathan Whitehorn 6734c8945a0SNathan Whitehorn /* 6744c8945a0SNathan Whitehorn * Displays the string, shifted as necessary, to fit within the box and show 6754c8945a0SNathan Whitehorn * the current character-offset. 6764c8945a0SNathan Whitehorn */ 6774c8945a0SNathan Whitehorn void 6784c8945a0SNathan Whitehorn dlg_show_string(WINDOW *win, 6794c8945a0SNathan Whitehorn const char *string, /* string to display (may be multibyte) */ 6804c8945a0SNathan Whitehorn int chr_offset, /* character (not bytes) offset */ 6814c8945a0SNathan Whitehorn chtype attr, /* window-attributes */ 6824c8945a0SNathan Whitehorn int y_base, /* beginning row on screen */ 6834c8945a0SNathan Whitehorn int x_base, /* beginning column on screen */ 6844c8945a0SNathan Whitehorn int x_last, /* number of columns on screen */ 6854c8945a0SNathan Whitehorn bool hidden, /* if true, do not echo */ 6864c8945a0SNathan Whitehorn bool force) /* if true, force repaint */ 6874c8945a0SNathan Whitehorn { 6884c8945a0SNathan Whitehorn x_last = MIN(x_last + x_base, getmaxx(win)) - x_base; 6894c8945a0SNathan Whitehorn 6904c8945a0SNathan Whitehorn if (hidden && !dialog_vars.insecure) { 6914c8945a0SNathan Whitehorn if (force) { 6924c8945a0SNathan Whitehorn (void) wmove(win, y_base, x_base); 6934c8945a0SNathan Whitehorn wrefresh(win); 6944c8945a0SNathan Whitehorn } 6954c8945a0SNathan Whitehorn } else { 6964c8945a0SNathan Whitehorn const int *cols = dlg_index_columns(string); 6974c8945a0SNathan Whitehorn const int *indx = dlg_index_wchars(string); 6984c8945a0SNathan Whitehorn int limit = dlg_count_wchars(string); 6994c8945a0SNathan Whitehorn 7004c8945a0SNathan Whitehorn int i, j, k; 7014c8945a0SNathan Whitehorn int input_x; 7024c8945a0SNathan Whitehorn int scrollamt; 7034c8945a0SNathan Whitehorn 7044c8945a0SNathan Whitehorn compute_edit_offset(string, chr_offset, x_last, &input_x, &scrollamt); 7054c8945a0SNathan Whitehorn 7062a3e3873SBaptiste Daroussin (void) wattrset(win, attr); 7074c8945a0SNathan Whitehorn (void) wmove(win, y_base, x_base); 7084c8945a0SNathan Whitehorn for (i = scrollamt, k = 0; i < limit && k < x_last; ++i) { 7094c8945a0SNathan Whitehorn int check = cols[i + 1] - cols[scrollamt]; 7104c8945a0SNathan Whitehorn if (check <= x_last) { 7114c8945a0SNathan Whitehorn for (j = indx[i]; j < indx[i + 1]; ++j) { 7124c8945a0SNathan Whitehorn chtype ch = UCH(string[j]); 7134c8945a0SNathan Whitehorn if (hidden && dialog_vars.insecure) { 7144c8945a0SNathan Whitehorn waddch(win, '*'); 7154c8945a0SNathan Whitehorn } else if (ch == TAB) { 7164c8945a0SNathan Whitehorn int count = cols[i + 1] - cols[i]; 7174c8945a0SNathan Whitehorn while (--count >= 0) 7184c8945a0SNathan Whitehorn waddch(win, ' '); 7194c8945a0SNathan Whitehorn } else { 7204c8945a0SNathan Whitehorn waddch(win, ch); 7214c8945a0SNathan Whitehorn } 7224c8945a0SNathan Whitehorn } 7234c8945a0SNathan Whitehorn k = check; 7244c8945a0SNathan Whitehorn } else { 7254c8945a0SNathan Whitehorn break; 7264c8945a0SNathan Whitehorn } 7274c8945a0SNathan Whitehorn } 7284c8945a0SNathan Whitehorn while (k++ < x_last) 7294c8945a0SNathan Whitehorn waddch(win, ' '); 7304c8945a0SNathan Whitehorn (void) wmove(win, y_base, x_base + input_x); 7314c8945a0SNathan Whitehorn wrefresh(win); 7324c8945a0SNathan Whitehorn } 7334c8945a0SNathan Whitehorn } 7344c8945a0SNathan Whitehorn 7354c8945a0SNathan Whitehorn #ifdef NO_LEAKS 7364c8945a0SNathan Whitehorn void 7374c8945a0SNathan Whitehorn _dlg_inputstr_leaks(void) 7384c8945a0SNathan Whitehorn { 7394c8945a0SNathan Whitehorn #if USE_CACHING 7404c8945a0SNathan Whitehorn while (cache_list != 0) { 7414c8945a0SNathan Whitehorn CACHE *next = cache_list->next; 7424c8945a0SNathan Whitehorn #ifdef HAVE_TSEARCH 7434c8945a0SNathan Whitehorn tdelete(cache_list, &sorted_cache, compare_cache); 7444c8945a0SNathan Whitehorn #endif 7454c8945a0SNathan Whitehorn if (cache_list->string != 0) 7464c8945a0SNathan Whitehorn free(cache_list->string); 7474c8945a0SNathan Whitehorn if (cache_list->list != 0) 7484c8945a0SNathan Whitehorn free(cache_list->list); 7494c8945a0SNathan Whitehorn free(cache_list); 7504c8945a0SNathan Whitehorn cache_list = next; 7514c8945a0SNathan Whitehorn } 7524c8945a0SNathan Whitehorn #endif /* USE_CACHING */ 7534c8945a0SNathan Whitehorn } 7544c8945a0SNathan Whitehorn #endif /* NO_LEAKS */ 755