
/* 
 * $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 */
/*	Copyright (c) 1988 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

#ident	"$Header: main.c 1.2 90/02/27 $ @(#)main.c	1.0 1989/12"
/*
 * kbdset.c	This program attaches kbd maps.  This is main().
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stropts.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <fcntl.h>
#include <sys/kbd.h>

extern char *gettxt();
extern int optind, opterr;
extern char *optarg;
extern int errno;
char *prog;
int uid, euid;
int outside, stralflag;

main(argc, argv)

	int argc;
	char **argv;
{
	register int c, fd, pub;

	opterr = outside = stralflag = 0;
	prog = *argv;
	while ((c = getopt(argc, argv, "oQqa:d:v:k:m:t:")) != EOF) {
		switch (c) {
		case 'o':
			outside = 1;
			break;
#if 0	/* DEBUGGING ONLY */
		case 'Q':
			stralflag = 1;	/* drop through */
#endif
		case 'q':
			doquery();
			exit(0);
			break;
		case 'a':
			tach(optarg);
			break;
		case 'd':
			detach(optarg);
			break;
		case 'v':
			verbose(optarg);
			break;
		case 'k':
		case 'm':
			hotkey(c, optarg);
			break;
		case 't':
			timer(optarg);
			break;
		case '?':
		default:
usage:
			fprintf(stderr, gettxt("kbdset:1", "Usage: %s [-oq] [-{a|d} table] [-v str] [-k hot] [-m n] [-t n]\n"), prog);
				exit(1);
		}
	}
	if (optind < argc)
		goto usage;
	exit(0);
}

doquery()

{
	register int rval, i, first, seq, type;
	struct strioctl sb;
	struct kbd_ctl cx;
	struct kbd_query q;

	if (stralflag) {	/* debugging query */
		sb.ic_cmd = KBD_QUERY;
		sb.ic_len = 1;
		sb.ic_timout = 15;
		sb.ic_dp = (char *) &q;
		ioctl(0, I_STR, &sb);
		return;
	}
	/*
	 * First, get timeout values (cx.c_type == IN, cx.c_arg = OUT)
	 */
	sb.ic_cmd = KBD_TGET;
	sb.ic_len = sizeof(struct kbd_ctl);
	sb.ic_timout = 15;
	sb.ic_dp = (char *) &cx;
	if (ioctl(0, I_STR, &sb) != 0)
		return;
	first = 1;
	type = KBD_QF_PUB;
	seq = 0;
	/*
	 * loop requesting the "next" on the list.  Begin with type
	 * "pub", then do "pri".  Keep sending ioctls until one fails.
	 * If errno is EAGAIN, we're finished.  Otherwise, it's a hard
	 * error of some time.
	 */
	for ( ; ; ) {	/* loop until "rval" gets error */
		sb.ic_cmd = KBD_LIST;	/* do these 4 always, just in case */
		sb.ic_len = sizeof(struct kbd_query);
		sb.ic_timout = 15;
		sb.ic_dp = (char *) &q;

		q.q_flag = type;
		q.q_seq = seq++;
		rval = ioctl(0, I_STR, &sb);
		if (rval) {
			if (errno != EAGAIN) {
				fprintf(stderr,
					gettxt("kbdset:2", "%s: query failed (errno %d).\n"),
					prog, errno);
				exit(1);
			}
			else {	/* EAGAIN */
				if (type) {
					type = 0;
					seq = 0;
					continue;
				}
				else
					return;	/* finished pub & pri */
			}
		}
		if (first) {
			if (q.q_hkin) {
				printf(gettxt("kbdset:3", "In Hot Key = "));
				pkey(q.q_hkin);
				printf("\n");
			}
			if (q.q_hkout) {
				printf(gettxt("kbdset:4", "Out Hot Key = "));
				pkey(q.q_hkout);
				printf("\n");
			}
			printf(gettxt("kbdset:5", "Timers: In = %d ; Out = %d\n"),
				(int) cx.c_type, (int) cx.c_arg);
/*
 * FIX ME: should have a way to retrieve timer information.
 */
			printf(gettxt("kbdset:6", "ID        Name             Size I/O Ref Cmp Type\n"));
			first = 0;
		}
		fflush(stdout);
		q.q_name[KBDNL-1] = '\0';
		printf("%8x  %-16s %4d ", q.q_id,
			q.q_name, q.q_asize);
		printf("%s ", (q.q_tach & Z_UP) ? gettxt("kbdset:7", "i") : "-");
		printf("%s ", (q.q_tach & Z_DOWN) ? gettxt("kbdset:8", "o") : "-");
		printf("%3d ", q.q_ref);
		if (q.q_flag & KBD_QF_COT)
			printf(" %2d ", q.q_nchild);
		else
			printf("  - ");

#if 0
/*
 * Not in this release
 */
		if (q.q_flag & KBD_QF_EXT)  /* external always public */
			printf(gettxt("kbdset:9", " ext"));
		else
#endif
			printf("%c%s", (q.q_flag & KBD_QF_TIM) ? '*' : ' ',
				(q.q_flag & KBD_QF_PUB) ? gettxt("kbdset:10", "pub") :
							  gettxt("kbdset:11", "pri"));
		if (q.q_flag & KBD_QF_COT) {
			for (i = 0; i < q.q_nchild; i++) {
				if ((i & 3) == 0)
					printf("\n            ");
				printf("[%8x]%s ", q.q_child[i],
					q.q_chtim[i] ? "*" : " ");
			}
		}
		printf("\n");
		fflush(stdout);
	}
}

