# line 1 "unix-mach.c"
/* $Id: unix-mach.c,v 1.6 89/05/06 17:13:45 lee Exp $
 * GLIB - a Generic LIBrarian and editor for synths
 *
 * Machine dependent stuff.
 *
 * Unix version
 * Tim Thompson
 * modifications: Greg Lee
 * $Log:	unix-mach.c,v $
 * Revision 1.6  89/05/06  17:13:45  lee
 * rel. to comp.sources.misc
 * 
 */
/* LINTLIBRARY */

#include "glib.h"
#include <ctype.h>

int Rows, Cols;

#include <curses.h>

/* Ultrix curses fix -- gl */
#ifdef ULTRIX
#undef nl()
#undef nonl()
#define nl()	(_tty.sg_flags |= CRMOD,_pfast = _rawmode,stty(_tty_ch, &_tty))
#define nonl()	(_tty.sg_flags &= ~CRMOD, _pfast = TRUE, stty(_tty_ch, &_tty))
#endif

#ifdef ARROW
#include <sys/ioctl.h>
#include <signal.h>
#include <setjmp.h>
jmp_buf wakeup;
#endif


#ifndef ARROW

initkbd()
{}

resetkbd()
{}

nmgetch()
{
    return (getchar() & 0x7f);
}

#else /*ARROW*/

/* Following code for arrow key support lifted from
 * James Gosling's sc spreadsheet calculator -- gl
 */
#define N_KEY 4

struct key_map {
    char *k_str;
    char k_val;
    char k_index;
}; 

struct key_map km[N_KEY];

char keyarea[N_KEY*10];

char *tgetstr();
char *getenv();

#ifdef TIOCSLTC
struct ltchars old_chars, new_chars;
#endif

char dont_use[] = {
    ctl('z'), ctl('r'), ctl('l'), ctl('b'), ctl('c'), ctl('f'), ctl('g'), ctl('['),
    ctl('h'), ctl('m'), ctl('j'), ctl('n'), ctl('p'), ctl('q'), ctl('s'), ctl('t'),
    ctl('u'), ctl('v'), ctl('e'), ctl('a'), 0,
};

initkbd()
{
    register struct key_map *kp;
    register i,j;
    char *ks;
    char *p = keyarea;
    static char buf[1024]; /* Why do I have to do this again? */

    if (tgetent(buf, getenv("TERM")) <= 0)
	return;

    km[0].k_str = tgetstr("kl", &p); km[0].k_val = ctl('b');
    km[1].k_str = tgetstr("kr", &p); km[1].k_val = ctl('f');
    km[2].k_str = tgetstr("ku", &p); km[2].k_val = ctl('p');
    km[3].k_str = tgetstr("kd", &p); km[3].k_val = ctl('n');
    ks = tgetstr("ks",&p);
    if (ks) 
	printf("%s",ks);

    /* Unmap arrow keys which conflict with our ctl keys   */
    /* Ignore unset, longer than length 1, and 1-1 mapped keys */

    for (i = 0; i < N_KEY; i++) {
	kp = &km[i];
	if (kp->k_str && (kp->k_str[1] == 0) && (kp->k_str[0] != kp->k_val))
	    for (j = 0; dont_use[j] != 0; j++)
	        if (kp->k_str[0] == dont_use[j]) {
		     kp->k_str = (char *)0;
		     break;
		}
    }


#ifdef TIOCSLTC
    ioctl(fileno(stdin), TIOCGLTC, (char *)&old_chars);
    new_chars = old_chars;
    if (old_chars.t_lnextc == ctl('v'))
	new_chars.t_lnextc = -1;
    if (old_chars.t_rprntc == ctl('r'))
	new_chars.t_rprntc = -1;
    ioctl(fileno(stdin), TIOCSLTC, (char *)&new_chars);
#endif
}

resetkbd()
{
#ifdef TIOCSLTC
    ioctl(fileno(stdin), TIOCSLTC, (char *)&old_chars);
#endif
}

