xref: /illumos-gate/usr/src/lib/libcurses/screen/mbaddch.c (revision d48be21240dfd051b689384ce2b23479d757f2d8)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*  Copyright (c) 1988 AT&T */
23 /*    All Rights Reserved   */
24 
25 
26 /*
27  *      Copyright (c) 1997, by Sun Microsystems, Inc.
28  *      All rights reserved.
29  */
30 
31 /*LINTLIBRARY*/
32 
33 #include	<sys/types.h>
34 #include	"curses_inc.h"
35 
36 /*
37  *	Clear the space occupied by a multicolumn character
38  */
39 
40 int
41 _mbclrch(WINDOW *win, int y, int x)
42 {
43 	chtype	*wcp, *ep, *wp, wc;
44 
45 	/* ASSERT(_scrmax > 1); */
46 
47 	wcp = win->_y[y];
48 	wp = wcp + x;
49 
50 	/* compute the bounds for the character */
51 	if (ISCBIT(*wp)) {
52 		for (; wp >= wcp; --wp)
53 			if (!ISCBIT(*wp))
54 				break;
55 		if (wp < wcp)
56 			return (ERR);
57 	}
58 	wc = RBYTE(*wp);
59 	ep = wp + _curs_scrwidth[TYPE(wc)];
60 	if (ep > wcp + win->_maxx)
61 		return (ERR);
62 
63 	/* update the change structure */
64 	/*LINTED*/
65 	if ((x = (int)(wp - wcp)) < win->_firstch[y])
66 		/*LINTED*/
67 		win->_firstch[y] = (short)x;
68 	/*LINTED*/
69 	if ((x = (int)(ep - wcp) - 1) > win->_lastch[y])
70 		/*LINTED*/
71 		win->_lastch[y] = (short)x;
72 
73 	/* clear the character */
74 	for (; wp < ep; ++wp)
75 		*wp = win->_bkgd;
76 	return (OK);
77 }
78 
79 
80 
81 /*
82  *	Make sure the window cursor point to a valid place.
83  *	If win->_insmode or isedge, the cursor has to
84  *	point to the start of a whole character; otherwise, the
85  *	cursor has to point to a part of a whole character.
86  */
87 
88 int
89 _mbvalid(WINDOW *win)
90 {
91 	chtype	*wp, *wcp, *ecp, wc;
92 	int		x;
93 	bool	isedge;
94 
95 	/* ASSERT(_scrmax > 1); */
96 
97 	x = win->_curx;
98 	wcp = win->_y[win->_cury];
99 	wp = wcp + x;
100 	if (!ISMBIT(*wp))
101 		return (OK);
102 
103 	ecp = wcp + win->_maxx;
104 	isedge = FALSE;
105 
106 	/* make wp points to the start column of a mb-character */
107 	if (ISCBIT(*wp)) {
108 		for (; wp >= wcp; --wp)
109 			if (!ISCBIT(*wp))
110 				break;
111 		if (wp < wcp) {
112 			for (wp = wcp + x + 1; wp < ecp; ++wp)
113 				if (!ISCBIT(*wp))
114 					break;
115 			if (wp >= ecp)
116 				return (ERR);
117 			isedge = TRUE;
118 		}
119 	}
120 
121 	/* make sure that wp points to a whole character */
122 	wc = RBYTE(*wp);
123 	if (wp + _curs_scrwidth[TYPE(wc)] > ecp) {
124 		for (wp -= 1; wp >= wcp; --wp)
125 			if (!ISCBIT(*wp))
126 				break;
127 		if (wp < wcp)
128 			return (ERR);
129 		isedge = TRUE;
130 	}
131 
132 	if (isedge || win->_insmode)
133 		/*LINTED*/
134 		win->_curx = (short)(wp-wcp);
135 	return (OK);
136 }
137 
138 
139 
140 /*
141  *	Add/insert multi-byte characters
142  */
143 
144 int
145 _mbaddch(WINDOW *win, chtype a, chtype c)
146 {
147 	int		n, x, y, nc, m, len, nbyte, ty;
148 	chtype		*wcp, wc;
149 	char		*wch, rc[2];
150 
151 	/* ASSERT(_mbtrue); */
152 
153 	/* decode the character into a sequence of bytes */
154 	nc = 0;
155 	if (ISCBIT(c))
156 		/*LINTED*/
157 		rc[nc++] = (char)(LBYTE(c)|MBIT);
158 	if (ISMBIT(c))
159 		/*LINTED*/
160 		rc[nc++] = (char)RBYTE(c);
161 
162 	a |= win->_attrs;
163 
164 	/* add the sequence to the image */
165 	for (n = 0; n < nc; ++n) {
166 		wc = RBYTE(rc[n]);
167 		ty = TYPE(wc);
168 		wch = win->_waitc;
169 
170 		/* first byte of a multi-byte character */
171 		if (ty > 0 || win->_nbyte < 0) {
172 			/*LINTED*/
173 			wch[0] = (char)wc;
174 			win->_nbyte = cswidth[ty] + (ty == 0 ? 0 : 1);
175 			win->_index = 1;
176 		} else {
177 		/* non-first byte */
178 			/*LINTED*/
179 			wch[win->_index] = (char)wc;
180 			win->_index += 1;
181 		}
182 
183 		/* if character is not ready to process */
184 		if (win->_index < win->_nbyte)
185 			continue;
186 
187 		/* begin processing the character */
188 		nbyte = win->_nbyte;
189 		win->_nbyte = -1;
190 		wc = RBYTE(wch[0]);
191 		len = _curs_scrwidth[TYPE(wc)];
192 
193 		/* window too small or char cannot be stored */
194 		if (len > win->_maxx || 2*len < nbyte)
195 			continue;
196 
197 		/* if the character won't fit into the line */
198 		if ((win->_curx + len) > win->_maxx &&
199 		    (win->_insmode || waddch(win, '\n') == ERR))
200 			continue;
201 
202 		y = win->_cury;
203 		x = win->_curx;
204 		wcp = win->_y[y] + x;
205 
206 		if (win->_insmode) {
207 			/* perform the right shift */
208 			if (_mbinsshift(win, len) == ERR)
209 				continue;
210 		} else if (_scrmax > 1) {
211 			/* clear any multi-byte char about to be overwritten */
212 			for (m = 0; m < len; ++m)
213 				if (ISMBIT(wcp[m]) &&
214 				    _mbclrch(win, y, x + m) == ERR)
215 					break;
216 			if (m < len)
217 				continue;
218 		}
219 
220 		/* pack two bytes at a time */
221 		for (m = nbyte/2; m > 0; m -= 1, wch += 2)
222 			*wcp++ = _CHAR((RBYTE(wch[1]) << 8) |
223 			    RBYTE(wch[0])) | CBIT | a;
224 
225 		/* do the remaining byte if any */
226 		if ((nbyte%2) != 0)
227 			*wcp++ = RBYTE(wch[0]) | CBIT | a;
228 
229 		/* fill-in for remaining display columns */
230 		for (m = (nbyte / 2) + (nbyte % 2); m < len; ++m)
231 			*wcp++ = (CBIT|MBIT) | a;
232 
233 		/* the first column has Continue BIT off */
234 		win->_y[y][x] &= ~CBIT;
235 
236 		if (win->_insmode == FALSE) {
237 			if (x < win->_firstch[y])
238 				/*LINTED*/
239 				win->_firstch[y] = (short)x;
240 			if ((x += len-1) >= win->_maxx)
241 				x = win->_maxx-1;
242 			if (x > win->_lastch[y])
243 				/*LINTED*/
244 				win->_lastch[y] = (short)x;
245 
246 			if ((win->_curx += len) >= win->_maxx) {
247 				if (y >= (win->_maxy-1) || y == win->_bmarg) {
248 					win->_curx = win->_maxx-1;
249 					if (wscrl(win, 1) == ERR)
250 						continue;
251 				} else {
252 					win->_cury += 1;
253 					win->_curx = 0;
254 				}
255 			}
256 		}
257 	}
258 
259 	return (OK);
260 }
261