tach(name)
	char *name;
{
	struct strioctl sb;
	struct kbd_tach t;
	struct kbd_ctl c;
	register int rval;

	sb.ic_cmd = KBD_ATTACH;
	sb.ic_timout = 15;
	sb.ic_len = sizeof(struct kbd_tach);
	sb.ic_dp = (char *) &t;

	strcpy(t.t_table, name);
	if (! outside)
		t.t_type = Z_UP;
	else
		t.t_type = Z_DOWN;

	rval = ioctl(0, I_STR, &sb);
	if (rval) {
		fprintf(stderr, gettxt("kbdset:12", "%s: attach failed (%d).\n"), prog, errno);
		exit(1);
	}

	sb.ic_cmd = KBD_ON;
	sb.ic_timout = 15;
	sb.ic_len = sizeof(struct kbd_ctl);
	sb.ic_dp = (char *) &c;
	c.c_type = (outside ? Z_DOWN : Z_UP);

	rval = ioctl(0, I_STR, &sb);
	if (rval) {
		fprintf(stderr, gettxt("kbdset:13", "%s: can't turn on mapping (%d).\n"), prog, errno);
		exit(1);
	}
}

hotkey(type, s)
	int type;	/* 'k' or 'm' */
	unsigned char *s;
{
	struct strioctl sb;
	struct kbd_ctl cx;
	register int rval;

	/*
	 * First, get current hot key
	 */
	sb.ic_cmd = KBD_HOTKEY;
	sb.ic_timout = 15;
	sb.ic_len = sizeof(struct kbd_ctl);
	sb.ic_dp = (char *) &cx;
	if (outside)
		cx.c_type = Z_GET | Z_DOWN;
	else
		cx.c_type = Z_GET | Z_UP;
	rval = ioctl(0, I_STR, &sb);
	if (rval) {
		fprintf(stderr, gettxt("kbdset:14", "%s: failed to retrieve hotkey (errno %d)\n"), prog, errno);
		exit(1);
	}
	/*
	 * Figure out whether to set key (k) or mode (m)
	 */
	if (type == 'k')
		cx.c_arg = (cx.c_arg & 0xFF00) | *s;
	else
		cx.c_arg = (cx.c_arg & 0x00FF) | (atoi(s) << 8);

	sb.ic_cmd = KBD_HOTKEY;
	sb.ic_timout = 15;
	sb.ic_len = sizeof(struct kbd_ctl);
	sb.ic_dp = (char *) &cx;
	if (outside)
		cx.c_type = Z_SET | Z_DOWN;
	else
		cx.c_type = Z_SET | Z_UP;
	rval = ioctl(0, I_STR, &sb);
	if (rval) {
		fprintf(stderr, gettxt("kbdset:15", "%s: failed to set hotkey (errno %d).\n"), prog, errno);
		exit(1);
	}
}

/*
 * Reset timer value for timed-mode tables.  Reset independent for
 * "in" and "out" sides.
 */

timer(s)
	unsigned char *s;
{
	struct strioctl sb;
	struct kbd_ctl cx;
	register int rval;

	sb.ic_cmd = KBD_TSET;
	sb.ic_timout = 15;
	sb.ic_len = sizeof(struct kbd_ctl);
	sb.ic_dp = (char *) &cx;
	if (outside)
		cx.c_type = Z_DOWN;
	else
		cx.c_type = Z_UP;
	cx.c_arg = atoi(s);
	rval = ioctl(0, I_STR, &sb);
	if (rval) {
		fprintf(stderr, gettxt("kbdset:16", "%s: Cannot reset timer\n"), prog, errno);
		exit(1);
	}
}

/*
 * Turn on verbose mode.
 */

verbose(s)
	unsigned char *s;
{
	struct strioctl sb;
	struct kbd_ctl cx;
	register int rval;

	sb.ic_cmd = KBD_VERB;
	sb.ic_timout = 15;
	sb.ic_len = strlen(s) + 1;
	sb.ic_dp = (char *) s;

	rval = ioctl(0, I_STR, &sb);
	if (rval) {
		fprintf(stderr, gettxt("kbdset:17", "%s: failed to set verbose (errno %d).\n"), prog, errno);
		exit(1);
	}
}

/*
 * Print a representation of a key
 */

pkey(c)
	unsigned char c;
{
	if (c & 0x80) {
		printf("\\%03o", (int) (c & 0xFF));
		return;
	}
	if (c == '\177') {
		printf(gettxt("kbdset:18", "DEL"));
		return;
	}
	if (c < ' ' || c > '~') {
		putchar('^');
		c += '@';
	}
	if (c == ' ')
		printf(gettxt("kbdset:19", "SPACE"));
	else
		putchar(c);
}

detach(name)
	char *name;
{
	struct strioctl sb;
	struct kbd_tach t;
	struct kbd_ctl c;
	register int rval;

	sb.ic_cmd = KBD_DETACH;
	sb.ic_timout = 15;
	sb.ic_len = sizeof(struct kbd_tach);
	sb.ic_dp = (char *) &t;

	strcpy(t.t_table, name);
	if (! outside)
		t.t_type = Z_UP;
	else
		t.t_type = Z_DOWN;

	rval = ioctl(0, I_STR, &sb);
	if (rval) {
		fprintf(stderr, gettxt("kbdset:20", "%s: detach failed (errno %d).\n"), prog, errno);
		exit(1);
	}
}
