/* "CodeWorker":	a scripting language for parsing and generating text.

Copyright (C) 1996-1997, 1999-2002 Cédric Lemaire

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library 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
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

To contact the author: codeworker@free.fr
*/

#ifdef WIN32
#	pragma warning (disable : 4786)
#endif

#include <iostream>
#include <fstream>
#include <memory>

#include "UtlException.h"

#ifndef WIN32
#	include "UtlString.h" // for Debian/gcc 2.95.4
#endif

#include "ScpStream.h"
#include "UtlTimer.h"

#include "DtaProject.h"
#include "DtaConsoleScript.h"
#include "DtaPatternScript.h"
#include "CppCompilerEnvironment.h"
#include "CGRuntime.h"
#include "CGExternalHandling.h"

#include "ExprScriptVariable.h"
#include "GrfFunction.h"
#include "Workspace.h"

namespace CodeWorker {
	std::string Workspace::_sTraceFileName = "";
	bool Workspace::_bWarningOnUnknownVariables = false;
	std::list<GrfFunction*> Workspace::_listOfExternalFunctions = std::list<GrfFunction*>();


	Workspace::Workspace() : _bConsole(true), _bDebugMode(false), _bTimeMeasure(false), _iScriptMode(NONE), _bQuietMode(false), _pQuietCGIOutput(0L), _bNoLogo(false) {
#ifndef WIN32
		initKeyboard();
#endif
	}

	Workspace::~Workspace() {
		if (isCGIMode()) {
			std::string sOutputDocument = CGRuntime::loadVirtualFile(_sGeneratedFileName);
			CGRuntime::deleteVirtualFile(_sGeneratedFileName);
			CGRuntime::deleteVirtualFile(_sScriptFileName);
			if (!CGRuntime::getProperty("HTTP_STATUS_CODE").empty()) {
				std::cout << CGRuntime::getEnv("SERVER_PROTOCOL") << " " << CGRuntime::getProperty("HTTP_STATUS_CODE") << " " << CGRuntime::getProperty("HTTP_REASON_LINE") << CGRuntime::endl();
			}
			bool bTypeReclaimed = true;
			if (!CGRuntime::getProperty("HTTP_LOCATION").empty()) {
				bTypeReclaimed = false;
				std::cout << "Location: " << CGRuntime::getProperty("HTTP_LOCATION") << CGRuntime::endl();
			}
			if (bTypeReclaimed && CGRuntime::getProperty("HTTP_CONTENT_TYPE").empty()) {
				CGRuntime::setProperty("HTTP_CONTENT_TYPE", "text/html");
			}
			if (!CGRuntime::getProperty("HTTP_CONTENT_TYPE").empty()) {
				std::cout << "Content-type: " << CGRuntime::getProperty("HTTP_CONTENT_TYPE") << CGRuntime::endl();
			}
			std::cout << CGRuntime::endl();
			std::cout << sOutputDocument << std::flush;
			delete _pQuietCGIOutput;
		}
#ifndef WIN32
		closeKeyboard();
#endif
	}

	int Workspace::executionHasFailed() {
		if (isCGIMode()) {
			CGRuntime::deleteVirtualFile(_sGeneratedFileName);
			CGRuntime::deleteVirtualFile(_sScriptFileName);
			if (!CGRuntime::getProperty("HTTP_STATUS_CODE").empty()) {
				std::cout << CGRuntime::getEnv("SERVER_PROTOCOL") << " " << CGRuntime::getProperty("HTTP_STATUS_CODE") << " " << CGRuntime::getProperty("HTTP_REASON_LINE") << CGRuntime::endl();
			}
			std::cout << "Content-type: text/html" << CGRuntime::endl();
			std::cout << CGRuntime::endl();
			std::cout << "<HTML>" << std::endl;
			std::cout << "\t<BODY>" << std::endl;
			std::string sError = _pQuietCGIOutput->getOutput();
			sError = CGRuntime::replaceString("\n", "<BR/>", sError);
			sError = CGRuntime::replaceString("\r", "", sError);
			std::cout << "\t\t" << sError << std::endl;
			std::cout << "\t</BODY>" << std::endl;
			std::cout << "</HTML>" << std::endl;
			delete _pQuietCGIOutput;
			_pQuietCGIOutput = 0L;
		}
		return -1;
	}

	void Workspace::setTraceFileName(const std::string& sTraceFileName) {
		_sTraceFileName = sTraceFileName;
		std::ofstream* pFile = CodeWorker::openOutputFile(_sTraceFileName.c_str());
		if (pFile != 0L) {
			pFile->close();
			delete pFile;
		}
	}

	std::string Workspace::readArgument(char** tsArgs, int& i) {
		return tsArgs[i];
	}

