/*
 * ncurses lib program copyright (C) 2009 - 2013 H.Niwa
 */

/*
 * 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, or (at your option)
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */

#include "config.h"

#if HAVE_LIBNCURSES

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <errno.h>
#include <setjmp.h>
#include <sys/time.h>
#include <math.h>
#include <libgen.h>
#include <setjmp.h>

#ifndef __MINGW32__
#ifdef __CYGWIN__
#include <ncurses/ncurses.h>
#else
#include <ncurses.h>
#endif
#endif

#include <string>
#include <complex>

#include "syserr.h"

#include "bin_node.h"
#include "gc.h"
#include "var.h"
#include "pred.h"
#include "context.h"
#include "unify.h"
#include "builtin.h"
#include "sysmodule.h"
#include "ncurlib.h"


int ncurlibflag = 0;

int cursmodule(Context* cx, Node* goalscar, Node* goalscdr, 
				Node* goals, List* module, int& r);

int curs_startcurses(Context* cx, Node* goalscar, List* module);

int curs_mvprintw(Context* cx, Node* goalscar, List* module);
int curs_printw(Context* cx, Node* goalscar, List* module);
int curs_refresh(Context* cx, Node* goalscar, List* module);
int curs_move(Context* cx, Node* goalscar, List* module);
int curs_cbreak(Context* cx, Node* goalscar, List* module);
int curs_nocbreak(Context* cx, Node* goalscar, List* module);
int curs_raw(Context* cx, Node* goalscar, List* module);
int curs_noraw(Context* cx, Node* goalscar, List* module);
int curs_echo(Context* cx, Node* goalscar, List* module);
int curs_noecho(Context* cx, Node* goalscar, List* module);
int curs_erase(Context* cx, Node* goalscar, List* module);
int curs_clear(Context* cx, Node* goalscar, List* module);
int curs_getch(Context* cx, Node* goalscar, List* module);
int curs_ungetch(Context* cx, Node* goalscar, List* module);
int curs_getstr(Context* cx, Node* goalscar, List* module);
int curs_inch(Context* cx, Node* goalscar, List* module);
int curs_instr(Context* cx, Node* goalscar, List* module);
int curs_isendwin(Context* cx, Node* goalscar, List* module);
int curs_beep(Context* cx, Node* goalscar, List* module);
int curs_flash(Context* cx, Node* goalscar, List* module);
int curs_hline(Context* cx, Node* goalscar, List* module);
int curs_vline(Context* cx, Node* goalscar, List* module);
int curs_keypad(Context* cx, Node* goalscar, List* module);
int curs_scrollok(Context* cx, Node* goalscar, List* module);
int curs_scrl(Context* cx, Node* goalscar, List* module);
int curs_LINES(Context* cx, Node* goalscar, List* module);
int curs_COLS(Context* cx, Node* goalscar, List* module);
int curs_delch(Context* cx, Node* goalscar, List* module);
int curs_mvdelch(Context* cx, Node* goalscar, List* module);
int curs_clrtobot(Context* cx, Node* goalscar, List* module);
int curs_clrtoeol(Context* cx, Node* goalscar, List* module);
int curs_border(Context* cx, Node* goalscar, List* module);



#define MAXNSTR	4096
static char	strbuf[MAXNSTR+1];

/* ---------------------------------------------------------*/

