/*
 *  htttp client program copyright (C) 2011 - 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"

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

#ifndef __MINGW32__ 

#include <libgen.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#endif /* __MINGW32__ */

#if HAVE_ICONV_H
#include <iconv.h>
#endif /* HAVE_ICONV_H */

#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 "module.h"
#include "help.h"
#include "code.h"
#include "winsock2util.h"

Node* erasecommenttagslist(Node* nd, int &contflg);

void urlencode(std::string &str1, std::string &str2)
{
	int i;
	unsigned char* p = (unsigned char*)str1.c_str();
	for (i = 0; i < str1.length(); i++) {
		int l = CharLen(p[i]);

		char bf[3];

		if (i + l > str1.length()) {
			break;
		}
		if (l > 1) {
			int  ni;
			for (ni = 0; ni < l; ni++) {
				str2 += "%";
				snprintf(bf, 3, "%02X", p[i+ni]);
				bf[3] = 0;
				str2 += bf;
			}
			i += l-1;
		} else if (l == 1) {
			switch (p[i]) {
			case ' ' :
				str2 += '+';
				break;
			case '-' :
				str2 += '-';
				break;
			case '.' :
				str2 += '.';
				break;
			case '_' :
				str2 += '_';
				break;
			default :
				if (((p[i] >= 'A') && (p[i] <= 'Z')) ||
				    ((p[i] >= 'a') && (p[i] <= 'z')) ||
				    ((p[i] >= '0') && (p[i] <= '9'))) {
					str2 += p[i];
					break;
				}
				str2 += "%";
				snprintf(bf, 3, "%02X", p[i]);
				bf[3] = 0;
				str2 += bf;
				break;
			}
		} else {
			break;
		}
	}
}


Node* urlencodelist(Node* nd)
{
	if (nd == Nil) {
		return nd;
	} else if (nd->kind() == ATOM) {
		std::string str="", fromstr="";
		((Atom*)nd)->toString(fromstr);

		urlencode(fromstr, str);
		return mka(str);

	} else if (nd->kind() == LIST) {
		return Cons(urlencodelist(nd->Car()), 
				urlencodelist(nd->Cdr()));
	} else {
		return nd;
	}
}

int UrlEncode(Context* cx, Node* goalscar, List* module)
{
	Node* g = goalscar->Cdr()->Val();
	int	arglen = ListLength(g);

	if (arglen != 2) {
		syserr("usage : <urlencode VAR STR>\n");
		return 0;
	}

	Node* nvar = g->Car()->Val();
	int rn;

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

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

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

	Node* n = urlencodelist(nstr1);

	Node* env = Nil->Cons(Nil);
	 
	SetEnv(env, nvar);

	((Undef*)nvar)->Set(n);

	PushStack(cx, Nil, Nil, env);

	return 1;
}

void urldecode(std::string &str1, std::string &str2)
{
	int i;
	char* p = (char*)str1.c_str();
	for (i = 0; i < str1.length(); i++) {
		if (p[i] == '%') {
			if (i + 2 >= str1.length()) {
				break;
			}
			unsigned char c1 = p[i+1]-'0';
			if (c1 >= 10) {
				c1 = p[i+1]-'A'+10;
				if (c1 >= 16) {
					c1 = p[i+1]-'a'+10;
				}
			}
			if (c1 >= 16) {
				break;
			}
			unsigned char c2 = p[i+2]-'0';
			if (c2 >= 10) {
				c2 = p[i+2]-'A'+10;
				if (c2 >= 16) {
					c2 = p[i+2]-'a'+10;
				}
			}
			if (c2 >= 16) {
				break;
			}
			unsigned char c = (c1 << 4) + c2;
			str2 += c;
			i += 2;
		} else if (p[i] == '+') {
			str2 += ' ';
		} else {
			str2 += p[i];
		}
	}
}

Node* urldecodelist(Node* nd)
{
	if (nd == Nil) {
		return nd;
	} else if (nd->kind() == ATOM) {
		std::string str="", fromstr="";
		((Atom*)nd)->toString(fromstr);

		urldecode(fromstr, str);
		return mka(str);

	} else if (nd->kind() == LIST) {
		return Cons(urldecodelist(nd->Car()), 
				urldecodelist(nd->Cdr()));
	} else {
		return nd;
	}
}

int UrlDecode(Context* cx, Node* goalscar, List* module)
{
	Node* g = goalscar->Cdr()->Val();
	int	arglen = ListLength(g);

	if (arglen != 2) {
		syserr("usage : <urldecode VAR STR>\n");
		return 0;
	}

	Node* nvar = g->Car()->Val();
	int rn;

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

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

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

	Node* n = urldecodelist(nstr1);

	Node* env = Nil->Cons(Nil);
	 
	SetEnv(env, nvar);

	((Undef*)nvar)->Set(n);

	PushStack(cx, Nil, Nil, env);

	return 1;
}



void htmlencode(std::string &str1, std::string &str2)
{
	int i;
	str2 = "";
	for (i = 0; i < str1.length(); i++) {
		char s = str1[i];
		if (s == '"') {
			str2 += "&quot;";
		} else if (s == '&') {
			str2 += "&amp;";
		} else if (s == '<') {
			str2 += "&lt;";
		} else if (s == '>') {
			str2 += "&gt;";
		} else if (s == ' ') {
			str2 += "&nbsp;";
		} else {
			str2 += s;
		}
	}	
}

Node* htmlencodelist(Node* nd)
{
	if (nd == Nil) {
		return nd;
	} else if (nd->kind() == ATOM) {
		std::string str="", fromstr="";
		((Atom*)nd)->toString(fromstr);

		htmlencode(fromstr, str);
		return mka(str);

	} else if (nd->kind() == LIST) {
		return Cons(htmlencodelist(nd->Car()), 
				htmlencodelist(nd->Cdr()));
	} else {
		return nd;
	}
}

int HtmlEncode(Context* cx, Node* goalscar, List* module)
{
	Node* g = goalscar->Cdr()->Val();
	int	arglen = ListLength(g);

	if (arglen != 2) {
		syserr("usage : <htmlencode VAR STR>\n");
		return 0;
	}

	Node* nvar = g->Car()->Val();
	int rn;

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

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

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

	Node* n = htmlencodelist(nstr1);

	Node* env = Nil->Cons(Nil);
	 
	SetEnv(env, nvar);

	((Undef*)nvar)->Set(n);

	PushStack(cx, Nil, Nil, env);

	return 1;
}


void htmldecode(std::string &str1, std::string &str2)
{
	int i;
	str2 = "";
	
	for (i = 0; i < str1.length(); ) {
		// space
		if ((0xff & str1[i]) == 0xc2) {
			if (i+1 < str1.length()) {
				if ((0xff & str1[i+1]) == 0xa0) {
					str2 += ' ';
					i++;
				}
			}
			i++;
			continue;
		}
			
		if (str1[i] != '&') {
			str2 += str1[i];
			i++;
			continue;
		}

		if (i+4 > str1.length()) {
			str2 += str1[i];
			i++;
			continue;
		}
		std::string s = str1.substr(i, 4);
		if (s == "&lt;") {
			str2 += '<';
			i += 4;
			continue;
		}
		if (s == "&gt;") {
			str2 += '>';
			i += 4;
			continue;
		}

		if (i+5 > str1.length()) {
			str2 += str1[i];
			i++;
			continue;
		}
		s = str1.substr(i, 5);
		if (s == "&amp;") {
			str2 += '&';
			i += 5;
			continue;
		}
		if (s == "&#34;") {
			str2 += '"';
			i += 5;
			continue;
		}
		if (s == "&#38;") {
			str2 += '&';
			i += 5;
			continue;
		}
		if (s == "&#60;") {
			str2 += '<';
			i += 5;
			continue;
		}
		if (s == "&#62;") {
			str2 += '>';
			i += 5;
			continue;
		}

		if (i+6 > str1.length()) {
			str2 += str1[i];
			i++;
			continue;
		}
		s = str1.substr(i, 6);
		if (s == "&quot;") {
			str2 += '"';
			i += 6;
			continue;
		}
		if (s == "&nbsp;") {
			str2 += ' ';
			i += 6;
			continue;
		}
		if (s == "&copy;") {
			str2 += 'C';
			i += 6;
			continue;
		}
		if (s == "&#x22;") {
			str2 += '"';
			i += 6;
			continue;
		}
		if (s == "&#x26;") {
			str2 += '&';
			i += 6;
			continue;
		}
		if (s == "&#x3C;") {
			str2 += '<';
			i += 6;
			continue;
		}
		if (s == "&#x3E;") {
			str2 += '>';
			i += 6;
			continue;
		}
		if (s == "&#xA9;") {
			str2 += 'C';
			i += 6;
			continue;
		}
		if (s == "&#169;") {
			str2 += 'C';
			i += 6;
			continue;
		}

		str2 += str1[i];
		i++;
	}
}


