ncurses 6.2 - patch 20210403
[ncurses.git] / ncurses / trace / lib_traceatr.c
1 /****************************************************************************
2  * Copyright 2018-2019,2020 Thomas E. Dickey                                *
3  * Copyright 1998-2017,2018 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 Dickey                           1996-on                 *
32  *     and: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
33  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
34  *     and: Juergen Pfeifer                                                 *
35  ****************************************************************************/
36
37 /*
38  *      lib_traceatr.c - Tracing/Debugging routines (attributes)
39  */
40
41 #include <curses.priv.h>
42
43 #ifndef CUR
44 #define CUR SP_TERMTYPE
45 #endif
46
47 MODULE_ID("$Id: lib_traceatr.c,v 1.94 2020/02/02 23:34:34 tom Exp $")
48
49 #define COLOR_OF(c) ((c < 0) ? "default" : (c > 7 ? color_of(c) : colors[c].name))
50
51 #define TRACE_BUF_SIZE(num) (_nc_globals.tracebuf_ptr[num].size)
52 #define COLOR_BUF_SIZE(num) (sizeof(my_buffer[num]))
53
54 #ifdef TRACE
55
56 static const char l_brace[] = StringOf(L_BRACE);
57 static const char r_brace[] = StringOf(R_BRACE);
58
59 #ifndef USE_TERMLIB
60
61 #define my_buffer _nc_globals.traceatr_color_buf
62 #define my_select _nc_globals.traceatr_color_sel
63 #define my_cached _nc_globals.traceatr_color_last
64
65 static char *
66 color_of(int c)
67 {
68     if (c != my_cached) {
69         my_cached = c;
70         my_select = !my_select;
71         if (isDefaultColor(c))
72             _nc_STRCPY(my_buffer[my_select], "default",
73                        COLOR_BUF_SIZE(my_select));
74         else
75             _nc_SPRINTF(my_buffer[my_select],
76                         _nc_SLIMIT(COLOR_BUF_SIZE(my_select))
77                         "color%d", c);
78     }
79     return my_buffer[my_select];
80 }
81
82 #undef my_buffer
83 #undef my_select
84 #endif /* !USE_TERMLIB */
85
86 NCURSES_EXPORT(char *)
87 _traceattr2(int bufnum, chtype newmode)
88 {
89 #define DATA(name) { name, { #name } }
90     static const struct {
91         unsigned int val;
92         const char name[14];
93     } names[] =
94     {
95         DATA(A_STANDOUT),
96             DATA(A_UNDERLINE),
97             DATA(A_REVERSE),
98             DATA(A_BLINK),
99             DATA(A_DIM),
100             DATA(A_BOLD),
101             DATA(A_ALTCHARSET),
102             DATA(A_INVIS),
103             DATA(A_PROTECT),
104             DATA(A_CHARTEXT),
105             DATA(A_NORMAL),
106             DATA(A_COLOR),
107 #if USE_ITALIC
108             DATA(A_ITALIC),
109 #endif
110     }
111 #ifndef USE_TERMLIB
112     ,
113         colors[] =
114     {
115         DATA(COLOR_BLACK),
116             DATA(COLOR_RED),
117             DATA(COLOR_GREEN),
118             DATA(COLOR_YELLOW),
119             DATA(COLOR_BLUE),
120             DATA(COLOR_MAGENTA),
121             DATA(COLOR_CYAN),
122             DATA(COLOR_WHITE),
123     }
124 #endif /* !USE_TERMLIB */
125     ;
126 #undef DATA
127     char *result = _nc_trace_buf(bufnum, (size_t) BUFSIZ);
128
129     if (result != 0) {
130         size_t n;
131         unsigned save_nc_tracing = _nc_tracing;
132
133         _nc_tracing = 0;
134
135         _nc_STRCPY(result, l_brace, TRACE_BUF_SIZE(bufnum));
136
137         for (n = 0; n < SIZEOF(names); n++) {
138
139             if ((newmode & names[n].val) != 0) {
140                 if (result[1] != '\0')
141                     (void) _nc_trace_bufcat(bufnum, "|");
142                 result = _nc_trace_bufcat(bufnum, names[n].name);
143
144                 if (names[n].val == A_COLOR) {
145                     char temp[80];
146                     short pairnum = (short) PairNumber(newmode);
147 #ifdef USE_TERMLIB
148                     /* pair_content lives in libncurses */
149                     _nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp))
150                                 "{%d}", pairnum);
151 #else
152                     NCURSES_COLOR_T fg, bg;
153
154                     if (pair_content(pairnum, &fg, &bg) == OK) {
155                         _nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp))
156                                     "{%d = {%s, %s}}",
157                                     pairnum,
158                                     COLOR_OF(fg),
159                                     COLOR_OF(bg));
160                     } else {
161                         _nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp))
162                                     "{%d}", pairnum);
163                     }
164 #endif
165                     result = _nc_trace_bufcat(bufnum, temp);
166                 }
167             }
168         }
169         if (ChAttrOf(newmode) == A_NORMAL) {
170             if (result != 0 && result[1] != '\0')
171                 (void) _nc_trace_bufcat(bufnum, "|");
172             (void) _nc_trace_bufcat(bufnum, "A_NORMAL");
173         }
174
175         _nc_tracing = save_nc_tracing;
176         result = _nc_trace_bufcat(bufnum, r_brace);
177     }
178     return result;
179 }
180
181 NCURSES_EXPORT(char *)
182 _traceattr(attr_t newmode)
183 {
184     return _traceattr2(0, newmode);
185 }
186
187 /* Trace 'int' return-values */
188 NCURSES_EXPORT(int)
189 _nc_retrace_int_attr_t(attr_t code)
190 {
191     T((T_RETURN("%s"), _traceattr(code)));
192     return (int) code;
193 }
194
195 /* Trace 'attr_t' return-values */
196 NCURSES_EXPORT(attr_t)
197 _nc_retrace_attr_t(attr_t code)
198 {
199     T((T_RETURN("%s"), _traceattr(code)));
200     return code;
201 }
202
203 const char *
204 _nc_altcharset_name(attr_t attr, chtype ch)
205 {
206 #define DATA(code, name) { code, { #name } }
207     typedef struct {
208         unsigned int val;
209         const char name[13];
210     } ALT_NAMES;
211 #if NCURSES_SP_FUNCS
212     SCREEN *sp = CURRENT_SCREEN;
213 #endif
214     static const ALT_NAMES names[] =
215     {
216         DATA('l', ACS_ULCORNER),        /* upper left corner */
217         DATA('m', ACS_LLCORNER),        /* lower left corner */
218         DATA('k', ACS_URCORNER),        /* upper right corner */
219         DATA('j', ACS_LRCORNER),        /* lower right corner */
220         DATA('t', ACS_LTEE),    /* tee pointing right */
221         DATA('u', ACS_RTEE),    /* tee pointing left */
222         DATA('v', ACS_BTEE),    /* tee pointing up */
223         DATA('w', ACS_TTEE),    /* tee pointing down */
224         DATA('q', ACS_HLINE),   /* horizontal line */
225         DATA('x', ACS_VLINE),   /* vertical line */
226         DATA('n', ACS_PLUS),    /* large plus or crossover */
227         DATA('o', ACS_S1),      /* scan line 1 */
228         DATA('s', ACS_S9),      /* scan line 9 */
229         DATA('`', ACS_DIAMOND), /* diamond */
230         DATA('a', ACS_CKBOARD), /* checker board (stipple) */
231         DATA('f', ACS_DEGREE),  /* degree symbol */
232         DATA('g', ACS_PLMINUS), /* plus/minus */
233         DATA('~', ACS_BULLET),  /* bullet */
234         DATA(',', ACS_LARROW),  /* arrow pointing left */
235         DATA('+', ACS_RARROW),  /* arrow pointing right */
236         DATA('.', ACS_DARROW),  /* arrow pointing down */
237         DATA('-', ACS_UARROW),  /* arrow pointing up */
238         DATA('h', ACS_BOARD),   /* board of squares */
239         DATA('i', ACS_LANTERN), /* lantern symbol */
240         DATA('0', ACS_BLOCK),   /* solid square block */
241         DATA('p', ACS_S3),      /* scan line 3 */
242         DATA('r', ACS_S7),      /* scan line 7 */
243         DATA('y', ACS_LEQUAL),  /* less/equal */
244         DATA('z', ACS_GEQUAL),  /* greater/equal */
245         DATA('{', ACS_PI),      /* Pi */
246         DATA('|', ACS_NEQUAL),  /* not equal */
247         DATA('}', ACS_STERLING),        /* UK pound sign */
248     };
249 #undef DATA
250
251     const char *result = 0;
252
253 #if NCURSES_SP_FUNCS
254     (void) sp;
255 #endif
256     if (SP_PARM != 0 && (attr & A_ALTCHARSET) && (acs_chars != 0)) {
257         char *cp;
258         char *found = 0;
259
260         for (cp = acs_chars; cp[0] && cp[1]; cp += 2) {
261             if (ChCharOf(UChar(cp[1])) == ChCharOf(ch)) {
262                 found = cp;
263                 /* don't exit from loop - there may be redefinitions */
264             }
265         }
266
267         if (found != 0) {
268             size_t n;
269
270             ch = ChCharOf(UChar(*found));
271             for (n = 0; n < SIZEOF(names); ++n) {
272                 if (names[n].val == ch) {
273                     result = names[n].name;
274                     break;
275                 }
276             }
277         }
278     }
279     return result;
280 }
281
282 NCURSES_EXPORT(char *)
283 _tracechtype2(int bufnum, chtype ch)
284 {
285     char *result = _nc_trace_buf(bufnum, (size_t) BUFSIZ);
286
287     if (result != 0) {
288         const char *found;
289         attr_t attr = ChAttrOf(ch);
290
291         _nc_STRCPY(result, l_brace, TRACE_BUF_SIZE(bufnum));
292         if ((found = _nc_altcharset_name(attr, ch)) != 0) {
293             (void) _nc_trace_bufcat(bufnum, found);
294             attr &= ~A_ALTCHARSET;
295         } else
296             (void) _nc_trace_bufcat(bufnum,
297                                     _nc_tracechar(CURRENT_SCREEN,
298                                                   (int) ChCharOf(ch)));
299
300         if (attr != A_NORMAL) {
301             (void) _nc_trace_bufcat(bufnum, " | ");
302             (void) _nc_trace_bufcat(bufnum,
303                                     _traceattr2(bufnum + 20, attr));
304         }
305
306         result = _nc_trace_bufcat(bufnum, r_brace);
307     }
308     return result;
309 }
310
311 NCURSES_EXPORT(char *)
312 _tracechtype(chtype ch)
313 {
314     return _tracechtype2(0, ch);
315 }
316
317 /* Trace 'chtype' return-values */
318 NCURSES_EXPORT(chtype)
319 _nc_retrace_chtype(chtype code)
320 {
321     T((T_RETURN("%s"), _tracechtype(code)));
322     return code;
323 }
324
325 #if USE_WIDEC_SUPPORT
326 NCURSES_EXPORT(char *)
327 _tracecchar_t2(int bufnum, const cchar_t *ch)
328 {
329     char *result = _nc_trace_buf(bufnum, (size_t) BUFSIZ);
330
331     if (result != 0) {
332         _nc_STRCPY(result, l_brace, TRACE_BUF_SIZE(bufnum));
333         if (ch != 0) {
334             const char *found;
335             attr_t attr = AttrOfD(ch);
336
337             if ((found = _nc_altcharset_name(attr, (chtype) CharOfD(ch))) != 0) {
338                 (void) _nc_trace_bufcat(bufnum, found);
339                 attr &= ~A_ALTCHARSET;
340             } else if (isWidecExt(CHDEREF(ch))) {
341                 (void) _nc_trace_bufcat(bufnum, "{NAC}");
342                 attr &= ~A_CHARTEXT;
343             } else {
344                 PUTC_DATA;
345                 int n;
346
347                 (void) _nc_trace_bufcat(bufnum, "{ ");
348                 for (PUTC_i = 0; PUTC_i < CCHARW_MAX; ++PUTC_i) {
349                     PUTC_ch = ch->chars[PUTC_i];
350                     if (PUTC_ch == L'\0') {
351                         if (PUTC_i == 0)
352                             (void) _nc_trace_bufcat(bufnum, "\\000");
353                         break;
354                     }
355                     PUTC_INIT;
356                     PUTC_n = (int) wcrtomb(PUTC_buf, ch->chars[PUTC_i], &PUT_st);
357                     if (PUTC_n <= 0) {
358                         if (PUTC_ch != L'\0') {
359                             /* it could not be a multibyte sequence */
360                             (void) _nc_trace_bufcat(bufnum,
361                                                     _nc_tracechar(CURRENT_SCREEN,
362                                                                   UChar(ch->chars[PUTC_i])));
363                         }
364                         break;
365                     } else if (ch->chars[PUTC_i] > 255) {
366                         char temp[80];
367                         _nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp))
368                                     "{%d:\\u%lx}",
369                                     _nc_wacs_width(ch->chars[PUTC_i]),
370                                     (unsigned long) ch->chars[PUTC_i]);
371                         (void) _nc_trace_bufcat(bufnum, temp);
372                         break;
373                     }
374                     for (n = 0; n < PUTC_n; n++) {
375                         if (n)
376                             (void) _nc_trace_bufcat(bufnum, ", ");
377                         (void) _nc_trace_bufcat(bufnum,
378                                                 _nc_tracechar(CURRENT_SCREEN,
379                                                               UChar(PUTC_buf[n])));
380                     }
381                 }
382                 (void) _nc_trace_bufcat(bufnum, " }");
383             }
384             if (attr != A_NORMAL) {
385                 (void) _nc_trace_bufcat(bufnum, " | ");
386                 (void) _nc_trace_bufcat(bufnum, _traceattr2(bufnum + 20, attr));
387             }
388 #if NCURSES_EXT_COLORS
389             /*
390              * Just in case the extended color is different from the chtype
391              * value, trace both.
392              */
393             if (ch->ext_color != PairNumber(attr)) {
394                 char temp[80];
395                 _nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp))
396                             " X_COLOR{%d:%d}", ch->ext_color, PairNumber(attr));
397                 (void) _nc_trace_bufcat(bufnum, temp);
398             }
399 #endif
400         }
401
402         result = _nc_trace_bufcat(bufnum, r_brace);
403     }
404     return result;
405 }
406
407 NCURSES_EXPORT(char *)
408 _tracecchar_t(const cchar_t *ch)
409 {
410     return _tracecchar_t2(0, ch);
411 }
412 #endif
413
414 #else
415 EMPTY_MODULE(_nc_lib_traceatr)
416 #endif /* TRACE */