#include <stdio.h>
#include <ioctl.h>

#define TOSTOP 0x0100
#define XKEY 0x0200

struct {
	char *name;
	short bits;
} modes[] = {
	{ "crmod", CRMOD },
	{ "cbreak", CBREAK },
	{ "echo", ECHO },
	{ "raw", RAW },
	{ "tostop", TOSTOP },
	{ "xkey", XKEY }
};

#define NMODES (sizeof(modes) / sizeof(modes[0]))

void prchar(s,c)
char *s;
char c;
{
    printf("%s ",s);
    if (c < ' ') printf("^%c ",c + '@');
    else if (c == 127) printf("^? ");
    else printf("%c ",c);
}

void prmode(s,f)
char *s;
int f;
{
    printf("%s%s ",(f ? "" : "-"),s);
}

int speed(sp)
int sp;
{
    return sp;
}

/*
 * atok: turns a string into an ASCII value.  ^x yields control-x
 * for X in @A-Za-z[\]^_ as long as there are only two chars.
 * ^? yields DEL (127) and other single chars yield themselves.
 */

int atok(s)
char *s;
{
    char c;

    if (!s || !*s) return -1;
    c = *s++;
    if (c == '^') {
	c = *s++;
	if (*s) return -1;
	if (c == '?') return 127;
	else if (c >= '@' && c <= '_') return (c - '@');
	else if (c >= 'a' && c <= 'z') return (c - '`');
	else return -1;
    }
    else if (*s) return -1;
    else return c;
}

main(argc,argv)
int argc;
char *argv[];
{
	int fd;
	int i;
	char *kp;
	long err;
	struct sgttyb sg;
	struct tchars tc;
	struct ltchars ltc;

	if ((fd = open("U:\\dev\\tty",0)) < 0) {
		perror("can't open tty");
		exit(1);
	}
	if (ioctl(fd,TIOCGETP,&sg) ||
	    ioctl(fd,TIOCGETC,&tc) ||
	    ioctl(fd,TIOCGLTC,&ltc)) {
		perror("can't do ioctl");
		exit(1);
	}

	--argc, ++argv;

	if (!argc) {
		/* print current state */
		prchar("intr",tc.t_intrc);
		prchar("quit",tc.t_quitc);
		prchar("start",tc.t_startc);
		prchar("stop",tc.t_stopc);
		prchar("eof",tc.t_eofc);
		prchar("brk",tc.t_brkc);
		putchar('\n');

		prchar("susp",ltc.t_suspc);
		prchar("dsusp",ltc.t_dsuspc);
		prchar("rprnt",ltc.t_rprntc);
		prchar("flush",ltc.t_flushc);
		prchar("werase",ltc.t_werasc);
		prchar("lnext",ltc.t_lnextc);
		putchar('\n');

		printf("ispeed %d ospeed %d ",
		    speed(sg.sg_ispeed),
		    speed(sg.sg_ospeed));
		prchar("erase",sg.sg_erase);
		prchar("kill",sg.sg_kill);
		putchar('\n');

		for (i=0; i<NMODES; i++) {
		    prmode(modes[i].name,sg.sg_flags & modes[i].bits);
		}
		putchar('\n');
		exit(0);
        }
	while (argc) {
	    if (strcmp("intr",argv[0]) == 0) {
		kp = &tc.t_intrc;
		goto key;
	    }
	    else if (strcmp("quit",argv[0]) == 0) {
		kp = &tc.t_quitc;
		goto key;
	    }
	    else if (strcmp("start",argv[0]) == 0) {
		kp = &tc.t_startc;
		goto key;
	    }
	    else if (strcmp("stop",argv[0]) == 0) {
		kp = &tc.t_stopc;
		goto key;
	    }
	    else if (strcmp("eof",argv[0]) == 0) {
		kp = &tc.t_eofc;
		goto key;
	    }
	    else if (strcmp("brk",argv[0]) == 0) {
		kp = &tc.t_brkc;
		goto key;
	    }
	    else if (strcmp("susp",argv[0]) == 0) {
		kp = &ltc.t_suspc;
		goto key;
	    }
	    else if (strcmp("dsusp",argv[0]) == 0) {
		kp = &ltc.t_dsuspc;
		goto key;
	    }
	    else if (strcmp("rprnt",argv[0]) == 0) {
		kp = &ltc.t_rprntc;
		goto key;
	    }
	    else if (strcmp("flush",argv[0]) == 0) {
		kp = &ltc.t_flushc;
		goto key;
	    }
	    else if (strcmp("werase",argv[0]) == 0) {
		kp = &ltc.t_werasc;
		goto key;
	    }
	    else if (strcmp("lnext",argv[0]) == 0) {
		kp = &ltc.t_lnextc;
key:
		if (argc == 1) {
		    printf("%s requires a key-name argument\n",argv[0]);
		    exit(1);
		}
		if ((*kp = atok(argv[1])) == -1) {
		    printf("Invalid key name for %s: %s\n",argv[0],argv[1]);
		    exit(1);
		}
		++argv, --argc;
	    }
	    else if (**argv == '-') {
		/* check against each mode */
		for (i=0; i<NMODES; i++) {
		    if (strcmp(modes[i].name,&argv[0][1]) == 0) {
			sg.sg_flags &= ~modes[i].bits;
			goto ok1;
		    }
		}
		printf("No such mode: %s\n",argv[0][1]);
		exit(1);
ok1:		;
	    }
	    else {
		for (i=0; i<NMODES; i++) {
		    if (strcmp(modes[i].name,*argv) == 0) {
			sg.sg_flags |= modes[i].bits;
			goto ok2;
		    }
		}
		printf("No such mode: %s\n",*argv);
		exit(1);
ok2:		;
	    }
	    ++argv, --argc;
	} /* end of "while (argc)" */

	if (ioctl(fd,TIOCSETP,&sg) ||
	    ioctl(fd,TIOCSETC,&tc) ||
	    ioctl(fd,TIOCSLTC,&ltc)) {
		perror("Can not set tty modes");
	}
	exit(0);
}
