2005/5/9

     
 

System.cpp

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// ALL RIGHTS RESERVED
//
// This file is part of ACDK.
// artefaktur provides this software "as is" without express or implied warranty.
// Any commercial use of this software requires a license.
//
// $Header: /cvsroot/acdk/acdk/acdk_core/src/acdk/lang/System.cpp,v 1.97 2005/05/02 23:09:42 kommer Exp $

#include <acdk.h>

#include <stdlib.h>

#ifdef HAS_UNISTD_H
#  include <unistd.h>
#endif
/FONT>

#include "System.h"
#include "Runtime.h"
#include "ThreadLocal.h"
#include "StackOverflowError.h"
#include "ArithmeticException.h"

#include "sys/core_value_scope.h"
#include <acdk/util/Vector.h>
#include <acdk/lang/Long.h>
#include <acdk/util/Properties.h>
#include <acdk/util/Locale.h>
#include <acdk/io/ConsoleReader.h>
#include <acdk/io/ConsoleWriter.h>
#include <acdk/io/ConsoleCharWriter.h>
#include <acdk/io/ConsoleCharReader.h>
#include <acdk/util/Date.h>
#include <acdk/util/StringTokenizer.h>
#include <acdk/util/logging/LogManager.h>
#include <acdk/io/InputReader.h>
#include <acdk/io/StringReader.h>
#include <acdk/io/NullWriter.h>

#include <acdk/io/PrintWriter.h>
#include <acdk/util/Vector.h>
#include <acdk/io/FileReader.h>
#include <acdk/io/FileWriter.h>
#include <acdk/io/File.h>
#include <acdk/locale/UCS2Encoding.h>

#include "SystemIntern.h"

#if defined(ACDK_USE_SYNC_SIGNALS)
# include "signal.h"
#endif
/FONT>