	bool Workspace::checkArguments(int iNargs, char** tsArgs, EXECUTE_FUNCTION executeFunction) {
		if (CGRuntime::existEnv("GATEWAY_INTERFACE") && CGRuntime::existEnv("REQUEST_METHOD")) {
			// CGI mode
			_bQuietMode = true;
			_pQuietCGIOutput = new CGQuietOutput;
			_sScriptFileName = CGRuntime::getEnv("PATH_TRANSLATED");
			_iScriptMode = GENERATE;
			_bConsole = false;
			std::string sRequestMethod = CGRuntime::getEnv("REQUEST_METHOD");
			std::string sQueryString;
			if ((stricmp(sRequestMethod.c_str(), "post") == 0) || (stricmp(sRequestMethod.c_str(), "put") == 0)) {
				std::string sContentLength = CGRuntime::getEnv("CONTENT_LENGTH");
				int iLength = atoi(sContentLength.c_str());
				char* tcQueryString = new char[iLength + 1];
				int iRemainingSize = iLength;
				while (iRemainingSize > 0) {
					int iBytes = fread(tcQueryString, 1, iRemainingSize, stdin);
					if (iBytes == 0) {
						delete [] tcQueryString;
						std::string sMessage = "CGI processing failed at initialization: ";
						if (iRemainingSize != iLength) {
							char tcNumber[32];
							sprintf(tcNumber, "%d", (iLength - iRemainingSize));
							sMessage += "incomplete extraction of the " + sRequestMethod + " query (have read " + std::string(tcNumber) + "/" + CGRuntime::getEnv("CONTENT_LENGTH") + " bytes)";
						} else {
							sMessage += "extraction of the " + sRequestMethod + " query didn't work (had " + CGRuntime::getEnv("CONTENT_LENGTH") + " bytes to read)";
						}
						throw UtlException(sMessage);
					}
					iRemainingSize -= iBytes;
				}
				tcQueryString[iLength] = '\0';
				sQueryString = tcQueryString;
				delete [] tcQueryString;
			} else if (CGRuntime::existEnv("QUERY_STRING")) {
				sQueryString = CGRuntime::getEnv("QUERY_STRING");
			}
			DtaScriptVariable* pREQUEST = DtaProject::getInstance().setGlobalVariable("_REQUEST");
			std::string::size_type iIndex = sQueryString.find('=');
			while (iIndex != std::string::npos) {
				std::string sAttribute = sQueryString.substr(0, iIndex);
				sAttribute = CGRuntime::decodeURL(sAttribute);
				std::string sValue;
				iIndex++;
				if (iIndex < sQueryString.size()) sQueryString = sQueryString.substr(iIndex);
				else sQueryString = ""; // bug VC++ 6 on substr()
				iIndex = sQueryString.find('&');
				if (iIndex == std::string::npos) {
					sValue = sQueryString;
					sQueryString = "";
				} else {
					sValue = sQueryString.substr(0, iIndex);
					iIndex++;
					if (iIndex < sQueryString.size()) sQueryString = sQueryString.substr(iIndex);
					else sQueryString = ""; // bug VC++ 6 on substr()
				}
				sValue = CGRuntime::decodeURL(sValue);
				if (CGRuntime::isIdentifier(sAttribute)) {
					DtaScriptVariable* pAttribute = DtaProject::getInstance().setGlobalVariable(sAttribute);
					pAttribute->setValue(sValue.c_str());
					pREQUEST->addElement(sAttribute)->setValue(pAttribute);
				} else {
					pREQUEST->addElement(sAttribute)->setValue(sValue.c_str());
				}
				iIndex = sQueryString.find('=');
			}
			if (!sQueryString.empty()) {
				sQueryString = CGRuntime::decodeURL(sQueryString);
				if (CGRuntime::isIdentifier(sQueryString)) {
					DtaScriptVariable* pAttribute = DtaProject::getInstance().setGlobalVariable(sQueryString);
					pREQUEST->addElement(sQueryString)->setValue(pAttribute);
				} else {
					pREQUEST->addElement(sQueryString);
				}
			}
			_sGeneratedFileName = CGRuntime::createVirtualTemporaryFile("");
		} else {
			// parsing the command line
			std::string sWorkingPath;
			std::list<std::string> listOfIncludePaths;
			std::map<std::string, std::string> mapOfDefinedTargets;
			bool bSpeed = false;
			int i = 1;
			bool bConsoleExplicitlyRequired = false;
			_bConsole = (executeFunction == 0L);
			_sScriptFileName = "";
			_sParsedFileName = "";
			_sGeneratedFileName = "";
			_iScriptMode = NONE;
			_sCppCompilation = "";
			_sCodeWorkerDir = "";
			_bQuietMode = false;
			std::string sFileExtension; // if the script filename is passed as the first argument
			if ((iNargs >= 2) && (tsArgs[1][0] != '-') && (executeFunction == 0)) {
				std::string sFile = tsArgs[1];
				if (sFile.size() > 4) {
					sFileExtension = sFile.substr(sFile.size() - 4);
					if ((sFileExtension != ".cwt") && (sFileExtension != ".cwp") && (sFileExtension != ".cws") && (sFileExtension != ".gen")) {
						sFileExtension = "";
					} else {
						_sScriptFileName = sFile;
						if (sFileExtension == ".cwp") {
							i++;
							if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: input filename expected after the BNF parsing script");
							_sParsedFileName = readArgument(tsArgs, i);
							_iScriptMode = PARSE_BNF;
						} else {
							_iScriptMode = SCRIPT;
						}
						i++;
					}
				}
			}
			if ((iNargs >= 2) && (stricmp(tsArgs[1], "-commands") == 0)) {
				// it isn't a script without arguments, but a command-line file
				if (iNargs != 3) throw UtlException("command-line processing: '-commands' expects a file name and nothing else behind");
				std::string sFile = tsArgs[2];
				return checkArgumentsFromFile(sFile, executeFunction);
			}
			if (!sFileExtension.empty() || (executeFunction != 0)) {
				_bConsole = false;
				if ((i < iNargs) && (tsArgs[i][0] != '-')) {
					DtaScriptVariable* pArgs = DtaProject::getInstance().setGlobalVariable("_ARGS");
					do {
						pArgs->pushItem(tsArgs[i]);
						i++;
					} while ((i < iNargs) && (tsArgs[i][0] != '-'));
				}
			}
			while (i < iNargs) {
				if (tsArgs[i][0] == '-') {
					const char* tcCommand = tsArgs[i] + 1;
					if (tcCommand[0] == '-') tcCommand++;
					if (stricmp(tcCommand, "script") == 0) {
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: script filename expected after '-script'");
						if (_iScriptMode != NONE) throw UtlException("command-line processing: '-translate' isn't allowed: another script mode has already been specified");
						_sScriptFileName = readArgument(tsArgs, i);
						_iScriptMode = SCRIPT;
						_bConsole = false;
					} else if (stricmp(tcCommand, "compile") == 0) {
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: script filename expected after '-compile'");
						if (_iScriptMode != NONE) throw UtlException("command-line processing: '-compile' isn't allowed: another script mode has already been specified");
						_sScriptFileName = readArgument(tsArgs, i);
						_iScriptMode = COMPILE;
						_bConsole = false;
					} else if (stricmp(tcCommand, "parsebnf") == 0) {
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: script filename expected after '-parseBNF'");
						if (_iScriptMode != NONE) throw UtlException("command-line processing: '-parseBNF' isn't allowed: another script mode has already been specified");
						_sScriptFileName = readArgument(tsArgs, i);
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: input filename expected after '-parseBNF <BNF-parsing-script>'");
						_sParsedFileName = readArgument(tsArgs, i);
						_iScriptMode = PARSE_BNF;
						_bConsole = false;
					} else if (stricmp(tcCommand, "generate") == 0) {
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: script filename expected after '-generate'");
						if (_iScriptMode != NONE) throw UtlException("command-line processing: '-generate' isn't allowed: another script mode has already been specified");
						_sScriptFileName = readArgument(tsArgs, i);
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: generated filename expected after '-generate <patternFile>'");
						_sGeneratedFileName = readArgument(tsArgs, i);
						_iScriptMode = GENERATE;
						_bConsole = false;
					} else if (stricmp(tcCommand, "expand") == 0) {
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: script filename expected after '-expand'");
						if (_iScriptMode != NONE) throw UtlException("command-line processing: '-expand' isn't allowed: another script mode has already been specified");
						_sScriptFileName = readArgument(tsArgs, i);
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: generated filename expected after '-expand <patternFile>'");
						_sGeneratedFileName = readArgument(tsArgs, i);
						_iScriptMode = EXPAND;
						_bConsole = false;
					} else if (stricmp(tcCommand, "autoexpand") == 0) {
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: filename expected after '-autoexpand'");
						if (_iScriptMode != NONE) throw UtlException("command-line processing: '-autoexpand' isn't allowed: another script mode has already been specified");
						_sScriptFileName = readArgument(tsArgs, i);
						_iScriptMode = AUTO_EXPAND;
						_bConsole = false;
					} else if (stricmp(tcCommand, "translate") == 0) {
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: filename of a BNF parsing script expected after '-translate'");
						if (_iScriptMode != NONE) throw UtlException("command-line processing: '-translate' isn't allowed: another script mode has already been specified");
						_sScriptFileName = readArgument(tsArgs, i);
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: source file expected after '-translate <BNF-script>'");
						_sParsedFileName = readArgument(tsArgs, i);
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: generated file expected after '-translate <BNF-script> <source-file>'");
						_sGeneratedFileName = readArgument(tsArgs, i);
						_iScriptMode = TRANSLATE;
						_bConsole = false;
					} else if (stricmp(tcCommand, "args") == 0) {
						DtaScriptVariable* pArgs = DtaProject::getInstance().setGlobalVariable("_ARGS");
						i++;
						while ((i < iNargs) && (tsArgs[i][0] != '-')) {
							pArgs->pushItem(tsArgs[i]);
							i++;
						}
						continue;
					} else if (stricmp(tcCommand, "insert") == 0) {
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: variable expected after '-insert'");
						std::string sVariable = readArgument(tsArgs, i);
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: value expected after '-insert'");
						std::string sValue = readArgument(tsArgs, i);
						DtaScript script;
						ScpStream theCommand(sVariable);
						std::auto_ptr<ExprScriptVariable> pExprVariable(script.parseVariableExpression(script.getBlock(), theCommand));
						if (theCommand.getInputLocation() != (int) sVariable.size()) throw UtlException("option '-insert': syntax error on the variable expression");
						DtaProject::getInstance().getVariable(*pExprVariable)->setValue(sValue.c_str());
					} else if (stricmp(tcCommand, "console") == 0) {
						bConsoleExplicitlyRequired = true;
					} else if (stricmp(tcCommand, "debug") == 0) {
						_bDebugMode = true;
						DtaScript::requiresParsingInformation(true);
					} else if (stricmp(tcCommand, "time") == 0) {
						_bTimeMeasure = true;
						DtaScript::requiresParsingInformation(true);
					} else if (stricmp(tcCommand, "varexist") == 0) {
						_bWarningOnUnknownVariables = true;
					} else if (stricmp(tcCommand, "nologo") == 0) {
						_bNoLogo = true;
					} else if (stricmp(tcCommand, "version") == 0) {
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: version name expected after '-version'");
						DtaProject::getInstance().setVersion(tsArgs[i]);
					} else if (stricmp(tcCommand, "fast") == 0) {
						bSpeed = true;
					} else if (stricmp(tcCommand, "c++") == 0) {
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: directory expected after '-c++'");
						if (!_sCppCompilation.empty()) throw UtlException("command-line processing: directory is given twice");
						_sCppCompilation = readArgument(tsArgs, i);
						i++;
						if ((i < iNargs) && (tsArgs[i][0] != '-')) {
							_sCodeWorkerDir = readArgument(tsArgs, i);
						} else {
							i--;
						}
					} else if (stricmp(tcCommand, "c++external") == 0) {
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: C++ filename expected after '-c++sp'");
						if (!_sCppServerPage.empty()) throw UtlException("command-line processing: C++ filename is given twice for server pages");
						_sCppServerPage = readArgument(tsArgs, i);
					} else if (stricmp(tcCommand, "genheader") == 0) {
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: comment expected after '-genheader'");
						DtaProject::getInstance().setGenerationHeader(tsArgs[i]);
					} else if (stricmp(tcCommand, "quantify") == 0) {
						i++;
						if ((i < iNargs) && (tsArgs[i][0] != '-')) {
							_sQuantifyFile = readArgument(tsArgs, i);
						} else {
							_sQuantifyFile = "true";
						}
						DtaScript::requiresParsingInformation(true);
					} else if (stricmp(tcCommand, "stdin") == 0) {
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: filename expected after '-stdin'");
						_sStandardInput = readArgument(tsArgs, i);
					} else if (stricmp(tcCommand, "stack") == 0) {
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: depth expected after '-stack'");
						int iStackDepth = atoi(tsArgs[i]);
						if (iStackDepth <= 0)  throw UtlException("command-line processing: invalid depth given after '-stack'");
						GrfFunction::_iMaxStackDepth = iStackDepth;
					} else if (stricmp(tcCommand, "path") == 0) {
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: working path expected after '-path'");
						sWorkingPath = readArgument(tsArgs, i);
						if ((sWorkingPath[sWorkingPath.size() - 1] != '\\') && (sWorkingPath[sWorkingPath.size() - 1] != '/')) sWorkingPath += '/';
					} else if ((stricmp(tcCommand, "define") == 0) || (stricmp(tcCommand, "D") == 0)) {
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: define target expected after '-define'");
						std::string sTargetName = readArgument(tsArgs, i);
						std::string sTargetValue;
						std::string::size_type iIndex = sTargetName.find("=");
						if (iIndex != std::string::npos) {
							if (iIndex == 0) throw UtlException("target name expected on the left side of '=' for define directive");
							if (iIndex + 1 < sTargetName.size()) {
								sTargetValue = sTargetName.substr(iIndex + 1);
								sTargetName = sTargetName.substr(0, iIndex);
							} else {
								sTargetName = sTargetName.substr(0, iIndex);
							}
						} else {
							sTargetValue = sTargetName;
						}
						mapOfDefinedTargets[sTargetName] = sTargetValue;
					} else if (stricmp(tcCommand, "I") == 0) {
						i++;
						if ((i >= iNargs) || (tsArgs[i][0] == '-')) throw UtlException("command-line processing: include path expected after '-I'");
						std::string sIncludePath = readArgument(tsArgs, i);
						if ((sIncludePath[sIncludePath.size() - 1] != '\\') && (sIncludePath[sIncludePath.size() - 1] != '/')) sIncludePath += '/';
						listOfIncludePaths.push_back(sIncludePath);
					} else if (stricmp(tcCommand, "commentBegin") == 0) {
						i++;
						if (i >= iNargs) throw UtlException("command-line processing: format of a beginning of comment expected after '-commentBegin'");
						std::string sCommentBegin = readArgument(tsArgs, i);
						DtaProject::getInstance().setCommentBegin(sCommentBegin);
					} else if (stricmp(tcCommand, "commentEnd") == 0) {
						i++;
						if (i >= iNargs) throw UtlException("command-line processing: end of comment format expected after '-commentEnd'");
						std::string sCommentEnd = readArgument(tsArgs, i);
						DtaProject::getInstance().setCommentEnd(sCommentEnd);
					} else if (stricmp(tcCommand, "help") == 0) {
						displayHelp();
						_bConsole = false;
						_bQuietMode = true;
					} else if (stricmp(tcCommand, "quiet") == 0) {
						_bQuietMode = true;
					} else if (stricmp(tcCommand, "-commands") == 0) {
						throw UtlException("command-line processing: '-commands' must be the first argument");
					} else throw UtlException(std::string("command-line processing: unknown option '-") + (tcCommand) + "'");
				} else if (strcmp(tsArgs[i], "?") == 0) {
					displayHelp();
					_bConsole = false;
					_bQuietMode = true;
				} else {
					std::string sMessage = "a command always begins with a '-', so invalid parameter '";
					sMessage += readArgument(tsArgs, i);
					sMessage += "'";
					throw UtlException(sMessage);
				}
				i++;
			}

			if (!_sTraceFileName.empty()) {
				std::ofstream* pFile = CodeWorker::openAppendFile(_sTraceFileName.c_str());
				if (pFile != 0L) {
					(*pFile) << "commandLine" << std::endl;
					for (i = 1; i < iNargs; i++) {
						(*pFile) << "\t" << i << ":" << tsArgs[i] << std::endl;
					}
					(*pFile) << std::endl;
					pFile->close();
					delete pFile;
				}
			}

			if (sWorkingPath.empty()) sWorkingPath = "./";
			DtaProject::getInstance().setWorkingPath(sWorkingPath.c_str());
			ScpStream::setListOfIncludePaths(listOfIncludePaths);
			DtaProject::getInstance().setMapOfDefinedTargets(mapOfDefinedTargets);
			DtaProject::getInstance().setSpeed(bSpeed);
			if (bConsoleExplicitlyRequired) _bConsole = true;
		}
		return true;
	}