int cursmodule(Context* cx, Node* goalscar, Node* goalscdr, 
				Node* goals, List* module, int& r)
{
	Node* retn;
	int	rn;

	std::string	s;

#ifndef __MINGW32__
	if (goalscar->Val()->Car()->kind() == ATOM) {
		((Atom*)(goalscar->Val()->Car()))->toString(s);


		if (s == "start") {
			r = curs_startcurses(cx, goalscar, module);
			return 1;
#if 0
		} else if (s == "initscr") {
			r = curs_initscr(cx, goalscar, module);
			return 1;
		} else if (s == "endwin") {
			r = curs_endwin(cx, goalscar, module);
			return 1;
#endif
		} else if (s == "mvprintw") {
			r = curs_mvprintw(cx, goalscar, module);
			return 1;
		} else if (s == "printw") {
			r = curs_printw(cx, goalscar, module);
			return 1;
		} else if (s == "move") {
			r = curs_move(cx, goalscar, module);
			return 1;
		} else if (s == "refresh") {
			r = curs_refresh(cx, goalscar, module);
			return 1;
		} else if (s == "cbreak") {
			r = curs_cbreak(cx, goalscar, module);
			return 1;
		} else if (s == "nocbreak") {
			r = curs_nocbreak(cx, goalscar, module);
			return 1;
		} else if (s == "raw") {
			r = curs_raw(cx, goalscar, module);
			return 1;
		} else if (s == "noraw") {
			r = curs_raw(cx, goalscar, module);
			return 1;
		} else if (s == "echo") {
			r = curs_echo(cx, goalscar, module);
			return 1;
		} else if (s == "noecho") {
			r = curs_noecho(cx, goalscar, module);
			return 1;
		} else if (s == "erase") {
			r = curs_erase(cx, goalscar, module);
			return 1;
		} else if (s == "clear") {
			r = curs_clear(cx, goalscar, module);
			return 1;
		} else if (s == "getch") {
			r = curs_getch(cx, goalscar, module);
			return 1;
		} else if (s == "ungetch") {
			r = curs_ungetch(cx, goalscar, module);
			return 1;
		} else if (s == "getstr") {
			r = curs_getstr(cx, goalscar, module);
			return 1;
		} else if (s == "inch") {
			r = curs_inch(cx, goalscar, module);
			return 1;
		} else if (s == "instr") {
			r = curs_instr(cx, goalscar, module);
			return 1;
		} else if (s == "isendwin") {
			r = curs_isendwin(cx, goalscar, module);
			return 1;
		} else if (s == "beep") {
			r = curs_beep(cx, goalscar, module);
			return 1;
		} else if (s == "flash") {
			r = curs_flash(cx, goalscar, module);
			return 1;
		} else if (s == "vline") {
			r = curs_vline(cx, goalscar, module);
			return 1;
		} else if (s == "hline") {
			r = curs_hline(cx, goalscar, module);
			return 1;
		} else if (s == "keypad") {
			r = curs_keypad(cx, goalscar, module);
			return 1;
		} else if (s == "scrollok") {
			r = curs_scrollok(cx, goalscar, module);
			return 1;
		} else if (s == "scrl") {
			r = curs_scrl(cx, goalscar, module);
			return 1;
		} else if (s == "LINES") {
			r = curs_LINES(cx, goalscar, module);
			return 1;
		} else if (s == "COLS") {
			r = curs_COLS(cx, goalscar, module);
			return 1;
		} else if (s == "delch") {
			r = curs_delch(cx, goalscar, module);
			return 1;
		} else if (s == "mvdelch") {
			r = curs_mvdelch(cx, goalscar, module);
			return 1;
		} else if (s == "clrtobot") {
			r = curs_clrtobot(cx, goalscar, module);
			return 1;
		} else if (s == "clrtoeol") {
			r = curs_clrtobot(cx, goalscar, module);
			return 1;
		} else if (s == "border") {
			r = curs_clrtobot(cx, goalscar, module);
			return 1;
		}
	}
#endif 	/* __MINGW32__ */

	r = -1;
	syserr("::curses %s: The predicate that did not exist in the curses module is used. \n",
			s.c_str());
	return 1;
}

#ifndef __MINGW32__

int curs_startcurses(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar->Cdr()) < 1) {
		syserr("usage : <curses PRED...> \n");
		return 0;
	}

	Node* gl   = goalscar->Cdr()->Val();

	initscr();
	start_color();

	ncurlibflag = 1;


	Context *cx2 = new Context(module, cx->modulename);
	cx2->selfname = cx->selfname;
	cx2->ioin = cx->ioin;
	cx2->ioout = cx->ioout;
	cx2->tokenflag = cx->tokenflag;
	cx2->token = cx->token;

	cx2->ode = cx->ode;
	cx2->integral = cx->integral;
	
	cxpush(cx2, gl);
	cxpush(cx2, goalscar);
	cxpush(cx2, module);

	int r = Unify(cx2, gl, module);

	cxpop(cx2);
	cxpop(cx2);
	cxpop(cx2);

	delete cx2;
	cx2 = 0;

	nocbreak();
	endwin();

	ncurlibflag = 0;

	return r;
		
}

