xref: /openbsd/lib/libcurses/trace/visbuf.c (revision c7ef0cfc)
1 /* $OpenBSD: visbuf.c,v 1.2 2023/10/17 09:52:09 nicm Exp $ */
2 
3 /****************************************************************************
4  * Copyright 2019-2021,2023 Thomas E. Dickey                                *
5  * Copyright 2001-2016,2017 Free Software Foundation, Inc.                  *
6  *                                                                          *
7  * Permission is hereby granted, free of charge, to any person obtaining a  *
8  * copy of this software and associated documentation files (the            *
9  * "Software"), to deal in the Software without restriction, including      *
10  * without limitation the rights to use, copy, modify, merge, publish,      *
11  * distribute, distribute with modifications, sublicense, and/or sell       *
12  * copies of the Software, and to permit persons to whom the Software is    *
13  * furnished to do so, subject to the following conditions:                 *
14  *                                                                          *
15  * The above copyright notice and this permission notice shall be included  *
16  * in all copies or substantial portions of the Software.                   *
17  *                                                                          *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
21  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
22  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
23  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
24  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
25  *                                                                          *
26  * Except as contained in this notice, the name(s) of the above copyright   *
27  * holders shall not be used in advertising or otherwise to promote the     *
28  * sale, use or other dealings in this Software without prior written       *
29  * authorization.                                                           *
30  ****************************************************************************/
31 
32 /****************************************************************************
33  *  Author: Thomas E. Dickey                        1996-on                 *
34  *     and: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
35  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
36  ****************************************************************************/
37 
38 /*
39  *	visbuf.c - Tracing/Debugging support routines
40  */
41 
42 #define NEED_NCURSES_CH_T
43 #include <curses.priv.h>
44 
45 #include <tic.h>
46 #include <ctype.h>
47 
48 MODULE_ID("$Id: visbuf.c,v 1.2 2023/10/17 09:52:09 nicm Exp $")
49 
50 #define NUM_VISBUFS 4
51 
52 #define NormalLen(len) (size_t) (((size_t)(len) + 1) * 4)
53 #define WideLen(len)   (size_t) (((size_t)(len) + 1) * 4 * (size_t) MB_CUR_MAX)
54 
55 #ifdef TRACE
56 static const char d_quote[] = StringOf(D_QUOTE);
57 static const char l_brace[] = StringOf(L_BRACE);
58 static const char r_brace[] = StringOf(R_BRACE);
59 #endif
60 
61 #if USE_STRING_HACKS && HAVE_SNPRINTF
62 #define VisChar(tp, chr, limit) _nc_vischar(tp, chr, limit)
63 #define LIMIT_ARG ,size_t limit
64 #else
65 #define VisChar(tp, chr, limit) _nc_vischar(tp, chr)
66 #define LIMIT_ARG		/* nothing */
67 #endif
68 
69 static char *
_nc_vischar(char * tp,unsigned c LIMIT_ARG)70 _nc_vischar(char *tp, unsigned c LIMIT_ARG)
71 {
72     if (tp == NULL) {
73 	return NULL;
74     } else if (c == '"' || c == '\\') {
75 	*tp++ = '\\';
76 	*tp++ = (char) c;
77     } else if (is7bits((int) c) && (isgraph((int) c) || c == ' ')) {
78 	*tp++ = (char) c;
79     } else if (c == '\n') {
80 	*tp++ = '\\';
81 	*tp++ = 'n';
82     } else if (c == '\r') {
83 	*tp++ = '\\';
84 	*tp++ = 'r';
85     } else if (c == '\b') {
86 	*tp++ = '\\';
87 	*tp++ = 'b';
88     } else if (c == '\t') {
89 	*tp++ = '\\';
90 	*tp++ = 't';
91     } else if (c == '\033') {
92 	*tp++ = '\\';
93 	*tp++ = 'e';
94     } else if (UChar(c) == 0x7f) {
95 	*tp++ = '\\';
96 	*tp++ = '^';
97 	*tp++ = '?';
98     } else if (is7bits(c) && iscntrl(UChar(c))) {
99 	*tp++ = '\\';
100 	*tp++ = '^';
101 	*tp++ = (char) ('@' + c);
102     } else {
103 	_nc_SPRINTF(tp, _nc_SLIMIT(limit)
104 		    "\\%03lo", (unsigned long) ChCharOf(c));
105 	tp += strlen(tp);
106     }
107     *tp = 0;
108     return tp;
109 }
110 
111 static const char *
_nc_visbuf2n(int bufnum,const char * buf,int len)112 _nc_visbuf2n(int bufnum, const char *buf, int len)
113 {
114     const char *vbuf = 0;
115     char *tp;
116     int count;
117 
118     if (buf == 0)
119 	return ("(null)");
120     if (buf == CANCELLED_STRING)
121 	return ("(cancelled)");
122 
123     if (len < 0)
124 	len = (int) strlen(buf);
125 
126     count = len;
127 #ifdef TRACE
128     vbuf = tp = _nc_trace_buf(bufnum, NormalLen(len));
129 #else
130     {
131 	static char *mybuf[NUM_VISBUFS];
132 	int c;
133 
134 	if (bufnum < 0) {
135 	    for (c = 0; c < NUM_VISBUFS; ++c) {
136 		FreeAndNull(mybuf[c]);
137 	    }
138 	    tp = 0;
139 	} else {
140 	    mybuf[bufnum] = typeRealloc(char, NormalLen(len), mybuf[bufnum]);
141 	    vbuf = tp = mybuf[bufnum];
142 	}
143     }
144 #endif
145     if (tp != 0) {
146 	int c;
147 
148 	*tp++ = D_QUOTE;
149 	while ((--count >= 0) && (c = *buf++) != '\0') {
150 	    tp = VisChar(tp, UChar(c), NormalLen(len));
151 	}
152 	*tp++ = D_QUOTE;
153 	*tp = '\0';
154     } else {
155 	vbuf = ("(_nc_visbuf2n failed)");
156     }
157     return (vbuf);
158 }
159 
160 NCURSES_EXPORT(const char *)
_nc_visbuf2(int bufnum,const char * buf)161 _nc_visbuf2(int bufnum, const char *buf)
162 {
163     return _nc_visbuf2n(bufnum, buf, -1);
164 }
165 
166 NCURSES_EXPORT(const char *)
_nc_visbuf(const char * buf)167 _nc_visbuf(const char *buf)
168 {
169     return _nc_visbuf2(0, buf);
170 }
171 
172 NCURSES_EXPORT(const char *)
_nc_visbufn(const char * buf,int len)173 _nc_visbufn(const char *buf, int len)
174 {
175     return _nc_visbuf2n(0, buf, len);
176 }
177 
178 #ifdef TRACE
179 #if USE_WIDEC_SUPPORT
180 
181 #if defined(USE_TERMLIB)
182 #define _nc_wchstrlen _my_wchstrlen
183 static int
_nc_wchstrlen(const cchar_t * s)184 _nc_wchstrlen(const cchar_t *s)
185 {
186     int result = 0;
187     while (CharOf(s[result]) != L'\0') {
188 	result++;
189     }
190     return result;
191 }
192 #endif
193 
194 static const char *
_nc_viswbuf2n(int bufnum,const wchar_t * buf,int len)195 _nc_viswbuf2n(int bufnum, const wchar_t *buf, int len)
196 {
197     const char *vbuf;
198     char *tp;
199     int count;
200 
201     if (buf == 0)
202 	return ("(null)");
203 
204     if (len < 0)
205 	len = (int) wcslen(buf);
206 
207     count = len;
208 #ifdef TRACE
209     vbuf = tp = _nc_trace_buf(bufnum, WideLen(len));
210 #else
211     {
212 	static char *mybuf[NUM_VISBUFS];
213 	mybuf[bufnum] = typeRealloc(char, WideLen(len), mybuf[bufnum]);
214 	vbuf = tp = mybuf[bufnum];
215     }
216 #endif
217     if (tp != 0) {
218 	wchar_t c;
219 
220 	*tp++ = D_QUOTE;
221 	while ((--count >= 0) && (c = *buf++) != '\0') {
222 	    char temp[CCHARW_MAX + 80];
223 	    int j = wctomb(temp, c), k;
224 	    if (j <= 0) {
225 		_nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp))
226 			    "\\u%08X", (unsigned) c);
227 		j = (int) strlen(temp);
228 	    }
229 	    for (k = 0; k < j; ++k) {
230 		tp = VisChar(tp, UChar(temp[k]), WideLen(len));
231 	    }
232 	}
233 	*tp++ = D_QUOTE;
234 	*tp = '\0';
235     } else {
236 	vbuf = ("(_nc_viswbuf2n failed)");
237     }
238     return (vbuf);
239 }
240 
241 NCURSES_EXPORT(const char *)
_nc_viswbuf2(int bufnum,const wchar_t * buf)242 _nc_viswbuf2(int bufnum, const wchar_t *buf)
243 {
244     return _nc_viswbuf2n(bufnum, buf, -1);
245 }
246 
247 NCURSES_EXPORT(const char *)
_nc_viswbuf(const wchar_t * buf)248 _nc_viswbuf(const wchar_t *buf)
249 {
250     return _nc_viswbuf2(0, buf);
251 }
252 
253 NCURSES_EXPORT(const char *)
_nc_viswbufn(const wchar_t * buf,int len)254 _nc_viswbufn(const wchar_t *buf, int len)
255 {
256     return _nc_viswbuf2n(0, buf, len);
257 }
258 
259 /* this special case is used for wget_wstr() */
260 NCURSES_EXPORT(const char *)
_nc_viswibuf(const wint_t * buf)261 _nc_viswibuf(const wint_t *buf)
262 {
263     static wchar_t *mybuf;
264     static unsigned mylen;
265     unsigned n;
266 
267     for (n = 0; buf[n] != 0; ++n) {
268 	;			/* empty */
269     }
270     if (mylen < ++n) {
271 	mylen = n + 80;
272 	if (mybuf != 0)
273 	    mybuf = typeRealloc(wchar_t, mylen, mybuf);
274 	else
275 	    mybuf = typeMalloc(wchar_t, mylen);
276     }
277     if (mybuf != 0) {
278 	for (n = 0; buf[n] != 0; ++n) {
279 	    mybuf[n] = (wchar_t) buf[n];
280 	}
281 	mybuf[n] = L'\0';
282     }
283 
284     return _nc_viswbuf2(0, mybuf);
285 }
286 #endif /* USE_WIDEC_SUPPORT */
287 
288 /* use these functions for displaying parts of a line within a window */
289 NCURSES_EXPORT(const char *)
_nc_viscbuf2(int bufnum,const NCURSES_CH_T * buf,int len)290 _nc_viscbuf2(int bufnum, const NCURSES_CH_T *buf, int len)
291 {
292     char *result = _nc_trace_buf(bufnum, (size_t) BUFSIZ);
293 
294     if (result != 0) {
295 	int first = 0;
296 
297 #if USE_WIDEC_SUPPORT
298 	if (len < 0)
299 	    len = _nc_wchstrlen(buf);
300 #endif /* USE_WIDEC_SUPPORT */
301 
302 	/*
303 	 * Display one or more strings followed by attributes.
304 	 */
305 	while (first < len) {
306 	    attr_t attr = AttrOf(buf[first]);
307 	    int last = len - 1;
308 	    int j;
309 
310 	    for (j = first + 1; j < len; ++j) {
311 		if (!SameAttrOf(buf[j], buf[first])) {
312 		    last = j - 1;
313 		    break;
314 		}
315 	    }
316 
317 	    (void) _nc_trace_bufcat(bufnum, l_brace);
318 	    (void) _nc_trace_bufcat(bufnum, d_quote);
319 	    for (j = first; j <= last; ++j) {
320 		const char *found = _nc_altcharset_name(attr, (chtype)
321 							CharOf(buf[j]));
322 		if (found != 0) {
323 		    (void) _nc_trace_bufcat(bufnum, found);
324 		    attr &= ~A_ALTCHARSET;
325 		} else
326 #if USE_WIDEC_SUPPORT
327 		if (!isWidecExt(buf[j])) {
328 		    PUTC_DATA;
329 
330 		    for (PUTC_i = 0; PUTC_i < CCHARW_MAX; ++PUTC_i) {
331 			int k;
332 			char temp[80];
333 
334 			PUTC_ch = buf[j].chars[PUTC_i];
335 			if (PUTC_ch == L'\0') {
336 			    if (PUTC_i == 0)
337 				(void) _nc_trace_bufcat(bufnum, "\\000");
338 			    break;
339 			}
340 			PUTC_INIT;
341 			PUTC_n = (int) wcrtomb(PUTC_buf,
342 					       buf[j].chars[PUTC_i], &PUT_st);
343 			if (PUTC_n <= 0 || buf[j].chars[PUTC_i] > 255) {
344 			    _nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp))
345 					"{%d:\\u%lx}",
346 					_nc_wacs_width(buf[j].chars[PUTC_i]),
347 					(unsigned long) buf[j].chars[PUTC_i]);
348 			    (void) _nc_trace_bufcat(bufnum, temp);
349 			    break;
350 			}
351 			for (k = 0; k < PUTC_n; k++) {
352 			    VisChar(temp, UChar(PUTC_buf[k]), sizeof(temp));
353 			    (void) _nc_trace_bufcat(bufnum, temp);
354 			}
355 		    }
356 		}
357 #else
358 		{
359 		    char temp[80];
360 		    VisChar(temp, UChar(buf[j]), sizeof(temp));
361 		    (void) _nc_trace_bufcat(bufnum, temp);
362 		}
363 #endif /* USE_WIDEC_SUPPORT */
364 	    }
365 	    (void) _nc_trace_bufcat(bufnum, d_quote);
366 	    if (attr != A_NORMAL) {
367 		(void) _nc_trace_bufcat(bufnum, " | ");
368 		(void) _nc_trace_bufcat(bufnum, _traceattr2(bufnum + 20, attr));
369 	    }
370 	    result = _nc_trace_bufcat(bufnum, r_brace);
371 	    first = last + 1;
372 	}
373     }
374     return result;
375 }
376 
377 NCURSES_EXPORT(const char *)
_nc_viscbuf(const NCURSES_CH_T * buf,int len)378 _nc_viscbuf(const NCURSES_CH_T *buf, int len)
379 {
380     return _nc_viscbuf2(0, buf, len);
381 }
382 #endif /* TRACE */
383