	bool Workspace::checkArgumentsFromFile(const std::string& sFilename, EXECUTE_FUNCTION executeFunction) {
		bool bSuccess = false;
		std::ifstream* pFile = CodeWorker::openInputFile(sFilename.c_str());
		if (pFile == 0L) {
			throw UtlException("unable to open command file \"" + sFilename + "\" for loading arguments");
		}
		try {
			while (CodeWorker::skipEmpty(*pFile)) {
				std::string sIdentifier;
				if (CodeWorker::readIdentifier(*pFile, sIdentifier)) {
					if (sIdentifier == "commandLine") {
						std::vector<std::string> listOfArguments;
						int iValue;
						int iIndex = 1;
						while (CodeWorker::skipEmpty(*pFile) && CodeWorker::readInt(*pFile, iValue)) {
							if (iValue != iIndex) {
								char tcMessage[80];
								sprintf(tcMessage, "bad argument index, '%d:' expected", iIndex);
								throw UtlException(*pFile, tcMessage);
							}
							CodeWorker::skipEmpty(*pFile);
							if (!CodeWorker::isEqualTo(*pFile, ':')) throw UtlException(*pFile, "':' expected");
							std::string sArgument;
							if (!CodeWorker::readLine(*pFile, sArgument)) throw UtlException(*pFile, "argument expected after ':'");
							listOfArguments.push_back(sArgument);
							iIndex++;
						}
						int iNbArgs = listOfArguments.size() + 1;
						char** tsArgs = new char*[iNbArgs];
						try {
							tsArgs[0] = 0L;
							for (int i = 1; i < iNbArgs; i++) tsArgs[i] = (char*) listOfArguments[i - 1].c_str();
							bSuccess = checkArguments(listOfArguments.size() + 1, tsArgs, executeFunction);
						} catch(UtlException&) {
							delete [] tsArgs;
							throw;
						} catch(std::exception&) {
							delete [] tsArgs;
							throw;
						} catch(...) {
							delete [] tsArgs;
							throw UtlException("ellipsis exception encountered while checking arguments of command line");
						}
						break;
					} else {
						throw UtlException(*pFile, "file of command-line switches: 'commandLine' keyword expected");
					}
				} else {
					throw UtlException(*pFile, "file of command-line switches: identifier expected");
				}
			}
		} catch(std::exception&) {
			pFile->close();
			delete pFile;
			throw;
		} catch(...) {
			pFile->close();
			delete pFile;
			throw UtlException("ellipsis exception encountered while checking arguments of command line");
		}
		pFile->close();
		delete pFile;
		return bSuccess;
	}