#if 0
int curs_initscr(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar) != 1) {
		syserr("usage : <initscr> \n");
		return 0;
	}

	initscr();
	return 1;
}

int curs_endwin(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar) != 1) {
		syserr("usage : <endwin> \n");
		return 0;
	}

	endwin();
	return 1;
}
#endif

int curs_mvprintw(Context* cx, Node* goalscar, List* module)
{
	int i;
	int l = ListLength(goalscar->Cdr());
	if (l < 2) {
		syserr("usage : <mvprintw X Y STR...> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("mvprintw: It can use only in curses.\n");
		return 0;
	}
	
	Node* g   = goalscar->Cdr()->Val();
	Node* nx  = g->Car();

	int rn;
	
	if ((rn = FuncArg(cx, nx, goalscar, module)) <= 0) {
		syserr("mvprintw: failed in the evaluation of the argument. \n");	
		return 0;
	}

	if (nx->kind() != ATOM) {
		syserr("usage : <mvprintw X Y STR> \n");
		return 0;
	}

	long long x;
	if (!((Atom*)nx)->toInt(x)) {
		syserr("usage : <mvprintw X Y STR> \n");
		return 0;
	}

	Node* ny  = g->Cdr()->Car();
	if ((rn = FuncArg(cx, ny, goalscar, module)) <= 0) {
		syserr("mvprintw: failed in the evaluation of the argument. \n");
		return 0;
	}

	if (ny->kind() != ATOM) {
		syserr("usage : <mvprintw X Y STR> \n");
		return 0;
	}

	long long y;
	if (!((Atom*)ny)->toInt(y)) {
		syserr("usage : <mvprintw X Y STR> \n");
		return 0;
	}

	move(y, x);

	g = g->Cdr()->Cdr();
	Node* npr;

	for (i = 0; i < l-2; i++) {
		npr = g->Car();
		
		if ((rn = FuncArg(cx, npr, goalscar, module)) <= 0) {
			syserr("mvprintw: failed in the evaluation of the argument. \n");
			return 0;
		}

		if (npr->kind() != ATOM) {
			syserr("usage : <mvprintw X Y STR> \n");
			return 0;
		}

		std::string s;
		((Atom*)npr)->toString(s);
		printw("%s", s.c_str());

		g = g->Cdr();
	}
	
	return 1;
		
}

int curs_printw(Context* cx, Node* goalscar, List* module)
{
	int i;
	int l = ListLength(goalscar->Cdr());
	if (l < 0) {
		syserr("usage : <printw STR...> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("printw: It can use only in curses.\n");
		return 0;
	}

	Node* g   = goalscar->Cdr()->Val();
	
	Node* npr;

	int rn;

	for (i = 0; i < l; i++) {
		npr = g->Car();
		
		if ((rn = FuncArg(cx, npr, goalscar, module)) <= 0) {
			syserr("printw: failed in the evaluation of the argument. \n");
			return 0;
		}

		if (npr->kind() != ATOM) {
			syserr("usage : <printw STR> \n");
			return 0;
		}

		std::string s;
		((Atom*)npr)->toString(s);
		printw("%s", s.c_str());

		g = g->Cdr();
	}
	
	return 1;
		
}

int curs_refresh(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar) != 1) {
		syserr("usage : <refresh> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("refresh: It can use only in curses.\n");
		return 0;
	}

	refresh();
	return 1;
}

int curs_move(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar->Cdr()) != 2) {
		syserr("usage : <move X Y> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("move: It can use only in curses.\n");
		return 0;
	}

	Node* g   = goalscar->Cdr()->Val();
	Node* nx  = g->Car();

	int rn;
	
	if ((rn = FuncArg(cx, nx, goalscar, module)) <= 0) {
		syserr("move: failed in the evaluation of the argument. \n");
		return 0;
	}

	if (nx->kind() != ATOM) {
		syserr("usage : <move X Y> \n");
		return 0;
	}

	long long x;
	if (!((Atom*)nx)->toInt(x)) {
		syserr("usage : <move X Y> \n");
		return 0;
	}

	Node* ny  = g->Cdr()->Car();
	if ((rn = FuncArg(cx, ny, goalscar, module)) <= 0) {
		syserr("move: failed in the evaluation of the argument. \n");
		return 0;
	}

	if (ny->kind() != ATOM) {
		syserr("usage : <move X Y> \n");
		return 0;
	}

	long long y;
	if (!((Atom*)ny)->toInt(y)) {
		syserr("usage : <move X Y> \n");
		return 0;
	}

	move(y, x);

	return 1;
}