namespace acdk {
namespace lang {



//using namespace acdk::io;
//using namespace acdk::util;
using sys::eofl;
using sys::coreout;

USING_CLASS(acdk::util::, Properties);
USING_CLASS(acdk::io::, ConsoleReader);
USING_CLASS(acdk::io::, ConsoleWriter);
USING_CLASS(acdk::io::, InputReader);
USING_CLASS(acdk::io::, PrintWriter);
USING_CLASS(acdk::io::, File);
USING_CLASS(acdk::io::, FileReader);


acdk::io::RInputReader System::in;
acdk::io::RPrintWriter System::out;
acdk::io::RPrintWriter System::err;
int System::_argc = 0;
char** System::_argv = 0;

OUT(int) 
System::getSystemStatus()
{
  static int _systemStatus = 0;
  return _systemStatus;
}

#if defined(ACDK_OS_WIN32)
bool System::_unixMode = false;
#endif
/FONT>
bool System::hasConsole = true; 

//static
sys::ObjectHeap::HeapType System::defaultHeapType = sys::ObjectHeap::PA_Heap;
//sys::ObjectHeap::HeapType System::defaultHeapType = sys::ObjectHeap::RC_Heap;
SystemImpl::SystemImpl()
: acdk::lang::Object()
, _properties(new acdk::util::Properties())
, _environment(new acdk::util::Properties())
, _argumentHolder(0)
{

}

#if !defined(DOXYGENONLY)
/// @internal
class SystemPropertiesListener
: extends acdk::lang::Object
, implements acdk::util::PropertiesChangeListener
{
public:
  SystemPropertiesListener() {}
  virtual void propertyChanged(acdk::util::PropertiesChangeAction action, IN(acdk::util::RProperties) props, IN(RString) key, IN(acdk::lang::Object) value) 
  {

  }
};
#endif //!defined(DOXYGENONLY)


SystemImpl::SystemImpl(int argc, char* argv[], char** envptr)
: acdk::lang::Object()
, _properties(new Properties())
, _environment(new acdk::util::Properties())
, _systemPropertiesListener(new SystemPropertiesListener())
, _argumentHolder(0)
{
  RStringArray args = new StringArray(argc);
  int i;
  for (i = 0; i < argc; i++) {
    args[i] = SCS(argv[i]);
  }
  _argumentHolder = new ArgumentHolder(args);
  init(argc, argv, envptr, args);
}

//virtual
SystemImpl::~SystemImpl()
{
  if (_argumentHolder != 0) {
    delete _argumentHolder;
    _argumentHolder = 0;
  }
}

void
SystemImpl::setProperties(IN(acdk::util::RProperties) props)
{
  _properties = props;
}

//static 
RStringArray 
SystemImpl::getAcdkPath()
{
  if (_acdkPath != Nil)
    return _acdkPath;

  RString p = System::getProperty("ACDKPATH");
  if (p != Nil && p->length() > 0)
    _acdkPath = acdk::util::StringTokenizer(p, acdk::io::File::pathSeparator()).allToken();
  if (_acdkPath == Nil)
    _acdkPath = new StringArray(0);
  RString acdkhome = System::getAcdkHome();
  RString acdktoolshome = System::getAcdkToolsHome();
  if (_acdkPath->find(acdkhome) == -1)
    _acdkPath->insert(0, acdkhome);

  if (acdkhome->equals(acdktoolshome) == false)
  {
    _acdkPath->insert(0, acdktoolshome);
  }
  return _acdkPath;
}



//static
void
System::exit(int status)
{
  if (_gSystem != Nil)
    _gSystem->deinit();
  _gSystem = Nil;
  ::exit(status);
}

//static
bool
System::gc()
{
    // gc-ing only current thread
  return sys::ObjectHeap::gc(true);
}

//static
int&
System::getArgc()
{
  if (_gSystem->_argumentHolder == 0) 
  {
    static int retint = 0;
    return retint;
  }
  return _gSystem->_argumentHolder->getArgc();
}
//static
char**
System::getArgv()
{
  if (_gSystem->_argumentHolder == 0)
    return 0;
  return _gSystem->_argumentHolder->getArgv();
}
//static
int&
System::getOriginalArgc()
{
    return _argc;
}
//static
char**
System::getOriginalArgv()
{
    return _argv;
}


//static
RSystemImpl System::_gSystem = Nil;

//static
RSystemImpl
System::getSystem()
{
  if (System::_gSystem == Nil) {
    // acdk_core is loaded dynamically (through scripting)
    _gSystem = new SystemImpl();
    //int argc, char* argv[], char** envptr, RStringArray args
    static char* nullargv[] = { 0 };
#if defined(ACDK_OS_WIN32) && !defined(__MWERKS__) && !defined(ACDK_OS_CYGWIN32)
    _gSystem->init(0, nullargv, _environ, new StringArray(0));
#else
/FONT>
    _gSystem->init(0, nullargv, 0, new StringArray(0));
#endif
/FONT>
  }
  return _gSystem;
}

RString 
System::getSystemCmdLineOps()
{
  return
    "common acdk options:\n"
    "  -acdk-home=<pathname>   set the path to acdk home directory\n"
    "  -acdk-home <pathname>\n"
    "  -acdk-tools-home=<pathname>   set the path to acdk tools home directory\n"
    "  -acdk-tools-home <pathname>\n"
    "  -acdk-path <pathlist>   Env path list for ACDKPATH, to find acdk libraries\n"
    "  -Dkey=value             Define a entry in the System properties\n"
    "  -acdk-gc                run with mark/sweep garbage collection (experimental)\n"
    "  -acdk-rc                run with reference counting garbage collection\n"
    "  -acdk-rcgc              run with reference counting and mark/sweek gc\n"
    "  -acdk-pa                run with PageAllocator garbage collection (default)\n"
    "  -acdk-st                run in single thread mode\n"
    "  -acdk-sp                run on a single processor\n"
    "  -cygpath                on windows platform runs in cygwin enviromnent\n"
    "  -acdk-enc <char enc>    use encoding for console in/output\n"
    "  -acdk-maxmem <number>   limit memory usage -1 no limit, otherwise number of MB\n"
    "  -loglevel <loglevel>    integer [0(all)-65535(Non)] or \n"
    "                                  [All|Trace|Debug|Info|Warn|Note|Error|Fatal|None]\n"
    "                          if a following -logto option is given, the logger will be configured\n"
    "                          with this LogLevel.\n"
    "  -logcat <category>      Log only with category. a following -logto option will be configured\n"
    "                          with this category.\n"
    "  -logto <consumer>       log consumer indentifier or file.\n"
    "                          known identifier are [out|err|dbg]\n"
    ;
}

RStringArray
SystemImpl::_filterArgs(IN(RStringArray) arguments)
{
  const char* mhstr = "-acdk-home=";
  const char* mhstr2 = "-acdk-home";
  const char* mthstr = "-acdk-tools-home=";
  const char* mthstr2 = "-acdk-tools-home";
  const char* mapstr = "-acdk-path";
  const char* acdk_gc = "-acdk-gc";
  const char* acdk_rc = "-acdk-rc";
  const char* acdk_rcgc = "-acdk-rcgc";
  const char* acdk_st = "-acdk-st";
  const char* acdk_pa = "-acdk-pa"; // using PageAllocator instead of RC_GC_Heap
  const char* acdk_console_encoding = "-acdk-enc";
  const char* acdk_maxmem = "-acdk-maxmem";
  const char* cygpath = "-cygpath";
  const char* acdk_tmc = "-acdk-tmc"; // trace method call
  RStringArray args = arguments;
  if (args == Nil) // if loaded lately from another scripting host
    return new StringArray(0);
  
  for (int i = 0; i < args->length(); i++) 
  {
    bool removeelement = false;
    RString arg = args[i];
    if (arg->startsWith(mhstr) == true) 
    {
      RString mh = args[i]->substr(strlen(mhstr));
      System::getProperties()->setProperty("ACDKHOME", mh);
      removeelement = true;
    } 
    else if (arg->equals(mhstr2) == true) 
    {
      ++i;
      System::getProperties()->setProperty("ACDKHOME", args[i]);
      args = acdk::util::Arrays::removeElement(args, i);
      --i;
      args = acdk::util::Arrays::removeElement(args, i);
      --i;
      removeelement = false;
    } 
    else if (arg->startsWith(mthstr) == true) 
    {
      RString mh = arg->substr(strlen(mhstr));
      System::getProperties()->setProperty("ACDK_TOOLS_HOME", mh);
      removeelement = true;
    } 
    else if (arg->equals(mthstr2) == true) 
    {
      ++i;
      System::getProperties()->setProperty("ACDK_TOOLS_HOME", args[i]);
      args = acdk::util::Arrays::removeElement(args, i);
      --i;
      args = acdk::util::Arrays::removeElement(args, i);
      --i;
      removeelement = false;
    } 
    else if (arg->equals(mapstr) == true)
    {
      ++i;
      System::getProperties()->setProperty("ACDKPATH", args[i]);
       args = acdk::util::Arrays::removeElement(args, i);
      --i;
      args = acdk::util::Arrays::removeElement(args, i);
      --i;
      removeelement = false;
    }
    else if (arg->equals(acdk_st) == true || arg->equals("-acdk-sp") == true) 
    {
      ObjectBase::singleThreaded = true;
      if (arg->equals("-acdk-sp") == true)
        acdk::lang::sys::core_atomicop::singleProcessor = true;
      removeelement = true;
    } 
    else if (arg->equals(acdk_tmc) == true) 
    {
      Runtime::_traceMethodCalls = true;
      removeelement = true;
    } 
    else if (arg->equals(acdk_pa) == true ||
             arg->equals(acdk_gc) == true ||
             arg->equals(acdk_rc) == true ||
             arg->equals(acdk_rcgc) == true
      ) 
    {
      removeelement = true;
    }
    else if (arg->equals(acdk_console_encoding) == true)
    {
      ++i;
      System::getProperties()->setProperty("user.encoding", args[i]);
      args = acdk::util::Arrays::removeElement(args, i);
      --i;
      args = acdk::util::Arrays::removeElement(args, i);
      --i;
      removeelement = false;
    }
    else if (arg->equals(acdk_maxmem) == true)
    {
      ++i;
      jlong num = acdk::lang::Long::parseLong(args[i]);
      if (num != -1)
        num = num * 1024 * 1024;
      System::setMaxMemoryUsage(num);
      System::setThreadMaxMemoryUsage(num);
      
      args = acdk::util::Arrays::removeElement(args, i);
      --i;
      args = acdk::util::Arrays::removeElement(args, i);
      --i;
      removeelement = false;
    }
    else if (arg->startsWith("-D") == true)
    {
      RString targ = arg->substr(2);
      int idx = targ->indexOf('=');
      if (idx != -1)
      {
        RString key = targ->substr(0, idx);
        RString value = targ->substr(idx + 1);
        System::setProperty(key, value);
        removeelement = true;
      }
    }
#if defined(ACDK_OS_WIN32)
    else if (arg->equals(cygpath) == true)
    {
      System::_unixMode = true;
      removeelement = true;
    }
#endif
/FONT>
    if (removeelement == true) 
    {
      args = acdk::util::Arrays::removeElement(args, i);
      --i;
    }
  }
  return acdk::util::logging::LogManager::parseCommandLine(args);
}

void 
_initAcdkHome()
{
  RString s = System::getProperty("ACDKHOME");
  if (s != Nil)
    return;
  s = System::getProperty("ACDK_HOME");
  if (s != Nil)
  {
    System::setProperty("ACDKHOME", s);
    return;
  }
  RString moddir = System::getModuleDir();
  moddir = acdk::io::File(moddir).getParentFile()->getCanonicalPath();
  System::setProperty("ACDKHOME", moddir);
}


//static 
RString 
System::getAcdkHome() 
{
  RString s = System::getProperty("ACDKHOME");
  if (s != Nil)
    return s;
  _initAcdkHome();
  s = System::getProperty("ACDKHOME");
  return s;
}

//static 
RString 
System::getAcdkToolsHome()
{
  RString s = System::getProperty("ACDK_TOOLS_HOME");
  if (s != Nil)
    return s;
  RString moddir = System::getModuleDir();
  moddir = acdk::io::File(moddir).getParentFile()->getCanonicalPath();
  System::setProperty("ACDK_TOOLS_HOME", moddir);
  return moddir;
  //return getAcdkHome();
}

//static 
RStringArray 
System::getAcdkPath()
{
  return getSystem()->getAcdkPath();
}

//static 
void 
System::addAcdkPath(IN(RString) dir)
{
   getSystem()->getAcdkPath()->append(dir);
}
  
//static 
void 
System::insertAcdkPath(IN(RString) dir)
{
  getSystem()->getAcdkPath()->insert(0, dir);
}

//virtual
RStringArray
SystemImpl::init(int argc, char* argv[], char** envptr, IN(RStringArray) arguments)
{
  System::_argc = argc;
  System::_argv = argv;
  _mainThread = new Thread(MainThreadType);
  _loadEnvProperties(envptr);
  
  _loadAppProperties();
  _unfilteredArgs = arguments;
  RStringArray args = _filterArgs(arguments);
  _filteredArgs = args;
  _initAcdkHome();
  
  //RConsoleReader cr = new ConsoleReader(ConsoleReader::Cin);
  //System::in = new InputReader((::acdk::io::RReader)cr);
    
  if (System::hasConsole == true)
    System::in = new InputReader((::acdk::io::RCharReader)new acdk::io::ConsoleCharReader());
  else
    System::in = new InputReader((::acdk::io::RCharReader)new acdk::io::StringReader(""));
  System::registerStaticReference(System::in);

  //System::registerStaticReference(System::in->getIn());
  //acdk::locale::REncoding uc2encoding = acdk::locale::UCS2Encoding::getUCS2Encoding();
  //System::out = new PrintWriter(new ConsoleWriter(ConsoleWriter::Cout), uc2encoding->getEncoder());
  if (System::hasConsole == true)
    System::out = new PrintWriter((::acdk::io::RCharWriter)new acdk::io::ConsoleCharWriter(acdk::io::CoutOutChannel));
  else
    System::out = new PrintWriter((::acdk::io::RWriter)new acdk::io::NullWriter());

  System::registerStaticReference(System::out);
  //System::registerStaticReference(System::out->getOut());
  //System::err = new PrintWriter(new ConsoleWriter(ConsoleWriter::Cerr), uc2encoding->getEncoder());
  if (System::hasConsole == true)
    System::err = new PrintWriter((::acdk::io::RCharWriter)new acdk::io::ConsoleCharWriter(acdk::io::CerrOutChannel));
  else
    System::err = new PrintWriter((::acdk::io::RWriter)new acdk::io::NullWriter());
  System::registerStaticReference(System::err);
  //System::registerStaticReference(System::err->getOut());
  System::getSystemStatus() |= SystemStatusConfigLoaded;
  return args;
}


//virtual
void
SystemImpl::deinit()
{
  Thread::removeSystemThread();
  Runtime::unregisterAllEventHandler(0);
  sys::ObjectHeap::clearAllStaticReferences();
  _mainThread = Nil;
}

//virtual
void
SystemImpl::reinit()
{
  RString moddir = System::getModuleDir();
  RString modname = System::getModuleName();
  File f(moddir, modname + ".cfg");
  if (f.exists() == false)
    return;
  RProperties def = (_properties == Nil ? RProperties(Nil) : _properties->defaults());
  FileReader fin(SR(File, f));
  _properties = new Properties(def);
  _properties->load((::acdk::io::RReader)SR(FileReader, fin));
  
}

//static
jlong
System::currentTimeMillis()
{
  return acdk::util::Date::getTickCount();
}


void
SystemImpl::_loadEnvProperties(char** envptr)
{
  if (envptr == 0)
    return;
  for (; *envptr != 0; envptr++) {
    RString tstr = SCS(*envptr);
    int fpos = -1;
    if ((fpos = tstr->indexOf(RString("="))) != -1) {
      if (tstr->length() > fpos + 1)
      {
        _properties->setProperty(tstr->substring(0, fpos), tstr->substring(fpos + 1));
        _environment->setProperty(tstr->substring(0, fpos), tstr->substring(fpos + 1));
      }
      else
      {
        _properties->setProperty(tstr->substring(0, fpos), "");
        _environment->setProperty(tstr->substring(0, fpos), "");
      }
    }
  }
}

void
SystemImpl_initStandardPropertyValues(IN(RProperties) props)
{
  /* from java
    java.version Java Runtime Environment version 
java.vendor Java Runtime Environment vendor 
java.vendor.url Java vendor URL 
java.home Java installation directory 
java.vm.specification.version Java Virtual Machine specification version 
java.vm.specification.vendor Java Virtual Machine specification vendor 
java.vm.specification.name Java Virtual Machine specification name 
java.vm.version Java Virtual Machine implementation version 
java.vm.vendor Java Virtual Machine implementation vendor 
java.vm.name Java Virtual Machine implementation name 
java.specification.version Java Runtime Environment specification version 
java.specification.vendor Java Runtime Environment specification vendor 
java.specification.name Java Runtime Environment specification name 
java.class.version Java class format version number 
java.class.path Java class path 
java.library.path List of paths to search when loading libraries 

  java.compiler Name of JIT compiler to use 
java.ext.dirs Path of extension directory or directories 

user.dir User's current working directory 
*/
  props->setProperty("acdk.vm.version", Integer::toString(ACDK_VERSION_NUMBER));
  props->setProperty("acdk.vm.vendor", "Ing.Buero Kommer, Artefaktur");
  props->setProperty("acdk.vm.name", ACDK_VERSION_STRING);

#if defined(ACDK_OS_WIN32)
  props->setProperty("acdk.io.tmpdir", System::getProperty("TEMP"));
  props->setProperty("user.name", System::getProperty("USERNAME"));
  props->setProperty("user.home", System::getProperty("HOMEDRIVE") + System::getProperty("HOMEPATH"));
  props->setProperty("line.separator", "\n\r");
  props->setProperty("os.name", System::getProperty("OS"));
  props->setProperty("os.arch", System::getProperty("PROCESSOR_ARCHITECTURE"));
  
#else // asuming unix
  props->setProperty("acdk.io.tmpdir", System::getProperty("TMP"));
  props->setProperty("user.name", System::getProperty("LOGNAME"));
  props->setProperty("user.home", System::getProperty("HOME"));
  props->setProperty("line.separator", "\n");
  props->setProperty("os.name", System::getProperty("OSTYPE"));
  props->setProperty("os.arch", System::getProperty("HOSTTYPE"));
#endif
/FONT>
  // user.dir will not set, use File::getCWD()
  
  props->setProperty("file.separator", File::separator());
  props->setProperty("path.separator", File::pathSeparator());

  RString encoding = "ASCII";
  RString language = "en";
  RString country = "US";
  acdk::util::Locale::getSystemLocaleValues(language, country, encoding);
  // we have to do this, otherwise Double/Float::toString() doesn't work like expected
  acdk::util::Locale::setSystemLocale(acdk::util::Locale::getUS(), acdk::util::SysLocaleNumberic);
  props->setProperty("user.language", language);
  props->setProperty("user.region", country);
  props->setProperty("user.variant", "");
  props->setProperty("user.encoding", encoding);
}

void
SystemImpl_loadAcdkProperties()
{
  RString cfgfile = System::getAcdkToolsHome() + File::separator() + "cfg" + File::separator() + "acdk.cfg";
  File f(cfgfile);
  if (f.exists() == false)
    return;
  FileReader fin(SR(File, f));
  RProperties props = new Properties(System::getProperties());
  SystemImpl_initStandardPropertyValues(props);
  props->load((::acdk::io::RReader)SR(FileReader, fin));
  System::setProperties(props);
}

void
SystemImpl::_loadAppProperties()
{
  SystemImpl_loadAcdkProperties();
  RString moddir = System::getModuleDir();
  RString modname = System::getModuleName();
  File tf(moddir, modname + ".cfg");
  if (tf.exists() == false)
  {
    if (modname->endsWith("_r") == true || modname->endsWith("_d") == true)
      modname = modname->substr(0, modname->length() - 2);
    else
      return;
  }
  File f(moddir, modname + ".cfg");
  if (f.exists() == false)
    return;

  FileReader fin(SR(File, f));
  _properties = new Properties(_properties);
  _properties->load((::acdk::io::RReader)SR(FileReader, fin));
  _systemPropertiesListener = new SystemPropertiesListener();
  _properties->addPropertyChangeListener(_systemPropertiesListener);
}

//static
RProperties
System::getProperties()
{
  return System::getSystem()->properties();
}

//static 
RStringArray 
System::getArguments()
{
  return System::getSystem()->getFilteredArgs();
}

//static 
RStringArray 
System::getUnfilteredArguments()
{
  return System::getSystem()->getUnfilteredArgs();
}

//static 
acdk::util::RProperties 
System::getEnvironment()
{
  return System::getSystem()->environment();
}

RProperties
SystemImpl::properties()
{
  return _properties;
}

RProperties
SystemImpl::environment()
{
  return _environment;
}



//static
RString
System::getProperty(IN(RString) key)
{
  return getProperties()->getProperty(key);
}

//static
RString
System::getProperty(IN(RString) key, IN(RString) def)
{
  return getProperties()->getProperty(key, def);
}

//static
void
System::reinit()
{
  RSystemImpl sys = getSystem();
  sys->reinit();
}

//static
void
System::setProperties(IN(RProperties) props)
{
  RSystemImpl sys = getSystem();
  sys->setProperties(props);
}

//static
RString
System::setProperty(IN(RString) key, IN(RString) value)
{
  return RString(getProperties()->setProperty(key, value));
}

//static
void
System::setErr(IN(acdk::io::RPrintWriter) newerr)
{
  System::err = newerr;
  registerStaticReference(System::err);
  //registerStaticReference(System::err->getOut());
}

//static
void
System::setIn(IN(acdk::io::RInputReader) newin)
{
  System::in = newin;
  registerStaticReference(System::in);
  //registerStaticReference(System::in->getIn());
}

//static
void
System::setOut(IN(acdk::io::RPrintWriter) newout)
{
  System::out = newout;
  registerStaticReference(System::out);
  //registerStaticReference(System::out->getOut());
}

void
prefilterArgs(int argc, char* argv[], char** envptr, const char** addargs)
{
  sys::ObjectHeap::HeapType oldHeapType = System::defaultHeapType;

  for (int i = 1; i < argc; i++) 
  {
    if (strcmp(argv[i], "-acdk-pa") == 0)
      System::defaultHeapType = sys::ObjectHeap::PA_Heap;
    else if (strcmp(argv[i], "-acdk-rc") == 0)
      System::defaultHeapType = sys::ObjectHeap::RC_Heap;
    else if (strcmp(argv[i], "-acdk-rcgc") == 0)
      System::defaultHeapType = sys::ObjectHeap::RC_GC_Heap;
    else if (strcmp(argv[i], "-acdk-gc") == 0)
      System::defaultHeapType = sys::ObjectHeap::GC_Heap;
  }
  if (System::defaultHeapType != oldHeapType)
  {
    sys::ObjectHeap::pushFrame(System::defaultHeapType, sys::HeapIsThread, "MainHeap");
  }
}

namespace sys {
  