Node* htmldecodelist(Node* nd)
{
	if (nd == Nil) {
		return nd;
	} else if (nd->kind() == ATOM) {
		std::string str="", fromstr="";
		((Atom*)nd)->toString(fromstr);

		htmldecode(fromstr, str);
		return mka(str);

	} else if (nd->kind() == LIST) {
		return Cons(htmldecodelist(nd->Car()), 
				htmldecodelist(nd->Cdr()));
	} else {
		return nd;
	}
}

int HtmlDecode(Context* cx, Node* goalscar, List* module)
{
	Node* g = goalscar->Cdr()->Val();
	int	arglen = ListLength(g);

	if (arglen != 2) {
		syserr("usage : <htmldecode VAR STR>\n");
		return 0;
	}

	Node* nvar = g->Car()->Val();
	int rn;

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

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

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

	Node* n = htmldecodelist(nstr1);

	Node* env = Nil->Cons(Nil);
	 
	SetEnv(env, nvar);

	((Undef*)nvar)->Set(n);

	PushStack(cx, Nil, Nil, env);

	return 1;
}


#ifndef __MINGW32__ 

#define BUFFER_SIZE 256

void tcppr(int sock, const char* sendtext)
{
	int i;
	int sendtextlen = strlen(sendtext);

	for (i = 0; i < sendtextlen; ) {
		int plen = strlen(&sendtext[i]);
		if (plen >= BUFFER_SIZE) {
			send(sock, &sendtext[i], BUFFER_SIZE, 0);
			i += BUFFER_SIZE;
		} else {
			send(sock, &sendtext[i], strlen(&sendtext[i]), 0);
			i += strlen(&sendtext[i]);
			break;
		}
	}
}

void tcprecv(std::string &recvtextbody, int sock)
{
	char buffer[BUFFER_SIZE+1];

	for (;;) {
		int recvlength = recv(sock, buffer, BUFFER_SIZE, 0);
		if (recvlength == 0) {
			break;
		}
		buffer[recvlength] = 0;
		recvtextbody += buffer;
	}		
}

void tcpclose(int sock)
{
	close(sock);
}


int tcpopen(const char* hostname, const char* path, const char* port)
{
	int sock;
	struct sockaddr_in dstAddr;

	int status;
	int numsnt;
	int err;

	int rcvlength;

	struct addrinfo hints, *res0, *res;
	memset(&hints, 0, sizeof(hints));
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_family = PF_UNSPEC;

	if ((err = getaddrinfo(hostname, port, &hints, &res0)) != 0) {
		fprintf(stderr, "can't find %s:%s\n", hostname, port);
		return -1;
	}

	for (res=res0; res!=NULL; res=res->ai_next) {
		sock = socket(res->ai_family, res->ai_socktype, 
						res->ai_protocol);
		if (sock < 0) {
			continue;
		}
		
		if (connect(sock, res->ai_addr, res->ai_addrlen) != 0) {
			close(sock);
			continue;
		}
		break;
	}

	freeaddrinfo(res0);

	if (res == NULL) {
		fprintf(stderr, "can not connet %s\n", hostname);
		return -1;
	}

	return sock;
}

#endif /* __MINGW32__ */


void getpostargs(std::string &srcstr, std::string &dststr)
{
	int i, j;
	std::string str1 = "", str2 = "";

	dststr = "";
	for (i = 0; ;) {
		str1 = "";
		str2 = "";
		int oldi = i;
		i = srcstr.find("=", i);
		if (i == std::string::npos) {
			str1 = srcstr.substr(oldi);
			str2 = "";
			urlencode(str1, str2);
			dststr += str2;
			break;
		}
		i++;
		dststr += srcstr.substr(oldi, i-oldi);
		j = srcstr.find("&", i);
		if (j == std::string::npos) {
			str1 = srcstr.substr(i);
			str2 = "";
			urlencode(str1, str2);
			dststr += str2;
			break;
		}
		str1 = srcstr.substr(i, j-i);
		str2 = "";
		urlencode(str1, str2);
		dststr += str2;
		i = j;
	}
}

int httpcode(std::string &header)
{
	if (header == "") {
		return 0;
	}
	int start = header.find(' ');
	start++;
	int end = header.find(' ', start);
	std::string cd = header.substr(start, end-start);
	
	if (cd != "200") {
		//fprintf(stderr, "%s\n", cd.c_str());
	}
	
	return (int)strtol(cd.c_str(), NULL, 10);
}

int httpGET(std::string &recvtextheader, std::string &recvtextbody,
 	const char* hostname, const char* path, const char* port, 
 	const char* data=NULL)
{
	int i;
	int retry = 10;

httpgetretry:
	
	int sock = tcpopen(hostname, path, port);
	if (sock == -1) {
		return -1;
	}

	std::string getpath = "GET ";
	getpath +=  path;
	if (data != NULL) {
		getpath += "?";
		std::string str1=data, str2="";
		getpostargs(str1, str2);
		getpath += str2;
	}
	getpath +=  " HTTP/1.0";
	tcppr(sock, getpath.c_str());
	tcppr(sock, "\r\n");
	
	tcppr(sock, "Content-Type: text/html\r\n");
//	tcppr(sock, "Content-Type: text/html; charset=UTF-8\r\n");

	std::string host = "Host: ";
	host += hostname;
	tcppr(sock, host.c_str());
	if (strncmp(port, "80", 6) != 0) {
		tcppr(sock, ":");
		tcppr(sock, port);
	}

//	tcppr(sock, "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6\r\n");

	tcppr(sock, "\r\n");
	tcppr(sock, "\r\n");

	tcprecv(recvtextbody, sock);

	i = recvtextbody.find("\r\n\r\n");
	if (i+4 < recvtextbody.length()) {
		recvtextheader = recvtextbody.substr(0, i);
		recvtextbody   = recvtextbody.substr(i+4);
	}

	tcpclose(sock);

//	printf("%s\n\n", recvtextheader.c_str());
//	printf("%s\n", recvtextbody.c_str());

	if (httpcode(recvtextheader) != 200) {
		retry--;
		if (retry == 0) {
			return -1;
		}

#ifndef __MINGW32__
		sleep(1);
#else
		RetrySleep(1);
#endif /* __MINGW32__ */
		
		recvtextheader = "";
		recvtextbody = "";
		goto httpgetretry;
	}

	return 1;
}