int curs_cbreak(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar) != 1) {
		syserr("usage : <cbreak> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("cbreak: It can use only in curses.\n");
		return 0;
	}

	cbreak();
	return 1;
}

int curs_nocbreak(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar) != 1) {
		syserr("usage : <cbreak> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("nocbreak: It can use only in curses.\n");
		return 0;
	}

	nocbreak();
	return 1;
}

int curs_raw(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar) != 1) {
		syserr("usage : <raw> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("raw: It can use only in curses.\n");
		return 0;
	}

	raw();
	return 1;
}

int curs_noraw(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar) != 1) {
		syserr("usage : <noraw> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("noraw: It can use only in curses.\n");
		return 0;
	}

	noraw();
	return 1;
}

int curs_echo(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar) != 1) {
		syserr("usage : <echo> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("echo: It can use only in curses.\n");
		return 0;
	}

	echo();
	return 1;
}

int curs_noecho(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar) != 1) {
		syserr("usage : <noecho> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("noecho: It can use only in curses.\n");
		return 0;
	}

	noecho();
	return 1;
}

int curs_erase(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar) != 1) {
		syserr("usage : <erase> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("erase: It can use only in curses.\n");
		return 0;
	}

	erase();
	return 1;
}

int curs_clear(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar) != 1) {
		syserr("usage : <clear> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("clear: It can use only in curses.\n");
		return 0;
	}

	clear();
	return 1;
}

int curs_getch(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar->Cdr()) != 1) {
		syserr("usage: <getch VAR>\n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("getch: It can use only in curses.\n");
		return 0;
	}

	Node* g    = goalscar->Cdr()->Val();
	Node* nvar = g->Car()->Val();

	int rn;
	
	if ((rn = FuncArg(cx, nvar, goalscar, module)) <= 0) {
		syserr("getch: failed in the evaluation of the argument. \n");
		return 0;
	}

	if (nvar->kind() != UNDEF) {
		syserr("usage: <getch VAR>\n");
		return 0;
	}

	long long c = getch();

	Node* env = Nil->Cons(Nil);

	SetEnv(env, nvar);
	((Undef*)(nvar->Val()))->Set(mka(c));

	PushStack(cx, Nil, Nil, env);
	return 1;
	
}

int curs_ungetch(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar->Cdr()) != 1) {
		syserr("usage: <ungetch VAL>\n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("ungetch: It can use only in curses.\n");
		return 0;
	}

	Node* g    = goalscar->Cdr()->Val();
	Node* nval = g->Car()->Val();

	int rn;
	
	if ((rn = FuncArg(cx, nval, goalscar, module)) <= 0) {
		syserr("ungetch: failed in the evaluation of the argument. \n");
		return 0;
	}

	if (nval->kind() != ATOM) {
		syserr("usage: <ungetch VAL>\n");
		return 0;
	}

	long long c;
	if (!((Atom*)nval)->toInt(c)) {
		syserr("usage: <ungetch VAL>\n");
		return 0;
	}
	
	ungetch(c);

	return 1;
	
}


