#pragma hdrfile "jsdb.csm"
#include "rslib.h"
#include "jsdb.h"
#include "rs/wrap_jsdb.h"
#pragma hdrstop

#include <time.h>
#include "js/jsdate.h"
#include "js/jsconfig.h"

bool JSDBEnvironment::Startup(int memSize, int stackSize,void* global_private)
{
 if (!rt)
 {
   rt = JS_NewRuntime(memSize);
   if (!rt) return false;
   AutoDeleteRuntime = true;
 }
 if (!cx)
 {
   cx = JS_NewContext(rt, stackSize);
   if (!cx) return false;
   AutoDeleteContext = true;
 }

 InitGlobal(global_private);
 DefineProcessFunctions();
 DefineShellFunctions();
 JS_InitStandardClasses(cx, global);
 InitClasses();
 return true;
}

void JSDBEnvironment::InitClasses()
    {
     Stream_InitClass(cx, global);
     Record_InitClass(cx, global);
#ifndef JSDB_MINIMAL
     Table_InitClass(cx, global);
     Index_InitClass(cx,global);
     Server_InitClass(cx, global);
     Form_InitClass(cx,global);
     Mail_InitClass(cx, global);
     Image_InitClass(cx, global);
     Archive_InitClass(cx, global);
     Num_InitClass(cx, global);
#ifndef TBL_NO_SQL
     ODBC_InitClass(cx, global);
#endif
#ifdef XP_WIN
     ActiveX_InitClass(cx, global);
#endif
     Process_InitClass(cx, global);
#endif
    }

JSDBEnvironment::~JSDBEnvironment()
{
 if (AutoDeleteContext && cx) {JS_GC(cx); JS_DestroyContext(cx);}
 if (AutoDeleteRuntime && rt) JS_DestroyRuntime(rt);
 JS_ShutDown();
}

JSBool JSDBEnvironment::ExecScript(::Stream& data, const char* filename, int line)
{
   MemoryStream text;
   text.Append(data);

   bool ok = false;

#ifndef JSDB_MINIMAL
   if (Debugger)
    DebugScriptSource(Debugger,filename,line,text,text.size());
#endif

//  if (JS_BufferIsCompilableUnit(cx, global, text, text.size()))
    {
     jsval rval;
     uint16* l = (uint16*)(void*)(char*)text;
     if (*l == 0xFEFF)
        ok = JS_EvaluateUCScript(cx, global, l + 1, text.size()/2 -1,filename,line,&rval);
     else
        ok = JS_EvaluateScript(cx, global, text, text.size(),filename,line,&rval);
    }
//     JSScript* script = JS_CompileScript(cx,obj,text,text.size(),filename,line);
//     JSObject* o2 = JS_NewScriptObject(cx,script);
//     ok = JS_CallFunctionName(cx,o2,"exec",0,0,&rval);
//else if (!JS_IsExceptionPending(cx))
// {
//  JS_ReportError(cx,"File %s is not compilable.",filename);
// }

   if (!ok && !JS_IsExceptionPending(cx))
   {
    if (errorOnFailure)
        return JS_FALSE;
    JS_ReportError(cx,"Execution error in %s.",filename);
    return JS_FALSE;
   }

 return ok;
}
/**
JSBool Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
 GETENV;
 if (Env->SafeMode) RETBOOL(false);

 if (argc < 1) RETBOOL(false);
 JSString *str;
 JSBool ok = JS_FALSE;

   Stream* data;

   GETFILE(0,data);

   try
   {
    if (data)
    {
     int line = 1;
     if (argc > 1) if (ISSTR(1)) filename = STR(1);
     if (argc > 2) if (ISINT(2)) line = INT(2);
     return JSDB_ExecScript(Env,cx,*data,data->filename(),line);
    }
    else
    {
     if (!ISSTR(0)) RETBOOL(false);
     FileStream in(STR(0),Stream::OMBinary,Stream::ReadOnly);
     return JSDB_ExecScript(Env,cx,in,in.filename(),1);
    }
   }
   catch(xdb& x)
   {
    ERR_MSG(Load,"File open failure",TStr(x.why(), x.info()));
   }
}
*/
// ---

