ncurses 6.1 - patch 20191207
[ncurses.git] / ncurses / trace / visbuf.c
1 /****************************************************************************
2  * Copyright (c) 2001-2017,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                        1996-on                 *
31  *     and: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
32  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
33  ****************************************************************************/
34
35 /*
36  *      visbuf.c - Tracing/Debugging support routines
37  */
38
39 #define NEED_NCURSES_CH_T
40 #include <curses.priv.h>
41
42 #include <tic.h>
43 #include <ctype.h>
44
45 MODULE_ID("$Id: visbuf.c,v 1.51 2019/05/04 20:31:31 tom Exp $")
46
47 #define NUM_VISBUFS 4
48
49 #define NormalLen(len) (size_t) (((size_t)(len) + 1) * 4)
50 #define WideLen(len)   (size_t) (((size_t)(len) + 1) * 4 * (size_t) MB_CUR_MAX)
51
52 #ifdef TRACE
53 static const char d_quote[] = StringOf(D_QUOTE);
54 static const char l_brace[] = StringOf(L_BRACE);
55 static const char r_brace[] = StringOf(R_BRACE);
56 #endif
57
58 #if USE_STRING_HACKS && HAVE_SNPRINTF
59 #define VisChar(tp, chr, limit) _nc_vischar(tp, chr, limit)
60 #define LIMIT_ARG ,size_t limit
61 #else
62 #define VisChar(tp, chr, limit) _nc_vischar(tp, chr)
63 #define LIMIT_ARG               /* nothing */
64 #endif
65
66 static char *
67 _nc_vischar(char *tp, unsigned c LIMIT_ARG)
68 {
69     if (c == '"' || c == '\\') {
70         *tp++ = '\\';
71         *tp++ = (char) c;
72     } else if (is7bits((int) c) && (isgraph((int) c) || c == ' ')) {
73         *tp++ = (char) c;
74     } else if (c == '\n') {
75         *tp++ = '\\';
76         *tp++ = 'n';
77     } else if (c == '\r') {
78         *tp++ = '\\';
79         *tp++ = 'r';
80     } else if (c == '\b') {
81         *tp++ = '\\';
82         *tp++ = 'b';
83     } else if (c == '\t') {
84         *tp++ = '\\';
85         *tp++ = 't';
86     } else if (c == '\033') {
87         *tp++ = '\\';
88         *tp++ = 'e';
89     } else if (UChar(c) == 0x7f) {
90         *tp++ = '\\';
91         *tp++ = '^';
92         *tp++ = '?';
93     } else if (is7bits(c) && iscntrl(UChar(c))) {
94         *tp++ = '\\';
95         *tp++ = '^';
96         *tp++ = (char) ('@' + c);
97     } else {
98         _nc_SPRINTF(tp, _nc_SLIMIT(limit)
99                     "\\%03lo", (unsigned long) ChCharOf(c));
100         tp += strlen(tp);
101     }
102     *tp = 0;
103     return tp;
104 }
105
106 static const char *
107 _nc_visbuf2n(int bufnum, const char *buf, int len)
108 {
109     const char *vbuf = 0;
110     char *tp;
111     int count;
112
113     if (buf == 0)
114         return ("(null)");
115     if (buf == CANCELLED_STRING)
116         return ("(cancelled)");
117
118     if (len < 0)
119         len = (int) strlen(buf);
120
121     count = len;
122 #ifdef TRACE
123     vbuf = tp = _nc_trace_buf(bufnum, NormalLen(len));
124 #else
125     {
126         static char *mybuf[NUM_VISBUFS];
127         int c;
128
129         if (bufnum < 0) {
130             for (c = 0; c < NUM_VISBUFS; ++c) {
131                 FreeAndNull(mybuf[c]);
132             }
133             tp = 0;
134         } else {
135             mybuf[bufnum] = typeRealloc(char, NormalLen(len), mybuf[bufnum]);
136             vbuf = tp = mybuf[bufnum];
137         }
138     }
139 #endif
140     if (tp != 0) {
141         int c;
142
143         *tp++ = D_QUOTE;
144         while ((--count >= 0) && (c = *buf++) != '\0') {
145             tp = VisChar(tp, UChar(c), NormalLen(len));
146         }
147         *tp++ = D_QUOTE;
148         *tp = '\0';
149     } else {
150         vbuf = ("(_nc_visbuf2n failed)");
151     }
152     return (vbuf);
153 }
154
155 NCURSES_EXPORT(const char *)
156 _nc_visbuf2(int bufnum, const char *buf)
157 {
158     return _nc_visbuf2n(bufnum, buf, -1);
159 }
160
161 NCURSES_EXPORT(const char *)
162 _nc_visbuf(const char *buf)
163 {
164     return _nc_visbuf2(0, buf);
165 }
166
167 NCURSES_EXPORT(const char *)
168 _nc_visbufn(const char *buf, int len)
169 {
170     return _nc_visbuf2n(0, buf, len);
171 }
172
173 #ifdef TRACE
174 #if USE_WIDEC_SUPPORT
175
176 #if defined(USE_TERMLIB)
177 #define _nc_wchstrlen _my_wchstrlen
178 static int
179 _nc_wchstrlen(const cchar_t *s)
180 {
181     int result = 0;
182     while (CharOf(s[result]) != L'\0') {
183         result++;
184     }
185     return result;
186 }
187 #endif
188
189 static const char *
190 _nc_viswbuf2n(int bufnum, const wchar_t *buf, int len)
191 {
192     const char *vbuf;
193     char *tp;
194     int count;
195
196     if (buf == 0)
197         return ("(null)");
198
199     if (len < 0)
200         len = (int) wcslen(buf);
201
202     count = len;
203 #ifdef TRACE
204     vbuf = tp = _nc_trace_buf(bufnum, WideLen(len));
205 #else
206     {
207         static char *mybuf[NUM_VISBUFS];
208         mybuf[bufnum] = typeRealloc(char, WideLen(len), mybuf[bufnum]);
209         vbuf = tp = mybuf[bufnum];
210     }
211 #endif
212     if (tp != 0) {
213         wchar_t c;
214
215         *tp++ = D_QUOTE;
216         while ((--count >= 0) && (c = *buf++) != '\0') {
217             char temp[CCHARW_MAX + 80];
218             int j = wctomb(temp, c), k;
219             if (j <= 0) {
220                 _nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp))
221                             "\\u%08X", (unsigned) c);
222                 j = (int) strlen(temp);
223             }
224             for (k = 0; k < j; ++k) {
225                 tp = VisChar(tp, UChar(temp[k]), WideLen(len));
226             }
227         }
228         *tp++ = D_QUOTE;
229         *tp = '\0';
230     } else {
231         vbuf = ("(_nc_viswbuf2n failed)");
232     }
233     return (vbuf);
234 }
235
236 NCURSES_EXPORT(const char *)
237 _nc_viswbuf2(int bufnum, const wchar_t *buf)
238 {
239     return _nc_viswbuf2n(bufnum, buf, -1);
240 }
241
242 NCURSES_EXPORT(const char *)
243 _nc_viswbuf(const wchar_t *buf)
244 {
245     return _nc_viswbuf2(0, buf);
246 }
247
248 NCURSES_EXPORT(const char *)
249 _nc_viswbufn(const wchar_t *buf, int len)
250 {
251     return _nc_viswbuf2n(0, buf, len);
252 }
253
254 /* this special case is used for wget_wstr() */
255 NCURSES_EXPORT(const char *)
256 _nc_viswibuf(const wint_t *buf)
257 {
258     static wchar_t *mybuf;
259     static unsigned mylen;
260     unsigned n;
261
262     for (n = 0; buf[n] != 0; ++n) {
263         ;                       /* empty */
264     }
265     if (mylen < ++n) {
266         mylen = n + 80;
267         if (mybuf != 0)
268             mybuf = typeRealloc(wchar_t, mylen, mybuf);
269         else
270             mybuf = typeMalloc(wchar_t, mylen);
271     }
272     if (mybuf != 0) {
273         for (n = 0; buf[n] != 0; ++n) {
274             mybuf[n] = (wchar_t) buf[n];
275         }
276         mybuf[n] = L'\0';
277     }
278
279     return _nc_viswbuf2(0, mybuf);
280 }
281 #endif /* USE_WIDEC_SUPPORT */
282
283 /* use these functions for displaying parts of a line within a window */
284 NCURSES_EXPORT(const char *)
285 _nc_viscbuf2(int bufnum, const NCURSES_CH_T * buf, int len)
286 {
287     char *result = _nc_trace_buf(bufnum, (size_t) BUFSIZ);
288
289     if (result != 0) {
290         int first = 0;
291
292 #if USE_WIDEC_SUPPORT
293         if (len < 0)
294             len = _nc_wchstrlen(buf);
295 #endif /* USE_WIDEC_SUPPORT */
296
297         /*
298          * Display one or more strings followed by attributes.
299          */
300         while (first < len) {
301             attr_t attr = AttrOf(buf[first]);
302             int last = len - 1;
303             int j;
304
305             for (j = first + 1; j < len; ++j) {
306                 if (!SameAttrOf(buf[j], buf[first])) {
307                     last = j - 1;
308                     break;
309                 }
310             }
311
312             (void) _nc_trace_bufcat(bufnum, l_brace);
313             (void) _nc_trace_bufcat(bufnum, d_quote);
314             for (j = first; j <= last; ++j) {
315                 const char *found = _nc_altcharset_name(attr, (chtype)
316                                                         CharOf(buf[j]));
317                 if (found != 0) {
318                     (void) _nc_trace_bufcat(bufnum, found);
319                     attr &= ~A_ALTCHARSET;
320                 } else
321 #if USE_WIDEC_SUPPORT
322                 if (!isWidecExt(buf[j])) {
323                     PUTC_DATA;
324
325                     for (PUTC_i = 0; PUTC_i < CCHARW_MAX; ++PUTC_i) {
326                         int k;
327                         char temp[80];
328
329                         PUTC_ch = buf[j].chars[PUTC_i];
330                         if (PUTC_ch == L'\0') {
331                             if (PUTC_i == 0)
332                                 (void) _nc_trace_bufcat(bufnum, "\\000");
333                             break;
334                         }
335                         PUTC_INIT;
336                         PUTC_n = (int) wcrtomb(PUTC_buf,
337                                                buf[j].chars[PUTC_i], &PUT_st);
338                         if (PUTC_n <= 0 || buf[j].chars[PUTC_i] > 255) {
339                             _nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp))
340                                         "{%d:\\u%lx}",
341                                         _nc_wacs_width(buf[j].chars[PUTC_i]),
342                                         (unsigned long) buf[j].chars[PUTC_i]);
343                             (void) _nc_trace_bufcat(bufnum, temp);
344                             break;
345                         }
346                         for (k = 0; k < PUTC_n; k++) {
347                             VisChar(temp, UChar(PUTC_buf[k]), sizeof(temp));
348                             (void) _nc_trace_bufcat(bufnum, temp);
349                         }
350                     }
351                 }
352 #else
353                 {
354                     char temp[80];
355                     VisChar(temp, UChar(buf[j]), sizeof(temp));
356                     (void) _nc_trace_bufcat(bufnum, temp);
357                 }
358 #endif /* USE_WIDEC_SUPPORT */
359             }
360             (void) _nc_trace_bufcat(bufnum, d_quote);
361             if (attr != A_NORMAL) {
362                 (void) _nc_trace_bufcat(bufnum, " | ");
363                 (void) _nc_trace_bufcat(bufnum, _traceattr2(bufnum + 20, attr));
364             }
365             result = _nc_trace_bufcat(bufnum, r_brace);
366             first = last + 1;
367         }
368     }
369     return result;
370 }
371
372 NCURSES_EXPORT(const char *)
373 _nc_viscbuf(const NCURSES_CH_T * buf, int len)
374 {
375     return _nc_viscbuf2(0, buf, len);
376 }
377 #endif /* TRACE */