示例#1
0
RendererPtr Object::getRendererByType(const LString &type_name)
{
  rendtab_t::const_iterator i = m_rendtab.begin();
  rendtab_t::const_iterator e = m_rendtab.end();
  for (; i!=e; ++i) {
    if ( type_name.equals(i->second->getTypeName()) )
      return i->second;
  }

  return RendererPtr();
}
void clResourcesManager::PreCacheC( const LString& Param )
{
	if ( Param.empty() )
	{
		Env->Console->DisplayInfoTip( "Usage: PRECACHE <shader or texture file name>" );
		return;
	}

	Env->Console->Display( "Precaching shader... " + Param );

	Env->Resources->LoadShader( Param );
}
示例#3
0
void LScrVector4D::setStrValue(const LString &val)
{
  Vector4D vec;
  if (!Vector4D::fromStringS(val, vec)) {
    LString msg = LString::format("cannot convert \"%s\" to vector", val.c_str());
    MB_THROW(qlib::RuntimeException, msg);
    return;
  }

  for (int i=1; i<=4; ++i)
    ai(i) = vec.ai(i);
}
/**
   This will convert requested filename with full path into a single file name
    e.g.  c:\\data\\textures\\texture1.tga
          c~_data_textures_texture1.tga
**/
LString clResourcesManager::ConvertName( const LString& FileName )
{
	LString ConvName;

	for ( size_t i = 0; i < FileName.length(); ++i )
	{
		switch ( FileName[i] )
		{
			case '\\':
			case '/':
			{
				ConvName.push_back( '_' );
				continue;
			}
			case ':':
			{
				ConvName.push_back( '~' );
				continue;
			}
			case ' ':
			{
				ConvName.push_back( '#' );
				continue;
			}
		}

		ConvName.push_back( FileName[i] );
	}

	return ConvName;
}
示例#5
0
void ExpatInStream::parse()
{
  // check base URI

  fs::path srcpath(getURI());
#if (BOOST_FILESYSTEM_VERSION==2)
  LString base_dir = srcpath.parent_path().directory_string();
#else
  LString base_dir = srcpath.parent_path().string();
#endif

  if (!base_dir.isEmpty())
    setBaseURI(base_dir);

  //detail::AbstFIOImpl *pimpl =
  //dynamic_cast<detail::AbstFIOImpl *>(getImpl().get());
  //if (pimpl!=NULL) {
  //MB_DPRINTLN("File: base URI %s", pimpl->getDirName().c_str());
  //setBaseURI((pimpl->getDirName())+LString(MB_PATH_SEPARATOR));
  //}

  char buf[bufsize];
  bool done=false;
  do {
    int len = super_t::read(buf, 0, sizeof(buf));
    done = len < sizeof(buf);
    if (XML_Parse(getParser(), buf, len, done) == XML_STATUS_ERROR) {
      LString msg =
        LString::format("%s at line %d\n",
                        XML_ErrorString(XML_GetErrorCode(getParser())),
                        getLineNo());
      MB_DPRINTLN("ExpatInStream> error: %s", msg.c_str());
      MB_THROW(qlib::IOException, msg);
    }
    else if (getError()) {
      MB_DPRINTLN("ExpatInStream> error: %s", getErrorMsg().c_str());
      MB_THROW(qlib::IOException, getErrorMsg());
    }
  } while (!done);
}
示例#6
0
void UndoManager::startTxn(const LString &desc)
{
  if (isDisabled()) return; // ignore nested txn !!

  if (m_pPendInfo!=NULL) {
    m_nTxnNestLevel ++;
    return;
  }
  m_pPendInfo = MB_NEW UndoInfo();
  m_pPendInfo->setDesc(desc);

  MB_DPRINTLN("===== START UNDO TXN (%s) =====", desc.c_str());
}
示例#7
0
int LString::indexOf(const LString &str, int start) const {
    if (str.length() > this->length()) return -1;
    if (str.length() == 1) return indexOf(str[0], start);

    ConstIterator si = str.cbegin();
    int indexCounter = start;
    int index = 0;
    for (ConstIterator i = at(start); i != cend(); i++, indexCounter++) {
        if (*si == *i) {
            if (si == str.cbegin()) {
                index = indexCounter;
            }
            si++;
            if (si == str.cend()) {
                return index;
            }
            continue;
        }

        si = str.cbegin();
    }
    return -1;
}
示例#8
0
void CrystalInfo::setSGByName(const LString &name)
{
  SymOpDB *pdb = SymOpDB::getInstance();
  int sgid = pdb->getSgIDByCName(name);
  if (sgid<1) {
    sgid = pdb->getSgIDByName(name);
    if (sgid<1) {
      LString msg = LString::format("Invalid s.g. name <%s>", name.c_str());
      MB_THROW (qlib::RuntimeException, msg);
      return;
    }
  }

  setSG(sgid);
}
示例#9
0
void clLocalizer::SetLocale( const LString& LocaleName )
{
	guard( "%s", LocaleName.c_str() );

	ClearLocalization();

	FLocaleName = LocaleName;

	const LString FileName( FLocalePath + "/Localizer-" + LocaleName + ".txt" );

	if ( Env->FileSystem->FileExists( FileName ) )
	{
		Env->Logger->LogP( L_NOTICE, "Reading locale from %s", FileName.c_str() );

		iIStream* Stream = Env->FileSystem->CreateFileReader( FileName );

		while ( !Stream->Eof() )
		{
			LString Line = Stream->ReadLine();

			size_t SepPos = Line.find( "~" );

			FATAL( SepPos == Line.npos, "Invalid locale translation file format: missing ~" );

			LString Text( Line.substr( 0, SepPos ) );
			LString Translation( Line.substr( SepPos + 1, Line.length() - SepPos - 1 ) );

			FTranslations[ Text ] = Translation;
		}

		delete( Stream );
	}
	else
	{
		Env->Logger->LogP( L_NOTICE, "Locale %s not found", FileName.c_str() );
	}

	this->SendAsync( L_EVENT_LOCALE_CHANGED, LEventArgs(), false );

	unguard();
}
示例#10
0
LString clConsole::ExecuteScriptCode( const LString& ScriptCode, bool DisplayResult )
{
	// delayed initilaization :
	if ( !FScriptCompiler->IsInitialized() )
	{
		InitializeScript();
	}

	LString Code = FScriptCompiler->CompileStatement( ScriptCode );

	if ( !Code.empty() )
	{
		std::vector<LString> CodeLines;
		LStr::LineToMultiline( Code, CodeLines );

		LString Result = Env->Linker->ExecuteCode( CodeLines );

		if ( DisplayResult )
		{
			Display( "Result = " + Result );
		}

		FSendCommandResult = Result;
	}
	else
	{
		if ( DisplayResult )
		{
			Display( "Error while compiling statement" );
		}

		FSendCommandResult.assign( "" );
	}

	return FSendCommandResult;
}
示例#11
0
RendererPtr Object::createRenderer(const LString &type_name)
{
  RendererFactory *pRF = RendererFactory::getInstance();
  RendererPtr pRend = pRF->create(type_name);

  if (!registerRendererImpl(pRend)) {
    // error !! cannot register renderer.
    LOG_DPRINTLN("ERROR !! cannot register renderer");
    LString msg = LString::format("Cannot register renderer %s", type_name.c_str());
    MB_THROW(qlib::RuntimeException, msg);
    return RendererPtr();
  }

MB_DPRINTLN("createRenderer clientObjID=%d OK", (int)pRend->getClientObjID());
  return pRend;
}
示例#12
0
//------------------------------------------------------------------------------
int LArguments::parse(int argc, char* argv[]) {
    LString opt;
    int find;
    int ret;
    for(int num = 1; num < argc; num++) {
        opt = LString(argv[num]);

        if(opt.find("--") == 0) {
            if((find = opt.find("=")) != (int)string::npos) {
                if((ret = parseInternalOptionWithParamater(opt.substr(0, find), opt.substr(find + 1))) != L_OK) {
                    return ret;
                    }
                }
            else {
                if((ret = parseInternalOption(opt)) != L_OK) {
                    return ret;
                    }
                }
            }
        else if(opt.find("-") == 0) {
            if((find = opt.find("=")) != (int)string::npos) {
                if((ret = parseInternalOptionWithParamater(opt.substr(0, find), opt.substr(find + 1))) != L_OK) {
                    return ret;
                    }
                }
            else {
                if((ret = parseInternalOption(opt)) != L_OK) {
                    return ret;
                    }
                }
            }
        else {
            if((ret = parseInternalArgument(opt)) != L_OK) {
                return ret;
                }
            }

        }
    return L_OK;
    }
