/*
 *
 * $Id: ibmpc.c,v 4.8 1994/03/17 00:58:33 mikes Exp $
 *
 * Program:	IBM PC specific routine
 *
 *
 * Michael Seibel
 * Networks and Distributed Computing
 * Computing and Communications
 * University of Washington
 * Administration Builiding, AG-44
 * Seattle, Washington, 98195, USA
 * Internet: mikes@cac.washington.edu
 *
 * Please address all bugs and comments to "pine-bugs@cac.washington.edu"
 *
 * Copyright 1991-1994  University of Washington
 *
 *  Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee to the University of
 * Washington is hereby granted, provided that the above copyright notice
 * appears in all copies and that both the above copyright notice and this
 * permission notice appear in supporting documentation, and that the name
 * of the University of Washington not be used in advertising or publicity
 * pertaining to distribution of the software without specific, written
 * prior permission.  This software is made available "as is", and
 * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
 * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
 * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
 * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * Pine and Pico are trademarks of the University of Washington.
 * No commercial use of these trademarks may be made without prior
 * written permission of the University of Washington.
 *
 */

/*
 * The routines in this file provide support for the IBM-PC and other
 * compatible terminals. It goes directly to the graphics RAM to do
 * screen output. It compiles into nothing if not an IBM-PC driver
 */

#include        <stdio.h>
#include	<conio.h>
#include	<time.h>
#include	"osdep.h"
#if     IBMPC
#define	termdef	1			/* don't define "term" external */
#include	"pico.h"
#include	"estruct.h"
#include        "efunc.h"
#include        "edef.h"

#ifdef	ANSI
    int  ibmmove(int, int);
    int  ibmeeol(void);
    int  ibmputc(int);
    int  ibmoutc(char);
    int  ibmeeop(void);
    int  ibmrev(int);
    void beep(unsigned int, unsigned int);
    int  cutebeep(void);
    int  ibmbeep(void);
    int  ibmopen(void);
    int  ibmclose(void);
#else
    int  ibmmove();
    int  ibmeeol();
    int  ibmputc();
    int  ibmoutc();
    int  ibmeeop();
    int  ibmrev();
    void beep();
    int  cutebeep();
    int  ibmbeep();
    int  ibmopen();
    int  ibmclose();
#endif


#define NROW    25              /* Screen size.                 */
#define NCOL    80              /* Edit if you want to.         */
#define	MARGIN	8		/* size of minimim margin and	*/
#define	SCRSIZ	64		/* scroll size for extended lines */
#define	NPAUSE	200		/* # times thru update to pause */
#define BEL     0x07            /* BEL character.               */
#define ESC     0x1B            /* ESC character.               */
#define	SPACE	32		/* space character		*/




#define	 SET_COLOR(fore,back)	((((back) & 0xf) << 4) | ((fore) & 0xf))

int	 nfcolor = 7;		/* current forground color */
int	 nbcolor = 1;		/* current background color */
int	 rfcolor = 0;		/* reverse forground color */
int	 rbcolor = 3;		/* reverse background color */
unsigned cattr;			/* current combined attribute */

static unsigned display_mode;	/*  */

/*
 * Standard terminal interface dispatch table. Most of the fields point into
 * "termio" code.
 */
TERM    term    = {
        NROW-1,
        NCOL,
	MARGIN,
	SCRSIZ,
        ibmopen,
        ibmclose,
        ttgetc,
	ibmputc,
        ttflush,
        ibmmove,
        ibmeeol,
        ibmeeop,
        ibmbeep,
	ibmrev
};


extern union REGS rg;


static char *colist[] = {
	"black",
	"blue",
	"green",
	"cyan",
	"red",
	"magenta",
	"yellow",
	"white",
        "BLACK",
        "BLUE",
        "GREEN",
        "CYAN",
        "RED",
        "MAGENTA",
        "YELLOW",
        "WHITE" };

/*
 * pico_setcolor - given the color name, return the color's value
 */
int
setcolor(s)
char *s;
{
    int i;

    for (i=0; i<16; i++)
      if (!strcmp(colist[i],s))
	return(i);

    return(7);
}


/*
 * pico_XXcolor() - each function sets a particular attribute
 */
pico_nfcolor(s)
char *s;
{
    nfcolor = setcolor(s);
}

pico_nbcolor(s)
char *s;
{
    nbcolor = setcolor(s);
}

pico_rfcolor(s)
char *s;
{
    rfcolor = setcolor(s);
}

pico_rbcolor(s)
char *s;
{
    rbcolor = setcolor(s);
}



/*
 * ibmmove - Use BIOS video services, function 2h to set cursor postion
 */
ibmmove(row, col)
int row, col;
{
    rg.h.ah = 2;		/* set cursor position function code */
    rg.h.bh = 0;		/* set screen page number */
    rg.h.dl = col;
    rg.h.dh = row;
    int86(BIOS_VIDEO, &rg, &rg);
}


/*
 * ibmeeol - erase to the end of the line
 */
