Home | History | Annotate | Line # | Download | only in libcurses
ins_wstr.c revision 1.18
      1 /*   $NetBSD: ins_wstr.c,v 1.18 2021/11/15 06:27: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.18 2021/11/15 06:27: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 i, 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 				w = min(win->maxx - x, TABSIZE - (x % TABSIZE));
    198 				width += w * wcwidth(ws[0]);
    199 				x += w * wcwidth(ws[0]);
    200 				scp++;
    201 				continue;
    202 		}
    203 		w = wcwidth(*scp);
    204 		if (w < 0)
    205 			w = 1;
    206 		tn--, width += w;
    207 		scp++;
    208 	}
    209 	__CTRACE(__CTRACE_INPUT, "wins_nwstr: width=%d,len=%d\n", width, len);
    210 
    211 	if (width > win->maxx - win->curx + 1) {
    212 		free(lstr);
    213 		return ERR;
    214 	}
    215 
    216 	scp = wstr;
    217 	x = win->curx;
    218 	y = win->cury;
    219 	len = 0;
    220 	width = 0;
    221 	slstr = lstr;
    222 
    223 	while (*scp && n) {
    224 		lstr = slstr;
    225 		lx = x;
    226 		while (*scp) {
    227 			if (!n)
    228 				break;
    229 			switch (*scp) {
    230 				case L'\b':
    231 					if (--x < 0)
    232 						x = 0;
    233 					if (--len < 0)
    234 						len = 0;
    235 					cw = wcwidth(*(scp - 1));
    236 					if (cw < 0)
    237 						cw = 1;
    238 					width -= cw;
    239 					scp++;
    240 					if (lstr != slstr)
    241 						lstr--;
    242 					continue;;
    243 
    244 				case L'\r':
    245 					width = 0;
    246 					len = 0;
    247 					x = 0;
    248 					scp++;
    249 					lstr = slstr;
    250 					continue;
    251 
    252 				case L'\n':
    253 					goto loopdone;
    254 					break;
    255 
    256 				case L'\t':
    257 					w = min(win->maxx - x,
    258 					    TABSIZE - (x % TABSIZE));
    259 					width += w * wcwidth(ws[0]);
    260 					x += w * wcwidth(ws[0]);
    261 					len += w;
    262 					scp++;
    263 					for (i = 0; i < w; i++ ) {
    264 						*lstr = *ws;
    265 						lstr++;
    266 					}
    267 					continue;
    268 			}
    269 			w = wcwidth(*scp);
    270 			if (w < 0)
    271 				w = 1;
    272 			*lstr = *scp;
    273 			n--, len++, width += w;
    274 			scp++, lstr++;
    275 		}
    276 
    277 loopdone:
    278 		start = &win->alines[y]->line[x];
    279 		sx = x;
    280 		lnp = win->alines[y];
    281 		pcw = WCOL(*start);
    282 		if (pcw < 0) {
    283 			sx += pcw;
    284 			start += pcw;
    285 		}
    286 		__CTRACE(__CTRACE_INPUT, "wins_nwstr: start@(%d)\n", sx);
    287 		pcw = WCOL(*start);
    288 		lnp->flags |= __ISDIRTY;
    289 		newx = sx + win->ch_off;
    290 		if (newx < *lnp->firstchp)
    291 			*lnp->firstchp = newx;
    292 #ifdef DEBUG
    293 		{
    294 			__CTRACE(__CTRACE_INPUT, "========before=======\n");
    295 			for (i = 0; i < win->maxx; i++)
    296 			__CTRACE(__CTRACE_INPUT,
    297 				    "wins_nwstr: (%d,%d)=(%x,%x,%p)\n",
    298 				    y, i, win->alines[y]->line[i].ch,
    299 				    win->alines[y]->line[i].attr,
    300 				    win->alines[y]->line[i].nsp);
    301 		}
    302 #endif /* DEBUG */
    303 
    304 		/* shift all complete characters */
    305 		if (sx + width + pcw <= win->maxx) {
    306 			__CTRACE(__CTRACE_INPUT, "wins_nwstr: shift all characters by %d\n", width);
    307 			temp1 = &win->alines[y]->line[win->maxx - 1];
    308 			temp2 = temp1 - width;
    309 			pcw = WCOL(*(temp2 + 1));
    310 			if (pcw < 0) {
    311 				__CTRACE(__CTRACE_INPUT,
    312 				    "wins_nwstr: clear from %d to EOL(%d)\n",
    313 				    win->maxx + pcw, win->maxx - 1);
    314 				temp2 += pcw;
    315 				while (temp1 > temp2 + width) {
    316 					temp1->ch = (wchar_t)btowc((int) win->bch);
    317 					if (_cursesi_copy_nsp(win->bnsp, temp1) == ERR) {
    318 						free(lstr);
    319 						return ERR;
    320 					}
    321 					temp1->attr = win->battr;
    322 					SET_WCOL(*temp1, 1);
    323 					__CTRACE(__CTRACE_INPUT,
    324 					    "wins_nwstr: empty cell(%p)\n", temp1);
    325 					temp1--;
    326 				}
    327 			}
    328 			while (temp2 >= start) {
    329 				(void)memcpy(temp1, temp2, sizeof(__LDATA));
    330 				temp1--, temp2--;
    331 			}
    332 #ifdef DEBUG
    333 			{
    334 				__CTRACE(__CTRACE_INPUT, "=====after shift====\n");
    335 				for (i = 0; i < win->maxx; i++)
    336 					__CTRACE(__CTRACE_INPUT,
    337 					    "wins_nwstr: (%d,%d)=(%x,%x,%p)\n",
    338 					    y, i,
    339 					    win->alines[y]->line[i].ch,
    340 					    win->alines[y]->line[i].attr,
    341 					    win->alines[y]->line[i].nsp);
    342 				__CTRACE(__CTRACE_INPUT, "=====lstr====\n");
    343 				for (i = 0; i < len; i++)
    344 					__CTRACE(__CTRACE_INPUT,
    345 					    "wins_nwstr: lstr[%d]= %x,\n",
    346 					    i, (unsigned) slstr[i]);
    347 			}
    348 #endif /* DEBUG */
    349 		}
    350 
    351 		/* update string columns */
    352 		x = lx;
    353 		for (lstr = slstr, temp1 = start; len; len--, lstr++) {
    354 			lnp = win->alines[y];
    355 			cc.vals[0] = *lstr;
    356 			cc.elements = 1;
    357 			cc.attributes = win->wattr;
    358 			_cursesi_addwchar(win, &lnp, &y, &x, &cc, 0);
    359 		}
    360 
    361 #ifdef DEBUG
    362 		{
    363 			__CTRACE(__CTRACE_INPUT, "lx = %d, x = %x\n", lx, x);
    364 			__CTRACE(__CTRACE_INPUT, "========after=======\n");
    365 			for (i = 0; i < win->maxx; i++)
    366 				__CTRACE(__CTRACE_INPUT,
    367 				    "wins_nwstr: (%d,%d)=(%x,%x,%p)\n",
    368 				    y, i,
    369 				    win->alines[y]->line[i].ch,
    370 				    win->alines[y]->line[i].attr,
    371 				    win->alines[y]->line[i].nsp);
    372 		}
    373 #endif /* DEBUG */
    374 
    375 		__touchline(win, (int) y, lx, (int) win->maxx - 1);
    376 
    377 		/*
    378 		 * Handle the newline here - we don't need to check
    379 		 * if we are allowed to scroll because this was checked
    380 		 * already.
    381 		 */
    382 		if (*scp == '\n') {
    383 			tx = win->curx;
    384 			ty = win->cury;
    385 			win->curx = x;
    386 			win->cury = y;
    387 			wclrtoeol(win);
    388 			win->curx = tx;
    389 			win->cury = ty;
    390 			if (y == win->scr_b)
    391 				scroll(win);
    392 			else
    393 				y++;
    394 			scp++;
    395 
    396 		}
    397 
    398 		newx = win->maxx - 1 + win->ch_off;
    399 		if (newx > *lnp->lastchp)
    400 			*lnp->lastchp = newx;
    401 	}
    402 	free(lstr);
    403 	__sync(win);
    404 	return OK;
    405 }
    406