int httpHEAD(std::string &recvtextheader,
	const char* hostname, const char* path, const char* port)
{
	int i;
	int retry = 10;

httpheadretry:

	int sock = tcpopen(hostname, path, port);
	if (sock == -1) {
		return -1;
	}
	
	std::string getpath = "HEAD ";
	getpath +=  path;
	getpath +=  " HTTP/1.0";
	tcppr(sock, getpath.c_str());
	tcppr(sock, "\r\n");
	
	tcppr(sock, "Content-Type: text/html\r\n");
//	tcppr(sock, "Content-Type: text/html; charset=UTF-8\r\n");

	std::string host = "Host: ";
	host += hostname;
	tcppr(sock, host.c_str());
	if (strncmp(port, "80", 6) != 0) {
		tcppr(sock, ":");
		tcppr(sock, port);
	}
	tcppr(sock, "\r\n");
	
	tcppr(sock, "\r\n");

	tcprecv(recvtextheader, sock);

	tcpclose(sock);

//	printf("%s\n", recvtextheader.c_str());

	if (httpcode(recvtextheader) != 200) {
		retry--;
		if (retry == 0) {
			return -1;
		}

#ifndef __MINGW32__
		sleep(1);
#else
		RetrySleep(1);
#endif /* __MINGW32__ */

		recvtextheader = "";
		goto httpheadretry;
	}

	return 1;
}


int httpPOST(std::string &recvtextheader, std::string &recvtextbody,
	const char* hostname, const char* path, const char* port, 
						const char* data)
{
	int i;
	int retry = 10;

httppostretry:	

	int sock = tcpopen(hostname, path, port);
	if (sock == -1) {
		return -1;
	}
	
	std::string getpath = "POST ";
	getpath +=  path;
	getpath +=  " HTTP/1.0";
	tcppr(sock, getpath.c_str());
	tcppr(sock, "\r\n");
	
	tcppr(sock, "Content-Type: text/html\r\n");
//	tcppr(sock, "Content-Type: text/html; charset=UTF-8\r\n");

	std::string host = "Host: ";
	host += hostname;
	tcppr(sock, host.c_str());
	if (strncmp(port, "80", 6) != 0) {
		tcppr(sock, ":");
		tcppr(sock, port);
	}
	tcppr(sock, "\r\n");

	std::string str1 = data;
	std::string datastr = "";
//	urlencode(str1, datastr);
	getpostargs(str1, datastr);
	
	std::string contentlength = "Content-Length: ";
	char ctlen[100] = "";
	snprintf(ctlen, 99, "%d", datastr.length());
	ctlen[99] = 0;
	contentlength += ctlen;
	tcppr(sock, contentlength.c_str());
	tcppr(sock, "\r\n");

	tcppr(sock, "\r\n");

	tcppr(sock, datastr.c_str());
	tcppr(sock, "\r\n");
	
	tcprecv(recvtextbody, sock);


	i = recvtextbody.find("\r\n\r\n");
	if (i+4 < recvtextbody.length()) {
		recvtextheader = recvtextbody.substr(0, i);
		recvtextbody   = recvtextbody.substr(i+4);
	}

	tcpclose(sock);

//	printf("%s\n", recvtextbody.c_str());

	if (httpcode(recvtextheader) != 200) {
		retry--;
		if (retry == 0) {
			return -1;
		}
		recvtextheader = "";
		recvtextbody = "";

#ifndef __MINGW32__
		sleep(1);
#else
		RetrySleep(1);
#endif /* __MINGW32__ */

		goto httppostretry;
	}

	return 1;
}


int uri_analysis(std::string &uri, std::string &host, std::string &port,
			std::string &path, std::string &arg)
{

	if (uri.substr(0, 7) != "http://") {
		if (uri.substr(0, 8) != "https://") {
			fprintf(stderr, "ssl is unsupported %s\n", uri.c_str());
			return 0;
		} else {
			fprintf(stderr, "not a URI %s\n", uri.c_str());
			return 0;
		}
	}

	int p1 = uri.find(":", 7);
	int p2 = uri.find("/", 7);
	int p3 = uri.find("?", 7);
				
	if (p1 != std::string::npos) {
		if (p2 != std::string::npos) {
			if (p3 != std::string::npos) {
				host = uri.substr(7, p1-7);
				port = uri.substr(p1+1, p2-p1-1);
				path = uri.substr(p2, p3-p2);
				arg = uri.substr(p3);
			} else {
				host = uri.substr(7, p1-7);
				port = uri.substr(p1+1, p2-p1-1);
				path = uri.substr(p2);
				arg =  "";
			}
		} else {
			if (p3 != std::string::npos) {
				host = uri.substr(7, p1-7);
				port = uri.substr(p1+1, p3-p1-1);
				path = "/";
				arg =  uri.substr(p3);
			} else {
				host = uri.substr(7, p1-7);
				port = uri.substr(p1+1);
				path = "/";
				arg =  "";
			}
		}
	} else {
		if (p2 != std::string::npos) {
			if (p3 != std::string::npos) {
				host = uri.substr(7, p2-7);
				port = "80";
				path = uri.substr(p2, p3-p2);
				arg = uri.substr(p3);
			} else {
				host = uri.substr(7, p2-7);
				port = "80";
				path = uri.substr(p2);
				arg = "";
			}
		} else {
			if (p3 != std::string::npos) {
				host = uri.substr(7, p3-7);
				port = "80";
				path = "/";
				arg = uri.substr(p3);
			} else {
				host = uri.substr(7);
				port = "80";
				path = "/";
				arg = "";
			}
		}
	}
	return 1;
}

int proxy_analysis(std::string &proxy, std::string &host, std::string &port)
{
	if (proxy.substr(0, 8) == "https://") {
		fprintf(stderr, "not a proxy %s\n", proxy.c_str());
		return 0;
	}
	
	if (proxy.substr(0, 7) == "http://") {
		proxy = proxy.substr(7);
	}
	
	int p1 = proxy.find(":", 7);
				
	if (p1 != std::string::npos) {
		host = proxy.substr(0, p1);
		port = proxy.substr(p1+1);
	} else {
		host = proxy;
		port = "80";
	}

	return 1;
}


int HttpGet(Context* cx, Node* goalscar, List* module)
{
	Node* g = goalscar->Cdr()->Val();
	int	arglen = ListLength(g);

	if ((arglen < 3) || (arglen > 4)) {
		syserr("usage : <httpget VAR_Header VAR_Body uri [proxy]> \n");
		return 0;
	}

	Node* nvar_header = g->Car()->Val();
	int rn;

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

	if (nvar_header->kind() != UNDEF) {
		syserr("usage : <httpget VAR_Header VAR_Body uri [proxy]>\n");
		return 0;
	}

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

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

	if (nvar_body->kind() != UNDEF) {
		syserr("usage : <httpget VAR_Header VAR_Body uri [proxy]>\n");
		return 0;
	}

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

	if (nuri->kind() != ATOM) {
		syserr("usage : <httpget VAR_Header VAR_Body uri [proxy]>\n");
		return 0;
	}

	std::string proxy = "";
	Node* nproxy = Nil;
	if (arglen == 4) {
		g = g->Cdr();
		nproxy = g->Car()->Val();
		if ((rn = FuncArg(cx, nproxy, goalscar, module)) <= 0) {
			syserr("httpget: failed in the evaluation of the argument. \n");
			return 0;
		}

		if (nproxy->kind() != ATOM) {
			syserr("usage : <httpget VAR_Header VAR_Body uri [proxy]>\n");
			return 0;
		}

		if (nproxy != Nil) {
			((Atom*)nproxy)->toString(proxy);
		}
	} 

	
	std::string varheader="", varbody="", uri="",
		hostname="", path="", port="", arg="";

	((Atom*)nuri)->toString(uri);

	if ((arglen == 3) || (proxy == "")) {
		uri_analysis(uri, hostname, port, path, arg);
		if (arg != "") {
			int rt = httpGET(varheader, varbody, 
			  hostname.c_str(), path.c_str(), port.c_str(), 
			  				arg.c_str()+1);
			if (rt <= 0) {
				return rt;
			}
		} else {
			int rt = httpGET(varheader, varbody, 
				hostname.c_str(), path.c_str(), port.c_str());
			if (rt <= 0) {
				return rt;
			}
		}
	} else if (arglen == 4) {
		proxy_analysis(proxy, hostname, port);
		
		httpGET(varheader, varbody, hostname.c_str(), uri.c_str(), 
						port.c_str());
	}
	
	Node* nvalheader = mka(varheader.c_str());
	Node* nvalbody = mka(varbody.c_str());

	Node* env = Nil->Cons(Nil);
	 
	SetEnv(env, nvar_header);
	SetEnv(env, nvar_body);

	((Undef*)nvar_header)->Set(nvalheader);
	((Undef*)nvar_body)->Set(nvalbody);

	PushStack(cx, Nil, Nil, env);

	return 1;
}