ibmeeol()
{
    int col, row, page;

    /* find the current cursor position */
    rg.h.ah = 3;		/* read cursor position function code */
    int86(BIOS_VIDEO, &rg, &rg);
    page = rg.h.bh;
    col = rg.h.dl;		/* record current column */
    row = rg.h.dh;		/* and row */

    rg.h.ah = 0x09;		/* write char to screen with new attrs */
    rg.h.al = ' ';
    rg.h.bl = cattr;
    rg.h.bh = page;
    rg.x.cx = NCOL-col;
    int86(BIOS_VIDEO, &rg, &rg);
}


/*
 * ibmputc - put a character at the current position in the
 *	     current colors
 */
ibmputc(ch)
int ch;
{
    int col, row, page;

    rg.h.ah = 0x03;			/* first, get current position */
    int86(BIOS_VIDEO, &rg, &rg);
    page = rg.h.bh;
    row = rg.h.dh;
    col = rg.h.dl;
    
    if(ch == '\b'){
	if(col > 0)		/* advance the cursor */
	  ibmmove(row, --col);
    }
    else{
	rg.h.ah = 0x09;		/* write char to screen with new attrs */
	rg.h.al = ch;
	rg.h.bl = cattr;		/* inverting if needed */
	rg.h.bh = page;
	rg.x.cx = 1;		/* only once */
	int86(BIOS_VIDEO, &rg, &rg);

	if(col < 80)		/* advance the cursor */
	  ibmmove(row, ++col);
    }
}


/* 
 * ibmoutc - output a single character with the right attributes, but
 *           don't advance the cursor
 */
ibmoutc(c)
char c;
{
    rg.h.ah = 0x09;		/* write char to screen with new attrs */
    rg.h.al = c;
    rg.h.bl = cattr;	/* inverting if needed */
    rg.h.bh = 0;
    rg.x.cx = 1;		/* only once */
    int86(BIOS_VIDEO, &rg, &rg);
}


/*
 * ibmeeop - clear from cursor to end of page
 */
ibmeeop()
{
    rg.h.ah = 6;		/* scroll page up function code */
    rg.h.al = 0;		/* # lines to scroll (clear it) */
    rg.x.cx = 0;		/* upper left corner of scroll */
    rg.x.dx = (term.t_nrow << 8) | (term.t_ncol - 1);
    rg.h.bh = cattr;
    int86(BIOS_VIDEO, &rg, &rg);

    ibmmove(0, 0);
}


/*
 * ibmrev - change reverse video state
 */
ibmrev(state)
int state;
{
    cattr = (state) ? SET_COLOR(rfcolor, rbcolor)
		    : SET_COLOR(nfcolor, nbcolor);
}


/*
 * getrevstate - return the current reverse state
 */
getrevstate()
{
    return(cattr == SET_COLOR(rfcolor, rbcolor));
}


/* 
 * beep - make the speaker sing!
 */
void
beep(freq, dur)
unsigned freq, dur;
{
    unsigned oport;

    if(!freq)
	return;

    freq = (unsigned)(1193180 / freq);
    /* set up the timer */
    outp(0x43, 0xb6);			/* set timer channel 2 registers */
    outp(0x42, (0xff&freq));		/* low order byte of count */
    outp(0x42, (freq>>8));		/* hi order byte of count */

    /* make the sound */
    oport = inp(0x61);
    outp(0x61, oport | 0x03);
    ssleep((clock_t)((dur < 75) ? 75 : dur));
    outp(0x61, oport);
}


/*
 * cutebeep - make the speeker sing the way we want!
 */
cutebeep()
{
    beep(575, 50);
    ssleep((clock_t)25);
    beep(485, 90);
}


/*
 * ibmbeep - system beep...
 */
ibmbeep()
{
    cutebeep();
}


/*
 * enter_text_mode - get current video mode, saving to be restored 
 *                   later, then explicitly set 80 col text mode.
 *
 *     NOTE: this gets kind of weird.  Both pine and pico call this
 *           during initialization.  To make sure it's only invoked once
 *           it only responds if passed NULL which pico only does if not
 *           called from in pine, and pine does all the time.  make sense?
 *           thought not.
 */
void
enter_text_mode(p)
PICO *p;
{
    static int i = 0;

    if(!p && !i++){
	rg.h.ah = 0x0f;			/* save old mode */
	int86(BIOS_VIDEO, &rg, &rg);
	display_mode = rg.h.al;

	rg.h.ah = 0;			/* then set text mode */
	rg.h.al = 2;
	int86(BIOS_VIDEO, &rg, &rg);		/* video services */
    }
}


/*
 * exit_text_mode - leave text mode by restoring saved original 
 *                  video mode.
 */
void
exit_text_mode(p)
PICO *p;
{
    static int i = 0;

    if(!p && !i++){			/* called many, invoke once! */
	rg.h.ah = 0;			/* just restore old mode */
	rg.h.al = display_mode;
	int86(BIOS_VIDEO, &rg, &rg);
    }
}


/*
 * ibmopen - setup text mode and setup key labels...
 */
ibmopen()
{

    enter_text_mode(Pmaster);

    cattr    = SET_COLOR(nfcolor, nbcolor);
    revexist = TRUE;
    inschar  = delchar = 0;

    ttopen();
}


ibmclose()
{
#if	COLOR
    ibmfcol(7);
    ibmbcol(0);
#endif

    exit_text_mode(Pmaster);

    ttclose();
}
#endif
