/*
 * a layers program for OS/2
 */
#include <stdio.h>
#include <os2def.h>
#define INCL_DOS T
#include <bsedos.h>

#define KBD	"KBD$"

char kbdinbfr[sizeof(MONIN)+10];
char kbdoutbfr[sizeof(MONOUT)+10];

MONIN *kbdin = (MONIN*)kbdinbfr;
MONOUT *kbdout= (MONOUT*)kbdoutbfr;

TID tid = -1;
int monit = -1;

VOID FAR watcher();	/* keyboard watcher thread */

STARTDATA scb = { sizeof scb, 1, 0, 0, 0, (char*)0, (char*)0, (char*)0,
		    (char*)0, 1 };

/*
 * the main program, or so we hope
 */
main(argc, argv)
char **argv;
{
    long alarmstk[100];
    char cmd[80];
    register i;

#define CHILDREN 4
    struct _child {
	int sid, pid;
    } child[CHILDREN];

    GINFOSEG *infop;

    short session;
    SEL gseg, lseg;
    char *shell;

    shell = (argc > 1) ? argv[1] : "c:/os2/cmd.exe";
    
    DosGetInfoSeg(&gseg, &lseg);
    infop = MAKEPGINFOSEG(gseg);
    session = infop->sgCurrent;

    kbdin->cb = sizeof(MONIN);
    kbdout->cb= sizeof(MONOUT);

    if (DosMonOpen(KBD, &monit) != 0)
	whoops("%s doesn't allow a monitor", KBD);
    if (DosMonReg(monit, kbdinbfr, kbdoutbfr, MONITOR_BEGIN, session) != 0)
	whoops("couldn't register monitor for %s", KBD);

    if (DosCreateThread(watcher, &tid, (char*)(alarmstk+sizeof alarmstk)) != 0)
	whoops("couldn't start watcher thread");

    DosSetPrty(2,3,0,tid);

    for (i=0; i<CHILDREN; i++) {
	scb.PgmName = shell;
	DosStartSession(&scb, &child[i].sid, &child[i].pid);
	DosMonReg(monit, kbdinbfr, kbdoutbfr, MONITOR_BEGIN, child[i].sid);
    }
	
    DosSelectSession(0,0L);
    while (1) {
	fputs(">>", stdout);
	fflush(stdout);
	gets(cmd);

	switch (cmd[0]) {
	case '1':
	case '2':
	case '3':
	case '4':
		DosSelectSession(child[cmd[0]-'1'].sid, 0L);
		break;
	}
    }
} /* main */


/*
 * watcher() sits in the input stream, looking for alt-esc.  If it sees
 * an alt-esc, it brings layers to the foreground so we can then select
 * another session.
 */
VOID FAR
watcher()
{
    static char pkt[1024];
    USHORT len;

    while (1) {
	len = sizeof pkt;
	if (DosMonRead(kbdinbfr, DCWW_WAIT, pkt, &len) != 0)
	    continue;
	if ((pkt[8] & 0x08) && (pkt[1] == 0x01))	/* alt-esc picks the */
	    DosSelectSession(0,0L);			/* current session */
	else						/* everything else */
	    DosMonWrite(kbdoutbfr, pkt, len);		/* just passes */
    }
} /* watcher */


/*
 * whoops: gives an error message, then dies
 */
whoops(msg, arg)
char *msg, *arg;
{
    if (tid >= 0)
	DosSuspendThread(tid);
    if (monit >= 0) {
	DosMonClose(monit);
	DosSelectSession(0,0L);
    }
    if (msg != (char*)0)
	fprintf(stderr, msg, arg);
    exit(0);
} /* whoops */