int HttpHead(Context* cx, Node* goalscar, List* module)
{
	Node* g = goalscar->Cdr()->Val();
	int	arglen = ListLength(g);

	if ((arglen < 2) || (arglen > 3)) {
		syserr("usage : <httphead VAR_Header uri [proxy] \n");
		return 0;
	}

	Node* nvar_header = g->Car()->Val();
	int rn;

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

	if (nvar_header->kind() != UNDEF) {
		syserr("usage : <httphead VAR_Header uri [proxy]>\n");
		return 0;
	}

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

	if (nuri->kind() != ATOM) {
		syserr("usage : <httphead VAR_Header uri [proxy]>\n");
		return 0;
	}

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

		if (nproxy->kind() != ATOM) {
			syserr("usage : <httphead VAR_Header uri [proxy]>\n");
			return 0;
		}
	} 

	
	std::string varheader="", varbody="", uri="", proxy="", 
		hostname="", path="", port="", arg="";

	((Atom*)nuri)->toString(uri);

	
	if (arglen == 2) {
		uri_analysis(uri, hostname, port, path, arg);
		int rt = httpHEAD(varheader, 
				hostname.c_str(), path.c_str(), port.c_str());
		if (rt <= 0) {
			return rt;
		}
	} else if (arglen == 3) {
		((Atom*)nproxy)->toString(proxy);
		proxy_analysis(proxy, hostname, port);

		int rt = httpHEAD(varheader, hostname.c_str(), uri.c_str(), 
							port.c_str());
		if (rt <= 0) {
			return rt;
		}

	}
	
	Node* nvalheader = mka(varheader.c_str());

	Node* env = Nil->Cons(Nil);
	 
	SetEnv(env, nvar_header);

	((Undef*)nvar_header)->Set(nvalheader);

	PushStack(cx, Nil, Nil, env);

	return 1;
}


int HttpPost(Context* cx, Node* goalscar, List* module)
{
	Node* g = goalscar->Cdr()->Val();
	int	arglen = ListLength(g);

	if ((arglen < 4) || (arglen > 5)) {
		syserr("usage : <httppost VAR_Header VAR_Body uri data [proxy] \n");
		return 0;
	}

	Node* nvar_header = g->Car()->Val();
	int rn;

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

	if (nvar_header->kind() != UNDEF) {
		syserr("usage : <httppost VAR_Header VAR_Body uri data [proxy]>\n");
		return 0;
	}

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

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

	if (nvar_body->kind() != UNDEF) {
		syserr("usage : <httppost VAR_Header VAR_Body uri data [proxy]>\n");
		return 0;
	}

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

	if (nuri->kind() != ATOM) {
		syserr("usage : <httppost VAR_Header VAR_Body uri data [proxy]>\n");
		return 0;
	}

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

	if (narg->kind() != ATOM) {
		syserr("usage : <httppost VAR_Header VAR_Body uri data [proxy]>\n");
		return 0;
	}

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

		if (nproxy->kind() != ATOM) {
			syserr("usage : <httppost VAR_Header VAR_Body uri data [proxy]>\n");
			return 0;
		}
	} 
	
	std::string varheader="", varbody="", uri="", proxy="", 
		hostname="", path="", port="", arg="", dummy="";

	((Atom*)nuri)->toString(uri);
	((Atom*)narg)->toString(arg);

	if (arglen == 4) {
		uri_analysis(uri, hostname, port, path, dummy);

		int rt = httpPOST(varheader, varbody, 
			  hostname.c_str(), path.c_str(), port.c_str(), 
			  				arg.c_str());
		if (rt <= 0) {
			return rt;
		}
	} else if (arglen == 5) {
		((Atom*)nproxy)->toString(proxy);
		proxy_analysis(proxy, hostname, port);

		int rt = httpPOST(varheader, varbody, hostname.c_str(), uri.c_str(), 
							port.c_str(), arg.c_str());
		if (rt <= 0) {
			return rt;
		}
	}
	
	Node* nvalheader = mka(varheader.c_str());
	Node* nvalbody = mka(varbody.c_str());

	Node* env = Nil->Cons(Nil);
	 
	SetEnv(env, nvar_header);
	SetEnv(env, nvar_body);

	((Undef*)nvar_header)->Set(nvalheader);
	((Undef*)nvar_body)->Set(nvalbody);

	PushStack(cx, Nil, Nil, env);

	return 1;
}



void str_tolower(std::string &str)
{
	int i;

	for (i = 0; i < str.length(); ) {
		int c  = str[i] & 0xff;
		int cl = CharLen(str[i]);
		if (cl == 1) {
			str[i] = tolower(c);
			i++;
		} else {
			i += cl;
		}
	}
}

void htmltags(Node* &nd, std::string &str, std::string &tag)
{
	int i = 0, j = 0;
	int nest = 0;

	if ((str == "") || (tag == "")) {
		return;
	}

	std::string ftag = "<"+tag;
	str_tolower(ftag);

	std::string lstr = str;
	str_tolower(lstr);

		
	for (i = 0; i < lstr.length();) {
		i = lstr.find(ftag, i);
		if (i == std::string::npos) {
			break;
		}

		nest = 0;
		for (j = i + ftag.length(); j < lstr.length(); j++) {
			if (lstr[j] == '<') {
				nest++;
			} else if (lstr[j] == '>') {
				if (nest == 0) {
					std::string stag = str.substr(i, j-i+1);
					nd = Append(nd, MkList(mka(stag.c_str())));
					break;
				}
				nest--;
			}
		}
		i = j + 1;
	}
}

void htmltags2(Node* &nd, std::string str, std::string &tag1, std::string &tag2)
{
  int i, j, k, l;
  int nest1, nest2;

  if ((str == "") || (tag1 == "") || (tag2 == "")) {
    return;
  }
    
  std::string ftag1 = "<"+tag1;
  str_tolower(ftag1);

  std::string ftag2 = "<"+tag2;
  str_tolower(ftag2);

  nd = Nil;
  
  std::string lstr = str;
  str_tolower(lstr);

  for (i = 0; i < lstr.length();) {

    i = lstr.find(ftag1, i);

    if (i == std::string::npos) {
      return;
    }

    int escflg = 0;
    nest1 = 0;
    for (j = i + ftag1.length(); j < lstr.length(); j++) {
      if (lstr[j] == '<') {
        nest1++;
      } else if (lstr[j] == '>') {
        if (nest1 == 0) {

          k = lstr.find(ftag2, j+1);

          if (k == std::string::npos) {
            return;
          }

          nest2 = 0;
          for (l = k + ftag2.length(); l < lstr.length(); l++) {
            if (lstr[l] == '<') {
              nest2++;
            } else if (lstr[l] == '>') {
              if (nest2 == 0) {

                std::string stag1 = str.substr(i, l-i+1);
                nd = Append(nd, MkList(mka(stag1.c_str())));
                escflg = 1;
                break;
              }
              nest2--;
            }
          }
        }
        if (escflg) {
          break;
        }
        nest1--;
      }
    }
    i = l + 1;

  }
  
}