	void Workspace::displayHelp() {
		CGRuntime::traceLine("Common usages:");
		CGRuntime::traceLine("\t<scriptFile> <arg1> ... <argN> [<switch>]*");
		CGRuntime::traceLine("\t-script <scriptFile> -I ... -D ...");
		CGRuntime::traceLine("\t-generate <patternFile> <generatedFile>");
		CGRuntime::traceLine("\t-expand <patternFile> <generatedFile>");
		CGRuntime::traceLine("\t-parseAsBNF <BNF-File> <parsedFile>");
		CGRuntime::traceLine("Alphabetical detailed list of all switches:");
//##markup##"display switches"
//##script##
//local sOptions;
//quiet(sOptions) parseAsBNF(
//	{
//		injector	::= #continue #ignore(blanks) [->table]2;
//		table	::=
//				"\\begin{tableii}{l|l}{.6}{Switch}{Description}"
//				#continue
//				[line]*
//				"\\end{tableii}"
//				;
//		line	::=
//				"\\lineii"
//				#continue
//				=> traceText("  ");
//				bracket => traceText(": ");
//				bracket => traceLine("");
//				;
//		bracket	::=
//				#continue
//				'{'
//				#!ignore
//				[
//						"\\\\"
//					|
//						"\\_"
//						=> traceText('_');
//					|
//						'\\' #readIdentifier:sCommand
//						command<sCommand>
//					|
//						"\""
//						=> traceText("\\\"");
//					|
//						" \\ref" ->'}'
//					|
//						['\r']? '\n' [' ' | '\t']*
//						=> traceText(' ');
//					|
//						[' ' | '\t']+
//						=> traceText(' ');
//					|
//						~'}':cChar
//						=> traceText(cChar);
//				]*
//				'}'
//				;
//		command<"samp">	::= bracket;
//		command<"textbf">	::= bracket;
//		command<"textit">	::=
//				=> traceText('<');
//				bracket
//				=> traceText('>');
//				;
//	}, project, "Documentation/CodeWorker.tex");
//local i = 0;
//local iLastLine = -1;
//local sText;
//@	CGRuntime::traceLine("@
//while $i < sOptions.length()$ {
//	local c = sOptions.charAt(i);
//  if $i - iLastLine >= 80$ {
//			set iLastLine = $i - (4 + sText.length())$;
//			@");@endl()@	CGRuntime::traceLine("   @
//	}
//	if c == ' ' {
//		@@sText@@
//		set sText = " ";
//	} else if c == '\n' {
//		set iLastLine = i;
//		@@sText@");@endl()@	CGRuntime::traceLine("@
//		set sText = "";
//	} else if c == '\r' {
//		increment(iLastLine);
//	} else {
//		set sText += c;
//	}
//	increment(i);
//}
//@@sText@");@endl()@@
//##script##
//##begin##"display switches"
	CGRuntime::traceLine("  -args [<arg>]*: Pass some arguments to the command line. The list of");
	CGRuntime::traceLine("    arguments stops at the end of the command line or as soon as an option is");
	CGRuntime::traceLine("    encountered. The arguments are stored in a global array variable called");
	CGRuntime::traceLine("    _ARGS.");
	CGRuntime::traceLine("  -autoexpand <file-to-expand>: The file <file-to-expand> is explored for");
	CGRuntime::traceLine("    expanding code at markups, executing a <template-based> script inserted");
	CGRuntime::traceLine("    just below each markup. It is identical to execute the script function");
	CGRuntime::traceLine("    autoexpand(<file-to-expand>, project).");
	CGRuntime::traceLine("  -c++ <generated-project-path> <CodeWorker-path>: To translate the leader");
	CGRuntime::traceLine("    script and all its dependencies in C++ source code, once the execution of");
	CGRuntime::traceLine("    the leader script has achieved (same job as compileToCpp()). The");
	CGRuntime::traceLine("    <CodeWorker-path> is optional and gives the path to includes and libraries");
	CGRuntime::traceLine("    of the software.");
	CGRuntime::traceLine("  -c++external <filename>: To generate C++ source code for implementing all");
	CGRuntime::traceLine("    functions declared as external into scripts.");
	CGRuntime::traceLine("  -commentBegin <format>: To specify the format of a beginning of comment.");
	CGRuntime::traceLine("  -commentEnd <format>: To specify the format of a comment's end.");
	CGRuntime::traceLine("  -compile <scriptFile>: To compile a script file, just to check whether the");
	CGRuntime::traceLine("    syntax is correct.");
	CGRuntime::traceLine("  -commands <commandFile>: To load all arguments processed ordinary on the");
	CGRuntime::traceLine("    command-line. It must be the only switch or else passed on the");
	CGRuntime::traceLine("    command-line.");
	CGRuntime::traceLine("  -console: To open a console session (default mode if no script to interpret");
	CGRuntime::traceLine("    is specified via -script or -compile or -generate or -expand.");
	CGRuntime::traceLine("  -debug: To debug a script in a console while executing it.");
	CGRuntime::traceLine("  -define VAR=<value> or -D ...: To define some variables, as when using the");
	CGRuntime::traceLine("    C++ preprocessor or when passing properties to the JAVA compiler. These");
	CGRuntime::traceLine("    variables are similar to properties, insofar as they aren't exploited");
	CGRuntime::traceLine("    during the preprocessing of scripts to interpret. This option conforms to");
	CGRuntime::traceLine("    the format -define VAR when no value has to be assigned ; in that case,");
	CGRuntime::traceLine("    <\"true\"> is assigned by default to variable VAR. The script function");
	CGRuntime::traceLine("    getProperty(\"VAR\") gives the value of variable VAR.");
	CGRuntime::traceLine("  -expand <pattern-script> <file-to-expand>: Script file <pattern-script> is");
	CGRuntime::traceLine("    executed to expand file <file-to-expand> into markers. It is identical to");
	CGRuntime::traceLine("    execute script function expand(<pattern-script>, project,");
	CGRuntime::traceLine("    <file-to-expand>).");
	CGRuntime::traceLine("  -fast: To optimize speed. While processing generation, the output file is");
	CGRuntime::traceLine("    built into memory, instead of into a temporary file.");
	CGRuntime::traceLine("  -generate <pattern-script> <file-to-generate>: Script file <pattern-script>");
	CGRuntime::traceLine("    is executed to generate file <file-to-generate>. It is identical to");
	CGRuntime::traceLine("    execute script function generate(<pattern-script>, project,");
	CGRuntime::traceLine("    <file-to-generate>).");
	CGRuntime::traceLine("  -genheader <text>: Adds a header at the beginning of all generated files,");
	CGRuntime::traceLine("    followed by a text (see procedure setGenerationHeader()).");
	CGRuntime::traceLine("  -help or ?: Help about the command line.");
	CGRuntime::traceLine("  -I <path>: Specify a path to explore when trying to find a file while");
	CGRuntime::traceLine("    invoking include or parseFree or parseAsBNF or generate or expand or ...");
	CGRuntime::traceLine("    This option may be repeated to specify more than one <path>.");
	CGRuntime::traceLine("  -insert <variable_expression> <value>: Creates a new node in the main parse");
	CGRuntime::traceLine("    tree project and assigns a constant value to it. It is identical to");
	CGRuntime::traceLine("    execute the statement insert <variable_expression> = \" <value> \" ;.");
	CGRuntime::traceLine("  -nologo: The interpreter doesn't write the copyright in the shell at the");
	CGRuntime::traceLine("    beginning.");
	CGRuntime::traceLine("  -parseBNF <BNF-parsing-script> <source-file>: The script file");
	CGRuntime::traceLine("    <BNF-parsing-script> parses <source-file> from an extended BNF grammar. It");
	CGRuntime::traceLine("    is identical to execute the script function");
	CGRuntime::traceLine("    parseAsBNF(<BNF-parsing-script>, project, <source-file>).");
	CGRuntime::traceLine("  -path <path>: Output directory, returned by the script function");
	CGRuntime::traceLine("    getWorkingPath(), and used ordinary to specify where to generate or copy a");
	CGRuntime::traceLine("    file.");
	CGRuntime::traceLine("  -quantify [<outputFile>]?: To execute scripts into quantify mode that");
	CGRuntime::traceLine("    consists of measuring the coverage and the time consuming. Results are");
	CGRuntime::traceLine("    saved to HTML file <outputFile> or displayed to the console if not");
	CGRuntime::traceLine("    present.");
	CGRuntime::traceLine("  -script <script-file>: Defines the <leader> script, which will be executed");
	CGRuntime::traceLine("    first.");
	CGRuntime::traceLine("  -stack <depth>: To limit the recursive call of functions, for avoiding an");
	CGRuntime::traceLine("    overflow stack memory. By default, the <depth> is set to 1000.");
	CGRuntime::traceLine("  -stdin <filename>: To change the standard input for reading from an existing");
	CGRuntime::traceLine("    file. It may be useful for running a scenario.");
	CGRuntime::traceLine("  -time: To display the execution time expressed in milliseconds, just before");
	CGRuntime::traceLine("    exiting.");
	CGRuntime::traceLine("  -translate <translation-script> <source-file> <file-to-generate>: Script");
	CGRuntime::traceLine("    file <translation-script> processes a <source-to-source> translation. It");
	CGRuntime::traceLine("    is identical to execute the script function");
	CGRuntime::traceLine("    translate(<translation-script>, project, <source-file>,");
	CGRuntime::traceLine("    <file-to-generate>).");
	CGRuntime::traceLine("  -varexist: To trigger a warning when the value of a variable that doesn't");
	CGRuntime::traceLine("    exist is required into a script.");
	CGRuntime::traceLine("  -version <version-name>: To force interpreted scripts as written in a");
	CGRuntime::traceLine("    precedent version given by <version-name>.");
	CGRuntime::traceLine("");
//##end##"display switches"
	}


