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