/*
 * ttmode.c -- 端末のモードを設定する
 */

/* Ng-1.3.1 (日本語MicroEmacs) からかっぱらった */

#include <stdio.h>
#include <sgtty.h>
#include <sys/ioctl.h>

#define YES 1
#define NO  0

static char obuf[BUFSIZ];
static int  nobuf;

struct sgttyb oldtty, newtty;
struct tchars oldtchars, newtchars;
struct ltchars oldltchars, newltchars;

/* 端末を raw モードにする */
int ttraw()
{
    if (ioctl(0, TIOCGETP, (char *)&oldtty) < 0) {
	fputs("can't get sgtty\n", stderr);
	return(NO);
    }
    bcopy((void *)&oldtty, (void *)&newtty, sizeof(newtty));
    newtty.sg_flags &= ~(ECHO | CRMOD);
    newtty.sg_flags |= (RAW | ANYP);
    if (ioctl(0, TIOCSETP, (char *)&newtty) < 0) {
	fputs("can't set sgtty\n", stderr);
	return(NO);
    }
    if (ioctl(0, TIOCGETC, (char *) &oldtchars) < 0) {
	fputs("ttopen can't get chars\n", stderr);
	return(NO);
    }
    bcopy((void *)&oldtchars, (void *)&newtchars, sizeof(newtchars));
    newtchars.t_intrc  = 0xFF;
    newtchars.t_quitc  = 0xFF;
    newtchars.t_startc = 0xFF;
    newtchars.t_stopc  = 0xFF;
    newtchars.t_eofc   = 0xFF;
    newtchars.t_brkc   = 0xFF;
    if (ioctl(0, TIOCSETC, (char *)&newtchars) < 0) {
	fputs("can't set chars\n", stderr);
	return(NO);
    }
    if (ioctl(0, TIOCGLTC, (char *)&oldltchars) < 0) {
	fputs("can't get ltchars", stderr);
	return(NO);
    }
    bcopy((void *)&oldltchars, (void *)&newltchars, sizeof(newltchars));
    newltchars.t_suspc  = 0xFF;
    newltchars.t_dsuspc = 0xFF;
    newltchars.t_rprntc = 0xFF;
    newltchars.t_flushc = 0xFF;
    newltchars.t_werasc = 0xFF;
    newltchars.t_lnextc = 0xFF;
    if (ioctl(0, TIOCSLTC, (char *)&newltchars) < 0) {
	fputs("ttraw can't set ltchars\n", stderr);
	return(NO);
    }
    return(YES);
}


void ttflush()
{
    if (nobuf != 0) {
	if (write(1, obuf, nobuf) != nobuf) {
	    fputs("ttflush(): write failed\n", stderr);
	}
	nobuf = 0;
    }
}


/* 文字出力 */
void ttputc(c)
    int c;
{
    if (nobuf >= BUFSIZ) {
	ttflush();
    }
    obuf[nobuf++] = c;
}


/* 文字入力 */
int ttgetc()
{
    char buf[1];

    while (read(0, &buf[0], 1) != 1) {
	; /* loop */
    }
    return(buf[0] & 0xff);
}


/* 入力されているか */
int typeahead()
{
    int x;

    return((ioctl(0, FIONREAD, (char *)&x) < 0) ? 0 : x);
}


/* 端末を cooked モードに *戻す* */
int ttcooked()
{
    ttflush();
    if (ioctl(0, TIOCSLTC, (char *)&oldltchars) < 0) {
	fputs("can't set ltchars\n", stderr);
	return(NO);
    }
    if (ioctl(0, TIOCSETC, (char *)&oldtchars) < 0) {
	fputs("can't set chars\n", stderr);
	return(NO);
    }
    if (ioctl(0, TIOCSETP, (char *)&oldtty) < 0) {
	fputs("can't set sgtty\n", stderr);
	return(NO);
    }
    return(YES);
}


int getkey()
{
    if (typeahead()) {
	return(ttgetc());
    }
    else {
	return(-1);
    }
}


#ifdef MAIN
void main(void)
{
    int ch;
    void usleep();

    fputs("Change to RAW mode\n", stderr);
    ttraw();
    while ((ch = getkey()) != '\004') {
	if (ch == -1) {
	    fputs("---\r", stderr);
	}
	else if ((' ' <= ch) && (ch <= '~')) {
	    fprintf(stderr, "'%c'\r", ch);
	}
	else {
	    fprintf(stderr, "%03.3x\r", ch);
	}
	usleep(100000);
    }
    ttcooked();
    fputs("\nRestore to COOKED mode\n", stderr);
    exit(0);
}
#endif