Node* htmltagslist(Node* nd, std::string &tag1)
{
	Node* n = Nil;
	
	if (nd == Nil) {
		return nd;
	} else if (nd->kind() == ATOM) {
		std::string str = "";
		
		((Atom*)nd)->toString(str);
		htmltags(n, str, tag1);

		return n;
	} else if (nd->kind() == LIST) {
		n = Cons(htmltagslist(nd->Car(), tag1), 
				htmltagslist(nd->Cdr(), tag1));
		return n;

	} else {
		return nd;
	}
		
}

Node* htmltags2list(Node* nd, std::string &tag1, std::string &tag2)
{
	Node*	n=Nil;
	
	if (nd == Nil) {
		return nd;
	} else if (nd->kind() == ATOM) {
		std::string resultstr = "", str = "";
		
		((Atom*)nd)->toString(str);
		htmltags2(n, str, tag1, tag2);
		
		return n;

	} else if (nd->kind() == LIST) {
		n = Cons(htmltags2list(nd->Car(), tag1, tag2), 
				htmltags2list(nd->Cdr(), tag1, tag2));
		return n;
	} else {
		return nd;
	}
		
}


int HtmlTags(Context* cx, Node* goalscar, List* module)
{
	Node* g = goalscar->Cdr()->Val();
	int	arglen = ListLength(g);

	if ((arglen != 3) && (arglen != 4)) {
		syserr("usage : <htmltags VAR STR TAG [TAG2]>\n");
		return 0;
	}

	Node* nvar = g->Car()->Val();
	int rn;

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

	if (nvar->kind() != UNDEF) {
		syserr("usage : <htmltags VAR STR TAG [TAG2]>\n");
		return 0;
	}

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

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

	if (ntag->kind() != ATOM) {
		syserr("usage : <htmltags VAR STR TAG [TAG2]>\n");
		return 0;
	}

	Node* n = Nil;
	std::string tag="", tag2="";
	((Atom*)ntag)->toString(tag);
	
	if (arglen == 4) {
		g = g->Cdr();
		Node* ntag2 = g->Car()->Val();
		if ((rn = FuncArg(cx, ntag2, goalscar, module)) <= 0) {
			syserr("htmltags: failed in the evaluation of the argument. \n");
			return 0;
		}

		if (ntag2->kind() != ATOM) {
			syserr("usage : <htmltags VAR STR TAG [TAG2]>\n");
			return 0;
		}

		((Atom*)ntag2)->toString(tag2);

		n = htmltags2list(nstr, tag, tag2);

	} else {
		n = htmltagslist(nstr, tag);
	}

	Node* env = Nil->Cons(Nil);
	 
	SetEnv(env, nvar);

	((Undef*)nvar)->Set(n);

	PushStack(cx, Nil, Nil, env);

	return 1;
}

void htmlsection(Node* &nd, std::string &str, std::string &tag)
{
	int i = 0, j = 0;
	int iprev = i, jprev = j;
	int nest = 0;
	std::string sect = "";

	if ((str == "") || (tag == "")) {
		return;
	}

	std::string ftag = "<"+tag;
	str_tolower(ftag);

	std::string lstr = str;
	str_tolower(lstr);

	i = lstr.find(ftag, 0);
	if (i == std::string::npos) {
		nd = Nil;
		return;
	}
	iprev = i;
	i++;

	for (;;) {
		i = lstr.find(ftag, i);
		if ((i == std::string::npos) || (i >= lstr.length())){
			sect = str.substr(iprev);
			nd = Append(nd, MkList(mka(sect.c_str())));
			break;
		}

		sect = str.substr(iprev, i-iprev);
		nd = Append(nd, MkList(mka(sect.c_str())));
		iprev = i;
		
		nest = 0;
		for (j = i + ftag.length(), jprev = j; j < lstr.length(); j++) {
			if (lstr[j] == '<') {
				nest++;
			} else if (lstr[j] == '>') {
				if (nest == 0) {
					break;
				}
				nest--;
			}
		}
		i = j + 1;
	}
}

Node* htmlsectionlist(Node* nd, std::string &tag1)
{
	Node* n = Nil;
	
	if (nd == Nil) {
		return nd;
	} else if (nd->kind() == ATOM) {
		std::string str = "";
		
		((Atom*)nd)->toString(str);
		htmlsection(n, str, tag1);

		return n;
	} else if (nd->kind() == LIST) {
		n = Cons(htmlsectionlist(nd->Car(), tag1), 
				htmlsectionlist(nd->Cdr(), tag1));
		return n;

	} else {
		return nd;
	}
		
}

int HtmlSection(Context* cx, Node* goalscar, List* module)
{
	Node* g = goalscar->Cdr()->Val();
	int	arglen = ListLength(g);

	if (arglen != 3) {
		syserr("usage : <htmlsection VAR STR TAG>\n");
		return 0;
	}

	Node* nvar = g->Car()->Val();
	int rn;

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

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

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

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

	if (ntag->kind() != ATOM) {
		syserr("usage : <htmlsection VAR STR TAG>\n");
		return 0;
	}

	Node* n = Nil;
	std::string tag="";
	((Atom*)ntag)->toString(tag);

	n = htmlsectionlist(nstr, tag);

	Node* env = Nil->Cons(Nil);
	 
	SetEnv(env, nvar);

	((Undef*)nvar)->Set(n);

	PushStack(cx, Nil, Nil, env);

	return 1;
}

void htmlsplit(Node* &nd, std::string &str, std::string &tag)
{
	int i = 0, j = 0;
	int nest = 0;

	if ((str == "") || (tag == "")) {
		return;
	}

	std::string ftag = "<"+tag;
	str_tolower(ftag);

	std::string lstr = str;
	str_tolower(lstr);

	for (i = 0; i < lstr.length();) {
		i = lstr.find(ftag, i);
		if (i == std::string::npos) {
			nd = Append(nd, MkList(mka(str.c_str())));
			break;
		}

		std::string str0 = str.substr(0, i);
		if (i != 0) {
			nd = Append(nd, MkList(mka(str0.c_str())));
		}
		nest = 0;
		for (j = i + ftag.length(); j < lstr.length(); j++) {
			if (lstr[j] == '<') {
				nest++;
			} else if (lstr[j] == '>') {
				if (nest == 0) {
					lstr = lstr.substr(i, lstr.length());
					str = str.substr(i, str.length());
					break;
				}
				nest--;
			}
		}
		i = j-i+1;
	}
}

Node* htmlsplitlist(Node* nd, std::string &tag)
{
	Node*	n=Nil;
	
	if (nd == Nil) {
		return nd;
	} else if (nd->kind() == ATOM) {
		std::string resultstr = "", str = "";
		
		((Atom*)nd)->toString(str);
		htmlsplit(n, str, tag);
		
		return n;

	} else if (nd->kind() == LIST) {
		n = Cons(htmlsplitlist(nd->Car(), tag), 
				htmlsplitlist(nd->Cdr(), tag));
		return n;
	} else {
		return nd;
	}
		
}

