ncurses 6.0 - patch 20170401
[ncurses.git] / ncurses / base / new_pair.c
1 /****************************************************************************
2  * Copyright (c) 2017 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 USE_NEW_PAIR
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.10 2017/03/28 09:14:15 tom Exp $")
64
65 #if USE_NEW_PAIR
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     sprintf(p, "%s", tag);
106     p += strlen(p);
107     for (n = 0; n < sp->_pair_limit; ++n) {
108         if (list[n].mode != cpFREE) {
109             sprintf(p, " %d%c(%d,%d)",
110                     n, n == pair ? '@' : ':', list[n].next, list[n].prev);
111             p += strlen(p);
112         }
113     }
114     T(("(%d/%d) %ld - %s",
115        next_len(sp, 0),
116        prev_len(sp, 0),
117        strlen(bigbuf), bigbuf));
118
119     if (next_len(sp, 0) != prev_len(sp, 0)) {
120         endwin();
121         exit(1);
122     }
123 }
124 #else
125 #define dumpit(sp, pair, tag)   /* nothing */
126 #endif
127
128 static int
129 compare_data(const void *a, const void *b)
130 {
131     const colorpair_t *p = (const colorpair_t *) a;
132     const colorpair_t *q = (const colorpair_t *) b;
133     return ((p->fg == q->fg)
134             ? (p->bg - q->bg)
135             : (p->fg - q->fg));
136 }
137
138 static int
139 _nc_find_color_pair(SCREEN *sp, int fg, int bg)
140 {
141     colorpair_t find;
142     int result;
143     void *pp;
144
145     find.fg = fg;
146     find.bg = bg;
147     if (sp != 0 &&
148         (pp = tfind(&find, &sp->_ordered_pairs, compare_data)) != 0) {
149         colorpair_t *temp = *(colorpair_t **) pp;
150         result = (int) (temp - sp->_color_pairs);
151     } else {
152         result = -1;
153     }
154     return result;
155 }
156
157 static void
158 delink_color_pair(SCREEN *sp, int pair)
159 {
160     colorpair_t *list = sp->_color_pairs;
161     int prev = list[pair].prev;
162     int next = list[pair].next;
163
164     /* delink this from its current location */
165     if (list[prev].next == pair &&
166         list[next].prev == pair) {
167         list[prev].next = next;
168         list[next].prev = prev;
169         dumpit(sp, pair, "delinked");
170     }
171 }
172
173 /*
174  * Use this call to update the fast-index when modifying an entry in the color
175  * pair table.
176  */
177 NCURSES_EXPORT(void)
178 _nc_reset_color_pair(SCREEN *sp, int pair, colorpair_t * next)
179 {
180     if (ValidPair(sp, pair)) {
181         colorpair_t *last = &(sp->_color_pairs[pair]);
182         delink_color_pair(sp, pair);
183         if (last->mode > cpFREE &&
184             (last->fg != next->fg || last->bg != next->bg)) {
185             /* remove the old entry from fast index */
186             tdelete(last, &sp->_ordered_pairs, compare_data);
187             /* create a new entry in fast index */
188             *last = *next;
189             tsearch(last, &sp->_ordered_pairs, compare_data);
190         }
191     }
192 }
193
194 /*
195  * Use this call to relink the newest pair to the front of the list, keeping
196  * "0" first.
197  */
198 NCURSES_EXPORT(void)
199 _nc_set_color_pair(SCREEN *sp, int pair, int mode)
200 {
201     if (ValidPair(sp, pair)) {
202         colorpair_t *list = sp->_color_pairs;
203         dumpit(sp, pair, "SET_PAIR");
204         list[0].mode = cpKEEP;
205         if (list[pair].mode <= cpFREE)
206             sp->_pairs_used++;
207         list[pair].mode = mode;
208         if (list[0].next != pair) {
209             /* link it at the front of the list */
210             list[pair].next = list[0].next;
211             list[list[pair].next].prev = pair;
212             list[pair].prev = 0;
213             list[0].next = pair;
214         }
215         dumpit(sp, pair, "...after");
216     }
217 }
218
219 NCURSES_EXPORT(int)
220 NCURSES_SP_NAME(alloc_pair) (NCURSES_SP_DCLx int fg, int bg)
221 {
222     int pair;
223
224     T((T_CALLED("alloc_pair(%d,%d)"), fg, bg));
225     if (SP_PARM == 0) {
226         pair = -1;
227     } else if ((pair = _nc_find_color_pair(SP_PARM, fg, bg)) < 0) {
228         /*
229          * Check if all of the slots have been used.  If not, find one and
230          * use that.
231          */
232         if (SP_PARM->_pairs_used + 1 < SP_PARM->_pair_limit) {
233             bool found = FALSE;
234             int hint = SP_PARM->_recent_pair;
235
236             /*
237              * The linear search is done to allow mixing calls to init_pair()
238              * and alloc_pair().  The former can make gaps...
239              */
240             for (pair = hint + 1; pair < SP_PARM->_pair_limit; pair++) {
241                 if (SP_PARM->_color_pairs[pair].mode == cpFREE) {
242                     T(("found gap %d", pair));
243                     found = TRUE;
244                     break;
245                 }
246             }
247             if (!found) {
248                 for (pair = 1; pair <= hint; pair++) {
249                     if (SP_PARM->_color_pairs[pair].mode == cpFREE) {
250                         T(("found gap %d", pair));
251                         found = TRUE;
252                         break;
253                     }
254                 }
255             }
256             if (found) {
257                 SP_PARM->_recent_pair = pair;
258             } else {
259                 pair = ERR;
260             }
261         } else {
262             /* reuse the oldest one */
263             pair = SP_PARM->_color_pairs[0].prev;
264             T(("reusing %d", pair));
265         }
266
267         if (_nc_init_pair(SP_PARM, pair, fg, bg) == ERR)
268             pair = ERR;
269     }
270     returnCode(pair);
271 }
272
273 NCURSES_EXPORT(int)
274 NCURSES_SP_NAME(find_pair) (NCURSES_SP_DCLx int fg, int bg)
275 {
276     int pair;
277
278     T((T_CALLED("find_pair(%d,%d)"), fg, bg));
279     pair = _nc_find_color_pair(SP_PARM, fg, bg);
280     returnCode(pair);
281 }
282
283 NCURSES_EXPORT(int)
284 NCURSES_SP_NAME(free_pair) (NCURSES_SP_DCLx int pair)
285 {
286     int result = ERR;
287     T((T_CALLED("free_pair(%d)"), pair));
288     if (ValidPair(SP_PARM, pair)) {
289         colorpair_t *cp = &(SP_PARM->_color_pairs[pair]);
290         if (pair != 0) {
291             _nc_change_pair(SP_PARM, pair);
292             delink_color_pair(SP_PARM, pair);
293             tdelete(cp, &SP_PARM->_ordered_pairs, compare_data);
294             cp->mode = cpFREE;
295             result = OK;
296             SP_PARM->_pairs_used--;
297         }
298     }
299     returnCode(result);
300 }
301
302 #if NCURSES_SP_FUNCS
303 NCURSES_EXPORT(int)
304 alloc_pair(int f, int b)
305 {
306     return NCURSES_SP_NAME(alloc_pair) (CURRENT_SCREEN, f, b);
307 }
308
309 NCURSES_EXPORT(int)
310 find_pair(int f, int b)
311 {
312     return NCURSES_SP_NAME(find_pair) (CURRENT_SCREEN, f, b);
313 }
314
315 NCURSES_EXPORT(int)
316 free_pair(int pair)
317 {
318     return NCURSES_SP_NAME(free_pair) (CURRENT_SCREEN, pair);
319 }
320 #endif
321
322 #if NO_LEAKS
323 NCURSES_EXPORT(void)
324 _nc_new_pair_leaks(SCREEN *sp)
325 {
326     if (sp->_color_pairs) {
327         while (sp->_color_pairs[0].next) {
328             free_pair(sp->_color_pairs[0].next);
329         }
330     }
331 }
332 #endif
333
334 #else
335 void _nc_new_pair(void);
336 void
337 _nc_new_pair(void)
338 {
339 }
340 #endif /* USE_NEW_PAIR */