int curs_getstr(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar->Cdr()) != 1) {
		syserr("usage: <getstr VAR>\n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("getstr: It can use only in curses.\n");
		return 0;
	}

	Node* g    = goalscar->Cdr()->Val();
	Node* nvar = g->Car()->Val();

	int rn;
	
	if ((rn = FuncArg(cx, nvar, goalscar, module)) <= 0) {
		syserr("getstr: failed in the evaluation of the argument. \n");
		return 0;
	}

	if (nvar->kind() != UNDEF) {
		syserr("usage: <getstr VAR>\n");
		return 0;
	}

	getnstr(strbuf, MAXNSTR);

	Node* env = Nil->Cons(Nil);

	SetEnv(env, nvar);
	((Undef*)(nvar->Val()))->Set(mka(strbuf));

	PushStack(cx, Nil, Nil, env);
	return 1;
	
}

int curs_inch(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar->Cdr()) != 1) {
		syserr("usage: <inch VAR>\n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("inch: It can use only in curses.\n");
		return 0;
	}

	Node* g    = goalscar->Cdr()->Val();
	Node* nvar = g->Car()->Val();

	int rn;
	
	if ((rn = FuncArg(cx, nvar, goalscar, module)) <= 0) {
		syserr("inch: failed in the evaluation of the argument. \n");
		return 0;
	}

	if (nvar->kind() != UNDEF) {
		syserr("usage: <inch VAR>\n");
		return 0;
	}

	long long c = inch();

	Node* env = Nil->Cons(Nil);

	SetEnv(env, nvar);
	((Undef*)(nvar->Val()))->Set(mka(c));

	PushStack(cx, Nil, Nil, env);
	return 1;
	
}

int curs_instr(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar->Cdr()) != 2) {
		syserr("usage: <instr VAR WIDTH>\n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("instr: It can use only in curses.\n");
		return 0;
	}

	Node* g      = goalscar->Cdr()->Val();
	Node* nvar   = g->Car()->Val();
	Node* nwidth = g->Cdr()->Car()->Val();

	int rn;
	
	if ((rn = FuncArg(cx, nvar, goalscar, module)) <= 0) {
		syserr("instr: failed in the evaluation of the argument. \n");
		return 0;
	}

	if (nvar->kind() != UNDEF) {
		syserr("usage: <instr VAR WIDTH>\n");
		return 0;
	}

	if ((rn = FuncArg(cx, nwidth, goalscar, module)) <= 0) {
		syserr("instr: failed in the evaluation of the argument. \n");
		return 0;
	}

	if (nwidth->kind() != ATOM) {
		syserr("usage: <innstr VAR WIDTH>\n");
		return 0;
	}

	long long width;
	if (!((Atom*)nwidth)->toInt(width)) {
		syserr("usage: <instr VAR WIDTH>\n");
		return 0;
	}
	if (width >= MAXNSTR) {
		width = MAXNSTR;
	}
	
	innstr(strbuf, width);

	Node* env = Nil->Cons(Nil);

	SetEnv(env, nvar);
	((Undef*)(nvar->Val()))->Set(mka(strbuf));

	PushStack(cx, Nil, Nil, env);
	return 1;
	
}

int curs_isendwin(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar) != 1) {
		syserr("usage : <isendwin> \n");
		return 0;
	}

	if(isendwin()) {
		return 1;
	} else {
		return -1;
	}
}

int curs_beep(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar) != 1) {
		syserr("usage : <beep> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("beep: It can use only in curses.\n");
		return 0;
	}

	beep();
	return 1;
}

int curs_flash(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar) != 1) {
		syserr("usage : <flash> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("flash: It can use only in curses.\n");
		return 0;
	}

	flash();
	return 1;
}