int HtmlSplit(Context* cx, Node* goalscar, List* module)
{
	Node* g = goalscar->Cdr()->Val();
	int	arglen = ListLength(g);

	if (arglen != 3) {
		syserr("usage : <htmlsplit VAR STR TAG> \n");
		return 0;
	}

	Node* nvar = g->Car()->Val();
	int rn;

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

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

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

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

	if (ntag->kind() != ATOM) {
		syserr("usage : <htmlsplit VAR STR TAG>\n");
		return 0;
	}

	Node* n = Nil;
	std::string tag="", tag2="";
	((Atom*)ntag)->toString(tag);
	
	n = htmlsplitlist(nstr, tag);

	Node* env = Nil->Cons(Nil);
	 
	SetEnv(env, nvar);

	((Undef*)nvar)->Set(n);

	PushStack(cx, Nil, Nil, env);

	return 1;
}


int htmlleft(Node* &nd, std::string str, std::string &tag)
{
	int i = 0, j = 0;
	int nest = 0;

	if ((str == "") || (tag == "")) {
		nd = mka(str);
		return 1;
	}

	std::string ftag = "<"+tag;
	str_tolower(ftag);

	std::string lstr = str;
	str_tolower(lstr);

	for (i = 0; i < lstr.length();) {
		i = lstr.find(ftag, i);
		if (i == std::string::npos) {
			nd = mka(str.c_str());
			return 1;
		}

		nest = 0;
		for (j = i + ftag.length(); j < lstr.length(); j++) {
			if (lstr[j] == '<') {
				nest++;
			} else if (lstr[j] == '>') {
				if (nest == 0) {
					str = str.substr(0,j+1);
					nd = mka(str.c_str());
					return 0;
				}
				nest--;
			}
		}
		i = j-i+1;
	}
	nd = mka(str.c_str());
	return 1;
}

int htmlleftlist(Node* &nout, Node* nstr, std::string &tag)
{
	Node*	n=Nil;
	
	if (nstr == Nil) {
		nout = nstr;
		return 1;
	} else if (nstr->kind() == ATOM) {
		std::string resultstr = "", str = "";
		
		((Atom*)nstr)->toString(str);
		int r = htmlleft(n, str, tag);

		nout = n;
		return r;

	} else if (nstr->kind() == LIST) {
		Node* n1;
		if (!htmlleftlist(n1, nstr->Car(), tag)) {
			nout = nstr;
			return 0;
		}
		Node* n2;
		int r = htmlleftlist(n2, nstr->Cdr(), tag);
		
		nout = Cons(n1, n2);
		return r;
	} else {
		nout = nstr;
		return 1;
	}
		
}

int HtmlLeft(Context* cx, Node* goalscar, List* module)
{
	Node* g = goalscar->Cdr()->Val();
	int	arglen = ListLength(g);

	if (arglen != 3) {
		syserr("usage : <htmlleft VAR STR TAG> \n");
		return 0;
	}

	Node* nvar = g->Car()->Val();
	int rn;

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

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

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

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

	if (ntag->kind() != ATOM) {
		syserr("usage : <htmlleft VAR STR TAG>\n");
		return 0;
	}

	Node* n = Nil;
	std::string tag="", tag2="";
	((Atom*)ntag)->toString(tag);
	
	htmlleftlist(n, nstr, tag);

	Node* env = Nil->Cons(Nil);
	 
	SetEnv(env, nvar);

	((Undef*)nvar)->Set(n);

	PushStack(cx, Nil, Nil, env);

	return 1;
}

int htmlright(int flg, Node* &nd, std::string str, std::string &tag)
{
	int i = 0, j = 0;
	int nest = 0;

	if (flg) {
		nd = mka(str.c_str());
		return 1;
	}
	
	if ((str == "") || (tag == "")) {
		nd = mka(str);
		return 0;
	}

	std::string ftag = "<"+tag;
	str_tolower(ftag);

	std::string lstr = str;
	str_tolower(lstr);

	i = lstr.find(ftag, i);
	if (i == std::string::npos) {
		nd = mka(str.c_str());
		return 0;
	}

	std::string str0 = str.substr(i, str.length());
	nd = mka(str0.c_str());
	return 1;
}

int htmlrightlist(int flg, Node* &nout, Node* nstr, std::string &tag)
{
	Node*	n=Nil;
	
	if (flg) {
		nout = nstr;
		return 1;
	}

	if (nstr == Nil) {
		nout = nstr;
		return 0;
	} else if (nstr->kind() == ATOM) {
		std::string resultstr = "", str = "";
		
		((Atom*)nstr)->toString(str);
		int r = htmlright(0, n, str, tag);

		nout = n;
		return r;

	} else if (nstr->kind() == LIST) {
		Node* n1;
		int r1 = htmlrightlist(0, n1, nstr->Car(), tag);
		if (r1) {
			nout = Cons(n1, nstr->Cdr());
			return 1;
		}

		Node* n2;
		int r2 = htmlrightlist(0, n2, nstr->Cdr(), tag);
		if (r2) {
			nout = n2;
			return 1;
		}

		nout = Nil;
		return 0;
	} else {
		nout = nstr;
		return 0;
	}
		
}

int HtmlRight(Context* cx, Node* goalscar, List* module)
{
	Node* g = goalscar->Cdr()->Val();
	int	arglen = ListLength(g);

	if (arglen != 3) {
		syserr("usage : <htmlright VAR STR TAG> \n");
		return 0;
	}

	Node* nvar = g->Car()->Val();
	int rn;

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

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

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

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

	if (ntag->kind() != ATOM) {
		syserr("usage : <htmlright VAR STR TAG>\n");
		return 0;
	}

	Node* n = Nil;
	std::string tag="", tag2="";
	((Atom*)ntag)->toString(tag);
	
	htmlrightlist(0, n, nstr, tag);

	Node* env = Nil->Cons(Nil);
	 
	SetEnv(env, nvar);

	((Undef*)nvar)->Set(n);

	PushStack(cx, Nil, Nil, env);

	return 1;
}


void erasealltags(std::string &str1, std::string &str2)
{
	int i;
	int flg = 0;
	std::string str = "";
	str2 = "";

	for (i = 0; i < str1.length(); i++) {
		if (str1[i] == '<') {
			flg = 1;
		} else if (str1[i] == '>') {
			flg = 0;
		} else if (!flg) {
			str += str1[i];
		}
	}

	htmldecode(str, str2);	
}

Node* erasealltagslist(Node* nd)
{

	if (nd == Nil) {
		return nd;
	} else if (nd->kind() == ATOM) {
		std::string str1 = "", str2 = "";
		
		((Atom*)nd)->toString(str1);
		erasealltags(str1, str2);
		
		Node* n = mka(str2.c_str());

		return n;

	} else if (nd->kind() == LIST) {
		Node* n = Cons(erasealltagslist(nd->Car()), 
				erasealltagslist(nd->Cdr()));

		return n;

	} else {
		return nd;
	}
		
}

int EraseAllTags(Context* cx, Node* goalscar, List* module)
{
	Node* g = goalscar->Cdr()->Val();
	int	arglen = ListLength(g);

	if (arglen != 2) {
		syserr("usage : <erasealltags VAR ARG>\n");
		return 0;
	}

	Node* nvar = g->Car()->Val();
	int rn;

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

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

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


	int   constflg = 0;
	Node* n = erasecommenttagslist(narg, constflg);

	n = erasealltagslist(n);

	Node* env = Nil->Cons(Nil);
	 
	SetEnv(env, nvar);

	((Undef*)nvar)->Set(n);

	PushStack(cx, Nil, Nil, env);

	return 1;
}