nmgetch() 
{
    register int c;
    register struct key_map *kp;
    register struct key_map *biggest;
    register int i;
    int almost;
    int maybe;

    static char dumpbuf[10];
    static char *dumpindex;

    int time_out();

    if (dumpindex && *dumpindex)
	    return (*dumpindex++);

    c = getchar() & 0x7f;
    biggest = 0;
    almost = 0;

    for (kp = &km[0]; kp < &km[N_KEY]; kp++) {
	if (!kp->k_str)
	    continue;
	if (c == kp->k_str[kp->k_index]) {
	    almost = 1;
	    kp->k_index++;
	    if (kp->k_str[kp->k_index] == 0) {
		c = kp->k_val;
       	        for (kp = &km[0]; kp < &km[N_KEY]; kp++)
	            kp->k_index = 0;
	        return(c);
	    }
	}
	if (!biggest && kp->k_index)
	    biggest = kp;
        else if (kp->k_index && biggest->k_index < kp->k_index)
	    biggest = kp;
    }

    if (almost) { 

        (void)signal(SIGALRM, time_out);
        alarm(1);

	if (setjmp(wakeup) == 0) { 
	    maybe = nmgetch();
	    alarm(0);
	    return(maybe);
	}

    }
    
    if (biggest) {
	for (i = 0; i<biggest->k_index; i++) 
	    dumpbuf[i] = biggest->k_str[i];
	dumpbuf[i++] = c;
	dumpbuf[i] = 0;
	dumpindex = &dumpbuf[1];
       	for (kp = &km[0]; kp < &km[N_KEY]; kp++)
	    kp->k_index = 0;
	return (dumpbuf[0]);
    }

    return(c);
}

time_out()
{
    longjmp(wakeup, -1);
}

#endif /* ARROW */

#ifdef DEVMIDI
#include <sys/types.h>
#include <fcntl.h>
#include <sys/midi.h>
int Midifd = -1;
#define MSIZE 40000
static char midibuff[MSIZE];
static char *nextmidi;
static int midibsize = 0;
static int midisofar = 0;
#endif

hello()
{
#ifdef DEVMIDI
#define MIDIDEVICE "/dev/midi"
	Midifd = open(MIDIDEVICE,O_RDWR);
	if ( Midifd < 0 ) {
		fprintf(stderr,"Can't open %s ?!\n",MIDIDEVICE);
		exit(1);
	}
	ioctl(Midifd,MIDIRESET);
	/* ioctl(Midifd,MIDITHRU); */
#endif
}

thrumode()
{
#ifdef DEVMIDI
	ioctl(Midifd,MIDITHRU);
#endif
}

uartmode()
{
#ifdef DEVMIDI
	ioctl(Midifd,MIDIRESET);
#endif
}

bye()
{
	windgoto(22,0);
	windrefresh();
	resetkbd();
	windexit(0);
}

/* getmousepos - get currect row and column of mouse */
void
getmousepos(amr,amc)
int *amr;
int *amc;
{
#ifdef USEMOUSE
	/* no such */
#else
	*amr = -1;
	*amc = -1;
#endif
}

/* statmouse - return mouse button state (0=nothing pressed,1=left,2=right) */
statmouse()
{
#ifdef USEMOUSE
	/* no such */
#else
	return(-1);
#endif
}

/* Return when either a console key or mouse button is pressed. */
mouseorkey()
{
#ifdef USEMOUSE
	/* no such */
#else
	return(nmgetch());
/*
	return(getconsole());
*/
#endif
}

flushconsole()
{
}

statconsole()
{
	return(1);
}

getconsole()
{
	return(getchar());
}

int siopenflag = 0;
FILE *sifile;
int soopenflag = 0;
FILE *sofile;
extern char Syinfname[100];
extern char Syofname[100];

getmidi()
{	int c;

#ifdef DEVMIDI
	if ( ! statmidi() )
		return -1;
	if ( midibsize > 0 ) {
		midibsize--;
		c = (*nextmidi++) & 0xff;
		return c;
	}
	return -1;
#else
	if (!synthinfileflag) return(-1);

	if (!siopenflag) {
#ifdef BSD
		OPENBINFILE(sifile,Syinfname,"r");
#else
		OPENBINFILE(sifile,Syinfname,"rb");
#endif
		if (sifile != NULL)
			siopenflag = 1;
	}
	if (siopenflag) {
		c = getc(sifile);
		if (c == EOF) {
			(void)fclose(sifile);
			siopenflag = 0;
		} else
			return(c);
	}
	return(-1);
#endif
}

statmidi()
{
#ifdef DEVMIDI
	int nb;
	if ( midibsize == 0 ) {
		nextmidi = midibuff;
		midisofar = 0;
	}

	/* If there's room in the buffer, grab as much MIDI input as we can. */
	while ( midisofar<MSIZE && (nb=read(Midifd,midibuff+midisofar,MSIZE-midisofar)) > 0 ) {
		midisofar += nb;
		midibsize += nb;
	}
	return (midibsize>0 ? 1 : 0);
#else
	if (!synthinfileflag) return(0);
	return(1);
#endif
}

