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