void erasetags(std::string &resultstr, std::string &str, std::string &tag)
{
	int i = 0, j = 0;
	int nest = 0;
	
	if ((str == "") || (tag == "")) {
		resultstr = str;
		return;
	}

	std::string ftag = "<"+tag;
	str_tolower(ftag);

	std::string lstr = str;
	str_tolower(lstr);

	resultstr = "";
		
	for (i = 0; i < lstr.length();) {
		int ii = lstr.find(ftag, i);
		if (ii == std::string::npos) {
			resultstr += str.substr(i);
			break;
		} else {
			resultstr += str.substr(j, ii-j);
		}
		i = ii;
		
		nest = 0;
		for (j = i + ftag.length(); j < lstr.length(); j++) {
			if (lstr[j] == '<') {
				nest++;
			} else if (lstr[j] == '>') {
				if (nest == 0) {
					break;
				}
				nest--;
			}
		}
		j++;
		i = j;
	}
}

void erasetags2(std::string &resultstr, std::string &str, 
			std::string &tag1, std::string &tag2, int &contflg)
{
  int i=0, j=0, k=0, l=0, ii = -1, ii1 = -1;
  int nest1, nest2;
  
  if ((str == "") || (tag1 == "") || (tag2 == "")) {
    resultstr = str;
    return;
  }
  
  std::string ftag1 = "<"+tag1;
  str_tolower(ftag1);
  
  std::string ftag2 = "<"+tag2;
  str_tolower(ftag2);

  std::string lstr = str;
  str_tolower(lstr);

  resultstr = "";

  i = 0;
  if (contflg > 0) {
  	do {
	  	ii1 = ii;
	        ii = lstr.find(ftag2, ii1+1);
	        ii1 = lstr.find(ftag1, ii1+1);
		if (ii == std::string::npos) {
			if (ii1 == std::string::npos) {
				return;
			} else {
				contflg++;
				for (;;) {
					ii1 = lstr.find(ftag1, ii1+1);
					if (ii1 == std::string::npos) {
						break;
					}
					contflg++;
				}
				return;
			}
		} else {
			if (ii1 == std::string::npos) {
				while (contflg > 1) {
					ii = lstr.find(ftag2, ii+1);
					if (ii == std::string::npos) {
						return;
					}
					contflg--;
				}
				break;
			}			
		}
	} while (ii > ii1);

	contflg--;

	i = ii + ftag2.length();
	for ( ; i < lstr.length(); i++) {
		if (lstr[i] == '>') {
			i++;
			break;
		}
	}
  }
  
  for ( ; i < lstr.length();) {

    int ii = lstr.find(ftag1, i);
    if (ii == std::string::npos) {
      resultstr += str.substr(i);
      return;
    } else {
      resultstr += str.substr(l, ii-l);
      contflg++;
    }
    i = ii;

    int escflg = 0;
    nest1 = 0;
    for (j = i + ftag1.length(); j < lstr.length(); j++) {
      if (lstr[j] == '<') {
        nest1++;
      } else if (lstr[j] == '>') {
        if (nest1 == 0) {

          int k=j, k1=k;
          do {
          	k1 = k;
	        k  = lstr.find(ftag2, k1+1);
	        k1 = lstr.find(ftag1, k1+1);
	        if (k == std::string::npos) {
		        if (k1 == std::string::npos) {
		        	return;
		        } else {
		        	contflg++;
				for (;;) {
					k1 = lstr.find(ftag1, k1+1);
					if (k1 == std::string::npos) {
						break;
					}
					contflg++;
				}
				return;
		        }
		} else {
		        if (k1 == std::string::npos) {
				while (contflg > 1) {
					k = lstr.find(ftag2, k+1);
					if (k == std::string::npos) {
						return;
					}
					contflg--;
				}
		        	break;
		        }
		}
	  } while (k > k1);

	  contflg--;

          nest2 = 0;
          for (l = k + ftag2.length(); l < lstr.length(); l++) {
            if (lstr[l] == '<') {
              nest2++;
            } else if (lstr[l] == '>') {
              if (nest2 == 0) {
                escflg = 1;
                break;
              }
              nest2--;
            }
          }
        }
        if (escflg) {
          break;
        }
        nest1--;
      }
    }
    l++;
    i = l;

  }
  
}

Node* erasetagslist(Node* nd, std::string &tag1)
{

	if (nd == Nil) {
		return nd;
	} else if (nd->kind() == ATOM) {
		std::string resultstr = "", str = "";
		
		((Atom*)nd)->toString(str);
		erasetags(resultstr, str, tag1);
		
		Node* n = mka(resultstr.c_str());

		return n;

	} else if (nd->kind() == LIST) {
		Node* n = Cons(erasetagslist(nd->Car(), tag1), 
				erasetagslist(nd->Cdr(), tag1));

		return n;

	} else {
		return nd;
	}
		
}

Node* erasetags2list(Node* nd, std::string &tag1, std::string &tag2, 
							int &contflg)
{

	if (nd == Nil) {
		return nd;
	} else if (nd->kind() == ATOM) {
		std::string resultstr = "", str = "";
		
		((Atom*)nd)->toString(str);
		erasetags2(resultstr, str, tag1, tag2, contflg);
		
		Node* n = mka(resultstr.c_str());

		return n;

	} else if (nd->kind() == LIST) {
		Node* n1 = erasetags2list(nd->Car(), tag1, tag2, contflg);
		Node* n2 = erasetags2list(nd->Cdr(), tag1, tag2, contflg);

		std::string s1 = "*", s2 = "*";

		if (n1->kind() == ATOM) {
			((Atom*)n1)->toString(s1);
		}
		if (n2->kind() == ATOM) {
			((Atom*)n2)->toString(s2);
		}

		Node* n = Nil;
		
		if (s1 == "") {
			n = n2;
		} else if (s2 == "") {
			n = n1;
		} else {
			n = Cons(n1, n2);
		}

		return n;

	} else {
		return nd;
	}
		
}

int EraseTags(Context* cx, Node* goalscar, List* module)
{
	Node* g = goalscar->Cdr()->Val();
	int	arglen = ListLength(g);

	if ((arglen != 3) && (arglen != 4)) {
		syserr("usage : <erasetags VAR STR TAG [TAG2]>\n");
		return 0;
	}

	Node* nvar = g->Car()->Val();
	int rn;

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

	if (nvar->kind() != UNDEF) {
		syserr("usage : <erasetags VAR STR TAG [TAG2]>\n");
		return 0;
	}

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

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

	if (ntag->kind() != ATOM) {
		syserr("usage : <erasetags VAR STR TAG [TAG2]>\n");
		return 0;
	}

	Node* n = Nil;
	std::string tag="", tag2="";
	((Atom*)ntag)->toString(tag);
	
	if (arglen == 4) {
		g = g->Cdr();
		Node* ntag2 = g->Car()->Val();
		if ((rn = FuncArg(cx, ntag2, goalscar, module)) <= 0) {
			syserr("erasetags: failed in the evaluation of the argument. \n");
			return 0;
		}

		if (ntag2->kind() != ATOM) {
			syserr("usage : <erasetags VAR STR TAG [TAG2]>\n");
			return 0;
		}

		((Atom*)ntag2)->toString(tag2);

		int contflg = 0;
		n = erasetags2list(nstr, tag, tag2, contflg);

	} else {
		n = erasetagslist(nstr, tag);
	}

	Node* env = Nil->Cons(Nil);
	 
	SetEnv(env, nvar);

	((Undef*)nvar)->Set(n);

	PushStack(cx, Nil, Nil, env);

	return 1;
}