JSBool IsSafe(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
 GETENV;
 RETBOOL(Env->SafeMode);
}

static JSBool
SafeMode(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
 GETENV;
 int key = 0;
 if (argc > 0 && ISINT(0)) key = INT(0);
 if (Env->SafeMode)
  {
   if (key == Env->SafeMode)
    Env->SafeMode = 0;
   RETINT(0);
  }

 Env->SafeMode = clock() ^ Env->Magic;
 if (Env->SafeMode == 0) Env->SafeMode = clock() ^ Env->Magic;
 Env->Magic = Env->SafeMode;
 RETINT(Env->SafeMode);
}

static JSBool
ShouldStop(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
    GETENV;
    if (Env->checkInterrupt != NULL) Env->checkInterrupt(Env);
    JS_MaybeGC(Env->cx);

    //if (!Env->shouldStop) JS_GC(Env->cx);
    //garbage collection is always good now and again.

    RETBOOL(Env->shouldStop);
}


static JSBool

Restart(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
   GETENV;
   Env->shouldStop = true;
   Env->restart = true;

   return JS_TRUE;
}


static JSBool
GoToSleep(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
JS_MaybeGC(cx);
 GETENV;
 if (Env->shouldStop) return JS_TRUE;
 int32 ms = 0;
 if (argc) TOINT(0,ms);
 if (ms < 0) ms = 0;
 if (Env->checkInterrupt != NULL) Env->checkInterrupt(Env);
#ifdef XP_WIN
 if (!Env->shouldStop) SleepEx(ms,true);
#else
 if (!Env->shouldStop) usleep(ms*1000);
#endif
 return JS_TRUE;
}

static JSBool
SetCWD(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
    GETENV;
    if (Env->SafeMode) RETSTR("");
    #ifdef XP_WIN
    jschar path[1024];
    if (!GetCurrentDirectoryW(1023,(wchar_t*)path)) path[0]=0;
    path[1023]=0;

    if (argc > 0 && ISSTR(0))
     SetCurrentDirectoryW((const wchar_t*)WSTR(0));

    RETSTRW(path);
    #else
    char path[1024];
    if (!getcwd(path,1023)) path[0]=0;
    path[1023]=0;

    if (argc > 0 && ISSTR(0))
    {
     chdir(STR(0));
    }

    RETSTR(path);
    #endif
}

static JSBool
GetEnv(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
    if (argc == 0) ERR_COUNT(system,getenv);
    if (!ISSTR(0)) ERR_TYPE(system,getev,1,String);

    RETSTR(getenv(STR(0)));
}

static JSBool
Quit(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
   GETENV;
   Env->shouldStop = true;
   Env->restart = false;

   return JS_TRUE;
}

#ifdef XP_WIN

HKEY ResolveRoot(const char* root)
{
      if (!strncasecmp(root,"HKEY_LOCAL_MACHIN",17)) return HKEY_LOCAL_MACHINE;
 else if (!strncasecmp(root,"HKEY_CURRENT_USER",17)) return HKEY_CURRENT_USER;
 else if (!strncasecmp(root,"HKEY_CLASSES_ROOT",17)) return HKEY_CLASSES_ROOT;
 else return 0;
}

//regSetKey("hkey_local_machine\SOFTWARE\...","key","value");
static JSBool
RegSetKey(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
 if (argc != 3) ERR_COUNT(JSDB,RegSetKey);
 if (!ISSTR(0)) ERR_TYPE(JSDB,RegSetKey,1,String);
 if (!ISSTR(1)) ERR_TYPE(JSDB,RegSetKey,2,String);

 GETENV;
 if (Env->SafeMode) RETBOOL(false);

 const char* root = STR(0);
 TStr section(root);
 Replace(section,'/','\\');
 char* code = strchr(section,'\\');
 if (code) code++;
 HKEY r = ResolveRoot(root);

 JSString* j2;
 char * s2;
 GETSTRING(2)

 RETBOOL(RegSetKey(code,STR(1),s2,r));
}


