/* vim: set filetype=c:
 *
 * console.c86  -  MGL runtime console I/O routines
 *
 * Copyright (C) 2003-2007 Gero Kuhlmann   <gero@gkminix.han.de>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id: console.c86,v 1.9 2007/01/06 18:31:38 gkminix Exp $
 */

#include "rtcommon.h86"



/*
 *****************************************************************************
 *
 * Global variables
 */
short selectnumber;



/*
 *****************************************************************************
 *
 * Initialize console I/O
 */
void init_console(void)
{
  /* We just initialize the ANSI handling */
  ansiinit();
}



/*
 *****************************************************************************
 *
 * Print an integer number
 */
__INTERNAL(printint, size_t, short val)
{
  char *s;
  size_t len;

  len = 0;
  if (val < 0) {
	cputc('-');
	len++;
	val = -val;
  }

  s = __numcvt((unsigned long)val, 10);
  while (*s) {
	cputc(*s);
	len++;
	s++;
  }
  return(len);
}


/* Function wrapper */
__PUBLIC(printint, 1, __A(short, 0));


/* Export info */
__EXPORT_PROC(printint, NONE, 1, __ARGS(__D(NUM, NONE)));



/*
 *****************************************************************************
 *
 * Print a string
 */
__INTERNAL(printstring, size_t, __nptr sptr)
{
  char *s = (char *)((int)sptr);

  return(cwrite(&(s[1]), (size_t)(s[0])));
}


/* Function wrapper */
__PUBLIC(printstring, 1, __A(__nptr, 0));


/* Export info */
__EXPORT_PROC(printstring, NONE, 1, __ARGS(__D(STRING, CONST)));



/*
 *****************************************************************************
 *
 * Print a character
 */
__INTERNAL(printchar, size_t, char c)
{
  cputc(c);
  return(1);
}


/* Function wrapper */
__PUBLIC(printchar, 1, __A(char, 0));


/* Export info */
__EXPORT_PROC(printchar, NONE, 1, __ARGS(__D(CHAR, NONE)));



/*
 *****************************************************************************
 *
 * Read an integer number
 */
__INTERNAL(getint, short, short timeout)
{
  size_t pos;
  bool_t sign;
  short c, retval;

  /* Check for correct arguments */
  if (timeout < 0)
	timeout = 0;

  /* Directly read a number from the keyboard */
  pos = 0;
  sign = FALSE;
  retval = 0;
  while (TRUE) {
	c = getkey((unsigned short)timeout);
	if (c == -1)
		break;
	c &= 0x7f;
	if ( c == CHR_CR || c == CHR_BREAK)
		break;
	if (c == '-') {
		if (pos == 0) {
			cputc(c);
			sign = TRUE;
			pos++;
		}
		continue;
	}
	if (c >= '0' && c <= '9') {
		if (retval < 3276 || (retval == 3276 && c <= '7')) {
			cputc(c);
			retval = retval * 10 + (c - '0');
			pos++;
		}
		continue;
	}
	if (c == CHR_BS) {
		if (pos > 0) {
			cputc('\b');
			cputc(' ');
			cputc('\b');
			pos--;
			if (pos == 0) {
				retval = 0;
				sign = FALSE;
			} else
				retval /= 10;
		}
		continue;
	}
  }
  return(sign ? -retval : retval);
}


/* Function wrapper */
__PUBLIC(getint, 1, __A(short, 0));


/* Export info */
__EXPORT_PROC(getint, NUM, 1, __ARGS(__D(NUM, NONE)));



/*
 *****************************************************************************
 *
 * Read a string
 */
__INTERNAL(getstring, __nptr, __nptr sptr, size_t slen, short timeout)
{
  char *s = (char *)((int)sptr);
  size_t pos;
  short c;

  /* Check for correct arguments */
  if (timeout < 0)
	timeout = 0;

  /* Directly read a string from the keyboard */
  pos = 0;
  while (TRUE) {
	c = getkey((unsigned short)timeout);
	if (c == -1)
		break;
	c &= 0x7f;
	if (c == CHR_CR || c == CHR_BREAK)
		break;
	if (!iscntrl(c)) {
		if (pos < slen) {
			cputc(c);
			pos++;
			s[pos] = c;
		}
		continue;
	}
	if (c == CHR_BS) {
		if (pos > 0) {
			cputc('\b');
			cputc(' ');
			cputc('\b');
			pos--;
		}
		continue;
	}
  }
  s[0] = (char)(pos & 0xff);
  return(sptr);
}


/* Function wrapper */
__PUBLIC(getstring, 3,
		__A(__nptr, 1), __A(size_t, 2),
		__A(short, 0)
);


/* Export info */
__EXPORT_PROC(getstring, STRING, 1, __ARGS(__D(NUM, NONE)));



/*
 *****************************************************************************
 *
 * Read a character
 */
__INTERNAL(getchar, char, short timeout)
{
  short c;

  /* Check for correct arguments */
  if (timeout < 0)
	timeout = 0;

  /* Directly read a character from the keyboard */
  c = getkey((unsigned short)timeout);
  if (c == -1)
	return(0);
  return(c & 0x7f);
}


/* Function wrapper */
__PUBLIC(getchar, 1, __A(short, 0));


/* Export info */
__EXPORT_PROC(getchar, CHAR, 1, __ARGS(__D(NUM, NONE)));



/*
 *****************************************************************************
 *
 * Read a character for select command
 */
__INTERNAL(select, char, short timeout)
{
  short c, x, y;

  /* Check for correct arguments */
  if (timeout < 0)
	timeout = 0;

  /* Clear the position where the character has to be typed in */
  ansigetpos(&x, &y);
  cputc(' ');
  ansisetpos(x, y);

  /* Directly read a character from the keyboard */
  while (TRUE) {
	c = getkey((unsigned short)timeout);
	if (c == -1)
		break;
	c &= 0x7f;
	if (c == CHR_CR || c == CHR_BREAK) {
		c = -1;
		break;
	}
	if (c >= '0' && c <= '9') {
		cputc(c);
		ansisetpos(x, y);
		selectnumber = (short)(c - '0');
		break;
	}
  }
  return(c);
}


/* Function wrapper */
__PUBLIC(select, 1, __A(short, 0));


/* Export info */
__EXPORT_PROC(select, CHAR, 1, __ARGS(__D(NUM, NONE)));


/* Export current selection number */
__EXPORT_VAR(selectnumber, NUM, 0);



/*
 *****************************************************************************
 *
 * Put the cursor onto a certain screen position
 */
__INTERNAL(gotoxy, int, short x, short y)
{
  ansisetpos(x, y);
  return(0);
}


/* Function wrapper */
__PUBLIC(gotoxy, 2, __A(short, 1), __A(short, 0));


/* Export info */
__EXPORT_PROC(gotoxy, NONE, 2, __ARGS(__D(NUM, NONE), __D(NUM, NONE)));