	bool Workspace::execute(EXECUTE_FUNCTION executeFunction) {
		bool bSuccess = true;
		UtlTimer myTimer;
		if (_bTimeMeasure) myTimer.start();
		std::auto_ptr<CGFileStandardInput> theStandardInput;
		if (!_sStandardInput.empty()) {
			std::auto_ptr<CGFileStandardInput> pFile(new CGFileStandardInput(_sStandardInput));
			theStandardInput = pFile;
		}
		try {
			if ((_iScriptMode != AUTO_EXPAND) && (_sScriptFileName.empty() || (executeFunction != 0L))) {
				if (executeFunction != 0L) {
					if		(_iScriptMode == PARSE_BNF)	CGRuntime::parseAsBNF(executeFunction, CGRuntime::getRootTree(), _sParsedFileName);
					else if	(_iScriptMode == EXPAND)	CGRuntime::expand(executeFunction, CGRuntime::getRootTree(), _sGeneratedFileName);
					else if	(_iScriptMode == TRANSLATE)	CGRuntime::translate(executeFunction, CGRuntime::getRootTree(), _sParsedFileName, _sGeneratedFileName);
					else if	(_iScriptMode == GENERATE)	CGRuntime::generate(executeFunction, CGRuntime::getRootTree(), _sGeneratedFileName);
					else executeFunction();
				}
			} else {
				if (executeFunction == 0L) {
					if (!_sGeneratedFileName.empty()) {
						ScpStream sCommand(8192);
						if (_iScriptMode == EXPAND) sCommand << "expand(";
						else if (_iScriptMode == TRANSLATE) sCommand << "translate(";
						else sCommand << "generate(";
						sCommand.writeString(_sScriptFileName.c_str());
						sCommand << ", project, ";
						if (_iScriptMode == TRANSLATE) {
							sCommand.writeString(_sParsedFileName.c_str());
							sCommand << ", ";
						}
						sCommand.writeString(_sGeneratedFileName.c_str());
						sCommand << ");";
						_script.parseStream(sCommand, _bDebugMode, _sQuantifyFile);
					} else if (!_sParsedFileName.empty()) {
						ScpStream sCommand(8192);
						sCommand << "parseAsBNF(";
						sCommand.writeString(_sScriptFileName.c_str());
						sCommand << ", project, ";
						sCommand.writeString(_sParsedFileName.c_str());
						sCommand << ");";
						_script.parseStream(sCommand, _bDebugMode, _sQuantifyFile);
					} else if (_iScriptMode == AUTO_EXPAND) {
						ScpStream sCommand(8192);
						sCommand << "autoexpand(";
						sCommand.writeString(_sScriptFileName.c_str());
						sCommand << ", project);";
						_script.parseStream(sCommand, _bDebugMode, _sQuantifyFile);
					} else {
						_script.parseFile(_sScriptFileName.c_str(), 0L, _bDebugMode, _sQuantifyFile);
					}
					if (_iScriptMode != COMPILE) _script.execute(CGRuntime::getThisInternalNode());
					if (!_sCppCompilation.empty()) {
						CppCompilerEnvironment theCompilerEnvironment(_sCppCompilation, _sCodeWorkerDir);
						_script.compileCpp(theCompilerEnvironment, _sScriptFileName);
					}
				}
			}
			if (_sCppServerPage.empty()) {
				if (!_listOfExternalFunctions.empty()) {
					CGRuntime::traceLine("warning: some functions have been declared external, but option '-c++external' wasn't required on the command line!");
				}
			} else {
				std::string sRadical;
				std::string::size_type iIndex = _sCppServerPage.find_last_of('.');
				if (iIndex != std::string::npos) sRadical = _sCppServerPage.substr(0, iIndex);
				else sRadical = _sCppServerPage;
				std::string sClassName;
				iIndex = sRadical.find_last_of("/\\");
				if (iIndex != std::string::npos) sClassName = sRadical.substr(iIndex + 1);
				else sClassName = sRadical;
				CppParsingTree_value theContext;
				theContext.setValue(sClassName);
				CGRuntime::generate(executeServerPageCppHeader, theContext, sRadical + ".h");
				CGRuntime::generate(executeServerPageCppBody, theContext, sRadical + ".cpp");
			}
		} catch(UtlException& exception) {
			if (CGRuntime::getExternalHandling() == 0L) {
				CGRuntime::traceLine(exception.getMessage());
				CGRuntime::traceText(exception.getTraceStack());
			} else {
				std::string sMessage = exception.getMessage() + "\n" +  exception.getTraceStack();
				CGRuntime::getExternalHandling()->traceLine(sMessage);
			}
			bSuccess = false;
		}
		if (_bConsole) {
			DtaConsoleScript console(_script);
			console.execute(CGRuntime::getThisInternalNode());
		}
		if (_bTimeMeasure) {
			myTimer.stop();
			if (CGRuntime::getExternalHandling() == 0L) {
				char tcNumber[32];
				sprintf(tcNumber, "%d", myTimer.getTimeInMillis());
				CGRuntime::traceLine("time execution = " + std::string(tcNumber) + "ms");
			} else {
				char tcMessage[80];
				sprintf(tcMessage, "time execution = %dms", myTimer.getTimeInMillis());
				CGRuntime::getExternalHandling()->traceLine(tcMessage);
			}
		}
		return bSuccess;
	}

