# line 1 "unix-mach.c"
/* $Id: unix-mach.c,v 1.7 89/05/14 13:51:18 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.7  89/05/14  13:51:18  lee
 * wind... functions implement 'V' command
 * 
 * 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;

#ifndef XGL
#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;

    void timeout();

    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, timeout);
        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);
}

void
timeout(int sig)
{
    longjmp(wakeup, -1);
}

#endif /* ARROW */

#endif /* not XGL */

hello()
{
}

bye()
{
#ifndef XGL
	windgoto(22,0);
	windrefresh();
	resetkbd();
	windexit(0);
#endif
	flushmidi();
#ifndef XGL
	printf("bye.\n");
#endif
}

#ifndef XGL
/* getmouse - get currect row and column of mouse */
getmouse(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());
}
#endif /*not XGL */

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

getmidi()
{	int c;

	if (!synthinfileflag)
#ifdef LINUXIO
#ifdef MIDIIN
	return(midigetc());
#else
	return(-1);
#endif
#else
	return(-1);
#endif

	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);
}

statmidi()
{
	if (!synthinfileflag)
#ifdef LINUXIO
#ifdef MIDIIN
		return(midipending());
#else
		return(0);
#endif
#else
		return(0);
#endif
	return(0);
}

/*ARGSUSED*/
sendmidi(c)
int c;
{
#ifdef LINUXIO
	if (!synthoutfileflag) {
		midich(c);
		return;
	}
#else
	if (!synthoutfileflag) return;
#endif

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

flushmidi()
{
	if (!synthinfileflag && !synthoutfileflag)
	while ( STATMIDI )
		(void)getmidi();

#ifdef LINUXIO
	if (!synthoutfileflag) {
		sbflush();
		return;
	}
#else
	if (!synthoutfileflag) return;
#endif

/* 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;
	}
}

long milliclock()
{
	static long hzcount = 0;

	return(hzcount++);
}

millisleep(n)
{
	sleep((unsigned)((n+500)/1000));
}

char *
alloc(n)
{
	char *p;

	if (!n) n++;
	if ( (p=(char *)malloc((unsigned)n)) == NULL ) {
		printf("*** Whoops *** alloc has failed?!?  No more memory!\n");
#ifdef XGL
		exit(1);
#else
		(void)fflush(stdout);
		bye();
#endif
	}
	return(p);
}

#ifndef XGL
windinit()
{
	char *getenv();

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

#define SROWS 24
#define SCOLS 81
int fdtrow, fdtcol;
int fdtopenflag = 0;
char *screen;

windgoto(r,c)
int r,c;
{
	if (!fditflag) move(r,c);
	else {
		fdtrow = r;
		fdtcol = 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()
{
	if (!fditflag) 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;
{
	char *s;
	char *malloc();
	int i;

	if (!fditflag) addch(c);
	else {
	    if (!fdtopenflag) {
		if ( (screen = malloc(SROWS * SCOLS)) == NULL) return;
		s = screen;
		for (i=0; i < SROWS*SCOLS; i++) *s++ = ' ';
		fdtopenflag = 1;
	    }
	    if (fdtopenflag) {
		screen[fdtrow*SCOLS + fdtcol] = c;
		fdtcol++;
	    }
	}
}

windrefresh()
{
	FILE *fdtfile;
	int i, j;

	if (!fditflag) refresh();

	else if (fdtopenflag) {
	    OPENBINFILE(fdtfile, "VPIC", "a");
	    for (i=0; i<SROWS; i++) {
		for (j=SCOLS-1; j>=0 && screen[i*SCOLS+j] == ' '; j--)
			screen[i*SCOLS+j] = 0;
		fprintf(fdtfile, "%s\n", screen+i*SCOLS);
	    }
	    fclose(fdtfile);
	    free(screen);
	    fdtopenflag = 0;
	}
}

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

windhigh()
{
	standout();
}

windnorm()
{
	standend();
}

#endif /* not XGL */

/****************
 * 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);
}

#ifndef XGL
#ifdef FAKECBREAK
#ifdef linux
#include <termio.h>
#else
#include <sys/termio.h>
#endif
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
#endif /* not XGL */
