ncurses 6.0 - patch 20170812
[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.14 2017/08/11 18:20:22 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         ExitProgram(EXIT_FAILURE);
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  * Discard all nodes in the fast-index.
175  */
176 NCURSES_EXPORT(void)
177 _nc_free_ordered_pairs(SCREEN *sp)
178 {
179     if (sp && sp->_ordered_pairs && sp->_pair_alloc) {
180         int n;
181         for (n = 0; n < sp->_pair_alloc; ++n) {
182             tdelete(&sp->_color_pairs[n], &sp->_ordered_pairs, compare_data);
183         }
184     }
185 }
186
187 /*
188  * Use this call to update the fast-index when modifying an entry in the color
189  * pair table.
190  */
191 NCURSES_EXPORT(void)
192 _nc_reset_color_pair(SCREEN *sp, int pair, colorpair_t * next)
193 {
194     colorpair_t *last;
195     if (ValidPair(sp, pair)) {
196         last = _nc_reserve_pairs(sp, pair);
197         delink_color_pair(sp, pair);
198         if (last->mode > cpFREE &&
199             (last->fg != next->fg || last->bg != next->bg)) {
200             /* remove the old entry from fast index */
201             tdelete(last, &sp->_ordered_pairs, compare_data);
202             /* create a new entry in fast index */
203             *last = *next;
204             tsearch(last, &sp->_ordered_pairs, compare_data);
205         }
206     }
207 }
208
209 /*
210  * Use this call to relink the newest pair to the front of the list, keeping
211  * "0" first.
212  */
213 NCURSES_EXPORT(void)
214 _nc_set_color_pair(SCREEN *sp, int pair, int mode)
215 {
216     if (ValidPair(sp, pair)) {
217         colorpair_t *list = sp->_color_pairs;
218         dumpit(sp, pair, "SET_PAIR");
219         list[0].mode = cpKEEP;
220         if (list[pair].mode <= cpFREE)
221             sp->_pairs_used++;
222         list[pair].mode = mode;
223         if (list[0].next != pair) {
224             /* link it at the front of the list */
225             list[pair].next = list[0].next;
226             list[list[pair].next].prev = pair;
227             list[pair].prev = 0;
228             list[0].next = pair;
229         }
230         dumpit(sp, pair, "...after");
231     }
232 }
233
234 /*
235  * If we reallocate the color-pair array, we have to adjust the fast-index.
236  */
237 NCURSES_EXPORT(void)
238 _nc_copy_pairs(SCREEN *sp, colorpair_t * target, colorpair_t * source, int length)
239 {
240     int n;
241     for (n = 0; n < length; ++n) {
242         void *find = tfind(source + n, &sp->_ordered_pairs, compare_data);
243         if (find != 0) {
244             tdelete(source + n, &sp->_ordered_pairs, compare_data);
245             tsearch(target + n, &sp->_ordered_pairs, compare_data);
246         }
247     }
248 }
249
250 NCURSES_EXPORT(int)
251 NCURSES_SP_NAME(alloc_pair) (NCURSES_SP_DCLx int fg, int bg)
252 {
253     int pair;
254
255     T((T_CALLED("alloc_pair(%d,%d)"), fg, bg));
256     if (SP_PARM == 0) {
257         pair = -1;
258     } else if ((pair = _nc_find_color_pair(SP_PARM, fg, bg)) < 0) {
259         /*
260          * Check if all of the slots have been used.  If not, find one and
261          * use that.
262          */
263         if (SP_PARM->_pairs_used + 1 < SP_PARM->_pair_limit) {
264             bool found = FALSE;
265             int hint = SP_PARM->_recent_pair;
266
267             /*
268              * The linear search is done to allow mixing calls to init_pair()
269              * and alloc_pair().  The former can make gaps...
270              */
271             for (pair = hint + 1; pair < SP_PARM->_pair_alloc; pair++) {
272                 if (SP_PARM->_color_pairs[pair].mode == cpFREE) {
273                     T(("found gap %d", pair));
274                     found = TRUE;
275                     break;
276                 }
277             }
278             if (!found && (SP_PARM->_pair_alloc < SP_PARM->_pair_limit)) {
279                 pair = SP_PARM->_pair_alloc;
280                 if (_nc_reserve_pairs(sp, pair) == 0) {
281                     pair = -1;
282                 } else {
283                     found = TRUE;
284                 }
285             }
286             if (!found) {
287                 for (pair = 1; pair <= hint; pair++) {
288                     if (SP_PARM->_color_pairs[pair].mode == cpFREE) {
289                         T(("found gap %d", pair));
290                         found = TRUE;
291                         break;
292                     }
293                 }
294             }
295             if (found) {
296                 SP_PARM->_recent_pair = pair;
297             } else {
298                 pair = ERR;
299             }
300         } else {
301             /* reuse the oldest one */
302             pair = SP_PARM->_color_pairs[0].prev;
303             T(("reusing %d", pair));
304         }
305
306         if (_nc_init_pair(SP_PARM, pair, fg, bg) == ERR)
307             pair = ERR;
308     }
309     returnCode(pair);
310 }
311
312 NCURSES_EXPORT(int)
313 NCURSES_SP_NAME(find_pair) (NCURSES_SP_DCLx int fg, int bg)
314 {
315     int pair;
316
317     T((T_CALLED("find_pair(%d,%d)"), fg, bg));
318     pair = _nc_find_color_pair(SP_PARM, fg, bg);
319     returnCode(pair);
320 }
321
322 NCURSES_EXPORT(int)
323 NCURSES_SP_NAME(free_pair) (NCURSES_SP_DCLx int pair)
324 {
325     int result = ERR;
326     T((T_CALLED("free_pair(%d)"), pair));
327     if (ValidPair(SP_PARM, pair) && pair < SP_PARM->_pair_alloc) {
328         colorpair_t *cp = &(SP_PARM->_color_pairs[pair]);
329         if (pair != 0) {
330             _nc_change_pair(SP_PARM, pair);
331             delink_color_pair(SP_PARM, pair);
332             tdelete(cp, &SP_PARM->_ordered_pairs, compare_data);
333             cp->mode = cpFREE;
334             result = OK;
335             SP_PARM->_pairs_used--;
336         }
337     }
338     returnCode(result);
339 }
340
341 #if NCURSES_SP_FUNCS
342 NCURSES_EXPORT(int)
343 alloc_pair(int f, int b)
344 {
345     return NCURSES_SP_NAME(alloc_pair) (CURRENT_SCREEN, f, b);
346 }
347
348 NCURSES_EXPORT(int)
349 find_pair(int f, int b)
350 {
351     return NCURSES_SP_NAME(find_pair) (CURRENT_SCREEN, f, b);
352 }
353
354 NCURSES_EXPORT(int)
355 free_pair(int pair)
356 {
357     return NCURSES_SP_NAME(free_pair) (CURRENT_SCREEN, pair);
358 }
359 #endif
360
361 #if NO_LEAKS
362 NCURSES_EXPORT(void)
363 _nc_new_pair_leaks(SCREEN *sp)
364 {
365     if (sp->_color_pairs) {
366         while (sp->_color_pairs[0].next) {
367             free_pair(sp->_color_pairs[0].next);
368         }
369     }
370 }
371 #endif
372
373 #else
374 void _nc_new_pair(void);
375 void
376 _nc_new_pair(void)
377 {
378 }
379 #endif /* USE_NEW_PAIR */