	void Workspace::executeServerPageCppHeader() {
		std::string sClassName;
		const char* tcClassName = CGRuntime::getThisTree().getValue();
		if (tcClassName == 0L) throw UtlException("while generating the C++ external stub: no class name specified!");
		sClassName = tcClassName;
		CGRuntime::writeText("#ifndef _" + sClassName + "_h_" + CGRuntime::endl());
		CGRuntime::writeText("#define _" + sClassName + "_h_" + CGRuntime::endl());
		CGRuntime::writeText(CGRuntime::endl());
		CGRuntime::writeText("#include <string>" + CGRuntime::endl());
		if (CGRuntime::getProtectedArea("INCLUDE FILES").empty()) {
			CGRuntime::populateProtectedArea("INCLUDE FILES", "#include \"UtlException.h\"" + CGRuntime::endl());
		} else {
			CGRuntime::setProtectedArea("INCLUDE FILES");
		}
		CGRuntime::writeText(CGRuntime::endl());
		CGRuntime::writeText("namespace CodeWorker {" + CGRuntime::endl());
		CGRuntime::writeText("\tclass CppParsingTree_var;" + CGRuntime::endl());
		CGRuntime::writeText("\tclass CppParsingTree_value;" + CGRuntime::endl());
		CGRuntime::writeText("}" + CGRuntime::endl() + CGRuntime::endl());
		CGRuntime::writeText("class " + sClassName + " {" + CGRuntime::endl());
		CGRuntime::writeText("\tprivate:" + CGRuntime::endl());
		CGRuntime::setProtectedArea("attributes");
		CGRuntime::writeText(CGRuntime::endl());
		CGRuntime::writeText("\tpublic:" + CGRuntime::endl());
		CGRuntime::writeText("\t\tstatic void init();" + CGRuntime::endl() + CGRuntime::endl());
		for (std::list<GrfFunction*>::const_iterator i = _listOfExternalFunctions.begin(); i != _listOfExternalFunctions.end(); ++i) {
			GrfFunction* pFunction = *i;
			std::string sFunctionName = pFunction->getFunctionName();
			if (pFunction->isATemplateInstantiation()) {
				if (pFunction->isATemplateDispatcher()) {
					CGRuntime::writeText("\t\t// template dispatcher '" + pFunction->getSignature() + "':" + CGRuntime::endl());
				} else {
					CGRuntime::writeText("\t\t// template function '" + pFunction->getSignature() + "':" + CGRuntime::endl());
				}
				sFunctionName = "_compilerTemplateFunction_" + sFunctionName + "_compilerInstantiation_" + CppCompilerEnvironment::convertTemplateKey(pFunction->getTemplateInstantiation());
			} else {
				CGRuntime::writeText("\t\t// function '" + pFunction->getSignature() + "':" + CGRuntime::endl());
			}
			CGRuntime::writeText("\t\tstatic std::string " + sFunctionName + "(");
			if (pFunction->isATemplateDispatcher()) {
				CGRuntime::writeText("const std::string& _compilerTemplateFunction_dispatching");
			}
			int iIndex = 0;
			for (std::list<std::string>::const_iterator j = pFunction->getParameters().begin(); j != pFunction->getParameters().end(); j++, iIndex++) {
				if ((j != pFunction->getParameters().begin()) || pFunction->isATemplateDispatcher()) CGRuntime::writeText(", ");
				switch(pFunction->getParameterType(iIndex)) {
					case VALUE_EXPRTYPE: CGRuntime::writeText("CodeWorker::CppParsingTree_value ");break;
					case REFERENCE_EXPRTYPE: CGRuntime::writeText("const CodeWorker::CppParsingTree_var& ");break;
					case VARIABLE_EXPRTYPE:	CGRuntime::writeText("const CodeWorker::CppParsingTree_var& ");break;
				}
				CGRuntime::writeText((*j));
			}
			CGRuntime::writeText(") throw(CodeWorker::UtlException);" + CGRuntime::endl());
			CGRuntime::writeText("\t\tstatic std::string " + sFunctionName + "_compilerVarlist(");
			if (pFunction->isATemplateDispatcher()) {
				CGRuntime::writeText("const std::string& _compilerTemplateFunction_dispatching, ");
			}
			CGRuntime::writeText("CodeWorker::CppParsingTree_var** tParameters) throw(CodeWorker::UtlException);" + CGRuntime::endl());
			if (pFunction->isATemplateDispatcher()) {
				CGRuntime::writeText("\t\tstatic std::string ");
				CGRuntime::writeText(pFunction->getFunctionName());
				CGRuntime::writeText("_compilerVarlist(CodeWorker::CppParsingTree_var** tParameters) throw(CodeWorker::UtlException);" + CGRuntime::endl());
			}
		}
		CGRuntime::writeText(CGRuntime::endl());
		CGRuntime::setProtectedArea("interfaces");
		CGRuntime::writeText("};" + CGRuntime::endl());
		CGRuntime::writeText(CGRuntime::endl());
		CGRuntime::writeText("#endif" + CGRuntime::endl());
	}

