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 * 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 * 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 *) 161 _nc_visbuf2(int bufnum, const char *buf) 162 { 163 return _nc_visbuf2n(bufnum, buf, -1); 164 } 165 166 NCURSES_EXPORT(const char *) 167 _nc_visbuf(const char *buf) 168 { 169 return _nc_visbuf2(0, buf); 170 } 171 172 NCURSES_EXPORT(const char *) 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 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 * 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 *) 242 _nc_viswbuf2(int bufnum, const wchar_t *buf) 243 { 244 return _nc_viswbuf2n(bufnum, buf, -1); 245 } 246 247 NCURSES_EXPORT(const char *) 248 _nc_viswbuf(const wchar_t *buf) 249 { 250 return _nc_viswbuf2(0, buf); 251 } 252 253 NCURSES_EXPORT(const char *) 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 *) 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 *) 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 *) 378 _nc_viscbuf(const NCURSES_CH_T *buf, int len) 379 { 380 return _nc_viscbuf2(0, buf, len); 381 } 382 #endif /* TRACE */ 383