1/**************************************************************************** 2 * Copyright 2018-2020,2021 Thomas E. Dickey * 3 * Copyright 2017 Free Software Foundation, Inc. * 4 * * 5 * Permission is hereby granted, free of charge, to any person obtaining a * 6 * copy of this software and associated documentation files (the * 7 * "Software"), to deal in the Software without restriction, including * 8 * without limitation the rights to use, copy, modify, merge, publish, * 9 * distribute, distribute with modifications, sublicense, and/or sell * 10 * copies of the Software, and to permit persons to whom the Software is * 11 * furnished to do so, subject to the following conditions: * 12 * * 13 * The above copyright notice and this permission notice shall be included * 14 * in all copies or substantial portions of the Software. * 15 * * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 19 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 23 * * 24 * Except as contained in this notice, the name(s) of the above copyright * 25 * holders shall not be used in advertising or otherwise to promote the * 26 * sale, use or other dealings in this Software without prior written * 27 * authorization. * 28 ****************************************************************************/ 29 30/**************************************************************************** 31 * Author: Thomas E. Dickey * 32 ****************************************************************************/ 33 34/* new_pair.c 35 * 36 * New color-pair functions, alloc_pair and free_pair 37 */ 38 39#define NEW_PAIR_INTERNAL 1 40#include <curses.priv.h> 41 42#ifndef CUR 43#define CUR SP_TERMTYPE 44#endif 45 46#ifdef USE_TERM_DRIVER 47#define MaxColors InfoOf(SP_PARM).maxcolors 48#else 49#define MaxColors max_colors 50#endif 51 52#if NCURSES_EXT_COLORS 53 54/* fix redefinition versys tic.h */ 55#undef entry 56#define entry my_entry 57#undef ENTRY 58#define ENTRY my_ENTRY 59 60#include <search.h> 61 62#endif 63 64MODULE_ID("$Id: new_pair.c,v 1.21 2021/02/14 00:17:09 tom Exp $") 65 66#if NCURSES_EXT_COLORS 67 68#ifdef NEW_PAIR_DEBUG 69 70static int 71prev_len(SCREEN *sp, int pair) 72{ 73 int result = 1; 74 int base = pair; 75 colorpair_t *list = sp->_color_pairs; 76 while (list[pair].prev != base) { 77 result++; 78 pair = list[pair].prev; 79 } 80 return result; 81} 82 83static int 84next_len(SCREEN *sp, int pair) 85{ 86 int result = 1; 87 int base = pair; 88 colorpair_t *list = sp->_color_pairs; 89 while (list[pair].next != base) { 90 result++; 91 pair = list[pair].next; 92 } 93 return result; 94} 95 96/* 97 * Trace the contents of LRU color-pairs. 98 */ 99static void 100dumpit(SCREEN *sp, int pair, const char *tag) 101{ 102 colorpair_t *list = sp->_color_pairs; 103 char bigbuf[256 * 20]; 104 char *p = bigbuf; 105 int n; 106 size_t have = sizeof(bigbuf); 107 108 _nc_STRCPY(p, tag, have); 109 for (n = 0; n < sp->_pair_limit; ++n) { 110 if (list[n].mode != cpFREE) { 111 p += strlen(p); 112 if ((size_t) (p - bigbuf) + 50 > have) 113 break; 114 _nc_SPRINTF(p, _nc_SLIMIT(have - (p - bigbuf)) 115 " %d%c(%d,%d)", 116 n, n == pair ? '@' : ':', list[n].next, list[n].prev); 117 } 118 } 119 T(("(%d/%d) %ld - %s", 120 next_len(sp, 0), 121 prev_len(sp, 0), 122 strlen(bigbuf), bigbuf)); 123 124 if (next_len(sp, 0) != prev_len(sp, 0)) { 125 endwin(); 126 ExitProgram(EXIT_FAILURE); 127 } 128} 129#else 130#define dumpit(sp, pair, tag) /* nothing */ 131#endif 132 133static int 134compare_data(const void *a, const void *b) 135{ 136 const colorpair_t *p = (const colorpair_t *) a; 137 const colorpair_t *q = (const colorpair_t *) b; 138 return ((p->fg == q->fg) 139 ? (p->bg - q->bg) 140 : (p->fg - q->fg)); 141} 142 143static int 144_nc_find_color_pair(SCREEN *sp, int fg, int bg) 145{ 146 colorpair_t find; 147 int result = -1; 148 149 find.fg = fg; 150 find.bg = bg; 151 if (sp != 0) { 152 void *pp; 153 if ((pp = tfind(&find, &sp->_ordered_pairs, compare_data)) != 0) { 154 colorpair_t *temp = *(colorpair_t **) pp; 155 result = (int) (temp - sp->_color_pairs); 156 } 157 } 158 return result; 159} 160 161static void 162delink_color_pair(SCREEN *sp, int pair) 163{ 164 colorpair_t *list = sp->_color_pairs; 165 int prev = list[pair].prev; 166 int next = list[pair].next; 167 168 /* delink this from its current location */ 169 if (list[prev].next == pair && 170 list[next].prev == pair) { 171 list[prev].next = next; 172 list[next].prev = prev; 173 dumpit(sp, pair, "delinked"); 174 } 175} 176 177/* 178 * Discard all nodes in the fast-index. 179 */ 180NCURSES_EXPORT(void) 181_nc_free_ordered_pairs(SCREEN *sp) 182{ 183 if (sp && sp->_ordered_pairs && sp->_pair_alloc) { 184 int n; 185 for (n = 0; n < sp->_pair_alloc; ++n) { 186 tdelete(&sp->_color_pairs[n], &sp->_ordered_pairs, compare_data); 187 } 188 } 189} 190 191/* 192 * Use this call to update the fast-index when modifying an entry in the color 193 * pair table. 194 */ 195NCURSES_EXPORT(void) 196_nc_reset_color_pair(SCREEN *sp, int pair, colorpair_t * next) 197{ 198 colorpair_t *last; 199 200 if (ValidPair(sp, pair)) { 201 bool used; 202 203 ReservePairs(sp, pair); 204 last = &(sp->_color_pairs[pair]); 205 delink_color_pair(sp, pair); 206 if (last->mode > cpFREE && 207 (last->fg != next->fg || last->bg != next->bg)) { 208 /* remove the old entry from fast index */ 209 tdelete(last, &sp->_ordered_pairs, compare_data); 210 used = FALSE; 211 } else { 212 used = (last->mode != cpFREE); 213 } 214 if (!used) { 215 /* create a new entry in fast index */ 216 *last = *next; 217 tsearch(last, &sp->_ordered_pairs, compare_data); 218 } 219 } 220} 221 222/* 223 * Use this call to relink the newest pair to the front of the list, keeping 224 * "0" first. 225 */ 226NCURSES_EXPORT(void) 227_nc_set_color_pair(SCREEN *sp, int pair, int mode) 228{ 229 if (ValidPair(sp, pair)) { 230 colorpair_t *list = sp->_color_pairs; 231 dumpit(sp, pair, "SET_PAIR"); 232 list[0].mode = cpKEEP; 233 if (list[pair].mode <= cpFREE) 234 sp->_pairs_used++; 235 list[pair].mode = mode; 236 if (list[0].next != pair) { 237 /* link it at the front of the list */ 238 list[pair].next = list[0].next; 239 list[list[pair].next].prev = pair; 240 list[pair].prev = 0; 241 list[0].next = pair; 242 } 243 dumpit(sp, pair, "...after"); 244 } 245} 246 247/* 248 * If we reallocate the color-pair array, we have to adjust the fast-index. 249 */ 250NCURSES_EXPORT(void) 251_nc_copy_pairs(SCREEN *sp, colorpair_t * target, colorpair_t * source, int length) 252{ 253 int n; 254 for (n = 0; n < length; ++n) { 255 void *find = tfind(source + n, &sp->_ordered_pairs, compare_data); 256 if (find != 0) { 257 tdelete(source + n, &sp->_ordered_pairs, compare_data); 258 tsearch(target + n, &sp->_ordered_pairs, compare_data); 259 } 260 } 261} 262 263NCURSES_EXPORT(int) 264NCURSES_SP_NAME(alloc_pair) (NCURSES_SP_DCLx int fg, int bg) 265{ 266 int pair; 267 268 T((T_CALLED("alloc_pair(%d,%d)"), fg, bg)); 269 if (SP_PARM == 0) { 270 pair = -1; 271 } else if ((pair = _nc_find_color_pair(SP_PARM, fg, bg)) < 0) { 272 /* 273 * Check if all of the slots have been used. If not, find one and 274 * use that. 275 */ 276 if (SP_PARM->_pairs_used + 1 < SP_PARM->_pair_limit) { 277 bool found = FALSE; 278 int hint = SP_PARM->_recent_pair; 279 280 /* 281 * The linear search is done to allow mixing calls to init_pair() 282 * and alloc_pair(). The former can make gaps... 283 */ 284 for (pair = hint + 1; pair < SP_PARM->_pair_alloc; pair++) { 285 if (SP_PARM->_color_pairs[pair].mode == cpFREE) { 286 T(("found gap %d", pair)); 287 found = TRUE; 288 break; 289 } 290 } 291 if (!found && (SP_PARM->_pair_alloc < SP_PARM->_pair_limit)) { 292 pair = SP_PARM->_pair_alloc; 293 ReservePairs(SP_PARM, pair); 294 if (SP_PARM->_color_pairs == 0) { 295 pair = -1; 296 } else { 297 found = TRUE; 298 } 299 } 300 if (!found) { 301 for (pair = 1; pair <= hint; pair++) { 302 if (SP_PARM->_color_pairs[pair].mode == cpFREE) { 303 T(("found gap %d", pair)); 304 found = TRUE; 305 break; 306 } 307 } 308 } 309 if (found) { 310 SP_PARM->_recent_pair = pair; 311 } else { 312 pair = ERR; 313 } 314 } else { 315 /* reuse the oldest one */ 316 pair = SP_PARM->_color_pairs[0].prev; 317 T(("reusing %d", pair)); 318 } 319 320 if (_nc_init_pair(SP_PARM, pair, fg, bg) == ERR) 321 pair = ERR; 322 } 323 returnCode(pair); 324} 325 326NCURSES_EXPORT(int) 327NCURSES_SP_NAME(find_pair) (NCURSES_SP_DCLx int fg, int bg) 328{ 329 int pair; 330 331 T((T_CALLED("find_pair(%d,%d)"), fg, bg)); 332 pair = _nc_find_color_pair(SP_PARM, fg, bg); 333 returnCode(pair); 334} 335 336NCURSES_EXPORT(int) 337NCURSES_SP_NAME(free_pair) (NCURSES_SP_DCLx int pair) 338{ 339 int result = ERR; 340 T((T_CALLED("free_pair(%d)"), pair)); 341 if (ValidPair(SP_PARM, pair) && pair < SP_PARM->_pair_alloc) { 342 colorpair_t *cp = &(SP_PARM->_color_pairs[pair]); 343 if (pair != 0) { 344 _nc_change_pair(SP_PARM, pair); 345 delink_color_pair(SP_PARM, pair); 346 tdelete(cp, &SP_PARM->_ordered_pairs, compare_data); 347 cp->mode = cpFREE; 348 result = OK; 349 SP_PARM->_pairs_used--; 350 } 351 } 352 returnCode(result); 353} 354 355#if NCURSES_SP_FUNCS 356NCURSES_EXPORT(int) 357alloc_pair(int f, int b) 358{ 359 return NCURSES_SP_NAME(alloc_pair) (CURRENT_SCREEN, f, b); 360} 361 362NCURSES_EXPORT(int) 363find_pair(int f, int b) 364{ 365 return NCURSES_SP_NAME(find_pair) (CURRENT_SCREEN, f, b); 366} 367 368NCURSES_EXPORT(int) 369free_pair(int pair) 370{ 371 return NCURSES_SP_NAME(free_pair) (CURRENT_SCREEN, pair); 372} 373#endif 374 375#if NO_LEAKS 376NCURSES_EXPORT(void) 377_nc_new_pair_leaks(SCREEN *sp) 378{ 379 if (sp->_color_pairs) { 380 while (sp->_color_pairs[0].next) { 381 free_pair(sp->_color_pairs[0].next); 382 } 383 } 384} 385#endif 386 387#else 388void _nc_new_pair(void); 389void 390_nc_new_pair(void) 391{ 392} 393#endif /* NCURSES_EXT_COLORS */ 394