1 1.25 blymn /* $NetBSD: ins_wstr.c,v 1.25 2024/12/23 02:58:03 blymn Exp $ */ 2 1.1 blymn 3 1.1 blymn /* 4 1.1 blymn * Copyright (c) 2005 The NetBSD Foundation Inc. 5 1.1 blymn * All rights reserved. 6 1.1 blymn * 7 1.1 blymn * This code is derived from code donated to the NetBSD Foundation 8 1.1 blymn * by Ruibiao Qiu <ruibiao (at) arl.wustl.edu,ruibiao (at) gmail.com>. 9 1.1 blymn * 10 1.1 blymn * 11 1.1 blymn * Redistribution and use in source and binary forms, with or without 12 1.1 blymn * modification, are permitted provided that the following conditions 13 1.1 blymn * are met: 14 1.1 blymn * 1. Redistributions of source code must retain the above copyright 15 1.1 blymn * notice, this list of conditions and the following disclaimer. 16 1.1 blymn * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 blymn * notice, this list of conditions and the following disclaimer in the 18 1.1 blymn * documentation and/or other materials provided with the distribution. 19 1.1 blymn * 3. Neither the name of the NetBSD Foundation nor the names of its 20 1.1 blymn * contributors may be used to endorse or promote products derived 21 1.1 blymn * from this software without specific prior written permission. 22 1.1 blymn * 23 1.1 blymn * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 24 1.1 blymn * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 25 1.1 blymn * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 26 1.1 blymn * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 1.1 blymn * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 1.1 blymn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 1.1 blymn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 1.1 blymn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 1.1 blymn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 1.1 blymn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 1.1 blymn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 1.1 blymn * SUCH DAMAGE. 35 1.1 blymn */ 36 1.1 blymn 37 1.1 blymn #include <sys/cdefs.h> 38 1.1 blymn #ifndef lint 39 1.25 blymn __RCSID("$NetBSD: ins_wstr.c,v 1.25 2024/12/23 02:58:03 blymn Exp $"); 40 1.1 blymn #endif /* not lint */ 41 1.1 blymn 42 1.1 blymn #include <string.h> 43 1.1 blymn #include <stdlib.h> 44 1.1 blymn 45 1.1 blymn #include "curses.h" 46 1.1 blymn #include "curses_private.h" 47 1.1 blymn 48 1.1 blymn /* 49 1.1 blymn * ins_wstr -- 50 1.6 wiz * insert a multi-character wide-character string into the current window 51 1.1 blymn */ 52 1.1 blymn int 53 1.1 blymn ins_wstr(const wchar_t *wstr) 54 1.1 blymn { 55 1.1 blymn return wins_wstr(stdscr, wstr); 56 1.1 blymn } 57 1.1 blymn 58 1.1 blymn /* 59 1.1 blymn * ins_nwstr -- 60 1.6 wiz * insert a multi-character wide-character string into the current window 61 1.1 blymn * with at most n characters 62 1.1 blymn */ 63 1.1 blymn int 64 1.1 blymn ins_nwstr(const wchar_t *wstr, int n) 65 1.1 blymn { 66 1.1 blymn return wins_nwstr(stdscr, wstr, n); 67 1.1 blymn } 68 1.1 blymn 69 1.1 blymn /* 70 1.1 blymn * mvins_wstr -- 71 1.1 blymn * Do an insert-string on the line at (y, x). 72 1.1 blymn */ 73 1.1 blymn int 74 1.1 blymn mvins_wstr(int y, int x, const wchar_t *wstr) 75 1.1 blymn { 76 1.1 blymn return mvwins_wstr(stdscr, y, x, wstr); 77 1.1 blymn } 78 1.1 blymn 79 1.1 blymn /* 80 1.1 blymn * mvins_nwstr -- 81 1.1 blymn * Do an insert-n-string on the line at (y, x). 82 1.1 blymn */ 83 1.1 blymn int 84 1.1 blymn mvins_nwstr(int y, int x, const wchar_t *wstr, int n) 85 1.1 blymn { 86 1.1 blymn return mvwins_nwstr(stdscr, y, x, wstr, n); 87 1.1 blymn } 88 1.1 blymn 89 1.1 blymn /* 90 1.1 blymn * mvwins_wstr -- 91 1.1 blymn * Do an insert-string on the line at (y, x) in the given window. 92 1.1 blymn */ 93 1.1 blymn int 94 1.1 blymn mvwins_wstr(WINDOW *win, int y, int x, const wchar_t *wstr) 95 1.1 blymn { 96 1.14 blymn if (wmove(win, y, x) == ERR) 97 1.1 blymn return ERR; 98 1.1 blymn 99 1.15 uwe return wins_wstr(win, wstr); 100 1.1 blymn } 101 1.1 blymn 102 1.1 blymn /* 103 1.1 blymn * mvwins_nwstr -- 104 1.1 blymn * Do an insert-n-string on the line at (y, x) in the given window. 105 1.1 blymn */ 106 1.1 blymn int 107 1.1 blymn mvwins_nwstr(WINDOW *win, int y, int x, const wchar_t *wstr, int n) 108 1.1 blymn { 109 1.14 blymn if (wmove(win, y, x) == ERR) 110 1.1 blymn return ERR; 111 1.1 blymn 112 1.15 uwe return wins_nwstr(win, wstr, n); 113 1.1 blymn } 114 1.1 blymn 115 1.1 blymn 116 1.1 blymn /* 117 1.1 blymn * wins_wstr -- 118 1.1 blymn * Do an insert-string on the line, leaving (cury, curx) unchanged. 119 1.1 blymn */ 120 1.1 blymn int 121 1.1 blymn wins_wstr(WINDOW *win, const wchar_t *wstr) 122 1.1 blymn { 123 1.1 blymn return wins_nwstr(win, wstr, -1); 124 1.1 blymn } 125 1.1 blymn 126 1.1 blymn /* 127 1.1 blymn * wins_nwstr -- 128 1.1 blymn * Do an insert-n-string on the line, leaving (cury, curx) unchanged. 129 1.1 blymn */ 130 1.1 blymn int 131 1.1 blymn wins_nwstr(WINDOW *win, const wchar_t *wstr, int n) 132 1.1 blymn { 133 1.1 blymn __LDATA *start, *temp1, *temp2; 134 1.1 blymn __LINE *lnp; 135 1.1 blymn const wchar_t *scp; 136 1.18 blymn cchar_t cc; 137 1.18 blymn wchar_t *lstr, *slstr; 138 1.20 kre int width, len, lx, sx, x, y, tx, ty, cw, pcw, newx, tn, w; 139 1.1 blymn wchar_t ws[] = L" "; 140 1.1 blymn 141 1.25 blymn if (__predict_false(win == NULL)) 142 1.25 blymn return ERR; 143 1.25 blymn 144 1.1 blymn /* check for leading non-spacing character */ 145 1.1 blymn if (!wstr) 146 1.1 blymn return OK; 147 1.1 blymn cw = wcwidth(*wstr); 148 1.5 drochner if (cw < 0) 149 1.5 drochner cw = 1; 150 1.1 blymn if (!cw) 151 1.1 blymn return ERR; 152 1.1 blymn 153 1.18 blymn lstr = malloc(sizeof(wchar_t) * win->maxx); 154 1.18 blymn if (lstr == NULL) 155 1.18 blymn return ERR; 156 1.18 blymn 157 1.1 blymn scp = wstr + 1; 158 1.1 blymn width = cw; 159 1.1 blymn len = 1; 160 1.1 blymn n--; 161 1.18 blymn y = win->cury; 162 1.18 blymn x = win->curx; 163 1.18 blymn tn = n; 164 1.18 blymn 165 1.18 blymn /* 166 1.18 blymn * Firstly, make sure the string will fit... 167 1.18 blymn */ 168 1.1 blymn while (*scp) { 169 1.18 blymn if (!tn) 170 1.1 blymn break; 171 1.18 blymn switch (*scp) { 172 1.18 blymn case L'\b': 173 1.18 blymn if (--x < 0) 174 1.18 blymn x = 0; 175 1.18 blymn cw = wcwidth(*(scp - 1)); 176 1.18 blymn if (cw < 0) 177 1.18 blymn cw = 1; 178 1.18 blymn width -= cw; 179 1.18 blymn scp++; 180 1.21 rillig continue; 181 1.18 blymn 182 1.18 blymn case L'\r': 183 1.18 blymn width = 0; 184 1.18 blymn x = 0; 185 1.18 blymn scp++; 186 1.18 blymn continue; 187 1.18 blymn 188 1.18 blymn case L'\n': 189 1.18 blymn if (y == win->scr_b) { 190 1.18 blymn if (!(win->flags & __SCROLLOK)) { 191 1.18 blymn free(lstr); 192 1.18 blymn return ERR; 193 1.18 blymn } 194 1.18 blymn } 195 1.18 blymn y++; 196 1.18 blymn scp++; 197 1.18 blymn continue; 198 1.18 blymn 199 1.18 blymn case L'\t': 200 1.19 blymn cw = wcwidth(ws[0]); 201 1.19 blymn if (cw < 0) 202 1.19 blymn cw = 1; 203 1.19 blymn w = cw * (TABSIZE - (x % TABSIZE)); 204 1.19 blymn width += w; 205 1.19 blymn x += w; 206 1.18 blymn scp++; 207 1.18 blymn continue; 208 1.18 blymn } 209 1.5 drochner w = wcwidth(*scp); 210 1.5 drochner if (w < 0) 211 1.5 drochner w = 1; 212 1.18 blymn tn--, width += w; 213 1.1 blymn scp++; 214 1.1 blymn } 215 1.2 blymn __CTRACE(__CTRACE_INPUT, "wins_nwstr: width=%d,len=%d\n", width, len); 216 1.1 blymn 217 1.18 blymn if (width > win->maxx - win->curx + 1) { 218 1.18 blymn free(lstr); 219 1.1 blymn return ERR; 220 1.1 blymn } 221 1.18 blymn 222 1.18 blymn scp = wstr; 223 1.18 blymn x = win->curx; 224 1.18 blymn y = win->cury; 225 1.18 blymn len = 0; 226 1.18 blymn width = 0; 227 1.18 blymn slstr = lstr; 228 1.18 blymn 229 1.18 blymn while (*scp && n) { 230 1.18 blymn lstr = slstr; 231 1.18 blymn lx = x; 232 1.18 blymn while (*scp) { 233 1.18 blymn if (!n) 234 1.18 blymn break; 235 1.18 blymn switch (*scp) { 236 1.18 blymn case L'\b': 237 1.18 blymn if (--x < 0) 238 1.18 blymn x = 0; 239 1.18 blymn if (--len < 0) 240 1.18 blymn len = 0; 241 1.18 blymn cw = wcwidth(*(scp - 1)); 242 1.18 blymn if (cw < 0) 243 1.18 blymn cw = 1; 244 1.18 blymn width -= cw; 245 1.18 blymn scp++; 246 1.18 blymn if (lstr != slstr) 247 1.18 blymn lstr--; 248 1.21 rillig continue; 249 1.18 blymn 250 1.18 blymn case L'\r': 251 1.18 blymn width = 0; 252 1.18 blymn len = 0; 253 1.18 blymn x = 0; 254 1.18 blymn scp++; 255 1.18 blymn lstr = slstr; 256 1.18 blymn continue; 257 1.18 blymn 258 1.18 blymn case L'\n': 259 1.18 blymn goto loopdone; 260 1.18 blymn 261 1.18 blymn case L'\t': 262 1.19 blymn cw = wcwidth(ws[0]); 263 1.19 blymn if (cw < 0) 264 1.19 blymn cw = 1; 265 1.19 blymn w = cw * (TABSIZE - (x % TABSIZE)); 266 1.19 blymn width += w; 267 1.19 blymn x += w; 268 1.18 blymn len += w; 269 1.18 blymn scp++; 270 1.19 blymn *lstr = *ws; 271 1.19 blymn lstr++; 272 1.18 blymn continue; 273 1.18 blymn } 274 1.18 blymn w = wcwidth(*scp); 275 1.18 blymn if (w < 0) 276 1.18 blymn w = 1; 277 1.18 blymn *lstr = *scp; 278 1.18 blymn n--, len++, width += w; 279 1.18 blymn scp++, lstr++; 280 1.18 blymn } 281 1.18 blymn 282 1.18 blymn loopdone: 283 1.18 blymn start = &win->alines[y]->line[x]; 284 1.18 blymn sx = x; 285 1.18 blymn lnp = win->alines[y]; 286 1.22 blymn pcw = start->wcols; 287 1.18 blymn if (pcw < 0) { 288 1.18 blymn sx += pcw; 289 1.18 blymn start += pcw; 290 1.18 blymn } 291 1.18 blymn __CTRACE(__CTRACE_INPUT, "wins_nwstr: start@(%d)\n", sx); 292 1.22 blymn pcw = start->wcols; 293 1.18 blymn lnp->flags |= __ISDIRTY; 294 1.18 blymn newx = sx + win->ch_off; 295 1.18 blymn if (newx < *lnp->firstchp) 296 1.18 blymn *lnp->firstchp = newx; 297 1.24 blymn 298 1.1 blymn #ifdef DEBUG 299 1.18 blymn { 300 1.20 kre int i; 301 1.20 kre 302 1.18 blymn __CTRACE(__CTRACE_INPUT, "========before=======\n"); 303 1.18 blymn for (i = 0; i < win->maxx; i++) 304 1.2 blymn __CTRACE(__CTRACE_INPUT, 305 1.24 blymn "wins_nwstr: (%d,%d)=(%x,%x,%d,%x,%p)\n", 306 1.18 blymn y, i, win->alines[y]->line[i].ch, 307 1.18 blymn win->alines[y]->line[i].attr, 308 1.24 blymn win->alines[y]->line[i].wcols, 309 1.24 blymn win->alines[y]->line[i].cflags, 310 1.18 blymn win->alines[y]->line[i].nsp); 311 1.18 blymn } 312 1.1 blymn #endif /* DEBUG */ 313 1.1 blymn 314 1.18 blymn /* shift all complete characters */ 315 1.18 blymn if (sx + width + pcw <= win->maxx) { 316 1.18 blymn __CTRACE(__CTRACE_INPUT, "wins_nwstr: shift all characters by %d\n", width); 317 1.18 blymn temp1 = &win->alines[y]->line[win->maxx - 1]; 318 1.18 blymn temp2 = temp1 - width; 319 1.22 blymn pcw = (temp2 + 1)->wcols; 320 1.18 blymn if (pcw < 0) { 321 1.2 blymn __CTRACE(__CTRACE_INPUT, 322 1.18 blymn "wins_nwstr: clear from %d to EOL(%d)\n", 323 1.18 blymn win->maxx + pcw, win->maxx - 1); 324 1.18 blymn temp2 += pcw; 325 1.18 blymn while (temp1 > temp2 + width) { 326 1.23 blymn temp1->ch = win->bch; 327 1.18 blymn if (_cursesi_copy_nsp(win->bnsp, temp1) == ERR) { 328 1.18 blymn free(lstr); 329 1.18 blymn return ERR; 330 1.18 blymn } 331 1.18 blymn temp1->attr = win->battr; 332 1.24 blymn temp1->cflags |= CA_BACKGROUND; 333 1.24 blymn temp1->cflags &= ~CA_CONTINUATION; 334 1.22 blymn temp1->wcols = 1; 335 1.18 blymn __CTRACE(__CTRACE_INPUT, 336 1.18 blymn "wins_nwstr: empty cell(%p)\n", temp1); 337 1.18 blymn temp1--; 338 1.18 blymn } 339 1.18 blymn } 340 1.18 blymn while (temp2 >= start) { 341 1.18 blymn (void)memcpy(temp1, temp2, sizeof(__LDATA)); 342 1.18 blymn temp1--, temp2--; 343 1.18 blymn } 344 1.18 blymn #ifdef DEBUG 345 1.18 blymn { 346 1.20 kre int i; 347 1.20 kre 348 1.18 blymn __CTRACE(__CTRACE_INPUT, "=====after shift====\n"); 349 1.18 blymn for (i = 0; i < win->maxx; i++) 350 1.18 blymn __CTRACE(__CTRACE_INPUT, 351 1.24 blymn "wins_nwstr: (%d,%d)=(%x,%x,%x,%p)\n", 352 1.18 blymn y, i, 353 1.18 blymn win->alines[y]->line[i].ch, 354 1.18 blymn win->alines[y]->line[i].attr, 355 1.24 blymn win->alines[y]->line[i].cflags, 356 1.18 blymn win->alines[y]->line[i].nsp); 357 1.18 blymn __CTRACE(__CTRACE_INPUT, "=====lstr====\n"); 358 1.18 blymn for (i = 0; i < len; i++) 359 1.18 blymn __CTRACE(__CTRACE_INPUT, 360 1.18 blymn "wins_nwstr: lstr[%d]= %x,\n", 361 1.18 blymn i, (unsigned) slstr[i]); 362 1.1 blymn } 363 1.18 blymn #endif /* DEBUG */ 364 1.1 blymn } 365 1.18 blymn 366 1.18 blymn /* update string columns */ 367 1.18 blymn x = lx; 368 1.18 blymn for (lstr = slstr, temp1 = start; len; len--, lstr++) { 369 1.18 blymn lnp = win->alines[y]; 370 1.18 blymn cc.vals[0] = *lstr; 371 1.18 blymn cc.elements = 1; 372 1.18 blymn cc.attributes = win->wattr; 373 1.18 blymn _cursesi_addwchar(win, &lnp, &y, &x, &cc, 0); 374 1.1 blymn } 375 1.18 blymn 376 1.1 blymn #ifdef DEBUG 377 1.1 blymn { 378 1.20 kre int i; 379 1.20 kre 380 1.18 blymn __CTRACE(__CTRACE_INPUT, "lx = %d, x = %x\n", lx, x); 381 1.18 blymn __CTRACE(__CTRACE_INPUT, "========after=======\n"); 382 1.18 blymn for (i = 0; i < win->maxx; i++) 383 1.2 blymn __CTRACE(__CTRACE_INPUT, 384 1.24 blymn "wins_nwstr: (%d,%d)=(%x,%x,%d,%x,%p)\n", 385 1.18 blymn y, i, 386 1.18 blymn win->alines[y]->line[i].ch, 387 1.18 blymn win->alines[y]->line[i].attr, 388 1.24 blymn win->alines[y]->line[i].wcols, 389 1.24 blymn win->alines[y]->line[i].cflags, 390 1.18 blymn win->alines[y]->line[i].nsp); 391 1.1 blymn } 392 1.1 blymn #endif /* DEBUG */ 393 1.1 blymn 394 1.18 blymn __touchline(win, (int) y, lx, (int) win->maxx - 1); 395 1.18 blymn 396 1.18 blymn /* 397 1.18 blymn * Handle the newline here - we don't need to check 398 1.18 blymn * if we are allowed to scroll because this was checked 399 1.18 blymn * already. 400 1.18 blymn */ 401 1.18 blymn if (*scp == '\n') { 402 1.18 blymn tx = win->curx; 403 1.18 blymn ty = win->cury; 404 1.18 blymn win->curx = x; 405 1.18 blymn win->cury = y; 406 1.18 blymn wclrtoeol(win); 407 1.18 blymn win->curx = tx; 408 1.18 blymn win->cury = ty; 409 1.18 blymn if (y == win->scr_b) 410 1.18 blymn scroll(win); 411 1.18 blymn else 412 1.18 blymn y++; 413 1.18 blymn scp++; 414 1.18 blymn 415 1.1 blymn } 416 1.18 blymn 417 1.18 blymn newx = win->maxx - 1 + win->ch_off; 418 1.18 blymn if (newx > *lnp->lastchp) 419 1.18 blymn *lnp->lastchp = newx; 420 1.1 blymn } 421 1.18 blymn free(lstr); 422 1.9 roy __sync(win); 423 1.1 blymn return OK; 424 1.1 blymn } 425