xref: /netbsd-src/lib/libcurses/border.c (revision 0a70793f25c6bfb9b7a174e0a82256150e459a51)
1 /*	$NetBSD: border.c,v 1.26 2024/12/25 15:35:29 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 2000 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Julian Coleman.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __RCSID("$NetBSD: border.c,v 1.26 2024/12/25 15:35:29 christos Exp $");
35 #endif				/* not lint */
36 
37 #include <stdlib.h>
38 #include <string.h>
39 
40 #include "curses.h"
41 #include "curses_private.h"
42 
43 #ifndef _CURSES_USE_MACROS
44 
45 /*
46  * border --
47  *	Draw a border around stdscr using the specified
48  *	delimiting characters.
49  */
50 int
51 border(chtype left, chtype right, chtype top, chtype bottom, chtype topleft,
52        chtype topright, chtype botleft, chtype botright)
53 {
54 	return wborder(stdscr, left, right, top, bottom, topleft, topright,
55 	    botleft, botright);
56 }
57 
58 #endif
59 
60 /*
61  * wborder --
62  *	Draw a border around the given window using the specified delimiting
63  *	characters.
64  */
65 int
66 wborder(WINDOW *win, chtype left, chtype right, chtype top, chtype bottom,
67 	chtype topleft, chtype topright, chtype botleft, chtype botright)
68 {
69 #ifndef HAVE_WCHAR
70 	int	 endy, endx, i;
71 	__LDATA	*fp, *lp;
72 
73 	if (__predict_false(win == NULL))
74 		return ERR;
75 
76 	if (!(left & __CHARTEXT))
77 		left |= ACS_VLINE;
78 	if (!(right & __CHARTEXT))
79 		right |= ACS_VLINE;
80 	if (!(top & __CHARTEXT))
81 		top |= ACS_HLINE;
82 	if (!(bottom & __CHARTEXT))
83 		bottom |= ACS_HLINE;
84 	if (!(topleft & __CHARTEXT))
85 		topleft |= ACS_ULCORNER;
86 	if (!(topright & __CHARTEXT))
87 		topright |= ACS_URCORNER;
88 	if (!(botleft & __CHARTEXT))
89 		botleft |= ACS_LLCORNER;
90 	if (!(botright & __CHARTEXT))
91 		botright |= ACS_LRCORNER;
92 
93 	__CTRACE(__CTRACE_INPUT, "wborder: window 0x%p\n", win);
94 	__CTRACE(__CTRACE_INPUT, "wborder: left = %c, 0x%x\n",
95 	    left & __CHARTEXT, left & __ATTRIBUTES);
96 	__CTRACE(__CTRACE_INPUT, "wborder: right = %c, 0x%x\n",
97 	    right & __CHARTEXT, right & __ATTRIBUTES);
98 	__CTRACE(__CTRACE_INPUT, "wborder: top = %c, 0x%x\n",
99 	    top & __CHARTEXT, top & __ATTRIBUTES);
100 	__CTRACE(__CTRACE_INPUT, "wborder: bottom = %c, 0x%x\n",
101 	    bottom & __CHARTEXT, bottom & __ATTRIBUTES);
102 	__CTRACE(__CTRACE_INPUT, "wborder: topleft = %c, 0x%x\n",
103 	    topleft & __CHARTEXT, topleft & __ATTRIBUTES);
104 	__CTRACE(__CTRACE_INPUT, "wborder: topright = %c, 0x%x\n",
105 	    topright & __CHARTEXT, topright & __ATTRIBUTES);
106 	__CTRACE(__CTRACE_INPUT, "wborder: botleft = %c, 0x%x\n",
107 	    botleft & __CHARTEXT, botleft & __ATTRIBUTES);
108 	__CTRACE(__CTRACE_INPUT, "wborder: botright = %c, 0x%x\n",
109 	    botright & __CHARTEXT, botright & __ATTRIBUTES);
110 
111 	/* Merge window and background attributes */
112 	left |= (left & __COLOR) ? (win->wattr & ~__COLOR) : win->wattr;
113 	left |= (left & __COLOR) ? (win->battr & ~__COLOR) : win->battr;
114 	right |= (right & __COLOR) ? (win->wattr & ~__COLOR) : win->wattr;
115 	right |= (right & __COLOR) ? (win->battr & ~__COLOR) : win->battr;
116 	top |= (top & __COLOR) ? (win->wattr & ~__COLOR) : win->wattr;
117 	top |= (top & __COLOR) ? (win->battr & ~__COLOR) : win->battr;
118 	bottom |= (bottom & __COLOR) ? (win->wattr & ~__COLOR) : win->wattr;
119 	bottom |= (bottom & __COLOR) ? (win->battr & ~__COLOR) : win->battr;
120 	topleft |= (topleft & __COLOR) ? (win->wattr & ~__COLOR) : win->wattr;
121 	topleft |= (topleft & __COLOR) ? (win->battr & ~__COLOR) : win->battr;
122 	topright |= (topright & __COLOR) ? (win->wattr & ~__COLOR) : win->wattr;
123 	topright |= (topright & __COLOR) ? (win->battr & ~__COLOR) : win->battr;
124 	botleft |= (botleft & __COLOR) ? (win->wattr & ~__COLOR) : win->wattr;
125 	botleft |= (botleft & __COLOR) ? (win->battr & ~__COLOR) : win->battr;
126 	botright |= (botright & __COLOR) ? (win->wattr & ~__COLOR) : win->wattr;
127 	botright |= (botright & __COLOR) ? (win->battr & ~__COLOR) : win->battr;
128 
129 	endx = win->maxx - 1;
130 	endy = win->maxy - 1;
131 	fp = win->alines[0]->line;
132 	lp = win->alines[endy]->line;
133 
134 	/* Sides */
135 	for (i = 1; i < endy; i++) {
136 		win->alines[i]->line[0].ch = (wchar_t) left & __CHARTEXT;
137 		win->alines[i]->line[0].attr = (attr_t) left & __ATTRIBUTES;
138 		win->alines[i]->line[endx].ch = (wchar_t) right & __CHARTEXT;
139 		win->alines[i]->line[endx].attr = (attr_t) right & __ATTRIBUTES;
140 	}
141 	for (i = 1; i < endx; i++) {
142 		fp[i].ch = (wchar_t) top & __CHARTEXT;
143 		fp[i].attr = (attr_t) top & __ATTRIBUTES;
144 		lp[i].ch = (wchar_t) bottom & __CHARTEXT;
145 		lp[i].attr = (attr_t) bottom & __ATTRIBUTES;
146 	}
147 
148 	/* Corners */
149 	if (!(win->maxy == LINES && win->maxx == COLS &&
150 	    (win->flags & __SCROLLOK) && (win->flags & __SCROLLWIN))) {
151 		fp[0].ch = (wchar_t) topleft & __CHARTEXT;
152 		fp[0].attr = (attr_t) topleft & __ATTRIBUTES;
153 		fp[endx].ch = (wchar_t) topright & __CHARTEXT;
154 		fp[endx].attr = (attr_t) topright & __ATTRIBUTES;
155 		lp[0].ch = (wchar_t) botleft & __CHARTEXT;
156 		lp[0].attr = (attr_t) botleft & __ATTRIBUTES;
157 		lp[endx].ch = (wchar_t) botright & __CHARTEXT;
158 		lp[endx].attr = (attr_t) botright & __ATTRIBUTES;
159 	}
160 	__touchwin(win, 0);
161 	return OK;
162 #else /* HAVE_WCHAR */
163 	cchar_t ls, rs, ts, bs, tl, tr, bl, br;
164 	cchar_t *lsp, *rsp, *tsp, *bsp, *tlp, *trp, *blp, *brp;
165 
166 #define S(in, out, def) \
167 	if (in & __CHARTEXT) { \
168 		__cursesi_chtype_to_cchar(in, &out); \
169 	} else { \
170 		memcpy(&out, def, sizeof(cchar_t)); \
171 		out.attributes |= in & __ATTRIBUTES; \
172 	} \
173 	out##p = &out;
174 
175 	S(left, ls, WACS_VLINE);
176 	S(right, rs, WACS_VLINE);
177 	S(top, ts, WACS_HLINE);
178 	S(bottom, bs, WACS_HLINE);
179 	S(topleft, tl, WACS_ULCORNER);
180 	S(topright, tr, WACS_URCORNER);
181 	S(botleft, bl, WACS_LLCORNER);
182 	S(botright, br, WACS_LRCORNER);
183 #undef S
184 	return wborder_set(win, lsp, rsp, tsp, bsp, tlp, trp, blp, brp);
185 #endif /* HAVE_WCHAR */
186 }
187 
188 int border_set(const cchar_t *ls, const cchar_t *rs, const cchar_t *ts,
189 	   const cchar_t *bs, const cchar_t *tl, const cchar_t *tr,
190 	   const cchar_t *bl, const cchar_t *br)
191 {
192 #ifndef HAVE_WCHAR
193 	return ERR;
194 #else
195 	return wborder_set(stdscr, ls, rs, ts, bs, tl, tr, bl, br);
196 #endif /* HAVE_WCHAR */
197 }
198 
199 int wborder_set(WINDOW *win, const cchar_t *ls, const cchar_t *rs,
200 		const cchar_t *ts, const cchar_t *bs,
201 		const cchar_t *tl, const cchar_t *tr,
202 		const cchar_t *bl, const cchar_t *br)
203 {
204 #ifndef HAVE_WCHAR
205 	return ERR;
206 #else
207 	int	 endy, endx, i, j, k, cw, pcw, tlcw, blcw, trcw, brcw;
208 	cchar_t left, right, bottom, top, topleft, topright, botleft, botright;
209 	nschar_t *np, *tnp;
210 
211 	if (__predict_false(win == NULL))
212 		return ERR;
213 
214 	if (ls && wcwidth(ls->vals[0]))
215 		memcpy(&left, ls, sizeof(cchar_t));
216 	else
217 		memcpy(&left, WACS_VLINE, sizeof(cchar_t));
218 	if (rs && wcwidth( rs->vals[0]))
219 		memcpy(&right, rs, sizeof(cchar_t));
220 	else
221 		memcpy(&right, WACS_VLINE, sizeof(cchar_t));
222 	if (ts && wcwidth( ts->vals[0]))
223 		memcpy(&top, ts, sizeof(cchar_t));
224 	else
225 		memcpy( &top, WACS_HLINE, sizeof(cchar_t));
226 	if (bs && wcwidth( bs->vals[0]))
227 		memcpy(&bottom, bs, sizeof(cchar_t));
228 	else
229 		memcpy(&bottom, WACS_HLINE, sizeof(cchar_t));
230 	if (tl && wcwidth(tl->vals[0]))
231 		memcpy( &topleft, tl, sizeof(cchar_t));
232 	else
233 		memcpy(&topleft, WACS_ULCORNER, sizeof(cchar_t));
234 	if (tr && wcwidth( tr->vals[0]))
235 		memcpy(&topright, tr, sizeof(cchar_t));
236 	else
237 		memcpy(&topright, WACS_URCORNER, sizeof( cchar_t ));
238 	if (bl && wcwidth( bl->vals[0]))
239 		memcpy(&botleft, bl, sizeof(cchar_t));
240 	else
241 		memcpy(&botleft, WACS_LLCORNER, sizeof(cchar_t));
242 	if (br && wcwidth( br->vals[0]))
243 		memcpy(&botright, br, sizeof(cchar_t));
244 	else
245 		memcpy(&botright, WACS_LRCORNER, sizeof(cchar_t));
246 
247 	__CTRACE(__CTRACE_INPUT, "wborder_set: window 0x%p\n", win);
248 	__CTRACE(__CTRACE_INPUT, "wborder_set: left = %c, 0x%x\n",
249 	    left.vals[0], left.attributes );
250 	__CTRACE(__CTRACE_INPUT, "wborder_set: right = %c, 0x%x\n",
251 	    right.vals[0], right.attributes );
252 	__CTRACE(__CTRACE_INPUT, "wborder_set: top = %c, 0x%x\n",
253 	    top.vals[0], top.attributes );
254 	__CTRACE(__CTRACE_INPUT, "wborder_set: bottom = %c, 0x%x\n",
255 	    bottom.vals[0], bottom.attributes );
256 	__CTRACE(__CTRACE_INPUT, "wborder_set: topleft = %c, 0x%x\n",
257 	    topleft.vals[0], topleft.attributes );
258 	__CTRACE(__CTRACE_INPUT, "wborder_set: topright = %c, 0x%x\n",
259 	    topright.vals[0], topright.attributes );
260 	__CTRACE(__CTRACE_INPUT, "wborder_set: botleft = %c, 0x%x\n",
261 	    botleft.vals[0], botleft.attributes );
262 	__CTRACE(__CTRACE_INPUT, "wborder_set: botright = %c, 0x%x\n",
263 	    botright.vals[0], botright.attributes );
264 
265 	/* Merge window attributes */
266 	left.attributes |= (left.attributes & __COLOR) ?
267 		(win->wattr & ~__COLOR) : win->wattr;
268 	left.attributes |= (left.attributes & __COLOR) ?
269 		(win->battr & ~__COLOR) : win->battr;
270 	right.attributes |= (right.attributes & __COLOR) ?
271 		(win->wattr & ~__COLOR) : win->wattr;
272 	right.attributes |= (right.attributes & __COLOR) ?
273 		(win->battr & ~__COLOR) : win->battr;
274 	top.attributes |= (top.attributes & __COLOR) ?
275 		(win->wattr & ~__COLOR) : win->wattr;
276 	top.attributes |= (top.attributes & __COLOR) ?
277 		(win->battr & ~__COLOR) : win->battr;
278 	bottom.attributes |= (bottom.attributes & __COLOR) ?
279 		(win->wattr & ~__COLOR) : win->wattr;
280 	bottom.attributes |= (bottom.attributes & __COLOR) ?
281 		(win->battr & ~__COLOR) : win->battr;
282 	topleft.attributes |= (topleft.attributes & __COLOR) ?
283 		(win->wattr & ~__COLOR) : win->wattr;
284 	topleft.attributes |= (topleft.attributes & __COLOR) ?
285 		(win->battr & ~__COLOR) : win->battr;
286 	topright.attributes |= (topright.attributes & __COLOR) ?
287 		(win->wattr & ~__COLOR) : win->wattr;
288 	topright.attributes |= (topright.attributes & __COLOR) ?
289 		(win->battr & ~__COLOR) : win->battr;
290 	botleft.attributes |= (botleft.attributes & __COLOR) ?
291 		(win->wattr & ~__COLOR) : win->wattr;
292 	botleft.attributes |= (botleft.attributes & __COLOR) ?
293 		(win->battr & ~__COLOR) : win->battr;
294 	botright.attributes |= (botright.attributes & __COLOR) ?
295 		(win->wattr & ~__COLOR) : win->wattr;
296 	botright.attributes |= (botright.attributes & __COLOR) ?
297 		(win->battr & ~__COLOR) : win->battr;
298 
299 	endx = win->maxx - 1;
300 	endy = win->maxy - 1;
301 
302 	/* Sides */
303 	for (i = 1; i < endy; i++) {
304 		/* left border */
305 		cw = wcwidth(left.vals[0]);
306 		if (cw < 0)
307 			cw = 1;
308 		for ( j = 0; j < cw; j++ ) {
309 			win->alines[i]->line[j].ch = left.vals[0];
310 			win->alines[i]->line[j].cflags &= ~CA_BACKGROUND;
311 			win->alines[i]->line[j].attr = left.attributes;
312 			np = win->alines[i]->line[j].nsp;
313 			if (np) {
314 				while (np) {
315 					tnp = np->next;
316 					free(np);
317 					np = tnp;
318 				}
319 				win->alines[i]->line[j].nsp = NULL;
320 			}
321 			if (j)
322 				win->alines[i]->line[j].wcols = -j;
323 			else {
324 				win->alines[i]->line[j].wcols = cw;
325 				if (left.elements > 1) {
326 					for (k = 1; k < left.elements; k++) {
327 						np = malloc(sizeof(nschar_t));
328 						if (!np)
329 							return ERR;
330 						np->ch = left.vals[ k ];
331 						np->next = win->alines[i]->line[j].nsp;
332 						win->alines[i]->line[j].nsp
333 							= np;
334 					}
335 				}
336 			}
337 		}
338 		for (j = cw; win->alines[i]->line[j].wcols < 0; j++) {
339 			__CTRACE(__CTRACE_INPUT,
340 			    "wborder_set: clean out partial char[%d]", j);
341 			win->alines[i]->line[j].ch = win->bch;
342 			win->alines[i]->line[j].cflags |= CA_BACKGROUND;
343 			if (_cursesi_copy_nsp(win->bnsp,
344 					      &win->alines[i]->line[j]) == ERR)
345 				return ERR;
346 			win->alines[i]->line[j].wcols = 1;
347 		}
348 		/* right border */
349 		cw = wcwidth(right.vals[0]);
350 		if (cw < 0)
351 			cw = 1;
352 		pcw = win->alines[i]->line[endx - cw].wcols;
353 		for ( j = endx - cw + 1; j <= endx; j++ ) {
354 			win->alines[i]->line[j].ch = right.vals[0];
355 			win->alines[i]->line[j].cflags &= ~CA_BACKGROUND;
356 			win->alines[i]->line[j].attr = right.attributes;
357 			np = win->alines[i]->line[j].nsp;
358 			if (np) {
359 				while (np) {
360 					tnp = np->next;
361 					free(np);
362 					np = tnp;
363 				}
364 				win->alines[i]->line[j].nsp = NULL;
365 			}
366 			if (j == endx - cw + 1) {
367 				win->alines[i]->line[j].wcols = cw;
368 				if (right.elements > 1) {
369 					for (k = 1; k < right.elements; k++) {
370 						np = malloc(sizeof(nschar_t));
371 						if (!np)
372 							return ERR;
373 						np->ch = right.vals[ k ];
374 						np->next = win->alines[i]->line[j].nsp;
375 						win->alines[i]->line[j].nsp
376 							= np;
377 					}
378 				}
379 			} else
380 				win->alines[i]->line[j].wcols =
381 				    endx - cw + 1 - j;
382 		}
383 		if (pcw != 1) {
384 			__CTRACE(__CTRACE_INPUT,
385 			    "wborder_set: clean out partial chars[%d:%d]",
386 			    endx - cw + pcw, endx - cw);
387 			k = pcw < 0 ? endx -cw + pcw : endx - cw;
388 			for (j = endx - cw; j >= k; j--) {
389 				win->alines[i]->line[j].ch = win->bch;
390 				win->alines[i]->line[j].cflags |= CA_BACKGROUND;
391 				if (_cursesi_copy_nsp(win->bnsp,
392 					       &win->alines[i]->line[j]) == ERR)
393 					return ERR;
394 				win->alines[i]->line[j].attr = win->battr;
395 				win->alines[i]->line[j].wcols = 1;
396 			}
397 		}
398 	}
399 	tlcw = wcwidth(topleft.vals[0]);
400 	if (tlcw < 0)
401 		tlcw = 1;
402 	blcw = wcwidth(botleft.vals[0]);
403 	if (blcw < 0)
404 		blcw = 1;
405 	trcw = wcwidth(topright.vals[0]);
406 	if (trcw < 0)
407 		trcw = 1;
408 	brcw = wcwidth(botright.vals[0]);
409 	if (brcw < 0)
410 		brcw = 1;
411 	/* upper border */
412 	cw = wcwidth(top.vals[0]);
413 	if (cw < 0)
414 		cw = 1;
415 	for (i = tlcw; i <= min( endx - cw, endx - trcw); i += cw) {
416 		for (j = 0; j < cw; j++) {
417 			win->alines[0]->line[i + j].ch = top.vals[0];
418 			win->alines[0]->line[i + j].cflags &= ~CA_BACKGROUND;
419 			win->alines[0]->line[i + j].attr = top.attributes;
420 			np = win->alines[0]->line[i + j].nsp;
421 			if (np) {
422 				while (np) {
423 					tnp = np->next;
424 					free(np);
425 					np = tnp;
426 				}
427 				win->alines[0]->line[i + j].nsp = NULL;
428 			}
429 			if (j)
430 				win->alines[ 0 ]->line[ i + j ].wcols = -j;
431 			else {
432 				win->alines[ 0 ]->line[ i + j ].wcols = cw;
433 				if ( top.elements > 1 ) {
434 					for (k = 1; k < top.elements; k++) {
435 						np = malloc(sizeof(nschar_t));
436 						if (!np)
437 							return ERR;
438 						np->ch = top.vals[k];
439 						np->next = win->alines[0]->line[i + j].nsp;
440 						win->alines[0]->line[i + j].nsp
441 							= np;
442 					}
443 				}
444 			}
445 		}
446 	}
447 	while (i <= endx - trcw) {
448 		win->alines[0]->line[i].ch = win->bch;
449 		win->alines[0]->line[i].cflags |= CA_BACKGROUND;
450 		if (_cursesi_copy_nsp(win->bnsp,
451 				      &win->alines[0]->line[i]) == ERR)
452 			return ERR;
453 		win->alines[0]->line[i].attr = win->battr;
454 		win->alines[0]->line[i].wcols = 1;
455 		i++;
456 	}
457 	/* lower border */
458 	for (i = blcw; i <= min( endx - cw, endx - brcw); i += cw) {
459 		for (j = 0; j < cw; j++) {
460 			win->alines[endy]->line[i + j].ch = bottom.vals[0];
461 			win->alines[endy]->line[i + j].cflags &= ~CA_BACKGROUND;
462 			win->alines[endy]->line[i + j].attr = bottom.attributes;
463 			np = win->alines[endy]->line[i + j].nsp;
464 			if (np) {
465 				while (np) {
466 					tnp = np->next;
467 					free(np);
468 					np = tnp;
469 				}
470 				win->alines[endy]->line[i + j].nsp = NULL;
471 			}
472 			if (j)
473 				win->alines[endy]->line[i + j].wcols = -j;
474 			else {
475 				win->alines[endy]->line[i + j].wcols = cw;
476 				if (bottom.elements > 1) {
477 					for (k = 1; k < bottom.elements; k++) {
478 						np = malloc(sizeof(nschar_t));
479 						if (!np)
480 							return ERR;
481 						np->ch = bottom.vals[ k ];
482 						np->next = win->alines[endy]->line[i + j].nsp;
483 						win->alines[endy]->line[i + j].nsp = np;
484 					}
485 				}
486 			}
487 		}
488 	}
489 	while (i <= endx - brcw) {
490 		win->alines[endy]->line[i].ch = win->bch;
491 		win->alines[endy]->line[i].cflags |= CA_BACKGROUND;
492 		if (_cursesi_copy_nsp(win->bnsp,
493 				      &win->alines[endy]->line[i]) == ERR)
494 			return ERR;
495 		win->alines[endy]->line[i].attr = win->battr;
496 		win->alines[endy]->line[i].wcols = 1;
497 		i++;
498 	}
499 
500 	/* Corners */
501 	if (!(win->maxy == LINES && win->maxx == COLS &&
502 		(win->flags & __SCROLLOK) && (win->flags & __SCROLLWIN))) {
503 		for (i = 0; i < tlcw; i++) {
504 			win->alines[0]->line[i].ch = topleft.vals[0];
505 			win->alines[0]->line[i].cflags &= ~CA_BACKGROUND;
506 			win->alines[0]->line[i].attr = topleft.attributes;
507 			np = win->alines[0]->line[i].nsp;
508 			if (np) {
509 				while (np) {
510 					tnp = np->next;
511 					free(np);
512 					np = tnp;
513 				}
514 				win->alines[0]->line[i].nsp = NULL;
515 			}
516 			if (i)
517 				win->alines[0]->line[i].wcols = -i;
518 			else {
519 				win->alines[0]->line[i].wcols = tlcw;
520 				if (topleft.elements > 1) {
521 					for (k = 1; k < topleft.elements; k++)
522 					{
523 						np = malloc(sizeof(nschar_t));
524 						if (!np)
525 							return ERR;
526 						np->ch = topleft.vals[k];
527 						np->next = win->alines[0]->line[i].nsp;
528 						win->alines[0]->line[i].nsp = np;
529 					}
530 				}
531 			}
532 		}
533 		for (i = endx - trcw + 1; i <= endx; i++) {
534 			win->alines[0]->line[i].ch = topright.vals[0];
535 			win->alines[0]->line[i].cflags &= ~CA_BACKGROUND;
536 			win->alines[0]->line[i].attr = topright.attributes;
537 			np = win->alines[0]->line[i].nsp;
538 			if (np) {
539 				while (np) {
540 					tnp = np->next;
541 					free(np);
542 					np = tnp;
543 				}
544 				win->alines[0]->line[i].nsp = NULL;
545 			}
546 			if (i == endx - trcw + 1) {
547 				win->alines[0]->line[i].wcols = trcw;
548 				if (topright.elements > 1) {
549 					for (k = 1; k < topright.elements;k ++)
550 					{
551 						np = malloc(sizeof(nschar_t));
552 						if (!np)
553 							return ERR;
554 						np->ch = topright.vals[k];
555 						np->next = win->alines[0]->line[i].nsp;
556 						win->alines[ 0 ]->line[i].nsp = np;
557 					}
558 				}
559 			} else
560 				win->alines[0]->line[i].wcols =
561 				    endx - trcw + 1 - i;
562 		}
563 		for (i = 0; i < blcw; i++) {
564 			win->alines[endy]->line[i].ch = botleft.vals[0];
565 			win->alines[endy]->line[i].cflags &= ~CA_BACKGROUND;
566 			win->alines[endy]->line[i].attr = botleft.attributes;
567 			np = win->alines[ endy ]->line[i].nsp;
568 			if (np) {
569 				while (np) {
570 					tnp = np->next;
571 					free(np);
572 					np = tnp;
573 				}
574 				win->alines[endy]->line[i].nsp = NULL;
575 			}
576 			if (i)
577 				win->alines[endy]->line[i].wcols = -i;
578 			else {
579 				win->alines[endy]->line[i].wcols = blcw;
580 				if (botleft.elements > 1) {
581 					for (k = 1; k < botleft.elements; k++) {
582 						np = malloc(sizeof(nschar_t));
583 						if (!np)
584 							return ERR;
585 						np->ch = botleft.vals[ k ];
586 						np->next = win->alines[endy]->line[i].nsp;
587 						win->alines[endy]->line[i].nsp = np;
588 					}
589 				}
590 			}
591 		}
592 		for (i = endx - brcw + 1; i <= endx; i++) {
593 			win->alines[endy]->line[i].ch = botright.vals[0];
594 			win->alines[endy]->line[i].cflags &= ~CA_BACKGROUND;
595 			win->alines[endy]->line[i].attr = botright.attributes;
596 			np = win->alines[endy]->line[i].nsp;
597 			if (np) {
598 				while (np) {
599 					tnp = np->next;
600 					free(np);
601 					np = tnp;
602 				}
603 				win->alines[endy]->line[i].nsp = NULL;
604 			}
605 			if (i == endx - brcw + 1) {
606 				win->alines[endy]->line[i].wcols = brcw;
607 				if (botright.elements > 1) {
608 					for (k = 1; k < botright.elements; k++){
609 						np = malloc(sizeof(nschar_t));
610 						if (!np)
611 							return ERR;
612 						np->ch = botright.vals[k];
613 						np->next = win->alines[endy]->line[i].nsp;
614 						win->alines[endy]->line[i].nsp = np;
615 					}
616 				}
617 			} else
618 				win->alines[endy]->line[i].wcols =
619 				    endx - brcw + 1 - i;
620 		}
621 	}
622 	__touchwin(win, 0);
623 	return OK;
624 #endif /* HAVE_WCHAR */
625 }
626