1 /**************************************************************************** 2 * Copyright 2018-2019,2020 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 64 MODULE_ID("$Id: new_pair.c,v 1.19 2020/02/02 23:34:34 tom Exp $") 65 66 #if NCURSES_EXT_COLORS 67 68 #ifdef NEW_PAIR_DEBUG 69 70 static int 71 prev_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 83 static int 84 next_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 */ 99 static void 100 dumpit(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 133 static int 134 compare_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 143 static int 144 _nc_find_color_pair(SCREEN *sp, int fg, int bg) 145 { 146 colorpair_t find; 147 int result; 148 void *pp; 149 150 find.fg = fg; 151 find.bg = bg; 152 if (sp != 0 && 153 (pp = tfind(&find, &sp->_ordered_pairs, compare_data)) != 0) { 154 colorpair_t *temp = *(colorpair_t **) pp; 155 result = (int) (temp - sp->_color_pairs); 156 } else { 157 result = -1; 158 } 159 return result; 160 } 161 162 static void 163 delink_color_pair(SCREEN *sp, int pair) 164 { 165 colorpair_t *list = sp->_color_pairs; 166 int prev = list[pair].prev; 167 int next = list[pair].next; 168 169 /* delink this from its current location */ 170 if (list[prev].next == pair && 171 list[next].prev == pair) { 172 list[prev].next = next; 173 list[next].prev = prev; 174 dumpit(sp, pair, "delinked"); 175 } 176 } 177 178 /* 179 * Discard all nodes in the fast-index. 180 */ 181 NCURSES_EXPORT(void) 182 _nc_free_ordered_pairs(SCREEN *sp) 183 { 184 if (sp && sp->_ordered_pairs && sp->_pair_alloc) { 185 int n; 186 for (n = 0; n < sp->_pair_alloc; ++n) { 187 tdelete(&sp->_color_pairs[n], &sp->_ordered_pairs, compare_data); 188 } 189 } 190 } 191 192 /* 193 * Use this call to update the fast-index when modifying an entry in the color 194 * pair table. 195 */ 196 NCURSES_EXPORT(void) 197 _nc_reset_color_pair(SCREEN *sp, int pair, colorpair_t * next) 198 { 199 colorpair_t *last; 200 if (ValidPair(sp, pair)) { 201 ReservePairs(sp, pair); 202 last = &(sp->_color_pairs[pair]); 203 delink_color_pair(sp, pair); 204 if (last->mode > cpFREE && 205 (last->fg != next->fg || last->bg != next->bg)) { 206 /* remove the old entry from fast index */ 207 tdelete(last, &sp->_ordered_pairs, compare_data); 208 /* create a new entry in fast index */ 209 *last = *next; 210 tsearch(last, &sp->_ordered_pairs, compare_data); 211 } 212 } 213 } 214 215 /* 216 * Use this call to relink the newest pair to the front of the list, keeping 217 * "0" first. 218 */ 219 NCURSES_EXPORT(void) 220 _nc_set_color_pair(SCREEN *sp, int pair, int mode) 221 { 222 if (ValidPair(sp, pair)) { 223 colorpair_t *list = sp->_color_pairs; 224 dumpit(sp, pair, "SET_PAIR"); 225 list[0].mode = cpKEEP; 226 if (list[pair].mode <= cpFREE) 227 sp->_pairs_used++; 228 list[pair].mode = mode; 229 if (list[0].next != pair) { 230 /* link it at the front of the list */ 231 list[pair].next = list[0].next; 232 list[list[pair].next].prev = pair; 233 list[pair].prev = 0; 234 list[0].next = pair; 235 } 236 dumpit(sp, pair, "...after"); 237 } 238 } 239 240 /* 241 * If we reallocate the color-pair array, we have to adjust the fast-index. 242 */ 243 NCURSES_EXPORT(void) 244 _nc_copy_pairs(SCREEN *sp, colorpair_t * target, colorpair_t * source, int length) 245 { 246 int n; 247 for (n = 0; n < length; ++n) { 248 void *find = tfind(source + n, &sp->_ordered_pairs, compare_data); 249 if (find != 0) { 250 tdelete(source + n, &sp->_ordered_pairs, compare_data); 251 tsearch(target + n, &sp->_ordered_pairs, compare_data); 252 } 253 } 254 } 255 256 NCURSES_EXPORT(int) 257 NCURSES_SP_NAME(alloc_pair) (NCURSES_SP_DCLx int fg, int bg) 258 { 259 int pair; 260 261 T((T_CALLED("alloc_pair(%d,%d)"), fg, bg)); 262 if (SP_PARM == 0) { 263 pair = -1; 264 } else if ((pair = _nc_find_color_pair(SP_PARM, fg, bg)) < 0) { 265 /* 266 * Check if all of the slots have been used. If not, find one and 267 * use that. 268 */ 269 if (SP_PARM->_pairs_used + 1 < SP_PARM->_pair_limit) { 270 bool found = FALSE; 271 int hint = SP_PARM->_recent_pair; 272 273 /* 274 * The linear search is done to allow mixing calls to init_pair() 275 * and alloc_pair(). The former can make gaps... 276 */ 277 for (pair = hint + 1; pair < SP_PARM->_pair_alloc; pair++) { 278 if (SP_PARM->_color_pairs[pair].mode == cpFREE) { 279 T(("found gap %d", pair)); 280 found = TRUE; 281 break; 282 } 283 } 284 if (!found && (SP_PARM->_pair_alloc < SP_PARM->_pair_limit)) { 285 pair = SP_PARM->_pair_alloc; 286 ReservePairs(SP_PARM, pair); 287 if (SP_PARM->_color_pairs == 0) { 288 pair = -1; 289 } else { 290 found = TRUE; 291 } 292 } 293 if (!found) { 294 for (pair = 1; pair <= hint; pair++) { 295 if (SP_PARM->_color_pairs[pair].mode == cpFREE) { 296 T(("found gap %d", pair)); 297 found = TRUE; 298 break; 299 } 300 } 301 } 302 if (found) { 303 SP_PARM->_recent_pair = pair; 304 } else { 305 pair = ERR; 306 } 307 } else { 308 /* reuse the oldest one */ 309 pair = SP_PARM->_color_pairs[0].prev; 310 T(("reusing %d", pair)); 311 } 312 313 if (_nc_init_pair(SP_PARM, pair, fg, bg) == ERR) 314 pair = ERR; 315 } 316 returnCode(pair); 317 } 318 319 NCURSES_EXPORT(int) 320 NCURSES_SP_NAME(find_pair) (NCURSES_SP_DCLx int fg, int bg) 321 { 322 int pair; 323 324 T((T_CALLED("find_pair(%d,%d)"), fg, bg)); 325 pair = _nc_find_color_pair(SP_PARM, fg, bg); 326 returnCode(pair); 327 } 328 329 NCURSES_EXPORT(int) 330 NCURSES_SP_NAME(free_pair) (NCURSES_SP_DCLx int pair) 331 { 332 int result = ERR; 333 T((T_CALLED("free_pair(%d)"), pair)); 334 if (ValidPair(SP_PARM, pair) && pair < SP_PARM->_pair_alloc) { 335 colorpair_t *cp = &(SP_PARM->_color_pairs[pair]); 336 if (pair != 0) { 337 _nc_change_pair(SP_PARM, pair); 338 delink_color_pair(SP_PARM, pair); 339 tdelete(cp, &SP_PARM->_ordered_pairs, compare_data); 340 cp->mode = cpFREE; 341 result = OK; 342 SP_PARM->_pairs_used--; 343 } 344 } 345 returnCode(result); 346 } 347 348 #if NCURSES_SP_FUNCS 349 NCURSES_EXPORT(int) 350 alloc_pair(int f, int b) 351 { 352 return NCURSES_SP_NAME(alloc_pair) (CURRENT_SCREEN, f, b); 353 } 354 355 NCURSES_EXPORT(int) 356 find_pair(int f, int b) 357 { 358 return NCURSES_SP_NAME(find_pair) (CURRENT_SCREEN, f, b); 359 } 360 361 NCURSES_EXPORT(int) 362 free_pair(int pair) 363 { 364 return NCURSES_SP_NAME(free_pair) (CURRENT_SCREEN, pair); 365 } 366 #endif 367 368 #if NO_LEAKS 369 NCURSES_EXPORT(void) 370 _nc_new_pair_leaks(SCREEN *sp) 371 { 372 if (sp->_color_pairs) { 373 while (sp->_color_pairs[0].next) { 374 free_pair(sp->_color_pairs[0].next); 375 } 376 } 377 } 378 #endif 379 380 #else 381 void _nc_new_pair(void); 382 void 383 _nc_new_pair(void) 384 { 385 } 386 #endif /* NCURSES_EXT_COLORS */ 387