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