1/*	$NetBSD: util.c,v 1.30 2011/12/15 14:25:12 phx Exp $ */
2
3/*-
4 * Copyright (c) 1998, 2006, 2012 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Juergen Hannken-Illjes and Julio M. Merino Vidal.
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/time.h>
33
34#include <dev/wscons/wsconsio.h>
35#include <dev/wscons/wsksymdef.h>
36
37#include <err.h>
38#include <errno.h>
39#include <limits.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <unistd.h>
44
45#include "wsconsctl.h"
46
47#define TABLEN(t)		(sizeof(t)/sizeof(t[0]))
48
49extern struct wskbd_map_data kbmap;	/* from keyboard.c */
50extern struct wskbd_map_data newkbmap;	/* from map_parse.y */
51
52struct nameint {
53	int value;
54	const char *name;
55};
56
57static struct nameint kbtype_tab[] = {
58	{ WSKBD_TYPE_LK201,		"lk201" },
59	{ WSKBD_TYPE_LK401,		"lk401" },
60	{ WSKBD_TYPE_PC_XT,		"pc-xt" },
61	{ WSKBD_TYPE_PC_AT,		"pc-at" },
62	{ WSKBD_TYPE_USB,		"usb" },
63	{ WSKBD_TYPE_HPC_KBD,		"hpc-kbd" },
64	{ WSKBD_TYPE_HPC_BTN,		"hpc-btn" },
65	{ WSKBD_TYPE_ARCHIMEDES,	"archimedes" },
66	{ WSKBD_TYPE_RISCPC,		"riscpc" },
67	{ WSKBD_TYPE_ADB,		"adb" },
68	{ WSKBD_TYPE_HIL,		"hil" },
69	{ WSKBD_TYPE_AMIGA,		"amiga" },
70	{ WSKBD_TYPE_MAPLE,		"maple" },
71	{ WSKBD_TYPE_ATARI,		"atari" },
72	{ WSKBD_TYPE_SUN,		"sun" },
73	{ WSKBD_TYPE_SUN5,		"sun-type5" },
74	{ WSKBD_TYPE_SGI,		"sgi" },
75	{ WSKBD_TYPE_MATRIXKP,		"matrix-keypad" },
76	{ WSKBD_TYPE_BLUETOOTH,		"bluetooth" },
77};
78
79static struct nameint mstype_tab[] = {
80	{ WSMOUSE_TYPE_VSXXX,		"dec-tc" },
81	{ WSMOUSE_TYPE_PS2,		"ps2" },
82	{ WSMOUSE_TYPE_USB,		"usb" },
83	{ WSMOUSE_TYPE_LMS,		"logitech-bus" },
84	{ WSMOUSE_TYPE_MMS,		"ms-inport" },
85	{ WSMOUSE_TYPE_TPANEL,		"touch-panel" },
86	{ WSMOUSE_TYPE_NEXT,		"next" },
87	{ WSMOUSE_TYPE_ARCHIMEDES,	"archimedes" },
88	{ WSMOUSE_TYPE_HIL,		"hil" },
89	{ WSMOUSE_TYPE_AMIGA,		"amiga" },
90	{ WSMOUSE_TYPE_MAXINE,		"dec-maxine" },
91	{ WSMOUSE_TYPE_MAPLE,		"maple" },
92	{ WSMOUSE_TYPE_BLUETOOTH,	"bluetooth" },
93};
94
95static struct nameint dpytype_tab[] = {
96	{ WSDISPLAY_TYPE_UNKNOWN,	"unknown" },
97	{ WSDISPLAY_TYPE_PM_MONO,	"dec-pm-mono" },
98	{ WSDISPLAY_TYPE_PM_COLOR,	"dec-pm-color" },
99	{ WSDISPLAY_TYPE_CFB,		"dec-cfb" },
100	{ WSDISPLAY_TYPE_XCFB,		"dec-xcfb" },
101	{ WSDISPLAY_TYPE_MFB,		"dec-mfb" },
102	{ WSDISPLAY_TYPE_SFB,		"dec-sfb" },
103	{ WSDISPLAY_TYPE_ISAVGA,	"vga-isa" },
104	{ WSDISPLAY_TYPE_PCIVGA,	"vga-pci" },
105	{ WSDISPLAY_TYPE_TGA,		"dec-tga-pci" },
106	{ WSDISPLAY_TYPE_SFBP,		"dec-sfb+" },
107	{ WSDISPLAY_TYPE_PCIMISC,	"generic-pci" },
108	{ WSDISPLAY_TYPE_NEXTMONO,	"next-mono" },
109	{ WSDISPLAY_TYPE_PX,		"dec-px" },
110	{ WSDISPLAY_TYPE_PXG,		"dec-pxg" },
111	{ WSDISPLAY_TYPE_TX,		"dec-tx" },
112	{ WSDISPLAY_TYPE_HPCFB,		"generic-hpc" },
113	{ WSDISPLAY_TYPE_VIDC,		"arm-vidc" },
114	{ WSDISPLAY_TYPE_SPX,		"dec-spx" },
115	{ WSDISPLAY_TYPE_GPX,		"dec-gpx" },
116	{ WSDISPLAY_TYPE_LCG,		"dec-lcg" },
117	{ WSDISPLAY_TYPE_VAX_MONO,	"dec-vax-mono" },
118	{ WSDISPLAY_TYPE_SB_P9100,	"sparcbook-p9100" },
119	{ WSDISPLAY_TYPE_EGA,		"ega" },
120	{ WSDISPLAY_TYPE_DCPVR,		"dreamcast-pvr" },
121	{ WSDISPLAY_TYPE_GBOX,		"hp-gator" },
122	{ WSDISPLAY_TYPE_TOPCAT,	"hp-topcat" },
123	{ WSDISPLAY_TYPE_RBOX,		"hp-renaissance" },
124	{ WSDISPLAY_TYPE_CATSEYE,	"hp-catseye" },
125	{ WSDISPLAY_TYPE_DVBOX,		"hp-davinci" },
126	{ WSDISPLAY_TYPE_TVRX,		"hp-tiger" },
127	{ WSDISPLAY_TYPE_HYPERION,	"hp-hyperion" },
128	{ WSDISPLAY_TYPE_AMIGACC,	"amiga-cc" },
129	{ WSDISPLAY_TYPE_GRF,		"grf" },
130	{ WSDISPLAY_TYPE_SUN24,		"sun24" },
131	{ WSDISPLAY_TYPE_NEWPORT,	"sgi-newport" },
132	{ WSDISPLAY_TYPE_GR2,		"sgi-gr2" },
133	{ WSDISPLAY_TYPE_SUNCG12,	"suncg12" },
134	{ WSDISPLAY_TYPE_SUNCG14,	"suncg14" },
135	{ WSDISPLAY_TYPE_SUNTCX,	"suntcx" },
136	{ WSDISPLAY_TYPE_SUNFFB,	"sunffb" },
137};
138
139static struct nameint kbdenc_tab[] = {
140	KB_ENCTAB
141};
142
143static struct nameint kbdvar_tab[] = {
144	KB_VARTAB
145};
146
147static struct nameint color_tab[] = {
148	{ WSCOL_UNSUPPORTED,		"unsupported" },
149	{ WSCOL_BLACK,			"black" },
150	{ WSCOL_RED,			"red" },
151	{ WSCOL_GREEN,			"green" },
152	{ WSCOL_BROWN,			"brown" },
153	{ WSCOL_BLUE,			"blue" },
154	{ WSCOL_MAGENTA,		"magenta" },
155	{ WSCOL_CYAN,			"cyan" },
156	{ WSCOL_WHITE,			"white" },
157};
158
159static struct nameint attr_tab[] = {
160	{ WSATTR_NONE,			"none" },
161	{ WSATTR_REVERSE,		"reverse" },
162	{ WSATTR_HILIT,			"hilit" },
163	{ WSATTR_BLINK,			"blink" },
164	{ WSATTR_UNDERLINE,		"underline" },
165	{ WSATTR_WSCOLORS,		"color" },
166};
167
168static struct field *field_tab;
169static int field_tab_len;
170
171static const char *int2name(int, int, struct nameint *, int);
172static int name2int(char *, struct nameint *, int);
173static void print_kmap(struct wskbd_map_data *);
174static unsigned int rd_bitfield(const char *);
175static void pr_bitfield(unsigned int);
176
177void
178field_setup(struct field *ftab, int len)
179{
180
181	field_tab = ftab;
182	field_tab_len = len;
183}
184
185struct field *
186field_by_name(char *name)
187{
188	int i;
189
190	for (i = 0; i < field_tab_len; i++)
191		if (strcmp(field_tab[i].name, name) == 0)
192			return field_tab + i;
193
194	errx(EXIT_FAILURE, "%s: not found", name);
195}
196
197struct field *
198field_by_value(void *addr)
199{
200	int i;
201
202	for (i = 0; i < field_tab_len; i++)
203		if (field_tab[i].valp == addr)
204			return field_tab + i;
205
206	errx(EXIT_FAILURE, "internal error: field_by_value: not found");
207}
208
209void
210field_disable_by_value(void *addr)
211{
212	struct field *f;
213
214	f = field_by_value(addr);
215	f->flags |= FLG_DISABLED;
216}
217
218static const char *
219int2name(int val, int uflag, struct nameint *tab, int len)
220{
221	static char tmp[20];
222	int i;
223
224	for (i = 0; i < len; i++)
225		if (tab[i].value == val)
226			return tab[i].name;
227
228	if (uflag) {
229		(void)snprintf(tmp, sizeof(tmp), "unknown_%d", val);
230		return tmp;
231	} else
232		return NULL;
233}
234
235static int
236name2int(char *val, struct nameint *tab, int len)
237{
238	int i;
239
240	for (i = 0; i < len; i++)
241		if (strcmp(tab[i].name, val) == 0)
242			return tab[i].value;
243	return -1;
244}
245
246void
247pr_field(struct field *f, const char *sep)
248{
249	const char *p;
250	unsigned int flags;
251	int first, i, mask;
252
253	if (sep)
254		(void)printf("%s%s", f->name, sep);
255
256	switch (f->format) {
257	case FMT_UINT:
258		(void)printf("%u", *((unsigned int *) f->valp));
259		break;
260	case FMT_INT:
261		(void)printf("%d", *((int *) f->valp));
262		break;
263	case FMT_STRING:
264		(void)printf("\"%s\"", *((char **) f->valp));
265		break;
266	case FMT_BITFIELD:
267		pr_bitfield(*((unsigned int *) f->valp));
268		break;
269	case FMT_KBDTYPE:
270		p = int2name(*((unsigned int *) f->valp), 1,
271		    kbtype_tab, TABLEN(kbtype_tab));
272		(void)printf("%s", p);
273		break;
274	case FMT_MSTYPE:
275		p = int2name(*((unsigned int *) f->valp), 1,
276		    mstype_tab, TABLEN(mstype_tab));
277		(void)printf("%s", p);
278		break;
279	case FMT_DPYTYPE:
280		p = int2name(*((unsigned int *) f->valp), 1,
281		    dpytype_tab, TABLEN(dpytype_tab));
282		(void)printf("%s", p);
283		break;
284	case FMT_KBDENC:
285		p = int2name(KB_ENCODING(*((unsigned int *) f->valp)), 1,
286		    kbdenc_tab, TABLEN(kbdenc_tab));
287		(void)printf("%s", p);
288
289		flags = KB_VARIANT(*((unsigned int *) f->valp));
290		for (i = 0; i < 32; i++) {
291			if (!(flags & (1 << i)))
292				continue;
293			p = int2name(flags & (1 << i), 1,
294			    kbdvar_tab, TABLEN(kbdvar_tab));
295			(void)printf(".%s", p);
296		}
297		break;
298	case FMT_KBMAP:
299		print_kmap((struct wskbd_map_data *) f->valp);
300		break;
301	case FMT_COLOR:
302		p = int2name(*((unsigned int *) f->valp), 1,
303		    color_tab, TABLEN(color_tab));
304		(void)printf("%s", p);
305		break;
306	case FMT_ATTRS:
307		mask = 0x10;
308		first = 1;
309		while (mask > 0) {
310			if (*((unsigned int *) f->valp) & mask) {
311				p = int2name(*((unsigned int *) f->valp) & mask,
312				    1, attr_tab, TABLEN(attr_tab));
313				(void)printf("%s%s", first ? "" : ",", p);
314				first = 0;
315			}
316			mask >>= 1;
317		}
318		if (first)
319			(void)printf("none");
320		break;
321	default:
322		errx(EXIT_FAILURE, "internal error: pr_field: no format %d",
323		    f->format);
324		break;
325	}
326
327	(void)printf("\n");
328}
329
330static void
331pr_bitfield(unsigned int f)
332{
333
334	if (f == 0)
335		(void)printf("none");
336	else {
337		unsigned int i;
338		int first, mask;
339
340		for (i = 0, first = 1, mask = 1; i < sizeof(f) * 8; i++) {
341			if (f & mask) {
342				(void)printf("%s%u", first ? "" : " ", i);
343				first = 0;
344			}
345			mask = mask << 1;
346		}
347	}
348}
349
350void
351rd_field(struct field *f, char *val, int merge)
352{
353	int i;
354	unsigned int u;
355	char *p;
356	struct wscons_keymap *mp;
357
358	switch (f->format) {
359	case FMT_UINT:
360		if (sscanf(val, "%u", &u) != 1)
361			errx(EXIT_FAILURE, "%s: not a number", val);
362		if (merge)
363			*((unsigned int *) f->valp) += u;
364		else
365			*((unsigned int *) f->valp) = u;
366		break;
367	case FMT_INT:
368		if (sscanf(val, "%d", &i) != 1)
369			errx(EXIT_FAILURE, "%s: not a number", val);
370		if (merge)
371			*((int *) f->valp) += i;
372		else
373			*((int *) f->valp) = i;
374		break;
375	case FMT_STRING:
376		if ((*((char **) f->valp) = strdup(val)) == NULL)
377			err(EXIT_FAILURE, "strdup");
378		break;
379	case FMT_BITFIELD:
380		*((unsigned int *) f->valp) = rd_bitfield(val);
381		break;
382	case FMT_KBDENC:
383		p = strchr(val, '.');
384		if (p != NULL)
385			*p++ = '\0';
386
387		i = name2int(val, kbdenc_tab, TABLEN(kbdenc_tab));
388		if (i == -1)
389			errx(EXIT_FAILURE, "%s: not a valid encoding", val);
390		*((unsigned int *) f->valp) = i;
391
392		while (p) {
393			val = p;
394			p = strchr(p, '.');
395			if (p != NULL)
396				*p++ = '\0';
397			i = name2int(val, kbdvar_tab, TABLEN(kbdvar_tab));
398			if (i == -1)
399				errx(EXIT_FAILURE, "%s: not a valid variant",
400				    val);
401			*((unsigned int *) f->valp) |= i;
402		}
403		break;
404	case FMT_KBMAP:
405		if (! merge)
406			kbmap.maplen = 0;
407		map_scan_setinput(val);
408		yyparse();
409		if (merge) {
410			if (newkbmap.maplen < kbmap.maplen)
411				newkbmap.maplen = kbmap.maplen;
412			for (u = 0; u < kbmap.maplen; u++) {
413				mp = newkbmap.map + u;
414				if (mp->command == KS_voidSymbol &&
415				    mp->group1[0] == KS_voidSymbol &&
416				    mp->group1[1] == KS_voidSymbol &&
417				    mp->group2[0] == KS_voidSymbol &&
418				    mp->group2[1] == KS_voidSymbol)
419					*mp = kbmap.map[u];
420			}
421		}
422		kbmap.maplen = newkbmap.maplen;
423		bcopy(newkbmap.map, kbmap.map,
424		    kbmap.maplen * sizeof(struct wscons_keymap));
425		break;
426	case FMT_COLOR:
427		i = name2int(val, color_tab, TABLEN(color_tab));
428		if (i == -1)
429			errx(EXIT_FAILURE, "%s: not a valid color", val);
430		*((unsigned int *) f->valp) = i;
431		break;
432	case FMT_ATTRS:
433		p = val;
434		while (p) {
435			val = p;
436			p = strchr(p, ',');
437			if (p != NULL)
438				*p++ = '\0';
439			i = name2int(val, attr_tab, TABLEN(attr_tab));
440			if (i == -1)
441				errx(EXIT_FAILURE, "%s: not a valid attribute",
442				    val);
443			*((unsigned int *) f->valp) |= i;
444		}
445		break;
446	default:
447		errx(EXIT_FAILURE, "internal error: rd_field: no format %d",
448		    f->format);
449		break;
450	}
451}
452
453static unsigned int
454rd_bitfield(const char *str)
455{
456	const char *ptr;
457	char *ep;
458	long lval;
459	unsigned int result;
460
461	ep = NULL;
462	ptr = str;
463	result = 0;
464	while (*ptr != '\0') {
465		errno = 0;
466		lval = strtol(ptr, &ep, 10);
467		if (*ep != '\0' && *ep != ' ')
468			errx(EXIT_FAILURE, "%s: not a valid number list", str);
469		if (errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN))
470			errx(EXIT_FAILURE, "%s: not a valid number list", str);
471		if (lval >= (long)sizeof(result) * 8)
472			errx(EXIT_FAILURE, "%ld: number out of range", lval);
473		result |= (1 << lval);
474
475		ptr = ep;
476		while (*ptr == ' ')
477			ptr++;
478	}
479
480	return result;
481}
482
483static void
484print_kmap(struct wskbd_map_data *map)
485{
486	unsigned int i;
487	struct wscons_keymap *mp;
488
489	for (i = 0; i < map->maplen; i++) {
490		mp = map->map + i;
491
492		if (mp->command == KS_voidSymbol &&
493		    mp->group1[0] == KS_voidSymbol &&
494		    mp->group1[1] == KS_voidSymbol &&
495		    mp->group2[0] == KS_voidSymbol &&
496		    mp->group2[1] == KS_voidSymbol)
497			continue;
498		(void)printf("\n");
499		(void)printf("keycode %u =", i);
500		if (mp->command != KS_voidSymbol)
501			(void)printf(" %s", ksym2name(mp->command));
502		(void)printf(" %s", ksym2name(mp->group1[0]));
503		if (mp->group1[0] != mp->group1[1] ||
504		    mp->group1[0] != mp->group2[0] ||
505		    mp->group1[0] != mp->group2[1]) {
506			(void)printf(" %s", ksym2name(mp->group1[1]));
507			if (mp->group1[0] != mp->group2[0] ||
508			    mp->group1[1] != mp->group2[1]) {
509				(void)printf(" %s", ksym2name(mp->group2[0]));
510				(void)printf(" %s", ksym2name(mp->group2[1]));
511			}
512		}
513	}
514}
515