int curs_hline(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar->Cdr()) != 2) {
		syserr("usage : <hline CHAR LENGTH> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("hline: It can use only in curses.\n");
		return 0;
	}
	
	Node* g   = goalscar->Cdr()->Val();
	Node* nch  = g->Car();

	int rn;
	
	if ((rn = FuncArg(cx, nch, goalscar, module)) <= 0) {
		syserr("hline: failed in the evaluation of the argument. \n");	
		return 0;
	}

	if (nch->kind() != ATOM) {
		syserr("usage : <hline CHAR LENGTH> \n");
		return 0;
	}
	std::string sch;
	((Atom*)nch)->toString(sch);

	Node* nlen  = g->Cdr()->Car();
	if ((rn = FuncArg(cx, nlen, goalscar, module)) <= 0) {
		syserr("hline: failed in the evaluation of the argument. \n");
		return 0;
	}

	if (nlen->kind() != ATOM) {
		syserr("usage : <hline CHAR LENGTH> \n");
		return 0;
	}

	long long len;
	if (!((Atom*)nlen)->toInt(len)) {
		syserr("usage : <hline CHAR LENGTH> \n");
		return 0;
	}

	hline(sch[0], (int)len);
	return 1;
		
}

int curs_vline(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar->Cdr()) != 2) {
		syserr("usage : <vline CHAR LENGTH> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("vline: It can use only in curses.\n");
		return 0;
	}
	
	Node* g   = goalscar->Cdr()->Val();
	Node* nch  = g->Car();

	int rn;
	
	if ((rn = FuncArg(cx, nch, goalscar, module)) <= 0) {
		syserr("vline: failed in the evaluation of the argument. \n");	
		return 0;
	}

	if (nch->kind() != ATOM) {
		syserr("usage : <vline CHAR LENGTH> \n");
		return 0;
	}
	std::string sch;
	((Atom*)nch)->toString(sch);

	Node* nlen  = g->Cdr()->Car();
	if ((rn = FuncArg(cx, nlen, goalscar, module)) <= 0) {
		syserr("vline: failed in the evaluation of the argument. \n");
		return 0;
	}

	if (nlen->kind() != ATOM) {
		syserr("usage : <vline CHAR LENGTH> \n");
		return 0;
	}

	long long len;
	if (!((Atom*)nlen)->toInt(len)) {
		syserr("usage : <vline CHAR LENGTH> \n");
		return 0;
	}

	vline(sch[0], (int)len);
	return 1;
		
}

int curs_keypad(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar->Cdr()) != 1) {
		syserr("usage : <keypad VAL> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("keypad: It can use only in curses.\n");
		return 0;
	}
	
	Node* g   = goalscar->Cdr()->Val();
	Node* nval  = g->Car();

	int rn;
	
	if ((rn = FuncArg(cx, nval, goalscar, module)) <= 0) {
		syserr("keypad: failed in the evaluation of the argument. \n");	
		return 0;
	}

	if (nval->kind() != ATOM) {
		syserr("usage : <keypad VAL> \n");
		return 0;
	}
	std::string sval;
	((Atom*)nval)->toString(sval);

	int val = FALSE;
	if ((sval == "TRUE") || (sval == "1")) {
		val = TRUE;
	}
	
	keypad(stdscr, val);
	return 1;
		
}

int curs_scrollok(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar->Cdr()) != 1) {
		syserr("usage : <scrollok VAL> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("scrollok: It can use only in curses.\n");
		return 0;
	}
	
	Node* g   = goalscar->Cdr()->Val();
	Node* nval  = g->Car();

	int rn;
	
	if ((rn = FuncArg(cx, nval, goalscar, module)) <= 0) {
		syserr("scrollok: failed in the evaluation of the argument. \n");	
		return 0;
	}

	if (nval->kind() != ATOM) {
		syserr("usage : <scrollok VAL> \n");
		return 0;
	}
	std::string sval;
	((Atom*)nval)->toString(sval);

	int val = FALSE;
	if ((sval == "TRUE") || (sval == "1")) {
		val = TRUE;
	}
	
	scrollok(stdscr, val);
	return 1;
		
}
int curs_scrl(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar->Cdr()) != 1) {
		syserr("usage : <scrl NUM> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("scrl: It can use only in curses.\n");
		return 0;
	}
	
	Node* g   = goalscar->Cdr()->Val();
	Node* nnum  = g->Car();

	int rn;
	
	if ((rn = FuncArg(cx, nnum, goalscar, module)) <= 0) {
		syserr("scrl: failed in the evaluation of the argument. \n");	
		return 0;
	}

	if (nnum->kind() != ATOM) {
		syserr("usage : <scrl NUM> \n");
		return 0;
	}
	long long n;
	((Atom*)nnum)->toInt(n);

	scrl((int)n);

	return 1;
}

