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