1/*	$NetBSD: acs.c,v 1.22 2021/09/06 07:03:49 rin 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: acs.c,v 1.22 2021/09/06 07:03:49 rin Exp $");
35#endif				/* not lint */
36
37#include "curses.h"
38#include "curses_private.h"
39
40chtype _acs_char[NUM_ACS];
41#ifdef HAVE_WCHAR
42#include <assert.h>
43#include <locale.h>
44#include <langinfo.h>
45#include <strings.h>
46
47cchar_t _wacs_char[ NUM_ACS ];
48#endif /* HAVE_WCHAR */
49
50/*
51 * __init_acs --
52 *	Fill in the ACS characters.  The 'acs_chars' terminfo entry is a list of
53 *	character pairs - ACS definition then terminal representation.
54 */
55void
56__init_acs(SCREEN *screen)
57{
58	int		count;
59	const char	*aofac;	/* Address of 'ac' */
60	unsigned char	acs, term;
61
62	/* Default value '+' for all ACS characters */
63	for (count=0; count < NUM_ACS; count++)
64		_acs_char[count]= '+';
65
66	/* Add the SUSv2 defaults (those that are not '+') */
67	ACS_RARROW = '>';
68	ACS_LARROW = '<';
69	ACS_UARROW = '^';
70	ACS_DARROW = 'v';
71	ACS_BLOCK = '#';
72/*	ACS_DIAMOND = '+';	*/
73	ACS_CKBOARD = ':';
74	ACS_DEGREE = 39;	/* ' */
75	ACS_PLMINUS = '#';
76	ACS_BOARD = '#';
77	ACS_LANTERN = '#';
78/*	ACS_LRCORNER = '+';	*/
79/*	ACS_URCORNER = '+';	*/
80/*	ACS_ULCORNER = '+';	*/
81/*	ACS_LLCORNER = '+';	*/
82/*	ACS_PLUS = '+';		*/
83	ACS_HLINE = '-';
84	ACS_S1 = '-';
85	ACS_S9 = '_';
86/*	ACS_LTEE = '+';		*/
87/*	ACS_RTEE = '+';		*/
88/*	ACS_BTEE = '+';		*/
89/*	ACS_TTEE = '+';		*/
90	ACS_VLINE = '|';
91	ACS_BULLET = 'o';
92	/* Add the extensions defaults */
93	ACS_S3 = '-';
94	ACS_S7 = '-';
95	ACS_LEQUAL = '<';
96	ACS_GEQUAL = '>';
97	ACS_PI = '*';
98	ACS_NEQUAL = '!';
99	ACS_STERLING = 'f';
100
101	if (t_acs_chars(screen->term) == NULL)
102		goto out;
103
104	aofac = t_acs_chars(screen->term);
105
106	while (*aofac != '\0') {
107		if ((acs = *aofac) == '\0')
108			return;
109		if ((term = *++aofac) == '\0')
110			return;
111	 	/* Only add characters 1 to 127 */
112		if (acs < NUM_ACS)
113			_acs_char[acs] = term | __ALTCHARSET;
114		aofac++;
115		__CTRACE(__CTRACE_INIT, "__init_acs: %c = %c\n", acs, term);
116	}
117
118	if (t_ena_acs(screen->term) != NULL)
119		ti_puts(screen->term, t_ena_acs(screen->term), 0,
120		    __cputchar_args, screen->outfd);
121
122out:
123	for (count=0; count < NUM_ACS; count++)
124		screen->acs_char[count]= _acs_char[count];
125}
126
127void
128_cursesi_reset_acs(SCREEN *screen)
129{
130	int count;
131
132	for (count=0; count < NUM_ACS; count++)
133		_acs_char[count]= screen->acs_char[count];
134}
135
136#ifdef HAVE_WCHAR
137/*
138 * __init_wacs --
139 *	Fill in the ACS characters.  The 'acs_chars' terminfo entry is a list of
140 *	character pairs - ACS definition then terminal representation.
141 */
142void
143__init_wacs(SCREEN *screen)
144{
145	int		count;
146	const char	*aofac;	/* Address of 'ac' */
147	unsigned char	acs, term;
148	char	*lstr;
149
150	/* Default value '+' for all ACS characters */
151	for (count=0; count < NUM_ACS; count++) {
152		_wacs_char[ count ].vals[ 0 ] = ( wchar_t )btowc( '+' );
153		_wacs_char[ count ].attributes = 0;
154		_wacs_char[ count ].elements = 1;
155	}
156
157	/* Add the SUSv2 defaults (those that are not '+') */
158	if (!strcmp(setlocale(LC_CTYPE, NULL), "C"))
159		setlocale(LC_CTYPE, "");
160	lstr = nl_langinfo(CODESET);
161	_DIAGASSERT(lstr);
162	if (strcasecmp(lstr, "UTF-8")) {
163		__CTRACE(__CTRACE_INIT, "__init_wacs: setting defaults\n" );
164		WACS_RARROW->vals[0]  = ( wchar_t )btowc( '>' );
165		WACS_LARROW->vals[0]  = ( wchar_t )btowc( '<' );
166		WACS_UARROW->vals[0]  = ( wchar_t )btowc( '^' );
167		WACS_DARROW->vals[0]  = ( wchar_t )btowc( 'v' );
168		WACS_BLOCK->vals[0]   = ( wchar_t )btowc( '#' );
169		WACS_CKBOARD->vals[0] = ( wchar_t )btowc( ':' );
170		WACS_DEGREE->vals[0]  = ( wchar_t )btowc( 39 );	/* ' */
171		WACS_PLMINUS->vals[0] = ( wchar_t )btowc( '#' );
172		WACS_BOARD->vals[0]   = ( wchar_t )btowc( '#' );
173		WACS_LANTERN->vals[0] = ( wchar_t )btowc( '#' );
174		WACS_HLINE->vals[0]   = ( wchar_t )btowc( '-' );
175		WACS_S1->vals[0]      = ( wchar_t )btowc( '-' );
176		WACS_S9->vals[0]      = ( wchar_t )btowc( '_' );
177		WACS_VLINE->vals[0]   = ( wchar_t )btowc( '|' );
178		WACS_BULLET->vals[0]  = ( wchar_t )btowc( 'o' );
179		WACS_S3->vals[0]      = ( wchar_t )btowc( 'p' );
180		WACS_S7->vals[0]      = ( wchar_t )btowc( 'r' );
181		WACS_LEQUAL->vals[0]  = ( wchar_t )btowc( 'y' );
182		WACS_GEQUAL->vals[0]  = ( wchar_t )btowc( 'z' );
183		WACS_PI->vals[0]      = ( wchar_t )btowc( '{' );
184		WACS_NEQUAL->vals[0]  = ( wchar_t )btowc( '|' );
185		WACS_STERLING->vals[0]= ( wchar_t )btowc( '}' );
186	} else {
187		/* Unicode defaults */
188		__CTRACE(__CTRACE_INIT,
189		    "__init_wacs: setting Unicode defaults\n" );
190		WACS_RARROW->vals[0]  = 0x2192;
191		ACS_RARROW = '+' | __ACS_IS_WACS;
192		WACS_LARROW->vals[0]  = 0x2190;
193		ACS_LARROW = ',' | __ACS_IS_WACS;
194		WACS_UARROW->vals[0]  = 0x2191;
195		ACS_UARROW = '-' | __ACS_IS_WACS;
196		WACS_DARROW->vals[0]  = 0x2193;
197		ACS_DARROW = '.' | __ACS_IS_WACS;
198		WACS_BLOCK->vals[0]   = 0x25ae;
199		ACS_BLOCK = '0' | __ACS_IS_WACS;
200		WACS_DIAMOND->vals[0] = 0x25c6;
201		ACS_DIAMOND = '`' | __ACS_IS_WACS;
202		WACS_CKBOARD->vals[0] = 0x2592;
203		ACS_CKBOARD = 'a' | __ACS_IS_WACS;
204		WACS_DEGREE->vals[0]  = 0x00b0;
205		ACS_DEGREE = 'f' | __ACS_IS_WACS;
206		WACS_PLMINUS->vals[0] = 0x00b1;
207		ACS_PLMINUS = 'g' | __ACS_IS_WACS;
208		WACS_BOARD->vals[0]   = 0x2592;
209		ACS_BOARD = 'h' | __ACS_IS_WACS;
210		WACS_LANTERN->vals[0] = 0x2603;
211		ACS_LANTERN = 'i' | __ACS_IS_WACS;
212		WACS_LRCORNER->vals[0]= 0x2518;
213		ACS_LRCORNER = 'j' | __ACS_IS_WACS;
214		WACS_URCORNER->vals[0]= 0x2510;
215		ACS_URCORNER = 'k' | __ACS_IS_WACS;
216		WACS_ULCORNER->vals[0]= 0x250c;
217		ACS_ULCORNER = 'l' | __ACS_IS_WACS;
218		WACS_LLCORNER->vals[0]= 0x2514;
219		ACS_LLCORNER = 'm' | __ACS_IS_WACS;
220		WACS_PLUS->vals[0]    = 0x253c;
221		ACS_PLUS = 'n' | __ACS_IS_WACS;
222		WACS_HLINE->vals[0]   = 0x2500;
223		ACS_HLINE = 'q' | __ACS_IS_WACS;
224		WACS_S1->vals[0]      = 0x23ba;
225		ACS_S1 = 'o' | __ACS_IS_WACS;
226		WACS_S9->vals[0]      = 0x23bd;
227		ACS_S9 = 's' | __ACS_IS_WACS;
228		WACS_LTEE->vals[0]    = 0x251c;
229		ACS_LTEE = 't' | __ACS_IS_WACS;
230		WACS_RTEE->vals[0]    = 0x2524;
231		ACS_RTEE = 'u' | __ACS_IS_WACS;
232		WACS_BTEE->vals[0]    = 0x2534;
233		ACS_BTEE = 'v' | __ACS_IS_WACS;
234		WACS_TTEE->vals[0]    = 0x252c;
235		ACS_TTEE = 'w' | __ACS_IS_WACS;
236		WACS_VLINE->vals[0]   = 0x2502;
237		ACS_VLINE = 'x' | __ACS_IS_WACS;
238		WACS_BULLET->vals[0]  = 0x00b7;
239		ACS_BULLET = '~' | __ACS_IS_WACS;
240		WACS_S3->vals[0]      = 0x23bb;
241		ACS_S3 = 'p' | __ACS_IS_WACS;
242		WACS_S7->vals[0]      = 0x23bc;
243		ACS_S7 = 'r' | __ACS_IS_WACS;
244		WACS_LEQUAL->vals[0]  = 0x2264;
245		ACS_LEQUAL = 'y' | __ACS_IS_WACS;
246		WACS_GEQUAL->vals[0]  = 0x2265;
247		ACS_GEQUAL = 'z' | __ACS_IS_WACS;
248		WACS_PI->vals[0]      = 0x03C0;
249		ACS_PI = '{' | __ACS_IS_WACS;
250		WACS_NEQUAL->vals[0]  = 0x2260;
251		ACS_NEQUAL = '|' | __ACS_IS_WACS;
252		WACS_STERLING->vals[0]= 0x00A3;
253		ACS_STERLING = '}' | __ACS_IS_WACS;
254	}
255
256	if (t_acs_chars(screen->term) == NULL) {
257		__CTRACE(__CTRACE_INIT,
258		    "__init_wacs: no alternative characters\n" );
259		goto out;
260	}
261
262	aofac = t_acs_chars(screen->term);
263
264	while (*aofac != '\0') {
265		if ((acs = *aofac) == '\0')
266			return;
267		if ((term = *++aofac) == '\0')
268			return;
269		/* Only add characters 1 to 127 */
270		if (acs < NUM_ACS) {
271			_wacs_char[acs].vals[ 0 ] = term;
272			_wacs_char[acs].attributes |= WA_ALTCHARSET;
273		}
274		aofac++;
275		__CTRACE(__CTRACE_INIT, "__init_wacs: %c = %c\n", acs, term);
276	}
277
278	if (t_ena_acs(screen->term) != NULL)
279		ti_puts(screen->term, t_ena_acs(screen->term), 0,
280			   __cputchar_args, screen->outfd);
281
282out:
283	for (count=0; count < NUM_ACS; count++) {
284		memcpy(&screen->wacs_char[count], &_wacs_char[count],
285			sizeof(cchar_t));
286		screen->acs_char[count]= _acs_char[count];
287	}
288}
289
290void
291_cursesi_reset_wacs(SCREEN *screen)
292{
293	int count;
294
295	for (count=0; count < NUM_ACS; count++)
296		memcpy( &_wacs_char[count], &screen->wacs_char[count],
297			sizeof( cchar_t ));
298}
299#endif /* HAVE_WCHAR */
300