  void cleanup_system_objects();
} // namespace sys
// this is a temp-value while system is initializing itself
static unsigned int __SP = 0;

void exit_func()
{
  if (::acdk::lang::sys::core_system::getState() == ::acdk::lang::sys::InMain)
    sys::coreout << "Process terminating via exit" << sys::eofl;
  ::acdk::lang::sys::core_system::setState(::acdk::lang::sys::AfterMain);
  System::getSystemStatus() &= ~(SystemStatusStartMain | SystemStatusInUsersMain);
  System::getSystemStatus() |= SystemStatusAfterUsersMain | SystemStatusAfterMain;
  
}
void terminate_func()
{
  ::acdk::lang::sys::core_system::setState(::acdk::lang::sys::AfterMain);
  System::getSystemStatus() &= ~(SystemStatusStartMain | SystemStatusInUsersMain);
  System::getSystemStatus() |= SystemStatusAfterUsersMain | SystemStatusAfterMain;
  sys::coreout << "Process terminating via terminate" << sys::eofl;
}

#if defined(ACDK_USE_MSC_STRUCTURED_C_HANDLING)
LONG ExceptionFilter(LPEXCEPTION_POINTERS pep) 
{
  if (pep->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION 
      //&& pep->ExceptionRecord->ExceptionInformation[0] == 0   // try to read (1 would be write)
      //&& pep->ExceptionRecord->ExceptionInformation[1] == 0 // address 0x0000000
      )
  {
    StringBuffer sb;
    sb << "NullPointer exception while try to ";
    if (pep->ExceptionRecord->ExceptionInformation[0] == 0)
      sb << "read ";
    else
      sb << "write ";
    sb << "at address " << Integer::toHexString(pep->ExceptionRecord->ExceptionInformation[1]);
    RNullPointerException ex = new NullPointerException(sb.toString());
    ex->_stackFrame._save_pcs(*pep->ContextRecord);
    throw ex;
  }
  else if (pep->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO ||
           pep->ExceptionRecord->ExceptionCode == EXCEPTION_FLT_DIVIDE_BY_ZERO)
  {
    RArithmeticException ex = new ArithmeticException("Divide by zero");
    ex->_stackFrame._save_pcs(*pep->ContextRecord);
    throw ex;
  }
  else if (pep->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW)
  {
    RStackOverflowError ex = new StackOverflowError("stack overflow");
    ex->_stackFrame._save_pcs(*pep->ContextRecord);
    throw ex;
  }

  return EXCEPTION_CONTINUE_SEARCH;
}
#endif
/FONT>

#if defined(ACDK_USE_SYNC_SIGNALS)

void sigsegv_signal_handler(int sig)
{
  printf("sigsegv_signal_handler\n");
  THROW0(NullPointerException);
}

#endif
/FONT>

int
System::main(ACDK_MainFunc mainfunc, int argc, char* argv[], char** envptr, const char** addargs/* = 0*/)
{
#if defined(ACDK_USE_SYNC_SIGNALS)
  signal(SIGSEGV, (sighandler_t)&sigsegv_signal_handler);
#endif
/FONT>
#if defined(ACDK_USE_MSC_STRUCTURED_C_HANDLING)
  __try {
#endif
/FONT>
  int ret = main2(mainfunc, argc, argv, envptr, addargs);
  return ret;
#if defined(ACDK_USE_MSC_STRUCTURED_C_HANDLING)
  } 
  __except(ExceptionFilter(GetExceptionInformation())) 
  {
    
  }
  return -1;
#endif
/FONT>
}
int
System::main2(ACDK_MainFunc mainfunc, int argc, char* argv[], char** envptr, const char** addargs/* = 0*/)
{
  sys::core_setbit_scope<int> _inMain(getSystemStatus(), SystemStatusStartMain);
  sys::core_setbit_leave_scope<int> _leaveMain(getSystemStatus(), SystemStatusAfterMain);
  __SP = sys::core_system::_getSP(); // this must be as early as possible!
  
  sys::core_system::acdk_core_static_bound = true;
#if !defined(__BORLANDC__) && !defined(__GNUG__) && !defined(__INTEL_COMPILER) 
  set_terminate(terminate_func);
#endif
/FONT>
  atexit(exit_func);
  int ret = -1;
  ::acdk::lang::sys::core_system::setState(::acdk::lang::sys::InMain);
  RThreadLocal _tl = new ThreadLocal(); // force initialization
  bool thrown_exception = false;
  {
    prefilterArgs(argc, argv, envptr, addargs);
    Runtime::initSignals();
    _gSystem = Nil;
    try {
      _gSystem = new SystemImpl();
      int allargs = argc;
      int i;
      
      if (addargs != 0) {
        for (i = 0; addargs[i] != 0; i++)
          ;
        allargs += i - 1;
      }
      RStringArray args = new StringArray(argc);
      for (i = 0; i < argc; i++) {
        args[i] = SCS(argv[i]);
      }
      if (addargs != 0) {
        for (i = 0; addargs[i] != 0; i++)
          args[argc + i] = SCS(addargs[i]);
      }
      if (_gSystem->_argumentHolder != 0) {
        delete _gSystem->_argumentHolder;
        _gSystem->_argumentHolder = 0;
      }
      _gSystem->_argumentHolder = new ArgumentHolder(args);
      args = _gSystem->init(argc, argv, envptr, args);
      _saveStackBase(__SP); // must be after having initialized the mainThread!
      __SP = 0;

      
      
      _initList_t *p = &_initList;
      while(p != 0) {
        Initializer* i = p->cl;
        if (i != 0)
          i->beforeMain();
        p = p->next;
      }
      {
        sys::core_setbit_scope<int> _inMain(getSystemStatus(), SystemStatusInUsersMain);
        sys::core_setbit_leave_scope<int> _leaveUserMain(getSystemStatus(), SystemStatusAfterUsersMain);
        ret = mainfunc(args);
      }
      p = &_initList;
      while(p != 0) {
        Initializer* i = p->cl;
        if (i != 0)
          i->afterMain();
        p = p->next;
      }
      __SP = getStackBase(); // re-initializing before destroying mainThread
      _gSystem->deinit();
    } catch (RThrowable ex) {
      sys::coreout << "Caught Throwable in System::main(): "
        << ex->getMessage()->c_str() << sys::eofl;
      if (System::err != Nil)
          ex->printStackTrace();
      ret = -1;
      thrown_exception = true;
    } catch (char* msg) {
      sys::coreout << "Caught unknown char* in System::main(): \n" << msg << sys::eofl;
      sys::coreout << "Caught unknown Exception in System::main(): " << sys::eofl;
      ret = -1;
      thrown_exception = true;
    } 
    /* must not check
  catch (...) {
      sys::coreout << "Caught unknown Exception in System::main(): " << sys::eofl;
      ret = -1;
      thrown_exception = true;
    }
*/
    sys::cleanup_system_objects();
    
    
    if (thrown_exception == true && _gSystem != Nil)
      _gSystem->deinit();
    // at last, becuase deinit use ThreadLocal
    _gSystem = Nil;
    ThreadLocal::threadEnd();
    ::acdk::lang::sys::core_system::setState(::acdk::lang::sys::AfterMain);
  }
  return ret;
}

#if defined(ACDK_OS_WIN32)
// defined in Process.cpp
RStringArray parseCommand(IN(RString) command, IN(RStringArray) _args, IN(RStringArray) _envp);

int 
System::main(ACDK_MainFunc mainfunc, HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
                                           int nCmdShow, const char** addargs)
{
  
  RStringArray args = new StringArray(0);
  RStringArray env = new StringArray(0);
  RString cmdLine = SCS(lpCmdLine);
  parseCommand(cmdLine, args, env);
  ArgumentHolder tempargs(args);
  System::hasConsole = false;
  int ret = main(mainfunc, tempargs.getArgc(), tempargs.getArgv(), _environ, addargs);
  return ret;
}
#endif //defined(ACDK_OS_WIN32)

//static 
void 
System::initAsSharedLibrary()
{
  if (System::isInMain() == true)
    return;
  getSystemStatus() |= SystemStatusStartMain;

  __SP = sys::core_system::_getSP(); // this must be as early as possible!
#if !defined(__BORLANDC__) && !defined(__GNUG__) && !defined(__INTEL_COMPILER) 
  set_terminate(terminate_func);
#endif
/FONT>
  atexit(exit_func);
  int ret = -1;
  ::acdk::lang::sys::core_system::setState(::acdk::lang::sys::InMain);
  Runtime::initSignals();

  _gSystem = Nil;
  try {
    _gSystem = new SystemImpl();
    RStringArray args = new StringArray(0);
    if (_gSystem->_argumentHolder != 0) {
      delete _gSystem->_argumentHolder;
      _gSystem->_argumentHolder = 0;
    }
    _gSystem->_argumentHolder = new ArgumentHolder(args);
    char* argv[1];
    argv[0] = 0;
#if defined(ACDK_OS_WIN32) && !defined(__MWERKS__) && !defined(ACDK_OS_CYGWIN32)
    args = _gSystem->init(0, argv, _environ, args);
#else
/FONT>
    args = _gSystem->init(0, argv, 0, args);
#endif
/FONT>
    _saveStackBase(__SP); // must be after having initialized the mainThread!
    __SP = 0;
    _initList_t *p = &_initList;
    while(p != 0) 
    {
      Initializer* i = p->cl;
      if (i != 0)
        i->beforeMain();
      p = p->next;
    }
    
    
  } catch (RThrowable ex) {
    sys::coreout << "Caught Throwable in System::main(): "
      << ex->getMessage()->c_str() << sys::eofl;
    if (System::err != Nil)
      ex->printStackTrace();
    ret = -1;

  } catch (char* msg) {
    sys::coreout << "Caught unknown char* in System::main(): \n" << msg << sys::eofl;
    sys::coreout << "Caught unknown Exception in System::main(): " << sys::eofl;
    ret = -1;
  } catch (...) {
    sys::coreout << "Caught unknown Exception in System::main(): " << sys::eofl;
    ret = -1;
  }
  getSystemStatus() |= SystemStatusInUsersMain | SystemStatusConfigLoaded;
}

//static 
void 
System::deInitAsSharedLibrary()
{
  if (System::isInMain() == false)
    return;
  getSystemStatus() &= ~SystemStatusInUsersMain;
  getSystemStatus() |= SystemStatusAfterUsersMain;

  _initList_t *p = &_initList;
  while(p != 0) 
  {
    Initializer* i = p->cl;
    if (i != 0)
      i->afterMain();
    p = p->next;
  }
  __SP = getStackBase(); // re-initializing before destroying mainThread
  _gSystem->deinit();
  sys::cleanup_system_objects();
  _gSystem = Nil;
  ThreadLocal::threadEnd();
  ::acdk::lang::sys::core_system::setState(::acdk::lang::sys::AfterMain);
  getSystemStatus() &= SystemStatusStartMain;
  getSystemStatus() |= SystemStatusAfterMain;

}


//static
void
System::printStackTrace(int ignoreFromTop)
{
  printStackTrace(err, ignoreFromTop + 1);
}

//static
void
System::printStackTrace(IN(acdk::io::RPrintWriter) outpw, int ignoreFromTop)
{
  ::acdk::lang::sys::BackTrace bt;
  RStackFrameArray stackFrames = bt.getStackFrames();
  printStackTrace(outpw, stackFrames, ignoreFromTop);
}

void
System_printStackFrame(IN(acdk::io::RPrintWriter) outpw, IN(RStackFrame) frame)
{
  StringBuffer sb;
  sb << "  called in ";
  if (frame->hasFileAndLine() == true)
  {
    sb << frame->getFileName() << ":" << frame->getFileLineNo();
  }
  if (frame->hasFunctionSignature() == true)
  {
    sb << ": " << frame->getFunctionSignature();
  }
  outpw->println(sb.toString());
}

//static
void
System::printStackTrace(IN(acdk::io::RPrintWriter) outpw, IN(RStackFrameArray) stackFrames, int ignoreFromTop)
{
  for (int i = ignoreFromTop; i < stackFrames.length(); i++) 
  {
    System_printStackFrame(outpw, stackFrames[i]);
  }
}


//static
int
System::identityHashCode(IN(acdk::lang::Object) obj)
{
  return (int)&obj;
}


//static
RString
System::getModulePath()
{
  static RString modpath;
  if (modpath != Nil)
    return modpath;
  char** p = getArgv();
  if (p == 0 || *p == 0)
    return "";
  File f(sys::core_system::fq_executable_filename(*p));
  modpath = f.getCanonicalPath();
  System::registerStaticReference(modpath);
  return modpath;
}

//static
RString
System::getModuleName(bool stripExt)
{
 
  File f(getModulePath());
  RString str = f.getName();
#ifdef ACDK_OS_WIN32
  if (stripExt == true && str->endsWith(".exe") == true)
    str = str->substr(0, str->length() - strlen(".exe"));
#endif 
  return str;
}


//static
RString
System::getModuleDir()
{
  char** p = getArgv();
  if (p == 0 || *p == 0)
    return File::getCWD();
  File f(getModulePath());
  RString str = f.getParent();
  if (str == Nil || str->length() == 0)
    return File::getCWD();
  return str;
}

RStringArray 
System::getEnvPath() 
{
  RString p = System::getEnvironment()->getProperty("PATH");
  if (p == Nil || p->length() == 0)
    return new StringArray(0);
  return acdk::util::StringTokenizer(p, acdk::io::File::pathSeparator()).allToken();
}


System::_initList_t System::_initList = {0, 0};

//ACDK_CORE_PUBLIC static 
void 
System::registerStaticReference(acdk::lang::Object* obj) // ### @todo remove this
{
  //sys::ObjectHeap::registerStaticReference(obj);
}

void
System::registerForInitialization(Initializer* i)
{
  _initList_t *p = &_initList;
  if (p->cl == 0)  
  {
    p->cl = i;
  }
  else
  {
    while(p->next != 0) 
    {
      p = p->next;
    }
    p->next = new _initList_t;
    p->next->cl = i;
    p->next->next = 0;
  }
  if (System::isInMain() == true) // already up and running
  {
    i->beforeMain();
  }
}

//static
void
System::_saveStackBase(unsigned int SP)
{
  Thread::currentThread()->_saveStackBase(SP);
}

//static
unsigned int
System::getStackBase()
{
  if (System::isInMain() == false)
    return sys::core_system::_getSP();
  if (__SP != 0) // before or within System::main()
    return __SP;
  return Thread::getStackBase();
}

//static 
RString 
System::getErrmsg() 
{ 
  return SCS(strerror(errno)); 
}

//static 
RString 
System::getErrmsg(int errnumber) 
{ 
  return SCS(strerror(errnumber)); 
}

//static
RString
System::getLastError()
{
#ifdef ACDK_OS_WIN32
  DWORD le = GetLastError();
  LPVOID lpMsgBuf;
  FormatMessage( 
    FORMAT_MESSAGE_ALLOCATE_BUFFER | 
    FORMAT_MESSAGE_FROM_SYSTEM | 
    FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL,
    le,
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
    (LPTSTR) &lpMsgBuf,
    0,
    NULL 
  );
  RString ret = new String((const char*)(LPCTSTR)lpMsgBuf, NormalSST |  CCAscii);
  LocalFree( lpMsgBuf );
  return ret;
#else
/FONT>
  return getErrmsg();
#endif
/FONT>
}


//ACDK_CORE_PUBLIC static 
int 
System::getErrno() 
{ 
  return errno; 
}

//ACDK_CORE_PUBLIC static 
void 
System::resetErrno() 
{ 
  errno = 0; 
}

//ACDK_CORE_PUBLIC 
//static 
void 
System::loadLibrary(IN(RString) libname)
{
  Runtime::getRuntime()->loadLibrary(libname);
}