//regGetKey("hkey_local_machine\SOFTWARE\...","key");
static JSBool
RegGetKey(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
 if (argc < 1) ERR_COUNT(JSDB,RegGetKey);
 if (!ISSTR(0)) ERR_TYPE(JSDB,RegGetKey,1,String);
 if (argc > 1 && !ISSTR(1)) ERR_TYPE(JSDB,RegGetKey,2,String);

 GETENV;
 if (Env->SafeMode) RETBOOL(false);

 const char* root = STR(0);
 TStr section(root);
 Replace(section,'/','\\');
 char* code = strchr(section,'\\');
 if (code) code++;
 HKEY r = ResolveRoot(root);

 TStr s;
 RegGetKey(code,argc > 1 ? STR(1) : 0,s,r);
 RETSTR(s);
}
#endif

static JSBool
ShellBrowse(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
 if (argc != 1) ERR_COUNT(JSDB,ShellBrowse);
 if (!ISSTR(0)) ERR_TYPE(JSDB,ShellBrowse,1,String);

 GETENV;
 if (Env->SafeMode) RETBOOL(false);

 char * file = STR(0);

#ifdef XP_WIN
 TStr s;
 RegGetKey("htmlfile\\shell\\open\\command","",s,HKEY_CLASSES_ROOT);

 RETINT(ShellExecute(GetFocus(),"open",file,NULL,NULL,SW_SHOWNORMAL));
#else
 int browsr=0;
 if (ISINT(1)) {  browsr = INT(1); }

 char exeC[1024]="\0";
 if(browsr==0) {
    sprintf(exeC,"mozilla %s >/dev/null 2>&1",file);
 } else if( browsr==1) {
    sprintf(exeC,"kfmclient exec %s >/dev/null 2>&1",file);
 } else if( browsr==2) {
    sprintf(exeC,"opera %s >/dev/null 2>&1",file);
 } else {
    RETINT(-1);
 }
 int retvb=system(exeC);
 RETINT(retvb);
#endif
}

static JSBool StartDebugger(JSContext *cx,
 JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
#ifdef JSDB_MINIMAL
 RETBOOL(false);
#else
JS_MaybeGC(cx);
 GETENV;
 if (argc == 0 || !ISSTR(0))
  {
   if (Env->Debugger)
   {
    JSDB_EndDebug(Env->rt,Env->Debugger);
    Env->Debugger = 0;
   }
   RETBOOL(false);
  }
 if (Env->SafeMode) RETBOOL(false);
 TStr address(STR(0));
 char* port = strchr(address,':');
 if (port) *port++ = 0;
 else port = "";
 if (Env->Debugger) JSDB_EndDebug(Env->rt,Env->Debugger);
 Env->Debugger = JSDB_StartDebug(Env->rt, address, atoi(port));
 RETBOOL(Env->Debugger != NULL);
#endif
}