/*ARGSUSED*/
sendmidi(c)
int c;
{
#ifdef DEVMIDI
	char buff[2];
	buff[0] = c;
	write(Midifd,buff,1);
#else
	if (!synthoutfileflag) return;

	if (!soopenflag) {
#ifdef BSD
		OPENBINFILE(sofile,Syofname,"w");
#else
		OPENBINFILE(sofile,Syofname,"wb");
#endif
		if (sofile != NULL)
			soopenflag = 1;
	}
	if (soopenflag)
		putc(c, sofile);
#endif
}

flushmidi()
{
#ifndef DEVMIDI
	if (!synthinfileflag && !synthoutfileflag)
#endif
	while ( STATMIDI )
		(void)getmidi();
#ifndef DEVMIDI

	if (!synthoutfileflag) return;

/* To close files used in redirection of midi output, set
 * synthoutfileflag and call me.
 */
	if (siopenflag) {
		(void)fclose(sifile);
		siopenflag = 0;
	}
	if (soopenflag) {
		(void)fclose(sofile);
		soopenflag = 0;
	}
#endif
}

long milliclock()
{
#ifdef DEVMIDI
	long t;

	ioctl(Midifd,MIDITIME,&t);
	return t;
#else
	static long hzcount = 0;

	return(hzcount++);
#endif
}

millisleep(n)
{
#ifdef DEVMIDI
	long et = milliclock() + n;
	while ( milliclock() < et )
		;
#else
	sleep((unsigned)((n+500)/1000));
#endif
}

char *
alloc(n)
{
	char *p;

	if ( (p=malloc((unsigned)n)) == (char *)NULL ) {
		printf("*** Whoops *** alloc has failed?!?  No more memory!\n");
		(void)fflush(stdout);
		bye();
	}
	return(p);
}

windinit()
{
	char *getenv();

	initscr();
	Cols = COLS;
	Rows = LINES;
	noecho();
	nonl();
#ifdef BSD
	crmode();
#else
	cbreak();
#endif
	initkbd();
}

windgoto(r,c)
int r,c;
{
	move(r,c);
}

windeeol()
{
	clrtoeol();
}

winderaserow(r)
{
	windgoto(r,0);
	windeeol();
}

windexit(r)
int r;
{
#ifdef BSD
	nocrmode();
#else
	nocbreak();
#endif
	nl();
	echo();
	endwin();
	(void)exit(r);
}

windclear()
{
	clear();
}

/* windgets - get a line of input from the console, handling backspaces */
windgets(s)
char *s;
{
	char *origs = s;
	int c;

	while ( (c=getconsole()) != '\n' && c!='\r' && c!= EOF ) {
		if ( c == '\b' ) {
			if ( s > origs ) {
				windstr("\b \b");
				s--;
			}
		}
		else {
			windputc(c);
			*s++ = c;
		}
		windrefresh();
	}
	*s = '\0';
}

windstr(s)
char *s;
{
	int c;

	while ( (c=(*s++)) != '\0' )
		windputc(c);
}

windputc(c)
int c;
{
	addch(c);
}

windrefresh()
{
	refresh();
}

beep()
{
	putchar('\007');
}

windhigh()
{
	standout();
}

windnorm()
{
	standend();
}

/****************
 * openls(), nextls(), and closels() are used to scan the current directory.
 ***************/

FILE *Phrlist = NULL;

openls()
{
	FILE *popen();
	
	Phrlist = popen("ls","r");
}
char *
nextls()
{
	static char fname[65];

	if ( fscanf(Phrlist,"%s",fname) != 1 )
		return(NULL);
	return(fname);
}
closels()
{
	pclose(Phrlist);
}

#ifdef FAKECBREAK
#include <sys/termio.h>
struct termio Initterm;
static int First = 1;
cbreak()
{
	struct termio termbuff;

	if ( First  ) {
		First = 0;
		ioctl(0,TCGETA,&Initterm);
	}
	termbuff = Initterm;
	termbuff.c_lflag &= (~ICANON);
	termbuff.c_cc[4] = 1;
	termbuff.c_cc[5] = 1;
	ioctl(0,TCSETA,&termbuff);
}
nocbreak()
{
	ioctl(0,TCSETA,&Initterm);
}
#endif