	void Workspace::executeServerPageCppBody() {
		std::string sClassName;
		const char* tcClassName = CGRuntime::getThisTree().getValue();
		if (tcClassName == 0L) throw UtlException("while generating the C++ external stub: no class name specified!");
		sClassName = tcClassName;
		CGRuntime::writeText("#ifdef WIN32" + CGRuntime::endl());
		CGRuntime::writeText("#pragma warning(disable: 4786)" + CGRuntime::endl());
		CGRuntime::writeText("#endif" + CGRuntime::endl());
		CGRuntime::writeText(CGRuntime::endl());
		if (CGRuntime::getProtectedArea("INCLUDE FILES").empty()) {
			CGRuntime::populateProtectedArea("INCLUDE FILES", "#include \"CppParsingTree.h\"" + CGRuntime::endl() + "#include \"CGRuntime.h\"" + CGRuntime::endl());
		} else {
			CGRuntime::setProtectedArea("INCLUDE FILES");
		}
		CGRuntime::writeText("#include \"" + sClassName + ".h\"" + CGRuntime::endl());
		CGRuntime::writeText(CGRuntime::endl());
		CGRuntime::writeText("void " + sClassName + "::init() {" + CGRuntime::endl());
		std::list<GrfFunction*>::const_iterator i;
		for (i = _listOfExternalFunctions.begin(); i != _listOfExternalFunctions.end(); ++i) {
			GrfFunction* pFunction = *i;
			std::string sFunctionName = pFunction->getFunctionName();
			if (pFunction->isATemplateInstantiation()) {
				sFunctionName = "_compilerTemplateFunction_" + sFunctionName + "_compilerInstantiation_" + CppCompilerEnvironment::convertTemplateKey(pFunction->getTemplateInstantiation());
			}
			if (pFunction->isATemplateDispatcher()) {
				CGRuntime::writeText("\tCodeWorker::CGRuntime::registerExternalFunction(\"");
				CGRuntime::writeText(pFunction->getSignature());
				CGRuntime::writeText("\", " + sClassName + "::");
				CGRuntime::writeText(pFunction->getFunctionName());
				CGRuntime::writeText("_compilerVarlist);" + CGRuntime::endl());
				CGRuntime::writeText("\tCodeWorker::CGRuntime::registerExternalTemplateDispatcherFunction(");
			} else {
				CGRuntime::writeText("\tCodeWorker::CGRuntime::registerExternalFunction(");
			}
			CGRuntime::writeText("\"" + pFunction->getSignature() + "\", " + sClassName + "::" + sFunctionName + "_compilerVarlist);" + CGRuntime::endl());
		}
		CGRuntime::writeText("}" + CGRuntime::endl() + CGRuntime::endl());
		for (i = _listOfExternalFunctions.begin(); i != _listOfExternalFunctions.end(); ++i) {
			GrfFunction* pFunction = *i;
			std::string sFunctionName = pFunction->getFunctionName();
			std::string sDisplayName = pFunction->getSignature();
			if (pFunction->isATemplateInstantiation()) {
				if (pFunction->isATemplateDispatcher()) {
					CGRuntime::writeText("// template dispatcher '" + sDisplayName + "':" + CGRuntime::endl());
				} else {
					CGRuntime::writeText("// template function '" + sDisplayName + "':" + CGRuntime::endl());
				}
				sFunctionName = "_compilerTemplateFunction_" + sFunctionName + "_compilerInstantiation_" + CppCompilerEnvironment::convertTemplateKey(pFunction->getTemplateInstantiation());
			} else {
				CGRuntime::writeText("// function '" + sDisplayName + "':" + CGRuntime::endl());
			}
			CGRuntime::writeText("std::string " + sClassName + "::" + sFunctionName + "(");
			if (pFunction->isATemplateDispatcher()) {
				CGRuntime::writeText("const std::string& _compilerTemplateFunction_dispatching");
			}
			int iIndex = 0;
			std::list<std::string>::const_iterator j;
			for (j = pFunction->getParameters().begin(); j != pFunction->getParameters().end(); j++, iIndex++) {
				if ((j != pFunction->getParameters().begin()) || pFunction->isATemplateDispatcher()) CGRuntime::writeText(", ");
				switch(pFunction->getParameterType(iIndex)) {
					case VALUE_EXPRTYPE: CGRuntime::writeText("CodeWorker::CppParsingTree_value ");break;
					case REFERENCE_EXPRTYPE: CGRuntime::writeText("const CodeWorker::CppParsingTree_var& ");break;
					case VARIABLE_EXPRTYPE:	CGRuntime::writeText("const CodeWorker::CppParsingTree_var& ");break;
				}
				CGRuntime::writeText((*j));
			}
			CGRuntime::writeText(") throw(CodeWorker::UtlException) {" + CGRuntime::endl());
			if (pFunction->isATemplateDispatcher()) {
				for (std::map<std::string, GrfFunction*>::const_iterator k = pFunction->getInstantiatedFunctions().begin(); k != pFunction->getInstantiatedFunctions().end(); k++) {
					CGRuntime::writeText("\tif (_compilerTemplateFunction_dispatching == \"" + k->first + "\") return " + sFunctionName + k->first + "(");
					for (j = pFunction->getParameters().begin(); j != pFunction->getParameters().end(); j++) {
						if (j != pFunction->getParameters().begin()) CGRuntime::writeText(", ");
						CGRuntime::writeText((*j));
					}
					CGRuntime::writeText(");" + CGRuntime::endl());
				}
				CGRuntime::writeText("\tif (!_compilerTemplateFunction_dispatching.empty()) throw CodeWorker::UtlException(\"template function '");
				CGRuntime::writeText(pFunction->getFunctionName());
				CGRuntime::writeText("<\\\"\" + _compilerTemplateFunction_dispatching + \"\\\">' hasn't been implemented\");" + CGRuntime::endl());
			}
			CGRuntime::setProtectedArea(sFunctionName);
			if (CGRuntime::getProtectedArea(sFunctionName).empty()) {
				CGRuntime::writeText("\treturn \"\";" + CGRuntime::endl());
			}
			CGRuntime::writeText("}" + CGRuntime::endl() + CGRuntime::endl());
			CGRuntime::writeText("std::string " + sClassName + "::" + sFunctionName + "_compilerVarlist(");
			if (pFunction->isATemplateDispatcher()) {
				CGRuntime::writeText("const std::string& _compilerTemplateFunction_dispatching, ");
			}
			CGRuntime::writeText("CodeWorker::CppParsingTree_var** tParameters) throw(CodeWorker::UtlException) {" + CGRuntime::endl());
			CGRuntime::writeText("\treturn " + sFunctionName + "(");
			if (pFunction->isATemplateDispatcher()) {
				CGRuntime::writeText("_compilerTemplateFunction_dispatching");
			}
			iIndex = 0;
			for (j = pFunction->getParameters().begin(); j != pFunction->getParameters().end(); j++, iIndex++) {
				if ((j != pFunction->getParameters().begin()) || pFunction->isATemplateDispatcher()) CGRuntime::writeText(", ");
				char tcFormat[64];
				sprintf(tcFormat, "*(tParameters[%d])", iIndex);
				CGRuntime::writeText(tcFormat);
			}
			CGRuntime::writeText(");" + CGRuntime::endl());
			CGRuntime::writeText("}" + CGRuntime::endl() + CGRuntime::endl());
			if (pFunction->isATemplateDispatcher()) {
				CGRuntime::writeText("std::string " + sClassName + "::" + pFunction->getFunctionName() + "_compilerVarlist(CodeWorker::CppParsingTree_var** tParameters) throw(CodeWorker::UtlException) {" + CGRuntime::endl());
				CGRuntime::writeText("\treturn " + sFunctionName + "(\"\", ");
				iIndex = 0;
				for (j = pFunction->getParameters().begin(); j != pFunction->getParameters().end(); j++, iIndex++) {
					if (j != pFunction->getParameters().begin()) CGRuntime::writeText(", ");
					char tcFormat[64];
					sprintf(tcFormat, "*(tParameters[%d])", iIndex);
					CGRuntime::writeText(tcFormat);
				}
				CGRuntime::writeText(");" + CGRuntime::endl());
				CGRuntime::writeText("}" + CGRuntime::endl() + CGRuntime::endl());
			}
		}
		CGRuntime::writeText(CGRuntime::endl());
		CGRuntime::setProtectedArea("implementation");
	}
}