static JSBool
directoryList(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval,bool dirs)
{
 GETENV;
 if (Env->SafeMode) RETBOOL(false);
 ENTERNATIVE(cx);

 TStringList files;
 #ifdef XP_WIN
 const char* search = "*.*";
#else
 const char* search = ".";
#endif
 if (argc > 0)
  if (ISSTR(0))
   search = STR(0);

#ifdef XP_WIN
 WIN32_FIND_DATA FindData;
 int skip = FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_OFFLINE;

 HANDLE finder = FindFirstFile(search,&FindData);
 if (finder != INVALID_HANDLE_VALUE)
 {
  do
  {
   if (FindData.cFileName[0] != '.' &&
       (FindData.dwFileAttributes & skip) == 0)
       if ((dirs && ((FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)) ||
           (!dirs && ((FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) ))
          files.Add(FindData.cFileName);
  } while (FindNextFile(finder,&FindData));

  FindClose(finder);
 }
#else

 DIR *ff;
 ff=opendir(search);
 if(ff==NULL) { perror("directoryList"); }

 struct dirent *dr;

 do {
  dr=readdir(ff);
  if(dr==NULL) { break; }
  if(dirs && dr->d_type==4) files.Add(dr->d_name);
  if(!dirs && dr->d_type!=4) files.Add(dr->d_name);
 } while (dr!=NULL);

 closedir(ff);
#endif

 if (!files.Count())
  RETOBJ(JS_NewArrayObject(cx,0,0));

 jsval * arr = new jsval[files.Count()];

 FOREACH(char*c, files)
   arr[i] = STRING_TO_JSVAL(ROOT(JS_NewStringCopyZ(cx,c)));
 DONEFOREACH

 JSObject * ret = JS_NewArrayObject(cx,files.Count(),arr);
 delete[] arr;
 RETOBJ(ret);
}


static JSBool
listFiles(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
 return directoryList(cx, obj, argc, argv, rval,false);
}
static JSBool
listDirs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
 return directoryList(cx, obj, argc, argv, rval,true);
}

static JSBool
jsCopyFile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
 if (argc != 2) ERR_COUNT(JSDB,CopyFile);
 if (!ISSTR(0)) ERR_TYPE(JSDB,CopyFile,1,String);
 if (!ISSTR(1)) ERR_TYPE(JSDB,CopyFile,2,String);
 GETENV;
 if (Env->SafeMode) RETBOOL(false);

 TStr oldfile(STR(0));
 TStr newfile(STR(1));
#ifdef XP_WIN
 Replace(oldfile,'/','\\');
 Replace(newfile,'/','\\');
 WStr o(oldfile);
 WStr n(newfile);
 RETBOOL(CopyFileW(o,n,false));
#else
 CopyFile(oldfile, newfile, false);
#endif
}

static JSBool
jsMoveFile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
 if (argc < 2) ERR_COUNT(JSDB,MoveFile);
 if (!ISSTR(0)) ERR_TYPE(JSDB,MoveFile,1,String);
 if (!ISSTR(1)) ERR_TYPE(JSDB,MoveFile,2,String);
 GETENV;
 if (Env->SafeMode) RETBOOL(false);

 TStr oldfile(STR(0));
 TStr newfile(STR(1));
#ifdef XP_WIN
 JSBool replace = 0;
 if (argc > 2) TOBOOL(2,replace);

 Replace(oldfile,'/','\\');
 Replace(newfile,'/','\\');
 WStr o(oldfile);
 WStr n(newfile);
 DWORD opts = MOVEFILE_COPY_ALLOWED;
 if (replace) opts |= MOVEFILE_REPLACE_EXISTING;

 RETBOOL(MoveFileExW(o,n,opts));
#else
 if(rename(oldfile,newfile)==0) { RETBOOL(true); }
    else { RETBOOL(false); }
#endif
}

static JSBool
FileExists(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
 if (argc != 1) ERR_COUNT(JSDB,FileExists);
 if (!ISSTR(0)) ERR_TYPE(JSDB,FileExists,1,String);
 GETENV;
 if (Env->SafeMode) RETBOOL(false);

 TStr oldfile(STR(0));
#ifdef XP_WIN
 Replace(oldfile,"/",'\\');
#endif
 RETBOOL(FileExists(oldfile));
}


/** returns an object with file information:
  attributes:
  date: last modified date
  creation: creation date, if available
  attributes:
  size
*/