int curs_LINES(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar->Cdr()) != 1) {
		syserr("usage: <LINES VAR>\n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("LINES: It can use only in curses.\n");
		return 0;
	}

	Node* g      = goalscar->Cdr()->Val();
	Node* nvar   = g->Car()->Val();
	int rn;
	
	if ((rn = FuncArg(cx, nvar, goalscar, module)) <= 0) {
		syserr("LINES: failed in the evaluation of the argument. \n");
		return 0;
	}

	if (nvar->kind() != UNDEF) {
		syserr("usage: <LINES VAR>\n");
		return 0;
	}

	long long lines = LINES;
	
	Node* env = Nil->Cons(Nil);

	SetEnv(env, nvar);
	((Undef*)(nvar->Val()))->Set(mka(lines));

	PushStack(cx, Nil, Nil, env);
	return 1;
	
}

int curs_COLS(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar->Cdr()) != 1) {
		syserr("usage: <COLS VAR>\n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("COLS: It can use only in curses.\n");
		return 0;
	}

	Node* g      = goalscar->Cdr()->Val();
	Node* nvar   = g->Car()->Val();
	int rn;
	
	if ((rn = FuncArg(cx, nvar, goalscar, module)) <= 0) {
		syserr("COLS: failed in the evaluation of the argument. \n");
		return 0;
	}

	if (nvar->kind() != UNDEF) {
		syserr("usage: <COLS VAR>\n");
		return 0;
	}

	long long cols = COLS;
	
	Node* env = Nil->Cons(Nil);

	SetEnv(env, nvar);
	((Undef*)(nvar->Val()))->Set(mka(cols));

	PushStack(cx, Nil, Nil, env);
	return 1;
	
}

int curs_delch(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar) != 1) {
		syserr("usage : <delch> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("delch: It can use only in curses.\n");
		return 0;
	}

	delch();
	return 1;
}

int curs_mvdelch(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar->Cdr()) != 2) {
		syserr("usage : <mvdelch X Y> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("mvdelch: It can use only in curses.\n");
		return 0;
	}
	
	Node* g   = goalscar->Cdr()->Val();
	Node* nx  = g->Car();

	int rn;
	
	if ((rn = FuncArg(cx, nx, goalscar, module)) <= 0) {
		syserr("mvdelch: failed in the evaluation of the argument. \n");	
		return 0;
	}

	if (nx->kind() != ATOM) {
		syserr("usage : <mvdelch X Y> \n");
		return 0;
	}

	long long x;
	if (!((Atom*)nx)->toInt(x)) {
		syserr("usage : <mvdelch X Y> \n");
		return 0;
	}

	Node* ny  = g->Cdr()->Car();
	if ((rn = FuncArg(cx, ny, goalscar, module)) <= 0) {
		syserr("mvdelch: failed in the evaluation of the argument. \n");
		return 0;
	}

	if (ny->kind() != ATOM) {
		syserr("usage : <mvdelch X Y> \n");
		return 0;
	}

	long long y;
	if (!((Atom*)ny)->toInt(y)) {
		syserr("usage : <mvdelch X Y> \n");
		return 0;
	}

	mvdelch(y, x);

	return 1;
		
}

int curs_clrtobot(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar) != 1) {
		syserr("usage : <clrtobot> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("clrtobot: It can use only in curses.\n");
		return 0;
	}
	
	clrtobot();
	return 1;
}

int curs_clrtoeol(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar) != 1) {
		syserr("usage : <clrtoeol> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("clrtoeol: It can use only in curses.\n");
		return 0;
	}
	
	clrtoeol();
	return 1;
}