示例#13
0
int CrystalInfo::sysNameToID(const LString &nm)
{
  if (nm.equalsIgnoreCase("TRICLINIC"))
    return TRICLINIC;
  if (nm.equalsIgnoreCase("MONOCLINIC"))
    return MONOCLINIC;
  if (nm.equalsIgnoreCase("ORTHORHOMBIC"))
    return ORTHORHOMBIC;
  if (nm.equalsIgnoreCase("TETRAGONAL"))
    return TETRAGONAL;
  if (nm.equalsIgnoreCase("TRIGONAL"))
    return TRIGONAL;
  if (nm.equalsIgnoreCase("RHOMBOHEDRAL"))
    return TRIGONAL;
  if (nm.equalsIgnoreCase("HEXAGONAL"))
    return HEXAGONAL;
  if (nm.equalsIgnoreCase("CUBIC"))
    return CUBIC;

  MB_DPRINTLN("XtalInfo: invalid xtal sysname <%s>", nm.c_str());
  return -1; // invalid sysname
}
示例#14
0
qlib::uid_t XmlRpcMgr::getService(const LString &clsname)
{
  ReoGetService evt;
  evt.m_clsname = clsname;
  evt.m_pRval = NULL;
  m_pQue->putWait(&evt);

  MB_DPRINTLN("XMLRPC> getService: svrthr clsname=%s, result=%d!!",
	      clsname.c_str(), evt.m_bOK);

  if (!evt.m_bOK || evt.m_pRval==NULL) {
    throw ( xmlrpc_c::fault(evt.m_errmsg.c_str(), xmlrpc_c::fault::CODE_UNSPECIFIED) );
    return qlib::invalid_uid;
  }

  return registerObj(static_cast<qlib::LScriptable*>(evt.m_pRval));
}
示例#15
0
/** Reduce any %xx escape sequences to the characters they represent. **/
void unescape_url(LString& url)
{
    register int i,j;

    for(i=0,j=0; j<url.size(); ++i,++j)
    {
        if((url.at(i) = url[j]) == '%')
        {
            url.at(i) = x2c(url.at(j+1), url.at(j+2));
            j+= 2 ;
        }
    }
    if (i < url.size())
        url.at(i) = '\0' ;
}
示例#16
0
qlib::uid_t XmlRpcMgr::createObj(const LString &clsname)
{
  ReoCreateObj evt;
  evt.m_clsname = clsname;
  evt.m_pRval = NULL;
  m_pQue->putWait(&evt);

  MB_DPRINTLN("XMLRPC> createObj: svrthr clsname=%s, result=%b!!",
	      clsname.c_str(), evt.m_bOK);

  if (!evt.m_bOK || evt.m_pRval==NULL) {
    throw ( xmlrpc_c::fault(evt.m_errmsg.c_str(), xmlrpc_c::fault::CODE_UNSPECIFIED) );
    return qlib::invalid_uid;
  }

  return registerObj(evt.m_pRval);
}
示例#17
0
void clConsole::ExecC( const LString& Param )
{
	guard();

	LString Parameter = Param;
	LStr::TrimSpaces( &Parameter );

	if ( Parameter.empty() )
	{
		DisplayInfoTip( "Usage: EXEC <File Name>" );
		return;
	}

	LString FName = LStr::GetToken( Parameter, 1 );

	Env->Logger->LogP( L_DEBUG, "Exec: %s", FName.c_str() );

	if ( Env->FileSystem->FileExists( FName ) )
	{
		iIStream* FCFGStream = Env->FileSystem->CreateFileReader( FName );

		while ( !FCFGStream->Eof() )
		{
			LString Cmd = FCFGStream->ReadLine();
			LStr::TrimSpaces( &Cmd );

			if ( !Cmd.empty() && Cmd.at( 0 ) != ';' )
			{
				SendCommand( Cmd );
			}
		}

		delete( FCFGStream );
	}
	else
	{
		Env->Logger->LogP( L_WARNING, "Config file %s not found", FName.c_str() );

		DisplayError( "Config file \"" + FName + "\" not found" );
	}

	unguard();
}
示例#18
0
LString LoadMaterialMap( sEnvironment* Env, const LString& FileName, clRenderState* Shader, LMatSysSlot Slot, iTexture* OverridenTex, const LString& Define, LTextureType Type )
{
	if ( OverridenTex )
	{
		Shader->SetTexture( Slot, OverridenTex, false );

		return Define;
	}

	if ( !FileName.empty() )
	{
		Shader->SetTexture( Slot, Env->Resources->LoadImg( FileName, Type )->GetTexture(), false );

		return Define;
	}

	return "";
}
示例#19
0
bool clMesh::LoadMesh( const LString& FileName )
{
	guard( "%s", FileName.c_str() );

	iIStream* Stream = Env->FileSystem->CreateFileReader( FileName );

	if ( Stream == NULL ) { return false; }

	LString Ext;
	Env->FileSystem->SplitPath( FileName, NULL, NULL, NULL, &Ext );
	LStr::ToUpper( &Ext );

	iMeshLoader* Loader = NULL;

	if ( Ext == ".ASE" )
	{
		Loader = Env->Linker->Instantiate( "clASELoader" );
	}
	else if ( Ext == ".LCM" )
	{
		Loader = Env->Linker->Instantiate( "clLCMLoader" );
	}
	else if ( Ext == ".MD5MESH" )
	{
		Loader = Env->Linker->Instantiate( "clMD5Loader" );
	}

	if ( !Loader )
	{
		delete( Stream );

		return false;
	}

	bool Result = Loader->LoadMesh( Stream, this );

	delete( Loader );
	delete( Stream );

	return Result;

	unguard();
}
示例#20
0
size_t clConsole::FindCommandsSeparator( const LString& CMDString ) const
{
	bool InToken = false;

	for ( size_t i = 0; i != CMDString.length(); ++i )
	{
		if ( CMDString[i] == '"' )
		{
			InToken = !InToken;
		}

		if ( CMDString[i] == ';' && !InToken )
		{
			return i;
		}
	}

	return 0;
}
示例#21
0
void clConsole::SaveVarsC( const LString& Param )
{
	if ( Param.empty() )
	{
		DisplayInfoTip( "Usage: SAVEVARS <FileName>" );
		return;
	}

	iOStream* Output = Env->FileSystem->CreateFileWriter( Param );

	for ( size_t i = 0; i != FCVars.size(); ++i )
	{
		Output->WriteLine( FCVars[i]->GetObjectID() + " \"" + FCVars[i]->GetString() + "\"" );
	}

	delete( Output );

	DisplayInfoTip( LStr::ToStr( ( int )FCVars.size() ) + " vars were saved into " + Param );
}
示例#22
0
void clConsole::SetPropertyC( const LString& Param )
{
	LString ObjID = LStr::GetToken( Param, 1 );
	LString PropID = LStr::GetToken( Param, 2 );
	LString PropVal = LStr::GetToken( Param, 3 );

	if ( ObjID.empty() || PropID.empty() || PropVal.empty() )
	{
		Env->Console->DisplayInfoTip( "Usage: SETPROPERTY <ObjectID> <Property name> <Property value>" );
		return;
	}

	Env->Linker->SetObjectProperty( ObjID, PropID, PropVal );
}
示例#23
0
// static
LString  LDataSrcContainer::selectSrcAltSrc(const LString &src,
                                            const LString &altsrc,
                                            const LString &base_path,
                                            bool &rbReadFromAltSrc)
{
  bool bReadFromAltSrc = false;

  LString abs_path;

  // First, try to convert "src" to abs path
  if (isAbsolutePath(src))
    abs_path = src;
  else if (!base_path.isEmpty())
    abs_path = makeAbsolutePath(src, base_path);
  
  if (abs_path.isEmpty() || !isFileReadable(abs_path)) {
    // Second, try to convert "altsrc" to abs path
    if (altsrc.isEmpty()) {
      // empty alt src --> no src path info available (ERROR)
      LString msg = LString::format("Fatal error, cannot open file: \"%s\"",
                                    abs_path.c_str());
      LOG_DPRINTLN("SceneXML> %s", msg.c_str());
      MB_THROW(qlib::IOException, msg);
      return LString();
    }

    if (isAbsolutePath(altsrc))
      abs_path = altsrc;
    else if (!base_path.isEmpty())
      abs_path = makeAbsolutePath(altsrc, base_path);

    if (!isFileReadable(abs_path)) {
      LString msg = LString::format("Fatal error, cannot open file: \"%s\"",
                                    abs_path.c_str());
      LOG_DPRINTLN("SceneXML> %s", msg.c_str());
      MB_THROW(qlib::IOException, msg);
      return LString();
    }
    // read from alt_src property (abs_path==alt_src)
    bReadFromAltSrc = true;
  }

  rbReadFromAltSrc = bReadFromAltSrc;
  return abs_path;
}
示例#24
0
LString LString::fromUtf8(const std::string &s) {
    if (s.size() == 0) return LString();
    const uint8_t *begin = reinterpret_cast<const uint8_t*>(s.c_str());
    const uint8_t *end = begin + s.size();
    LString ret;
    ret.reserve(s.size());

    LChar *destBegin = ret.begin();
    LChar *destEnd = ret.end();
    bool conversionSucceeded = utf8ToUtf32(&begin, end, &destBegin, destEnd);
    assert(conversionSucceeded && "Failed conversion utf8 -> utf32");

    ret.resize(destBegin - ret.begin());
    return ret;
}
示例#25
0
void CrystalInfo::readQdfData(const DataTab &in)
{
  LString val;

  if (in.containsKey("CrystalInfo.lena")) {
    val = in.get("CrystalInfo.lena");
    val.toDouble(&m_cella);
  }

  if (in.containsKey("CrystalInfo.lenb")) {
    val = in.get("CrystalInfo.lenb");
    val.toDouble(&m_cellb);
  }

  if (in.containsKey("CrystalInfo.lenc")) {
    val = in.get("CrystalInfo.lenc");
    val.toDouble(&m_cellc);
  }

  if (in.containsKey("CrystalInfo.anga")) {
    val = in.get("CrystalInfo.anga");
    val.toDouble(&m_alpha);
  }
  if (in.containsKey("CrystalInfo.angb")) {
    val = in.get("CrystalInfo.angb");
    val.toDouble(&m_beta);
  }
  if (in.containsKey("CrystalInfo.angg")) {
    val = in.get("CrystalInfo.angg");
    val.toDouble(&m_gamma);
  }

  if (in.containsKey("CrystalInfo.sgid")) {
    val = in.get("CrystalInfo.sgid");
    val.toInt(&m_nSG);
  }
}
示例#26
0
bool SelCommand::compile(const LString &com, qlib::uid_t nCtxtID /*= qlib::invalid_uid*/)
{
  if (m_pSelRoot!=NULL)
    delete m_pSelRoot;

  if (com.isEmpty())
    return true;

  SelSuperNode *pnode = NULL;

  // Enter new context
  qsys::AutoStyleCtxt ctxt(nCtxtID);
  pnode = SelCompiler::getInstance()->compile(com);
  
  if (pnode==NULL) {
    return false;
  }

  m_pSelRoot = pnode;
  m_origcmd = com;
  //m_pCurClient = NULL;
  return true;
}
示例#27
0
ResiPatch *TopoDB::findLinkImpl(const LString &aPrevRes, const LString &aNextRes)
{
  // Resolve alias name
  ResiToppar *pTopPrev = get(aPrevRes);
  ResiToppar *pTopNext = get(aNextRes);
  if (pTopPrev==NULL || pTopNext==NULL) return NULL;
  const LString prev_res = pTopPrev->getName();
  const LString next_res = pTopNext->getName();

  // At first, find the complete matching entry
  LString key(prev_res.c_str());
  key.append(':');
  key.append(next_res.c_str());

  //MB_DPRINT("linkage find %s\n",key.c_str());

  if (m_linkDict.containsKey(key)) {
    Linkage link = m_linkDict.get(key);
    return patchGet(link.patch_name);
  }

  // find the (prev==wildcard) case
  key = LString("*:") + next_res.c_str();
  if (m_linkDict.containsKey(key)) {
    //MB_DPRINT("linkage find %s\n",key.c_str());
    Linkage link = m_linkDict.get(key);
    return patchGet(link.patch_name);
  }

  // find the (next==wildcard) case
  key = LString(prev_res.c_str()) + ":*";
  if (m_linkDict.containsKey(key)) {
    //MB_DPRINT("linkage find %s\n",key.c_str());
    Linkage link = m_linkDict.get(key);
    return patchGet(link.patch_name);
  }

  return NULL;
}
示例#28
0
/// load from icc file
void CmsXform::loadIccFile(const LString &path)
{
#ifdef HAVE_LCMS2_H
  m_pimpl->cleanup();
  cmsHPROFILE hInProf = cmsCreate_sRGBProfile();
  cmsHPROFILE hOutProf = cmsOpenProfileFromFile(path, "r");
  if (hOutProf==NULL) {
    MB_THROW(qlib::IOException, "cannot open icc file: "+path);
    return;
  }

  int nProofIntent = m_nIntent;
  
  m_info = LString();
  LString info;

  info = GetProfileInfo(hOutProf, cmsInfoDescription);
  info = info.chomp();
  if (!info.isEmpty())
    m_info += info+"\n";

  info = GetProfileInfo(hOutProf, cmsInfoManufacturer);
  info = info.chomp();
  if (!info.isEmpty())
    m_info += info+"\n";

  info = GetProfileInfo(hOutProf, cmsInfoModel);
  info = info.chomp();
  if (!info.isEmpty())
    m_info += info+"\n";

  info = GetProfileInfo(hOutProf, cmsInfoCopyright);
  info = info.chomp();
  if (!info.isEmpty())
    m_info += info+"\n";

#ifdef USEPROOFING
  cmsUInt16Number alarm[cmsMAXCHANNELS];
  for (int i=0; i < cmsMAXCHANNELS; i++)
    alarm[i] = 0xFFFF;
  cmsSetAlarmCodes(alarm);

  m_pimpl->m_hTr = cmsCreateProofingTransform(hInProf,
                                              TYPE_RGB_8,
                                              hInProf,
                                              TYPE_RGB_8,
                                              hOutProf,
                                              nProofIntent,
                                              nProofIntent,
                                              //INTENT_ABSOLUTE_COLORIMETRIC,
                                              //INTENT_PERCEPTUAL,
                                              cmsFLAGS_SOFTPROOFING);
  
  cmsHPROFILE hNullProf = cmsCreateNULLProfile();
  m_pimpl->m_hTrChk = cmsCreateProofingTransform(hInProf,
                                                 TYPE_RGB_DBL,
                                                 hNullProf,
                                                 TYPE_GRAY_DBL,
                                                 hOutProf,
                                                 nProofIntent,
                                                 nProofIntent,
                                                 cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK|cmsFLAGS_NOCACHE);
  cmsCloseProfile(hNullProf);

#else
  m_pimpl->m_hTr1 = cmsCreateTransform(hInProf,
                                       TYPE_RGB_8,
                                       hOutProf,
                                       //TYPE_CMYK_8,
                                       TYPE_CMYK_FLT,
                                       nProofIntent, 0);
  m_pimpl->m_hTr2 = cmsCreateTransform(hOutProf,
                                       //TYPE_CMYK_8,
                                       TYPE_CMYK_FLT,
                                       hInProf,
                                       TYPE_RGB_8,
                                       //INTENT_ABSOLUTE_COLORIMETRIC,
                                       INTENT_PERCEPTUAL,
                                       0);

#endif

  cmsCloseProfile(hInProf);
  cmsCloseProfile(hOutProf);
#endif
  return;
}
示例#29
0
ResiPatch *TopoDB::patchPrefixGet(char prefix, const LString &key) const
{
  LString pfxname = LString(prefix) + key.c_str();
  return m_patchTab.get(pfxname.c_str());
}
示例#30
0
// write PDB file to stream
bool PDBFileWriter::write(qlib::OutStream &outs)
{
  m_pMol = getTarget<MolCoord>();

  if (m_pMol==NULL) {
    LOG_DPRINTLN("PDBWriter> MolCoord is not attached !!");
    return false;
  }

  // check extension record handlers
  PDBFileReader::HndlrTab &htab = PDBFileReader::m_htab;
  bool bUseHndlr = htab.size()>0;

  MolCoord *pMol = m_pMol;
  qlib::PrintStream prs(outs);

  //
  //  write header
  //
  //LString sbuf = pqsys->getVersion();
  //prs.formatln("REMARK   PDB File Generated by CueMol (ver %s)", sbuf.c_str());
  prs.formatln("REMARK   PDB File Generated by CueMol2");

  //
  //  write SSBOND record
  //
  writeSSBonds(prs);

  //
  //  write LINK record
  //
  writeLinks(prs);

  writeSecstr(prs);

  //
  //  write extension records (CRYST1)
  //
  if (bUseHndlr) {
    LString sbuf;
    PDBFileReader::HndlrTab::const_iterator iter = htab.begin();
    for (; iter!=htab.end(); ++iter) {
      PDBFileReader::RecordHandler *ph = iter->second;
      if (ph!=NULL && ph->write(sbuf, pMol)) {
        prs.println(sbuf);
      }
    }
  }
  
  //
  //  write body (ATOM/ANISOU records)
  //

  int nserial = 1;

  // Sort chain names by ASCII order
  // take care of '_' (empty) chain
  std::list<LString> chnames;
  {
    MolCoord::ChainIter iter = pMol->begin();
    bool bHasEmptyChain = false;
    for (; iter!=pMol->end(); ++iter) {
      MolChainPtr pChn = iter->second;
      LString chnam = (pChn->getName().c_str()); 
      if (chnam.equals("_")) {
        bHasEmptyChain = true;
        continue;
      }
      chnames.push_back(chnam);
    }
    chnames.sort();
    if (bHasEmptyChain)
      chnames.push_back("_");
  }
  
  std::list<LString>::const_iterator cniter = chnames.begin();
  for (; cniter!=chnames.end(); ++cniter) {
    LString chnam = *cniter;
    MolChainPtr pChn = pMol->getChain(chnam);

    // format chain name
    char cch = convChainName(chnam);

    LString resnam;
    MolChain::ResidCursor2 riter = pChn->begin2();
    // int nlastres = 0;
    for (; riter!=pChn->end2(); ++riter) {
      //MolResiduePtr pRes = *riter;
      MolResiduePtr pRes = riter->second;
      if (pRes.isnull()) continue;
      ResidIndex rindex = pRes->getIndex();
      resnam = pRes->getName();
      
      // format residue name
      // resnam = resnam.toUpperCase();
      resnam = resnam.substr(0,3);

      // sort atom by AID
      std::list<int> atmlist;
      {
        MolResidue::AtomCursor aiter = pRes->atomBegin();
        for (; aiter!=pRes->atomEnd(); ++aiter) {
          atmlist.push_back(aiter->second);
        }
        atmlist.sort();
      }

      std::list<int>::const_iterator iter = atmlist.begin();
      for (; iter!=atmlist.end(); ++iter) {
        int aid = *iter;
        MolAtomPtr pAtm = pMol->getAtom(aid);
        if (pAtm.isnull())
          continue;

        if (!m_pSel.isnull()) {
          if (!m_pSel->isSelected(pAtm))
            continue; // skip nonselected atom
        }

        writeAtomLine(nserial, rindex, resnam,
                      cch, pAtm, prs);
        nserial++;
      }
      // nlastres = rindex.first;
    }

    // print TER record
    /*prs.formatln("TER   "
                 "%5d"
                 "      "
                 "%3s "
                 "%1s"
                 "%4d"
                 "                                                      ",
                 nserial, resnam.c_str(), chnam.c_str(), nlastres);*/
    prs.println("TER");
    nserial ++;
  }  

  //prs.println("END                                                                             ");
  prs.println("END");
  return true;
}