void erasecommenttags(std::string &resultstr, std::string &str, int &contflg)
{
	int i = 0, j = 0, ii = 0;
	
	if (str == "") {
		resultstr = str;
		return;
	}

	std::string ftag1 = "<!--";
	std::string ftag2 = "-->";
	
	resultstr = "";

	// for the comment's cutting during the list
	i = 0;
	if (contflg) {
		ii = str.find(ftag2, 0);
		if (ii == std::string::npos) {
			return;
		} else {
			i = ii + 3;
			contflg = 0;
		}
	}

		
	for ( ; i < str.length();) {
		ii = str.find(ftag1, i);
		if (ii == std::string::npos) {
			resultstr += str.substr(i);
			break;
		} else {
			resultstr += str.substr(j, ii-j);
		}
		i = ii;
		
		ii = str.find(ftag2, i);
		if (ii == std::string::npos) {
			contflg = 1;
			break;
		}

		i = ii+3;
	}
}

Node* erasecommenttagslist(Node* nd, int &contflg)
{

	if (nd == Nil) {
		return nd;
	} else if (nd->kind() == ATOM) {
		std::string resultstr = "", str = "";
		
		((Atom*)nd)->toString(str);
		erasecommenttags(resultstr, str, contflg);
		
		Node* n = mka(resultstr.c_str());

		return n;

	} else if (nd->kind() == LIST) {
		Node* n1 = erasecommenttagslist(nd->Car(), contflg);
		Node* n2 = erasecommenttagslist(nd->Cdr(), contflg);

		std::string s1 = "*", s2 = "*";

		if (n1->kind() == ATOM) {
			((Atom*)n1)->toString(s1);
		}
		if (n2->kind() == ATOM) {
			((Atom*)n2)->toString(s2);
		}

		Node* n = Nil;
		
		if (s1 == "") {
			n = n2;
		} else if (s2 == "") {
			n = n1;
		} else {
			n = Cons(n1, n2);
		}

		return n;

	} else {
		return nd;
	}
		
}

int EraseCommentTags(Context* cx, Node* goalscar, List* module)
{
	Node* g = goalscar->Cdr()->Val();
	int	arglen = ListLength(g);

	if (arglen != 2) {
		syserr("usage : <eraseCommenttags VAR STR>\n");
		return 0;
	}

	Node* nvar = g->Car()->Val();
	int rn;

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

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

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

	Node* n = Nil;
	
	int   constflg = 0;	
	n = erasecommenttagslist(nstr, constflg);

	Node* env = Nil->Cons(Nil);
	 
	SetEnv(env, nvar);

	((Undef*)nvar)->Set(n);

	PushStack(cx, Nil, Nil, env);

	return 1;
}


void splittags(Node* &nd, std::string &str, std::string &tag)
{
	int i = 0, j = 0, oldi = 0;
	int nest = 0;

	nd = Nil;
	
	if ((str == "") || (tag == "")) {
		return;
	}

	std::string ftag = "<"+tag;
	str_tolower(ftag);

	std::string lstr = str;
	str_tolower(lstr);

	std::string stag = "";

	for (i = 0; i < lstr.length();) {
		oldi = i;
		i = lstr.find(ftag, i);
		if (i == std::string::npos) {
			stag = str.substr(oldi);
			nd = Append(nd, MkList(mka(stag.c_str())));
			break;
		}

		nest = 0;
		for (j = i + ftag.length(); j < lstr.length(); j++) {
			if (lstr[j] == '<') {
				nest++;
			} else if (lstr[j] == '>') {
				if (nest == 0) {
					stag = str.substr(oldi, j-oldi+1);
					nd = Append(nd, MkList(mka(stag.c_str())));
					break;
				}
				nest--;
			}
		}
		i = j + 1;
	}
	if (nd == Nil) {
		nd = mka(str);
	}
}

Node* splittagslist(Node* nd, std::string &tag1)
{
	Node* n = Nil;
	
	if (nd == Nil) {
		return nd;
	} else if (nd->kind() == ATOM) {
		std::string str = "";
		
		((Atom*)nd)->toString(str);
		splittags(n, str, tag1);

		return n;
	} else if (nd->kind() == LIST) {
		n = Cons(splittagslist(nd->Car(), tag1), 
				splittagslist(nd->Cdr(), tag1));
		return n;

	} else {
		return nd;
	}
		
}

int SplitTags(Context* cx, Node* goalscar, List* module)
{
	Node* g = goalscar->Cdr()->Val();
	int	arglen = ListLength(g);

	if (arglen != 3) {
		syserr("usage : <splittags VAR STR TAG>\n");
		return 0;
	}

	Node* nvar = g->Car()->Val();
	int rn;

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

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

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

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

	if (ntag->kind() != ATOM) {
		syserr("usage : <splittags VAR STR TAG>\n");
		return 0;
	}

	Node* n = Nil;
	std::string tag="";
	((Atom*)ntag)->toString(tag);
	
	n = splittagslist(nstr, tag);

	Node* env = Nil->Cons(Nil);
	 
	SetEnv(env, nvar);

	((Undef*)nvar)->Set(n);

	PushStack(cx, Nil, Nil, env);

	return 1;
}


Node* crlf2lflist(Node* nd)
{
	if (nd->kind() != LIST) {
		std::string str1="", str2="";
		int i;

		((Atom*)nd)->toString(str1);
		
		for (i=0; i < str1.length(); i++) {
			if (str1[i] == 0x0d) {
				if (i+1 < str1.length()) {
					i++;
					if (str1[i] != 0x0a) {
						str2 += 0x0a;
					}
					str2 += str1[i];
				}
			} else {
				str2 += str1[i];
			}
		}
		
		return mka(str2);
	}

	Node* ncar = nd->Car();
	Node* ncdr = nd->Cdr();

	Node* n1 = crlf2lflist(ncar);
	if (ncdr == Nil) {
		return n1;
	}

	Node* n2 = crlf2lflist(ncdr);

	return Cons(n1, n2);
}

int CRLF2LF(Context* cx, Node* goalscar, List* module)
{
	Node* g = goalscar->Cdr()->Val();
	int	arglen = ListLength(g);

	if (arglen != 2) {
		syserr("usage : <CRLF2LF VAR list>\n");
		return 0;
	}

	Node* nvar = g->Car()->Val();
	int rn;

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

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

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

	Node* n = crlf2lflist(nlist);
	
	Node* env = Nil->Cons(Nil);
	 
	SetEnv(env, nvar);

	((Undef*)nvar)->Set(n);

	PushStack(cx, Nil, Nil, env);

	return 1;
}

Node* lf2crlflist(Node* nd)
{
	if (nd->kind() != LIST) {
		std::string str1="", str2="";
		int i;

		((Atom*)nd)->toString(str1);
		
		for (i=0; i < str1.length(); i++) {
			if (str1[i] == 0x0a) {
				str2 += 0x0d;
				str2 += 0x0a;
			} else if (str1[i] == 0x0d) {
				str2 += 0x0d;
				if (i+1 < str1.length()) {
					i++;
					str2 += 0x0a;
					if (str1[i] != 0x0a) {
						str2 += str1[i];
					}
				} else {
					str2 += 0x0a;
				}
			} else {
				str2 += str1[i];
			}
		}
		
		return mka(str2);
	}

	Node* ncar = nd->Car();
	Node* ncdr = nd->Cdr();

	Node* n1 = lf2crlflist(ncar);
	if (ncdr == Nil) {
		return n1;
	}

	Node* n2 = lf2crlflist(ncdr);

	return Cons(n1, n2);
}

int LF2CRLF(Context* cx, Node* goalscar, List* module)
{
	Node* g = goalscar->Cdr()->Val();
	int	arglen = ListLength(g);

	if (arglen != 2) {
		syserr("usage : <LF2CRLF VAR list>\n");
		return 0;
	}

	Node* nvar = g->Car()->Val();
	int rn;

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

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

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

	Node* n = lf2crlflist(nlist);
	
	Node* env = Nil->Cons(Nil);
	 
	SetEnv(env, nvar);

	((Undef*)nvar)->Set(n);

	PushStack(cx, Nil, Nil, env);

	return 1;
}