static JSBool
FileStatus(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
 if (argc != 1) ERR_COUNT(JSDB,FileStatus);
 if (!ISSTR(0)) ERR_TYPE(JSDB,FileStatus,1,String);
 GETENV;
 if (Env->SafeMode) RETOBJ(NULL);

 TStr oldfile(STR(0));
 if (!*oldfile) RETOBJ(NULL);

#ifdef XP_WIN
 Replace(oldfile,"/",'\\');

 WStr w(oldfile);
 WIN32_FILE_ATTRIBUTE_DATA attr;
 if (!GetFileAttributesExW(w,GetFileExInfoStandard,&attr)) RETOBJ(NULL);

 JSObject* o = JS_NewObject(cx,NULL,NULL,NULL);
 JS_AddRoot(cx, &o);
 MemoryStream attrs;

 if (attr.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) attrs << "archive,";
 if (attr.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) attrs << "compressed,";
 if (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) attrs << "directory,";
 if (attr.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) attrs << "hidden,";
 if (attr.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) attrs << "offline,";
 if (attr.dwFileAttributes & FILE_ATTRIBUTE_READONLY) attrs << "readonly,";
 if (attr.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) attrs << "system,";
 if (attr.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) attrs << "temporary,";
#else

 JSObject* o = JS_NewObject(cx,NULL,NULL,NULL);
 JS_AddRoot(cx, &o);
 MemoryStream attrs;

 struct stat ms;
 int x = stat(oldfile,&ms);
 if (x == -1)
   RETOBJ(NULL);
 if (S_ISDIR(ms.st_mode)) attrs << "directory,";
 if (S_ISLNK(ms.st_mode)) attrs << "symlink,";
 if (S_ISREG(ms.st_mode)) attrs << "regular,";
 if (S_ISCHR(ms.st_mode)) attrs << "chardev,";
 if (S_ISBLK(ms.st_mode)) attrs << "blockdev,";
 if (S_ISFIFO(ms.st_mode)) attrs << "fifo,";
 if (S_ISSOCK(ms.st_mode)) attrs << "socket,";

// if (mystat.st_mode & S_IFMT == S_IWRITE) return 1; //read only
// return JS_FALSE; //read and write
#endif
 JSString * s = JS_NewStringCopyZ(cx,attrs);
 jsval val = STRING_TO_JSVAL(s);
 JS_SetProperty(cx,o,"attributes",&val);

#ifdef XP_WIN
 if (attr.nFileSizeHigh == 0 && INT_FITS_IN_JSVAL(attr.nFileSizeLow))
   val = INT_TO_JSVAL(attr.nFileSizeLow);
 else
 {
  double d = 1 << 32;
  d = d * (double)(attr.nFileSizeHigh) + (double)(unsigned long)attr.nFileSizeLow;
  val = DOUBLE_TO_JSVAL(d);
 }
#else
   val = INT_TO_JSVAL(ms.st_size);
#endif
 JS_SetProperty(cx,o,"size",&val);

#ifdef XP_WIN
 SYSTEMTIME t;
 FileTimeToSystemTime(&attr.ftLastWriteTime,&t);
 JSObject* d = js_NewDateObject(cx,t.wYear,t.wMonth-1,t.wDay,t.wHour,t.wMinute,t.wSecond);
 val = OBJECT_TO_JSVAL(d);
 JS_SetProperty(cx,o,"date",&val);

 FileTimeToSystemTime(&attr.ftCreationTime,&t);
 d = js_NewDateObject(cx,t.wYear,t.wMonth-1,t.wDay,t.wHour,t.wMinute,t.wSecond);
 val = OBJECT_TO_JSVAL(d);
 JS_SetProperty(cx,o,"creation",&val);
#else
 struct tm t;

 t=*localtime(&ms.st_mtime);
 JSObject* d = js_NewDateObject(cx,t.tm_year+1900,t.tm_mon,t.tm_mday,t.tm_hour,t.tm_min,t.tm_sec);
 val = OBJECT_TO_JSVAL(d);
 JS_SetProperty(cx,o,"date",&val);

 t=*localtime(&ms.st_ctime);
 d = js_NewDateObject(cx,t.tm_year+1900,t.tm_mon,t.tm_mday,t.tm_hour,t.tm_min,t.tm_sec);
 val = OBJECT_TO_JSVAL(d);
 JS_SetProperty(cx,o,"creation",&val);
#endif


 JS_RemoveRoot(cx,&o);
 RETOBJ(o);
}

static JSBool
ShellExec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
JS_MaybeGC(cx);
 GETENV;
 if (argc == 0) ERR_COUNT(JSDB,ShellExec);
 if (!ISSTR(0)) ERR_TYPE(JSDB,ShellExec,1,String);
 if (!Env->AllowExec) RETBOOL(false);

