Home | History | Annotate | Line # | Download | only in libcurses
      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