int curs_border(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar->Cdr()) != 8) {
		syserr("usage : <border LS RS TS BS TL TR BL BR> \n");
		return 0;
	}

	if (!ncurlibflag) {
		syserr("border: It can use only in curses.\n");
		return 0;
	}
	
	Node* g   = goalscar->Cdr()->Val();

	Node* nls  = g->Car();
	g = g->Cdr();
	
	int rn;
	
	if ((rn = FuncArg(cx, nls, goalscar, module)) <= 0) {
		syserr("border: failed in the evaluation of the argument. \n");	
		return 0;
	}

	if (nls->kind() != ATOM) {
		syserr("usage : <border LS RS TS BS TL TR BL BR> \n");
		return 0;
	}

	std::string sls;
	((Atom*)nls)->toString(sls);

	Node* nrs  = g->Car();
	g = g->Cdr();
	
	if ((rn = FuncArg(cx, nrs, goalscar, module)) <= 0) {
		syserr("border: failed in the evaluation of the argument. \n");	
		return 0;
	}

	if (nrs->kind() != ATOM) {
		syserr("usage : <border LS RS TS BS TL TR BL BR> \n");
		return 0;
	}

	std::string srs;
	((Atom*)nrs)->toString(srs);

	
	Node* nts  = g->Car();
	g = g->Cdr();
	
	if ((rn = FuncArg(cx, nts, goalscar, module)) <= 0) {
		syserr("border: failed in the evaluation of the argument. \n");	
		return 0;
	}

	if (nts->kind() != ATOM) {
		syserr("usage : <border LS RS TS BS TL TR BL BR> \n");
		return 0;
	}

	std::string sts;
	((Atom*)nts)->toString(sts);

	Node* nbs  = g->Car();
	g = g->Cdr();
	
	if ((rn = FuncArg(cx, nbs, goalscar, module)) <= 0) {
		syserr("border: failed in the evaluation of the argument. \n");	
		return 0;
	}

	if (nbs->kind() != ATOM) {
		syserr("usage : <border LS RS TS BS TL TR BL BR> \n");
		return 0;
	}

	std::string sbs;
	((Atom*)nbs)->toString(sbs);


	Node* ntl  = g->Car();
	g = g->Cdr();
	
	if ((rn = FuncArg(cx, ntl, goalscar, module)) <= 0) {
		syserr("border: failed in the evaluation of the argument. \n");	
		return 0;
	}

	if (ntl->kind() != ATOM) {
		syserr("usage : <border LS RS TS BS TL TR BL BR> \n");
		return 0;
	}

	std::string stl;
	((Atom*)ntl)->toString(stl);

	Node* ntr  = g->Car();
	g = g->Cdr();
	
	if ((rn = FuncArg(cx, ntr, goalscar, module)) <= 0) {
		syserr("border: failed in the evaluation of the argument. \n");	
		return 0;
	}

	if (ntr->kind() != ATOM) {
		syserr("usage : <border LS RS TS BS TL TR BL BR> \n");
		return 0;
	}

	std::string str;
	((Atom*)ntr)->toString(str);

	Node* nbl  = g->Car();
	g = g->Cdr();
	
	if ((rn = FuncArg(cx, nbl, goalscar, module)) <= 0) {
		syserr("border: failed in the evaluation of the argument. \n");	
		return 0;
	}

	if (nbl->kind() != ATOM) {
		syserr("usage : <border LS RS TS BS TL TR BL BR> \n");
		return 0;
	}

	std::string sbl;
	((Atom*)nbl)->toString(sbl);

	Node* nbr  = g->Car();
	g = g->Cdr();
	
	if ((rn = FuncArg(cx, nbr, goalscar, module)) <= 0) {
		syserr("border: failed in the evaluation of the argument. \n");	
		return 0;
	}

	if (nbr->kind() != ATOM) {
		syserr("usage : <border LS RS TS BS TL TR BL BR> \n");
		return 0;
	}

	std::string sbr;
	((Atom*)nbr)->toString(sbr);


	border(sls[0], srs[0], sts[0], sbs[0], stl[0], str[0], sbl[0], sbr[0]);

	return 1;
		
}

#endif /* __MINGW32__ */





#endif /* HAVE_LIBNCURSES */