#ifdef XP_WIN
 char* params = 0;
 if (argc > 1 && ISSTR(1)) params=STR(1);
 char* dir = 0;
 if (argc > 2 && ISSTR(2)) dir=STR(2);

 HINSTANCE proc =
    ShellExecute(NULL,NULL,STR(0),params,dir,SW_SHOWNORMAL);

 RETBOOL((int)proc > 32);
#else
 RETBOOL(system(STR(0)) != -1);
#endif
}

static JSFunctionSpec shell_functions2[] = {
    {"sleep",           GoToSleep,      0},
    {"quit",            Quit,           0},
    {"exit",            Quit,           0},
    {"jsShouldStop",      ShouldStop,     0},
    {"jsRestart",         Restart,        0},
    {"jsSafeMode",      SafeMode, 0},
    {"jsIsSafe",        IsSafe,0},
    {0}
};

static JSFunctionSpec shell_functions3[] = {
    {"copyFile",        jsCopyFile,       2},
    {"moveFile",        jsMoveFile,       2},
    {"openBrowser",     ShellBrowse,    1},
    {"fileExists",      FileExists,     1},
#ifdef XP_WIN
    {"regGetKey",       RegGetKey,     2},
    {"regSetKey",       RegSetKey,     3},
#endif
    {"listFiles",       listFiles,           1},
    {"listFolders",       listDirs,           1},
    {"listDirectories",       listDirs,           1},
    {"jsShellExec",        ShellExec,3},
    {"jsDebug",         StartDebugger,           0},
    {0}
};

extern JSBool
Options(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);

extern JSBool
BuildDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);

extern JSBool
Version(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);

static JSFunctionSpec system_functions[] = {
    {"attributes",     FileStatus, 0},
    {"browse",     ShellBrowse,    1},
//    {"buildDate",       BuildDate,    0},
    {"copy",        jsCopyFile,       2},
    {"debug",         StartDebugger,           0},
    {"directories",       listDirs,           1},
    {"execute",        ShellExec,3},
    {"exists",      FileExists,     1},
    {"exit",            Quit,           0},
    {"files",       listFiles,           1},
    {"folders",       listDirs,           1},
    {"getenv",          GetEnv, 1},
    {"setcwd",          SetCWD, 1},
#ifdef XP_WIN
    {"getKey",       RegGetKey,     2},
    {"setKey",       RegSetKey,     3},
#endif
    {"isSafe",        IsSafe,0},
    {"move",        jsMoveFile,       2},
    {"options",         Options,      2},
    {"quit",            Quit,           0},
    {"restart",         Restart,        0},
    {"safeMode",      SafeMode, 0},
    {"shouldStop",      ShouldStop,     0},
    {"sleep",           GoToSleep,      0},
//    {"version",         Version,      0},
    {0}
};

JSObject* JSDBEnvironment::DefineSystemObject(JSFunctionSpec* extra)
{
 JSObject * o= JS_NewObject(cx, NULL, NULL, NULL);
 jsval val = OBJECT_TO_JSVAL(o);
 JSBool foundp=0;
 JS_DefineFunctions(cx, o, system_functions);
 if (extra) JS_DefineFunctions(cx, o, extra);
 JS_SetProperty(cx, global, "system", &val);
 JS_SetPropertyAttributes(cx, global,"system",JSPROP_PERMANENT, &foundp);
 jsval ptr = INT_TO_JSVAL(JS_VERSION);
 JS_SetProperty(cx, o,"version",&ptr);
 ptr = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,__DATE__));
 JS_SetProperty(cx, o,"buildDate",&ptr);

 return o;
}

void JSDBEnvironment::DefineProcessFunctions()
{
 JS_DefineFunctions(cx, global, shell_functions2);
}

void JSDBEnvironment::DefineShellFunctions()
{
 JS_DefineFunctions(cx, global, shell_functions3);
}
