inputstr.c revision 220749
1217309Snwhitehorn/* 2220749Snwhitehorn * $Id: inputstr.c,v 1.69 2011/01/16 21:52:35 tom Exp $ 3217309Snwhitehorn * 4220749Snwhitehorn * inputstr.c -- functions for input/display of a string 5217309Snwhitehorn * 6220749Snwhitehorn * Copyright 2000-2010,2011 Thomas E. Dickey 7217309Snwhitehorn * 8217309Snwhitehorn * This program is free software; you can redistribute it and/or modify 9217309Snwhitehorn * it under the terms of the GNU Lesser General Public License, version 2.1 10217309Snwhitehorn * as published by the Free Software Foundation. 11217309Snwhitehorn * 12217309Snwhitehorn * This program is distributed in the hope that it will be useful, but 13217309Snwhitehorn * WITHOUT ANY WARRANTY; without even the implied warranty of 14217309Snwhitehorn * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15217309Snwhitehorn * Lesser General Public License for more details. 16217309Snwhitehorn * 17217309Snwhitehorn * You should have received a copy of the GNU Lesser General Public 18217309Snwhitehorn * License along with this program; if not, write to 19217309Snwhitehorn * Free Software Foundation, Inc. 20217309Snwhitehorn * 51 Franklin St., Fifth Floor 21217309Snwhitehorn * Boston, MA 02110, USA. 22217309Snwhitehorn */ 23217309Snwhitehorn 24217309Snwhitehorn#include <dialog.h> 25217309Snwhitehorn#include <dlg_keys.h> 26217309Snwhitehorn 27217309Snwhitehorn#include <errno.h> 28217309Snwhitehorn 29217309Snwhitehorn#ifdef HAVE_SETLOCALE 30217309Snwhitehorn#include <locale.h> 31217309Snwhitehorn#endif 32217309Snwhitehorn 33217309Snwhitehorn#if defined(HAVE_SEARCH_H) && defined(HAVE_TSEARCH) 34217309Snwhitehorn#include <search.h> 35217309Snwhitehorn#else 36217309Snwhitehorn#undef HAVE_TSEARCH 37217309Snwhitehorn#endif 38217309Snwhitehorn 39217309Snwhitehorn#ifdef NEED_WCHAR_H 40217309Snwhitehorn#include <wchar.h> 41217309Snwhitehorn#endif 42217309Snwhitehorn 43217309Snwhitehorn#if defined(USE_WIDE_CURSES) 44217309Snwhitehorn#define USE_CACHING 1 45217309Snwhitehorn#elif defined(HAVE_XDIALOG) 46217309Snwhitehorn#define USE_CACHING 1 /* editbox really needs caching! */ 47217309Snwhitehorn#else 48217309Snwhitehorn#define USE_CACHING 0 49217309Snwhitehorn#endif 50217309Snwhitehorn 51217309Snwhitehorntypedef struct _cache { 52217309Snwhitehorn struct _cache *next; 53217309Snwhitehorn#if USE_CACHING 54217309Snwhitehorn struct _cache *cache_at; /* unique: associate caches by CACHE */ 55217309Snwhitehorn const char *string_at; /* unique: associate caches by char* */ 56217309Snwhitehorn#endif 57220749Snwhitehorn size_t s_len; /* strlen(string) - we add 1 for EOS */ 58220749Snwhitehorn size_t i_len; /* length(list) - we add 1 for EOS */ 59217309Snwhitehorn char *string; /* a copy of the last-processed string */ 60217309Snwhitehorn int *list; /* indices into the string */ 61217309Snwhitehorn} CACHE; 62217309Snwhitehorn 63217309Snwhitehorn#if USE_CACHING 64217309Snwhitehorn#define SAME_CACHE(c,s,l) (c->string != 0 && memcmp(c->string,s,l) == 0) 65217309Snwhitehorn 66217309Snwhitehornstatic CACHE *cache_list; 67217309Snwhitehorn 68217309Snwhitehorn#ifdef HAVE_TSEARCH 69217309Snwhitehornstatic void *sorted_cache; 70217309Snwhitehorn#endif 71217309Snwhitehorn 72217309Snwhitehorn#ifdef USE_WIDE_CURSES 73217309Snwhitehornstatic int 74217309Snwhitehornhave_locale(void) 75217309Snwhitehorn{ 76217309Snwhitehorn static int result = -1; 77217309Snwhitehorn if (result < 0) { 78217309Snwhitehorn char *test = setlocale(LC_ALL, 0); 79217309Snwhitehorn if (test == 0 || *test == 0) { 80217309Snwhitehorn result = FALSE; 81217309Snwhitehorn } else if (strcmp(test, "C") && strcmp(test, "POSIX")) { 82217309Snwhitehorn result = TRUE; 83217309Snwhitehorn } else { 84217309Snwhitehorn result = FALSE; 85217309Snwhitehorn } 86217309Snwhitehorn } 87217309Snwhitehorn return result; 88217309Snwhitehorn} 89217309Snwhitehorn#endif 90217309Snwhitehorn 91217309Snwhitehorn#ifdef HAVE_TSEARCH 92217309Snwhitehornstatic int 93217309Snwhitehorncompare_cache(const void *a, const void *b) 94217309Snwhitehorn{ 95217309Snwhitehorn const CACHE *p = (const CACHE *) a; 96217309Snwhitehorn const CACHE *q = (const CACHE *) b; 97217309Snwhitehorn int result = 0; 98220749Snwhitehorn result = (int) (p->cache_at - q->cache_at); 99217309Snwhitehorn if (result == 0) 100220749Snwhitehorn result = (int) (p->string_at - q->string_at); 101217309Snwhitehorn return result; 102217309Snwhitehorn} 103217309Snwhitehorn#endif 104217309Snwhitehorn 105217309Snwhitehornstatic CACHE * 106217309Snwhitehornfind_cache(CACHE * cache, const char *string) 107217309Snwhitehorn{ 108217309Snwhitehorn CACHE *p; 109217309Snwhitehorn 110217309Snwhitehorn#ifdef HAVE_TSEARCH 111217309Snwhitehorn void *pp; 112217309Snwhitehorn CACHE find; 113217309Snwhitehorn 114217309Snwhitehorn memset(&find, 0, sizeof(find)); 115217309Snwhitehorn find.cache_at = cache; 116217309Snwhitehorn find.string_at = string; 117217309Snwhitehorn 118217309Snwhitehorn if ((pp = tfind(&find, &sorted_cache, compare_cache)) != 0) { 119217309Snwhitehorn p = *(CACHE **) pp; 120217309Snwhitehorn } else { 121217309Snwhitehorn p = 0; 122217309Snwhitehorn } 123217309Snwhitehorn#else 124217309Snwhitehorn for (p = cache_list; p != 0; p = p->next) { 125217309Snwhitehorn if (p->cache_at == cache 126217309Snwhitehorn && p->string_at == string) { 127217309Snwhitehorn break; 128217309Snwhitehorn } 129217309Snwhitehorn } 130217309Snwhitehorn#endif 131217309Snwhitehorn return p; 132217309Snwhitehorn} 133217309Snwhitehorn 134217309Snwhitehornstatic void 135217309Snwhitehornmake_cache(CACHE * cache, const char *string) 136217309Snwhitehorn{ 137217309Snwhitehorn CACHE *p; 138217309Snwhitehorn 139217309Snwhitehorn p = dlg_calloc(CACHE, 1); 140217309Snwhitehorn assert_ptr(p, "load_cache"); 141217309Snwhitehorn p->next = cache_list; 142217309Snwhitehorn cache_list = p; 143217309Snwhitehorn 144217309Snwhitehorn p->cache_at = cache; 145217309Snwhitehorn p->string_at = string; 146217309Snwhitehorn 147217309Snwhitehorn *cache = *p; 148217309Snwhitehorn#ifdef HAVE_TSEARCH 149217309Snwhitehorn (void) tsearch(p, &sorted_cache, compare_cache); 150217309Snwhitehorn#endif 151217309Snwhitehorn} 152217309Snwhitehorn 153217309Snwhitehornstatic void 154217309Snwhitehornload_cache(CACHE * cache, const char *string) 155217309Snwhitehorn{ 156217309Snwhitehorn CACHE *p; 157217309Snwhitehorn 158217309Snwhitehorn if ((p = find_cache(cache, string)) != 0) { 159217309Snwhitehorn *cache = *p; 160217309Snwhitehorn } else { 161217309Snwhitehorn make_cache(cache, string); 162217309Snwhitehorn } 163217309Snwhitehorn} 164217309Snwhitehorn 165217309Snwhitehornstatic void 166217309Snwhitehornsave_cache(CACHE * cache, const char *string) 167217309Snwhitehorn{ 168217309Snwhitehorn CACHE *p; 169217309Snwhitehorn 170217309Snwhitehorn if ((p = find_cache(cache, string)) != 0) { 171217309Snwhitehorn CACHE *q = p->next; 172217309Snwhitehorn *p = *cache; 173217309Snwhitehorn p->next = q; 174217309Snwhitehorn } 175217309Snwhitehorn} 176217309Snwhitehorn#else 177217309Snwhitehorn#define SAME_CACHE(c,s,l) (c->string != 0) 178217309Snwhitehorn#define load_cache(cache, string) /* nothing */ 179217309Snwhitehorn#define save_cache(cache, string) /* nothing */ 180217309Snwhitehorn#endif /* USE_WIDE_CURSES */ 181217309Snwhitehorn 182217309Snwhitehorn/* 183217309Snwhitehorn * If the given string has not changed, we do not need to update the index. 184217309Snwhitehorn * If we need to update the index, allocate enough memory for it. 185217309Snwhitehorn */ 186217309Snwhitehornstatic bool 187217309Snwhitehornsame_cache2(CACHE * cache, const char *string, unsigned i_len) 188217309Snwhitehorn{ 189217309Snwhitehorn unsigned need; 190220749Snwhitehorn size_t s_len = strlen(string); 191217309Snwhitehorn 192217309Snwhitehorn if (cache->s_len != 0 193217309Snwhitehorn && cache->s_len >= s_len 194217309Snwhitehorn && cache->list != 0 195220749Snwhitehorn && SAME_CACHE(cache, string, (size_t) s_len)) { 196217309Snwhitehorn return TRUE; 197217309Snwhitehorn } 198217309Snwhitehorn 199217309Snwhitehorn need = (i_len + 1); 200217309Snwhitehorn if (cache->list == 0) { 201217309Snwhitehorn cache->list = dlg_malloc(int, need); 202217309Snwhitehorn } else if (cache->i_len < i_len) { 203217309Snwhitehorn cache->list = dlg_realloc(int, need, cache->list); 204217309Snwhitehorn } 205217309Snwhitehorn cache->i_len = i_len; 206217309Snwhitehorn 207217309Snwhitehorn if (cache->s_len >= s_len && cache->string != 0) { 208217309Snwhitehorn strcpy(cache->string, string); 209217309Snwhitehorn } else { 210217309Snwhitehorn if (cache->string != 0) 211217309Snwhitehorn free(cache->string); 212217309Snwhitehorn cache->string = dlg_strclone(string); 213217309Snwhitehorn } 214217309Snwhitehorn cache->s_len = s_len; 215217309Snwhitehorn 216217309Snwhitehorn return FALSE; 217217309Snwhitehorn} 218217309Snwhitehorn 219217309Snwhitehorn#ifdef USE_WIDE_CURSES 220217309Snwhitehorn/* 221217309Snwhitehorn * Like same_cache2(), but we are only concerned about caching a copy of the 222217309Snwhitehorn * string and its associated length. 223217309Snwhitehorn */ 224217309Snwhitehornstatic bool 225220749Snwhitehornsame_cache1(CACHE * cache, const char *string, size_t i_len) 226217309Snwhitehorn{ 227220749Snwhitehorn size_t s_len = strlen(string); 228217309Snwhitehorn 229217309Snwhitehorn if (cache->s_len == s_len 230220749Snwhitehorn && SAME_CACHE(cache, string, (size_t) s_len)) { 231217309Snwhitehorn return TRUE; 232217309Snwhitehorn } 233217309Snwhitehorn 234217309Snwhitehorn if (cache->s_len >= s_len && cache->string != 0) { 235217309Snwhitehorn strcpy(cache->string, string); 236217309Snwhitehorn } else { 237217309Snwhitehorn if (cache->string != 0) 238217309Snwhitehorn free(cache->string); 239217309Snwhitehorn cache->string = dlg_strclone(string); 240217309Snwhitehorn } 241217309Snwhitehorn cache->s_len = s_len; 242217309Snwhitehorn cache->i_len = i_len; 243217309Snwhitehorn 244217309Snwhitehorn return FALSE; 245217309Snwhitehorn} 246217309Snwhitehorn#endif /* USE_CACHING */ 247217309Snwhitehorn 248217309Snwhitehorn/* 249217309Snwhitehorn * Counts the number of bytes that make up complete wide-characters, up to byte 250217309Snwhitehorn * 'len'. If there is no locale set, simply return the original length. 251217309Snwhitehorn */ 252217309Snwhitehorn#ifdef USE_WIDE_CURSES 253217309Snwhitehornstatic int 254217309Snwhitehorndlg_count_wcbytes(const char *string, size_t len) 255217309Snwhitehorn{ 256217309Snwhitehorn int result; 257217309Snwhitehorn 258217309Snwhitehorn if (have_locale()) { 259217309Snwhitehorn static CACHE cache; 260217309Snwhitehorn 261217309Snwhitehorn load_cache(&cache, string); 262217309Snwhitehorn if (!same_cache1(&cache, string, len)) { 263217309Snwhitehorn while (len != 0) { 264217309Snwhitehorn int part = 0; 265217309Snwhitehorn size_t code = 0; 266217309Snwhitehorn const char *src = cache.string; 267217309Snwhitehorn mbstate_t state; 268217309Snwhitehorn char save = cache.string[len]; 269217309Snwhitehorn 270217309Snwhitehorn cache.string[len] = '\0'; 271217309Snwhitehorn memset(&state, 0, sizeof(state)); 272217309Snwhitehorn code = mbsrtowcs((wchar_t *) 0, &src, len, &state); 273217309Snwhitehorn cache.string[len] = save; 274217309Snwhitehorn if ((int) code >= 0) { 275217309Snwhitehorn break; 276217309Snwhitehorn } 277217309Snwhitehorn ++part; 278217309Snwhitehorn --len; 279217309Snwhitehorn } 280217309Snwhitehorn cache.i_len = len; 281217309Snwhitehorn save_cache(&cache, string); 282217309Snwhitehorn } 283217309Snwhitehorn result = (int) cache.i_len; 284217309Snwhitehorn } else { 285217309Snwhitehorn result = (int) len; 286217309Snwhitehorn } 287217309Snwhitehorn return result; 288217309Snwhitehorn} 289217309Snwhitehorn#endif /* USE_WIDE_CURSES */ 290217309Snwhitehorn 291217309Snwhitehorn/* 292217309Snwhitehorn * Counts the number of wide-characters in the string. 293217309Snwhitehorn */ 294217309Snwhitehornint 295217309Snwhitehorndlg_count_wchars(const char *string) 296217309Snwhitehorn{ 297217309Snwhitehorn int result; 298217309Snwhitehorn 299217309Snwhitehorn#ifdef USE_WIDE_CURSES 300217309Snwhitehorn if (have_locale()) { 301217309Snwhitehorn static CACHE cache; 302217309Snwhitehorn size_t len = strlen(string); 303217309Snwhitehorn 304217309Snwhitehorn load_cache(&cache, string); 305217309Snwhitehorn if (!same_cache1(&cache, string, len)) { 306217309Snwhitehorn const char *src = cache.string; 307217309Snwhitehorn mbstate_t state; 308217309Snwhitehorn int part = dlg_count_wcbytes(cache.string, len); 309217309Snwhitehorn char save = cache.string[part]; 310217309Snwhitehorn size_t code; 311217309Snwhitehorn wchar_t *temp = dlg_calloc(wchar_t, len + 1); 312217309Snwhitehorn 313217309Snwhitehorn cache.string[part] = '\0'; 314217309Snwhitehorn memset(&state, 0, sizeof(state)); 315217309Snwhitehorn code = mbsrtowcs(temp, &src, (size_t) part, &state); 316217309Snwhitehorn cache.i_len = ((int) code >= 0) ? wcslen(temp) : 0; 317217309Snwhitehorn cache.string[part] = save; 318217309Snwhitehorn free(temp); 319217309Snwhitehorn save_cache(&cache, string); 320217309Snwhitehorn } 321217309Snwhitehorn result = (int) cache.i_len; 322217309Snwhitehorn } else 323217309Snwhitehorn#endif /* USE_WIDE_CURSES */ 324217309Snwhitehorn { 325217309Snwhitehorn result = (int) strlen(string); 326217309Snwhitehorn } 327217309Snwhitehorn return result; 328217309Snwhitehorn} 329217309Snwhitehorn 330217309Snwhitehorn/* 331217309Snwhitehorn * Build an index of the wide-characters in the string, so we can easily tell 332217309Snwhitehorn * which byte-offset begins a given wide-character. 333217309Snwhitehorn */ 334217309Snwhitehornconst int * 335217309Snwhitehorndlg_index_wchars(const char *string) 336217309Snwhitehorn{ 337217309Snwhitehorn static CACHE cache; 338217309Snwhitehorn unsigned len = (unsigned) dlg_count_wchars(string); 339217309Snwhitehorn unsigned inx; 340217309Snwhitehorn 341217309Snwhitehorn load_cache(&cache, string); 342217309Snwhitehorn if (!same_cache2(&cache, string, len)) { 343217309Snwhitehorn const char *current = string; 344217309Snwhitehorn 345217309Snwhitehorn cache.list[0] = 0; 346217309Snwhitehorn for (inx = 1; inx <= len; ++inx) { 347217309Snwhitehorn#ifdef USE_WIDE_CURSES 348217309Snwhitehorn if (have_locale()) { 349217309Snwhitehorn mbstate_t state; 350217309Snwhitehorn int width; 351217309Snwhitehorn memset(&state, 0, sizeof(state)); 352217309Snwhitehorn width = (int) mbrlen(current, strlen(current), &state); 353217309Snwhitehorn if (width <= 0) 354217309Snwhitehorn width = 1; /* FIXME: what if we have a control-char? */ 355217309Snwhitehorn current += width; 356217309Snwhitehorn cache.list[inx] = cache.list[inx - 1] + width; 357217309Snwhitehorn } else 358217309Snwhitehorn#endif /* USE_WIDE_CURSES */ 359217309Snwhitehorn { 360217309Snwhitehorn (void) current; 361217309Snwhitehorn cache.list[inx] = (int) inx; 362217309Snwhitehorn } 363217309Snwhitehorn } 364217309Snwhitehorn save_cache(&cache, string); 365217309Snwhitehorn } 366217309Snwhitehorn return cache.list; 367217309Snwhitehorn} 368217309Snwhitehorn 369217309Snwhitehorn/* 370217309Snwhitehorn * Given the character-offset to find in the list, return the corresponding 371217309Snwhitehorn * array index. 372217309Snwhitehorn */ 373217309Snwhitehornint 374217309Snwhitehorndlg_find_index(const int *list, int limit, int to_find) 375217309Snwhitehorn{ 376217309Snwhitehorn int result; 377217309Snwhitehorn for (result = 0; result <= limit; ++result) { 378217309Snwhitehorn if (to_find == list[result] 379217309Snwhitehorn || result == limit 380217309Snwhitehorn || to_find < list[result + 1]) 381217309Snwhitehorn break; 382217309Snwhitehorn } 383217309Snwhitehorn return result; 384217309Snwhitehorn} 385217309Snwhitehorn 386217309Snwhitehorn/* 387217309Snwhitehorn * Build a list of the display-columns for the given string's characters. 388217309Snwhitehorn */ 389217309Snwhitehornconst int * 390217309Snwhitehorndlg_index_columns(const char *string) 391217309Snwhitehorn{ 392217309Snwhitehorn static CACHE cache; 393217309Snwhitehorn unsigned len = (unsigned) dlg_count_wchars(string); 394217309Snwhitehorn unsigned inx; 395217309Snwhitehorn 396217309Snwhitehorn load_cache(&cache, string); 397217309Snwhitehorn if (!same_cache2(&cache, string, len)) { 398217309Snwhitehorn cache.list[0] = 0; 399217309Snwhitehorn#ifdef USE_WIDE_CURSES 400217309Snwhitehorn if (have_locale()) { 401217309Snwhitehorn size_t num_bytes = strlen(string); 402217309Snwhitehorn const int *inx_wchars = dlg_index_wchars(string); 403217309Snwhitehorn mbstate_t state; 404217309Snwhitehorn 405217309Snwhitehorn for (inx = 0; inx < len; ++inx) { 406217309Snwhitehorn wchar_t temp[2]; 407217309Snwhitehorn size_t check; 408217309Snwhitehorn int result; 409217309Snwhitehorn 410217309Snwhitehorn if (string[inx_wchars[inx]] == TAB) { 411217309Snwhitehorn result = ((cache.list[inx] | 7) + 1) - cache.list[inx]; 412217309Snwhitehorn } else { 413217309Snwhitehorn memset(&state, 0, sizeof(state)); 414217309Snwhitehorn memset(temp, 0, sizeof(temp)); 415217309Snwhitehorn check = mbrtowc(temp, 416217309Snwhitehorn string + inx_wchars[inx], 417217309Snwhitehorn num_bytes - (size_t) inx_wchars[inx], 418217309Snwhitehorn &state); 419217309Snwhitehorn if ((int) check <= 0) { 420217309Snwhitehorn result = 1; 421217309Snwhitehorn } else { 422217309Snwhitehorn result = wcwidth(temp[0]); 423217309Snwhitehorn } 424217309Snwhitehorn if (result < 0) { 425220749Snwhitehorn const wchar_t *printable; 426220749Snwhitehorn cchar_t temp2, *temp2p = &temp2; 427220749Snwhitehorn setcchar(temp2p, temp, 0, 0, 0); 428220749Snwhitehorn printable = wunctrl(temp2p); 429217309Snwhitehorn result = printable ? (int) wcslen(printable) : 1; 430217309Snwhitehorn } 431217309Snwhitehorn } 432217309Snwhitehorn cache.list[inx + 1] = result; 433217309Snwhitehorn if (inx != 0) 434217309Snwhitehorn cache.list[inx + 1] += cache.list[inx]; 435217309Snwhitehorn } 436217309Snwhitehorn } else 437217309Snwhitehorn#endif /* USE_WIDE_CURSES */ 438217309Snwhitehorn { 439217309Snwhitehorn for (inx = 0; inx < len; ++inx) { 440217309Snwhitehorn chtype ch = UCH(string[inx]); 441217309Snwhitehorn 442217309Snwhitehorn if (ch == TAB) 443217309Snwhitehorn cache.list[inx + 1] = 444217309Snwhitehorn ((cache.list[inx] | 7) + 1) - cache.list[inx]; 445217309Snwhitehorn else if (isprint(ch)) 446217309Snwhitehorn cache.list[inx + 1] = 1; 447217309Snwhitehorn else { 448217309Snwhitehorn const char *printable; 449217309Snwhitehorn printable = unctrl(ch); 450217309Snwhitehorn cache.list[inx + 1] = (printable 451217309Snwhitehorn ? (int) strlen(printable) 452217309Snwhitehorn : 1); 453217309Snwhitehorn } 454217309Snwhitehorn if (inx != 0) 455217309Snwhitehorn cache.list[inx + 1] += cache.list[inx]; 456217309Snwhitehorn } 457217309Snwhitehorn } 458217309Snwhitehorn save_cache(&cache, string); 459217309Snwhitehorn } 460217309Snwhitehorn return cache.list; 461217309Snwhitehorn} 462217309Snwhitehorn 463217309Snwhitehorn/* 464217309Snwhitehorn * Returns the number of columns used for a string. That happens to be the 465217309Snwhitehorn * end-value of the cols[] array. 466217309Snwhitehorn */ 467217309Snwhitehornint 468217309Snwhitehorndlg_count_columns(const char *string) 469217309Snwhitehorn{ 470217309Snwhitehorn int result = 0; 471217309Snwhitehorn int limit = dlg_count_wchars(string); 472217309Snwhitehorn if (limit > 0) { 473217309Snwhitehorn const int *cols = dlg_index_columns(string); 474217309Snwhitehorn result = cols[limit]; 475217309Snwhitehorn } else { 476217309Snwhitehorn result = (int) strlen(string); 477217309Snwhitehorn } 478217309Snwhitehorn return result; 479217309Snwhitehorn} 480217309Snwhitehorn 481217309Snwhitehorn/* 482217309Snwhitehorn * Given a column limit, count the number of wide characters that can fit 483217309Snwhitehorn * into that limit. The offset is used to skip over a leading character 484217309Snwhitehorn * that was already written. 485217309Snwhitehorn */ 486217309Snwhitehornint 487217309Snwhitehorndlg_limit_columns(const char *string, int limit, int offset) 488217309Snwhitehorn{ 489217309Snwhitehorn const int *cols = dlg_index_columns(string); 490217309Snwhitehorn int result = dlg_count_wchars(string); 491217309Snwhitehorn 492217309Snwhitehorn while (result > 0 && (cols[result] - cols[offset]) > limit) 493217309Snwhitehorn --result; 494217309Snwhitehorn return result; 495217309Snwhitehorn} 496217309Snwhitehorn 497217309Snwhitehorn/* 498217309Snwhitehorn * Updates the string and character-offset, given various editing characters 499217309Snwhitehorn * or literal characters which are inserted at the character-offset. 500217309Snwhitehorn */ 501217309Snwhitehornbool 502217309Snwhitehorndlg_edit_string(char *string, int *chr_offset, int key, int fkey, bool force) 503217309Snwhitehorn{ 504217309Snwhitehorn int i; 505217309Snwhitehorn int len = (int) strlen(string); 506217309Snwhitehorn int limit = dlg_count_wchars(string); 507217309Snwhitehorn const int *indx = dlg_index_wchars(string); 508217309Snwhitehorn int offset = dlg_find_index(indx, limit, *chr_offset); 509217309Snwhitehorn int max_len = dlg_max_input(MAX_LEN); 510217309Snwhitehorn bool edit = TRUE; 511217309Snwhitehorn 512217309Snwhitehorn /* transform editing characters into equivalent function-keys */ 513217309Snwhitehorn if (!fkey) { 514217309Snwhitehorn fkey = TRUE; /* assume we transform */ 515217309Snwhitehorn switch (key) { 516217309Snwhitehorn case 0: 517217309Snwhitehorn break; 518217309Snwhitehorn case ESC: 519217309Snwhitehorn case TAB: 520217309Snwhitehorn fkey = FALSE; /* this is used for navigation */ 521217309Snwhitehorn break; 522217309Snwhitehorn default: 523217309Snwhitehorn fkey = FALSE; /* ...no, we did not transform */ 524217309Snwhitehorn break; 525217309Snwhitehorn } 526217309Snwhitehorn } 527217309Snwhitehorn 528217309Snwhitehorn if (fkey) { 529217309Snwhitehorn switch (key) { 530217309Snwhitehorn case 0: /* special case for loop entry */ 531217309Snwhitehorn edit = force; 532217309Snwhitehorn break; 533217309Snwhitehorn case DLGK_GRID_LEFT: 534217309Snwhitehorn if (*chr_offset) 535217309Snwhitehorn *chr_offset = indx[offset - 1]; 536217309Snwhitehorn break; 537217309Snwhitehorn case DLGK_GRID_RIGHT: 538217309Snwhitehorn if (offset < limit) 539217309Snwhitehorn *chr_offset = indx[offset + 1]; 540217309Snwhitehorn break; 541217309Snwhitehorn case DLGK_BEGIN: 542217309Snwhitehorn if (*chr_offset) 543217309Snwhitehorn *chr_offset = 0; 544217309Snwhitehorn break; 545217309Snwhitehorn case DLGK_FINAL: 546217309Snwhitehorn if (offset < limit) 547217309Snwhitehorn *chr_offset = indx[limit]; 548217309Snwhitehorn break; 549217309Snwhitehorn case DLGK_DELETE_LEFT: 550217309Snwhitehorn if (offset) { 551217309Snwhitehorn int gap = indx[offset] - indx[offset - 1]; 552217309Snwhitehorn *chr_offset = indx[offset - 1]; 553217309Snwhitehorn if (gap > 0) { 554217309Snwhitehorn for (i = *chr_offset; 555217309Snwhitehorn (string[i] = string[i + gap]) != '\0'; 556217309Snwhitehorn i++) { 557217309Snwhitehorn ; 558217309Snwhitehorn } 559217309Snwhitehorn } 560217309Snwhitehorn } 561217309Snwhitehorn break; 562217309Snwhitehorn case DLGK_DELETE_RIGHT: 563217309Snwhitehorn if (limit) { 564217309Snwhitehorn if (--limit == 0) { 565217309Snwhitehorn string[*chr_offset = 0] = '\0'; 566217309Snwhitehorn } else { 567217309Snwhitehorn int gap = ((offset <= limit) 568217309Snwhitehorn ? (indx[offset + 1] - indx[offset]) 569217309Snwhitehorn : 0); 570217309Snwhitehorn if (gap > 0) { 571217309Snwhitehorn for (i = indx[offset]; 572217309Snwhitehorn (string[i] = string[i + gap]) != '\0'; 573217309Snwhitehorn i++) { 574217309Snwhitehorn ; 575217309Snwhitehorn } 576217309Snwhitehorn } else if (offset > 0) { 577217309Snwhitehorn string[indx[offset - 1]] = '\0'; 578217309Snwhitehorn } 579217309Snwhitehorn if (*chr_offset > indx[limit]) 580217309Snwhitehorn *chr_offset = indx[limit]; 581217309Snwhitehorn } 582217309Snwhitehorn } 583217309Snwhitehorn break; 584217309Snwhitehorn case DLGK_DELETE_ALL: 585217309Snwhitehorn string[*chr_offset = 0] = '\0'; 586217309Snwhitehorn break; 587217309Snwhitehorn case DLGK_ENTER: 588217309Snwhitehorn edit = 0; 589217309Snwhitehorn break; 590217309Snwhitehorn#ifdef KEY_RESIZE 591217309Snwhitehorn case KEY_RESIZE: 592217309Snwhitehorn edit = 0; 593217309Snwhitehorn break; 594217309Snwhitehorn#endif 595217309Snwhitehorn case DLGK_GRID_UP: 596217309Snwhitehorn case DLGK_GRID_DOWN: 597217309Snwhitehorn case DLGK_FIELD_NEXT: 598217309Snwhitehorn case DLGK_FIELD_PREV: 599217309Snwhitehorn edit = 0; 600217309Snwhitehorn break; 601217309Snwhitehorn case ERR: 602217309Snwhitehorn edit = 0; 603217309Snwhitehorn break; 604217309Snwhitehorn default: 605217309Snwhitehorn beep(); 606217309Snwhitehorn break; 607217309Snwhitehorn } 608217309Snwhitehorn } else { 609217309Snwhitehorn if (key == ESC || key == ERR) { 610217309Snwhitehorn edit = 0; 611217309Snwhitehorn } else { 612217309Snwhitehorn if (len < max_len) { 613217309Snwhitehorn for (i = ++len; i > *chr_offset; i--) 614217309Snwhitehorn string[i] = string[i - 1]; 615217309Snwhitehorn string[*chr_offset] = (char) key; 616217309Snwhitehorn *chr_offset += 1; 617217309Snwhitehorn } else { 618217309Snwhitehorn (void) beep(); 619217309Snwhitehorn } 620217309Snwhitehorn } 621217309Snwhitehorn } 622217309Snwhitehorn return edit; 623217309Snwhitehorn} 624217309Snwhitehorn 625217309Snwhitehornstatic void 626217309Snwhitehorncompute_edit_offset(const char *string, 627217309Snwhitehorn int chr_offset, 628217309Snwhitehorn int x_last, 629217309Snwhitehorn int *p_dpy_column, 630217309Snwhitehorn int *p_scroll_amt) 631217309Snwhitehorn{ 632217309Snwhitehorn const int *cols = dlg_index_columns(string); 633217309Snwhitehorn const int *indx = dlg_index_wchars(string); 634217309Snwhitehorn int limit = dlg_count_wchars(string); 635217309Snwhitehorn int offset = dlg_find_index(indx, limit, chr_offset); 636217309Snwhitehorn int offset2; 637217309Snwhitehorn int dpy_column; 638217309Snwhitehorn int n; 639217309Snwhitehorn 640217309Snwhitehorn for (n = offset2 = 0; n <= offset; ++n) { 641217309Snwhitehorn if ((cols[offset] - cols[n]) < x_last 642217309Snwhitehorn && (offset == limit || (cols[offset + 1] - cols[n]) < x_last)) { 643217309Snwhitehorn offset2 = n; 644217309Snwhitehorn break; 645217309Snwhitehorn } 646217309Snwhitehorn } 647217309Snwhitehorn 648217309Snwhitehorn dpy_column = cols[offset] - cols[offset2]; 649217309Snwhitehorn 650217309Snwhitehorn if (p_dpy_column != 0) 651217309Snwhitehorn *p_dpy_column = dpy_column; 652217309Snwhitehorn if (p_scroll_amt != 0) 653217309Snwhitehorn *p_scroll_amt = offset2; 654217309Snwhitehorn} 655217309Snwhitehorn 656217309Snwhitehorn/* 657217309Snwhitehorn * Given the character-offset in the string, returns the display-offset where 658217309Snwhitehorn * we will position the cursor. 659217309Snwhitehorn */ 660217309Snwhitehornint 661217309Snwhitehorndlg_edit_offset(char *string, int chr_offset, int x_last) 662217309Snwhitehorn{ 663217309Snwhitehorn int result; 664217309Snwhitehorn 665217309Snwhitehorn compute_edit_offset(string, chr_offset, x_last, &result, 0); 666217309Snwhitehorn 667217309Snwhitehorn return result; 668217309Snwhitehorn} 669217309Snwhitehorn 670217309Snwhitehorn/* 671217309Snwhitehorn * Displays the string, shifted as necessary, to fit within the box and show 672217309Snwhitehorn * the current character-offset. 673217309Snwhitehorn */ 674217309Snwhitehornvoid 675217309Snwhitehorndlg_show_string(WINDOW *win, 676217309Snwhitehorn const char *string, /* string to display (may be multibyte) */ 677217309Snwhitehorn int chr_offset, /* character (not bytes) offset */ 678217309Snwhitehorn chtype attr, /* window-attributes */ 679217309Snwhitehorn int y_base, /* beginning row on screen */ 680217309Snwhitehorn int x_base, /* beginning column on screen */ 681217309Snwhitehorn int x_last, /* number of columns on screen */ 682217309Snwhitehorn bool hidden, /* if true, do not echo */ 683217309Snwhitehorn bool force) /* if true, force repaint */ 684217309Snwhitehorn{ 685217309Snwhitehorn x_last = MIN(x_last + x_base, getmaxx(win)) - x_base; 686217309Snwhitehorn 687217309Snwhitehorn if (hidden && !dialog_vars.insecure) { 688217309Snwhitehorn if (force) { 689217309Snwhitehorn (void) wmove(win, y_base, x_base); 690217309Snwhitehorn wrefresh(win); 691217309Snwhitehorn } 692217309Snwhitehorn } else { 693217309Snwhitehorn const int *cols = dlg_index_columns(string); 694217309Snwhitehorn const int *indx = dlg_index_wchars(string); 695217309Snwhitehorn int limit = dlg_count_wchars(string); 696217309Snwhitehorn 697217309Snwhitehorn int i, j, k; 698217309Snwhitehorn int input_x; 699217309Snwhitehorn int scrollamt; 700217309Snwhitehorn 701217309Snwhitehorn compute_edit_offset(string, chr_offset, x_last, &input_x, &scrollamt); 702217309Snwhitehorn 703217309Snwhitehorn wattrset(win, attr); 704217309Snwhitehorn (void) wmove(win, y_base, x_base); 705217309Snwhitehorn for (i = scrollamt, k = 0; i < limit && k < x_last; ++i) { 706217309Snwhitehorn int check = cols[i + 1] - cols[scrollamt]; 707217309Snwhitehorn if (check <= x_last) { 708217309Snwhitehorn for (j = indx[i]; j < indx[i + 1]; ++j) { 709217309Snwhitehorn chtype ch = UCH(string[j]); 710217309Snwhitehorn if (hidden && dialog_vars.insecure) { 711217309Snwhitehorn waddch(win, '*'); 712217309Snwhitehorn } else if (ch == TAB) { 713217309Snwhitehorn int count = cols[i + 1] - cols[i]; 714217309Snwhitehorn while (--count >= 0) 715217309Snwhitehorn waddch(win, ' '); 716217309Snwhitehorn } else { 717217309Snwhitehorn waddch(win, ch); 718217309Snwhitehorn } 719217309Snwhitehorn } 720217309Snwhitehorn k = check; 721217309Snwhitehorn } else { 722217309Snwhitehorn break; 723217309Snwhitehorn } 724217309Snwhitehorn } 725217309Snwhitehorn while (k++ < x_last) 726217309Snwhitehorn waddch(win, ' '); 727217309Snwhitehorn (void) wmove(win, y_base, x_base + input_x); 728217309Snwhitehorn wrefresh(win); 729217309Snwhitehorn } 730217309Snwhitehorn} 731217309Snwhitehorn 732217309Snwhitehorn#ifdef NO_LEAKS 733217309Snwhitehornvoid 734217309Snwhitehorn_dlg_inputstr_leaks(void) 735217309Snwhitehorn{ 736217309Snwhitehorn#if USE_CACHING 737217309Snwhitehorn while (cache_list != 0) { 738217309Snwhitehorn CACHE *next = cache_list->next; 739217309Snwhitehorn#ifdef HAVE_TSEARCH 740217309Snwhitehorn tdelete(cache_list, &sorted_cache, compare_cache); 741217309Snwhitehorn#endif 742217309Snwhitehorn if (cache_list->string != 0) 743217309Snwhitehorn free(cache_list->string); 744217309Snwhitehorn if (cache_list->list != 0) 745217309Snwhitehorn free(cache_list->list); 746217309Snwhitehorn free(cache_list); 747217309Snwhitehorn cache_list = next; 748217309Snwhitehorn } 749217309Snwhitehorn#endif /* USE_CACHING */ 750217309Snwhitehorn} 751217309Snwhitehorn#endif /* NO_LEAKS */ 752