  /**
    return the overal limit of memory usage
  */
//ACDK_CORE_PUBLIC static 
jlong 
System::getMaxMemoryUsage()
{
  return sys::ObjectHeap::getMaxMemoryUsage();
}

//ACDK_CORE_PUBLIC static 
void 
System::setMaxMemoryUsage(jlong maxmem)
{
  sys::ObjectHeap::setMaxMemoryUsage(maxmem);
}

  /**
    return the limit of memory usage inside this thread
  */
//  ACDK_CORE_PUBLIC static 
jlong 
System::getThreadMaxMemoryUsage()
{
  return sys::ObjectHeap::getThreadMaxMemoryUsage();
}

//ACDK_CORE_PUBLIC static 
void 
System::setThreadMaxMemoryUsage(jlong maxmem)
{
  sys::ObjectHeap::setThreadMaxMemoryUsage(maxmem);
}


class System_RootObjectListenerCollector
: extends acdk::lang::Object,
  implements acdk::lang::ref::NotifyObjectEventListener
{
public:
  RObjectArray _objects;
  bool _includeStaticReferences;
  System_RootObjectListenerCollector(bool includeStaticReferences)
  : _objects(new ObjectArray(0))
  , _includeStaticReferences(includeStaticReferences)
  {
  }
  virtual void notifyBeforeConstruction(acdk::lang::Object* obj) { }
  virtual bool notifyBeforeDestruction(acdk::lang::Object* obj)  { return true; }
  virtual void notifyWhileDestruction(acdk::lang::Object* obj) { }
  virtual bool listHeaps(IN(::acdk::lang::sys::RHeapFrame) theheap) { return false; }
  virtual bool listedAllocated(IN(::acdk::lang::sys::RHeapFrame) theheap, void* optr, ::acdk::lang::sys::AllocatedType type, int size) 
  { 
    acdk::lang::Object* obj = (acdk::lang::Object*)optr;
    if (_includeStaticReferences == false)
    {
      
      if (sys::ObjectHeap::isStaticReferenceObject(obj) == true)
        return true;
      if (dynamic_cast<Class*>(obj) != 0)
        return true;
    }
    _objects->append(obj);
    return true; 
  }
};



//static 
RObjectArray 
System::getRootObjects(bool includeStaticReferences)
{
  System_RootObjectListenerCollector col(includeStaticReferences);
  sys::ObjectHeap::listObjects(&col, sys::ListRootsOnly | sys::ListObjectsRecursive);
  RObjectArray ret = col._objects;
  if (ret->length() > 0 && ret[ret->length() - 1] == ret)
    ret->remove(ret->length() - 1);
  return ret;
}
//ACDK_CORE_PUBLIC static 
RObjectArray 
System::getObjectList(int flags)
{
  System_RootObjectListenerCollector col(true);
  sys::ObjectHeap::listObjects(&col, flags);
  RObjectArray ret = col._objects;
  if (ret->length() > 0 && ret[ret->length() - 1] == ret)
    ret->remove(ret->length() - 1);
  return ret;
}

//static
int
System::getPlatformFlags()
{
  int flags = 0;
#if defined(ACDK_OS_WIN32)
  flags |= PfWin32;
#endif
/FONT>
#if defined(ACDK_OS_UNIX)
  flags |= PfUnix;
#endif
/FONT>
#if defined(ACKD_OS_LINUX)
  flags |= PfLinux;
#endif
/FONT>
#if defined(ACDK_OS_BSD)
  flags |= PfFreeBSD;
#endif
/FONT>
#if defined(ACDK_OS_SOLARIS)
  flags |= PfSolaris;
#endif
/FONT>
#if defined(ACDK_OS_CYGWIN32)
  flags |= PfCygwin;
#endif
/FONT>
#if defined(_MSC_VER)
  flags |= PfCcVc;
#endif
/FONT>
#if defined(__GNUG__)
  flags |= PfCcGcc;
#endif
/FONT>
#if defined(__BORLANDC__)
  flags |= PfCcBcc;
#endif
/FONT>
  flags |= Pf32Bit;
#if defined(ACDK_BIGENDIAN)
  flags |= PfBigEndian;
#endif
/FONT>
#if defined(ACDK_LITTLEENDIAN)
  flags |= PfLittleEndian;
#endif
/FONT>
  return flags;
}

} // lang
} // acdk
#if defined(ACDK_OS_CYGWIN32)

int WINAPI
acdk_core_init(HANDLE h, DWORD reason, void *foo)
{
    return 1;
}

#endif //defined(ACDK_OS_CYGWIN32)