Exemple #1
0
void MangoShadowFetch::prepareMass (OracleEnv &env)
{
   env.dbgPrintf("preparing shadow table for molecular mass match\n");

   QS_DEF(Array<char>, where);

   {
      ArrayOutput where_out(where);
      where_out.printf("");
      where_out.writeChar(0);
   }

   _fetch_type = _MASS;
   _env.reset(new OracleEnv(env.ctx(), env.logger()));
   _statement.reset(new OracleStatement(_env.ref()));

   _statement->append("SELECT mol_rowid FROM %s WHERE mass >= :mass_min AND mass <= :mass_max",
                      _table_name.ptr());

   _statement->prepare();
   _statement->defineStringByPos(1, _rowid.ptr(), sizeof(_rowid));

   ArrayOutput output(_counting_select);
   output.printf("SELECT COUNT(*) FROM %s WHERE WHERE mass >= :mass_min AND mass <= :mass_max",
           _table_name.ptr());
}
Exemple #2
0
void RingoFastIndex::_match (OracleEnv &env, int idx)
{
   _last_id = idx;

   BingoStorage &storage = this->_context.context().context().storage;
   QS_DEF(Array<char>, stored);
   
   storage.get(idx, stored);

   if (stored[0] != 0)
      return; // reaction was removed from index

   BufferScanner scanner(stored);

   scanner.skip(1); // skip the deletion mark
   scanner.skip(scanner.readByte()); // skip the compessed rowid
   
   profTimerStart(tall, "match");
   bool res = _context.substructure.matchBinary(scanner);
   profTimerStop(tall);
   
   if (res)
   {
      OraRowidText & rid = matched.at(matched.add());

      _decompressRowid(stored, rid);
      profIncTimer("match.found", profTimerGetTime(tall));
      _matched++;
   }
   else
   {
      profIncTimer("match.not_found", profTimerGetTime(tall));
      _unmatched++;
   }
}
Exemple #3
0
bool MangoTautomer::parseSub (const char *params)
{
   if (params == 0)
      return false;

   preserve_bonds_on_highlighting = false;

   BufferScanner scanner(params);

   scanner.skipSpace();

   if (scanner.isEOF())
      return false;

   QS_DEF(Array<char>, word);
   scanner.readWord(word, 0);

   if (strcasecmp(word.ptr(), "TAU") != 0)
      return false;
   
   setParameters(params);
   _params.substructure = true;

   return true;
}
Exemple #4
0
ORAEXT OCILobLocator *oraLoadFileToBLOB (OCIExtProcContext *ctx, char *filename,
                                         short filename_indicator, short *return_indicator)
{
   OCILobLocator *result = 0;

   ORABLOCK_BEGIN
   {
      *return_indicator = OCI_IND_NULL;

      OracleEnv env(ctx, logger);

      if (filename_indicator != OCI_IND_NOTNULL)
         throw BingoError("Null filename given");

      FileScanner scanner(filename);

      QS_DEF(Array<char>, buf);

      scanner.readAll(buf);

      OracleLOB lob(env);

      lob.createTemporaryBLOB();
      lob.write(0, buf.ptr(), buf.size()); 
      *return_indicator = OCI_IND_NOTNULL;
      lob.doNotDelete();
      result = lob.get();
   }
   ORABLOCK_END

   return result;
}
void MangoSimilarity::loadQuery (Scanner &scanner)
{
    QS_DEF(Molecule, query);

    MoleculeAutoLoader loader(scanner);

    loader.treat_x_as_pseudoatom = _context.treat_x_as_pseudoatom;
    loader.ignore_closing_bond_direction_mismatch =
        _context.ignore_closing_bond_direction_mismatch;
    loader.loadMolecule(query);

    _initQuery(query);

    MoleculeFingerprintBuilder builder(query, _context.fp_parameters);

    builder.skip_tau = true;
    builder.skip_ext = true;
    builder.skip_ord = true;
    builder.skip_any_atoms = true;
    builder.skip_any_bonds = true;
    builder.skip_any_atoms_bonds = true;

    builder.process();
    _query_fp.copy(builder.get(), _context.fp_parameters.fingerprintSize());
    _query_ones = builder.countBits_Sim();
}
Exemple #6
0
ORAEXT OCIString *oraLoadFileToString (OCIExtProcContext *ctx, char *filename,
                                       short filename_indicator, short *return_indicator)
{
   OCIString *result = 0;

   ORABLOCK_BEGIN
   {
      OracleEnv env(ctx, logger);

      *return_indicator = OCI_IND_NULL;

      if (filename_indicator != OCI_IND_NOTNULL)
         throw BingoError("Null filename given");

      FileScanner scanner(filename);
      QS_DEF(Array<char>, buf);

      scanner.readAll(buf);

      env.callOCI(OCIStringAssignText(env.envhp(), env.errhp(), (text *)buf.ptr(), buf.size(), &result));

      *return_indicator = OCI_IND_NOTNULL;
   }
   ORABLOCK_END

   return result;
}
bool MangoSimilarity::matchBinary (Scanner &scanner)
{
    QS_DEF(Molecule, target);

    CmfLoader loader(_context.cmf_dict, scanner);

    loader.skip_cistrans = true;
    loader.skip_stereocenters = true;
    loader.skip_valence = true;

    loader.loadMolecule(target);

    MoleculeFingerprintBuilder builder(target, _context.fp_parameters);

    builder.skip_tau = true;
    builder.skip_ext = true;
    builder.skip_ord = true;
    builder.skip_any_atoms = true;
    builder.skip_any_bonds = true;
    builder.skip_any_atoms_bonds = true;

    builder.process();

    int common_ones = bitCommonOnes(builder.get(), _query_fp.ptr(), _context.fp_parameters.fingerprintSize());

    int target_ones = builder.countBits_Sim();

    return match(target_ones, common_ones);
}
static void product_proc( Molecule &product, Array<int> &monomers_indices, void *userdata )
{
   ProductEnumeratorCallbackData *rpe_data = (ProductEnumeratorCallbackData *)userdata;

   Reaction &reaction = rpe_data->out_reactions->push();

   QS_DEF(Molecule, new_product);
   new_product.clear();
   new_product.clone(product, NULL, NULL);   

   MoleculeLayout mol_layout(new_product);
   mol_layout.respect_existing_layout = false;
   mol_layout.make();
   new_product.clearBondDirections();
   new_product.stereocenters.markBonds();
   new_product.allene_stereo.markBonds();

   reaction.clear();

   for (int i = 0; i < monomers_indices.size(); i++)
      reaction.addReactantCopy(rpe_data->rpe->getMonomer(monomers_indices[i]), NULL, NULL);

   reaction.addProductCopy(new_product, NULL, NULL);
   reaction.markStereocenterBonds();

   reaction.name.copy(product.name);
}
ORAEXT OCIString * oraConfigGetString (OCIExtProcContext *ctx, int context_id, 
                                       char *key_name, short key_name_indicator, 
                                       short *return_indicator)
{
   OCIString *result = NULL;

   ORABLOCK_BEGIN
   {
      *return_indicator = OCI_IND_NULL;

      OracleEnv env(ctx, logger);

      if (key_name_indicator != OCI_IND_NOTNULL)
         throw BingoError("Null key is given");

      QS_DEF(Array<char>, value);
      BingoOracleContext &context = BingoOracleContext::get(env, context_id, false, 0);
      if (!context.configGetString(env, key_name, value))
         throw BingoError("Key wasn't found");

      env.callOCI(OCIStringAssignText(env.envhp(), env.errhp(), (text *)value.ptr(), value.size() - 1, &result));

      *return_indicator = OCI_IND_NOTNULL;
   }
   ORABLOCK_END

   return result;
}
Exemple #10
0
ORAEXT OCINumber * oraRingoSub (OCIExtProcContext *ctx, int context_id,
    OCILobLocator *target_loc, short target_ind,
    OCILobLocator *query_loc,  short query_ind,
    const char    *params,     short params_ind,
    short *return_ind)
{
   OCINumber *result = NULL;

   ORABLOCK_BEGIN
   {
      OracleEnv env(ctx, logger);

      *return_ind = OCI_IND_NULL;

      if (query_ind  != OCI_IND_NOTNULL)
         throw BingoError("Null query given");
      if (target_ind != OCI_IND_NOTNULL)
         throw BingoError("Null target given");
      if (params_ind != OCI_IND_NOTNULL)
         params = 0;

      RingoOracleContext &context = RingoOracleContext::get(env, context_id, false);

      QS_DEF(Array<char>, query_buf);
      QS_DEF(Array<char>, target_buf);

      OracleLOB target_lob(env, target_loc);
      OracleLOB query_lob(env, query_loc);

      target_lob.readAll(target_buf, false);
      query_lob.readAll(query_buf, false);

      if (!context.substructure.parse(params))
         throw BingoError("can not parse parameters: %s", params);
      
      result = _ringoSub(env, context, query_buf, target_buf, params);

      if (result == 0)
         // This is needed for Oracle 9. Returning NULL drops the extproc.
         result = OracleExtproc::createInt(env, 0);
      else
         *return_ind = OCI_IND_NOTNULL;
   }
   ORABLOCK_END

   return result;
}
Exemple #11
0
bool MangoGross::checkGross (const char *target_gross_str)
{
   QS_DEF(Array<int>, target_gross);

   MoleculeGrossFormula::fromString(target_gross_str, target_gross);

   return checkGross(target_gross);
}
Exemple #12
0
bool _ringoRegisterReaction (OracleEnv &env, const char *rowid,
                             const Array<char> &reaction_buf,
                             RingoOracleContext &context,
                             RingoIndex &index,
                             BingoFingerprints &fingerprints)
{
   QS_DEF(Array<char>, data);
   QS_DEF(Array<char>, compressed_rowid);
   ArrayOutput output(data);

   output.writeChar(0); // 0 -- present, 1 -- removed from index
   
   ArrayOutput rid_output(compressed_rowid);
   RowIDSaver rid_saver(context.context().rid_dict, rid_output);

   rid_saver.saveRowID(rowid);

   output.writeByte((byte)compressed_rowid.size());
   output.writeArray(compressed_rowid);

   TRY_READ_TARGET_RXN
   {
      BufferScanner scanner(reaction_buf);

      try
      {
         index.prepare(scanner, output, NULL);
      }
      catch (CmfSaver::Error &e) { env.dbgPrintf(bad_reaction_warning_rowid, rowid, e.message()); return false;}
      catch (CrfSaver::Error &e) { env.dbgPrintf(bad_reaction_warning_rowid, rowid, e.message()); return false;}
   }
   CATCH_READ_TARGET_RXN_ROWID(rowid, return false);

   // some magic: round it up to avoid ora-22282
   if (data.size() % 2 == 1)
      output.writeChar(0);
   
   int blockno, offset;
   
   context.context().storage.add(env, data, blockno, offset);
   
   fingerprints.addFingerprint(env, index.getFingerprint());

   context.shadow_table.addReaction(env, index, rowid, blockno + 1, offset);
   return true;
}
void MangoSubstructure::_initSmartsQuery (QueryMolecule &query_in, QueryMolecule &query_out)
{
    QS_DEF(Array<int>, transposition);

    MoleculeSubstructureMatcher::makeTransposition(query_in, transposition);
    query_out.makeSubmolecule(query_in, transposition, 0);
    _nei_query_counters.calculate(query_out);
    query_out.optimize();
}
Exemple #14
0
void MangoShadowFetch::prepareExact (OracleEnv &env, int right_part)
{
   const MangoExact & instance = _context.exact;

   if (right_part == 1)
      env.dbgPrintf("preparing shadow table for exact\n");
   else 
      env.dbgPrintf("preparing shadow table for non-exact\n");

   _fetch_type = _EXACT;
   _right_part = right_part;
   _need_xyz = instance.needCoords();

   _env.reset(new OracleEnv(env.ctx(), env.logger()));
   _statement.reset(new OracleStatement(_env.ref()));
   _lob_cmf.reset(new OracleLOB(_env.ref()));

   _statement->append("SELECT sh.mol_rowid, sh.cmf");
   if (_need_xyz)
      _statement->append(", sh.xyz", _table_name.ptr());
   _statement->append(" FROM %s sh", _table_name.ptr());

   QS_DEF(Array<char>, table_copies);
   QS_DEF(Array<char>, where_clause);
   _prepareExactQueryStrings(table_copies, where_clause);

   _statement->append(table_copies.ptr());
   _statement->append(where_clause.ptr());

   _statement->prepare();
   _statement->defineStringByPos(1, _rowid.ptr(), sizeof(_rowid));
   _statement->defineBlobByPos(2, _lob_cmf.ref());
   
   if (_need_xyz)
   {
      _lob_xyz.reset(new OracleLOB(_env.ref()));
      _statement->defineBlobByPos(3, _lob_xyz.ref());
   }

   ArrayOutput output_cnt(_counting_select);
   output_cnt.printf("SELECT COUNT(*) FROM %s sh", _table_name.ptr());
   output_cnt.printf("%s", table_copies.ptr());
   output_cnt.printf("%s", where_clause.ptr());
}
Exemple #15
0
void MangoGross::parseQuery (Scanner &scanner)
{
   scanner.skipSpace();

   char c = scanner.readChar();

   if (c == '>')
   {
      if (scanner.readChar() != '=')
         throw Error("expecting '=' after '>'");
      _sign = 1;
   }
   else if (c == '<')
   {
      if (scanner.readChar() != '=')
         throw Error("expecting '=' after '<'");
      _sign = -1;
   }
   else if (c == '=')
      _sign = 0;
   else
      throw Error("expected one of '<= >= =', got %c", c);

   MoleculeGrossFormula::fromString(scanner, _query_gross);

   ArrayOutput out(_conditions);

   bool first = true;

   if (_sign == 0)
   {
      QS_DEF(Array<char>, query_gross_str);

      MoleculeGrossFormula::toString(_query_gross, query_gross_str);

      out.printf("gross = '%s'", query_gross_str.ptr());
   }
   else for (int i = 0; i < NELEM(MangoIndex::counted_elements); i++)
   {
      int elem = MangoIndex::counted_elements[i];

      if (_query_gross[elem] <= 0 && _sign == 1)
         continue;

      if (!first)
         out.printf(" AND ");

      first = false;

      if (_sign == 1)
         out.printf("cnt_%s >= %d", Element::toString(elem), _query_gross[elem]);
      else // _sign == -1
         out.printf("cnt_%s <= %d", Element::toString(elem), _query_gross[elem]);
   }
   out.writeChar(0);
}
Exemple #16
0
void bingoProfilingPrintStatistics (bool print_all)
{
   // Print profiling statistics
   QS_DEF(Array<char>, buffer);
   ArrayOutput output(buffer);
   profGetStatistics(output, print_all);
   buffer.push(0);
   logger.dbgPrintf("Profiling statistics:\n");
   logger.dbgPrintf(buffer.ptr());
   logger.dbgPrintf("\n");
}
Exemple #17
0
bool RingoFastIndex::getLastRowid (OraRowidText &id)
{
   if (_last_id < 0)
      return false;

   BingoStorage &storage = this->_context.context().context().storage;
   QS_DEF(Array<char>, stored);
   
   storage.get(_last_id, stored);
   _decompressRowid(stored, id);
   return true;
}
Exemple #18
0
bool mangoPrepareMolecule (OracleEnv &env, const char *rowid,
                            const Array<char> &molfile_buf,
                            MangoOracleContext &context,
                            MangoIndex &index,
                            Array<char> &data,
                            OsLock *lock_for_exclusive_access)
{
   profTimerStart(tall, "moleculeIndex.prepare");

   ArrayOutput output(data);

   output.writeChar(0); // 0 -- present, 1 -- removed from index

   QS_DEF(Array<char>, compressed_rowid);
   ArrayOutput rid_output(compressed_rowid);

   {
      // RowIDSaver modifies context.context().rid_dict and 
      // requires exclusive access for this
      OsLockerNullable locker(lock_for_exclusive_access);

      RowIDSaver rid_saver(context.context().rid_dict, rid_output);

      rid_saver.saveRowID(rowid);
   }

   output.writeByte((byte)compressed_rowid.size());
   output.writeArray(compressed_rowid);

   TRY_READ_TARGET_MOL
   {
      BufferScanner scanner(molfile_buf);

      try
      {
         index.prepare(scanner, output, lock_for_exclusive_access);
      }
      catch (CmfSaver::Error &e) 
      {
         OsLockerNullable locker(lock_for_exclusive_access);
         env.dbgPrintf(bad_molecule_warning_rowid, rowid, e.message());
         return false;
      }
   }
   CATCH_READ_TARGET_MOL_ROWID(rowid, return false);

   // some magic: round it up to avoid ora-22282
   if (data.size() % 2 == 1)
      output.writeChar(0);
   
   return true;
}
Exemple #19
0
ORAEXT OCIString *oraBingoGetName (OCIExtProcContext *ctx,
                              OCILobLocator *source_locator, short source_indicator,
                              short *return_indicator)
{
   OCIString *result = NULL;

   ORABLOCK_BEGIN
   {
      OracleEnv env(ctx, logger);

      if (source_indicator == OCI_IND_NULL)
         throw BingoError("null source given");
      
      QS_DEF(Array<char>, source);
      QS_DEF(Array<char>, name);
      OracleLOB source_lob(env, source_locator);
      
      source_lob.readAll(source, false);

      BufferScanner scanner(source);
      bingoGetName(scanner, name);

      if (name.size() < 1)
      {
         // This is needed for Oracle 9. Returning NULL drops the extproc.
         OCIStringAssignText(env.envhp(), env.errhp(), (text *)"nil", 3, &result);
         *return_indicator = OCI_IND_NULL;
      }
      else
      {
         name.push(0);
         OCIStringAssignText(env.envhp(), env.errhp(), (text *)name.ptr(), strlen(name.ptr()), &result);
         *return_indicator = OCI_IND_NOTNULL;
      }
   }
   ORABLOCK_END
   
   return result;
}
void MangoSubstructure::_initQuery (QueryMolecule &query_in, QueryMolecule &query_out)
{
    _correctQueryStereo(query_in);

    QueryMoleculeAromatizer::aromatizeBonds(query_in, AromaticityOptions::BASIC);
    _nei_query_counters.calculate(query_in);

    QS_DEF(Array<int>, transposition);

    _nei_query_counters.makeTranspositionForSubstructure(query_in, transposition);

    query_out.makeSubmolecule(query_in, transposition, 0);
    _nei_query_counters.calculate(query_out);
}
Exemple #21
0
void RingoFastIndex::_decompressRowid (const Array<char> &stored, OraRowidText &rid)
{
   BufferScanner scanner(stored.ptr() + 2, stored[1]);

   RowIDLoader loader(_context.context().context().rid_dict, scanner);
   QS_DEF(Array<char>, rowid);

   loader.loadRowID(rowid);

   if (rowid.size() != 18)
      throw Error("rowid size=%d?", rowid.size());

   memcpy(rid.ptr(), rowid.ptr(), 18);
   rid.ptr()[18] = 0;
}
void MangoSubstructure::loadQuery (Scanner &scanner)
{
    MoleculeAutoLoader loader(scanner);
    QS_DEF(QueryMolecule, source);

    loader.treat_x_as_pseudoatom = _context.treat_x_as_pseudoatom;
    loader.ignore_closing_bond_direction_mismatch =
        _context.ignore_closing_bond_direction_mismatch;
    loader.loadQueryMolecule(source);

    if (!source.have_xyz && match_3d != 0)
        throw Error("cannot do 3D match without XYZ in the query");

    _initQuery(source, _query);
    _query_fp_valid = false;
    _query_extra_valid = false;
}
void MangoSubstructure::loadSMARTS (Scanner &scanner)
{
    SmilesLoader loader(scanner);
    QS_DEF(QueryMolecule, source);

    loader.ignore_closing_bond_direction_mismatch =
        _context.ignore_closing_bond_direction_mismatch;
    loader.loadSMARTS(source);

    if (!source.have_xyz && match_3d != 0)
        throw Error("cannot do 3D match without XYZ in the query");

    _initSmartsQuery(source, _query);
    _query_fp_valid = false;
    _query_extra_valid = false;
    _use_pi_systems_matcher = false;
}
void RingoIndex::prepare (Scanner &rxnfile, Output &output, OsLock *lock_for_exclusive_access)
{
   QS_DEF(Reaction, reaction);
      
   ReactionAutoLoader rrd(rxnfile);
   _context->setLoaderSettings(rrd);
   rrd.loadReaction(reaction);

   // Skip all SGroups
   for (int mol_idx = reaction.begin(); mol_idx != reaction.end(); mol_idx = reaction.next(mol_idx)) 
      reaction.getBaseMolecule(mol_idx).clearSGroups();

   Reaction::checkForConsistency(reaction);

   ReactionAutomapper ram(reaction);
   ram.correctReactingCenters(true);

   reaction.aromatize(AromaticityOptions::BASIC);

   _hash = RingoExact::calculateHash(reaction);
   {
      ArrayOutput out(_hash_str);
      out.printf("%02X", _hash);
      _hash_str.push(0);
   }

   if (!skip_calculate_fp)
   {
      ReactionFingerprintBuilder builder(reaction, _context->fp_parameters);

      builder.process();
      _fp.copy(builder.get(), _context->fp_parameters.fingerprintSizeExtOrdSim() * 2);
   }

   ArrayOutput output_crf(_crf);
   {
      // CrfSaver modifies _context->cmf_dict and 
      // requires exclusive access for this
      OsLockerNullable locker(lock_for_exclusive_access);
      CrfSaver saver(_context->cmf_dict, output_crf);
      saver.saveReaction(reaction);
   }

   output.writeArray(_crf);
}
Exemple #25
0
bool MangoExact::parse (const char *params)
{
   if (params == 0)
   {
      setParameters("");
      return true;
   }

   QS_DEF(Array<char>, params_upper);

   params_upper.upper(params);

   if (strstr(params_upper.ptr(), "TAU") != NULL)
      return false;

   setParameters(params);
   return true;
}
bool MangoSubstructure::parse (const char *params)
{
    match_3d = 0;
    rms_threshold = 0;
    _use_pi_systems_matcher = false;
    preserve_bonds_on_highlighting = false;

    if (params == 0)
        return true;

    BufferScanner scanner(params);

    QS_DEF(Array<char>, word);

    scanner.skipSpace();
    while (!scanner.isEOF())
    {
        scanner.skipSpace();
        scanner.readWord(word, 0);

        bool is_aff = strcasecmp(word.ptr(), "AFF") == 0;
        bool is_conf = strcasecmp(word.ptr(), "CONF") == 0;
        if (is_aff || is_conf)
        {
            if (match_3d != 0)
                return false;
            if (is_aff)
                match_3d = MoleculeSubstructureMatcher::AFFINE;
            if (is_conf)
                match_3d = MoleculeSubstructureMatcher::CONFORMATION;

            scanner.skipSpace();
            rms_threshold = scanner.readFloat();
        }
        else if (strcasecmp(word.ptr(), "RES") == 0)
            _use_pi_systems_matcher = true;
        else
            return false;
    }


    return true;
}
Exemple #27
0
bool mangoPrepareAndRegisterMolecule (OracleEnv &env, const char *rowid,
                             const Array<char> &molfile_buf,
                             MangoOracleContext &context,
                             MangoIndex &index,
                             BingoFingerprints &fingerprints, bool append)
{
   QS_DEF(Array<char>, prepared_data);
   
   if (mangoPrepareMolecule(env, rowid, molfile_buf, context, 
      index, prepared_data, NULL))
   {
      mangoRegisterMolecule(env, rowid, context, 
         index, fingerprints, prepared_data, append);

      return true;
   }

   return false;
}
static void product_proc( Molecule &product, Array<int> &monomers_indices, void *userdata )
{
   ProductEnumeratorCallbackData *rpe_data = (ProductEnumeratorCallbackData *)userdata;

   Reaction &reaction = rpe_data->out_reactions->push();

   QS_DEF(Molecule, new_product);
   new_product.clear();
   new_product.clone(product, NULL, NULL);   

   reaction.clear();

   for (int i = 0; i < monomers_indices.size(); i++)
      reaction.addReactantCopy(rpe_data->rpe->getMonomer(monomers_indices[i]), NULL, NULL);

   reaction.addProductCopy(new_product, NULL, NULL);

   reaction.name.copy(product.name);
}
void bingoGetName (Scanner &scanner, Array<char> &result)
{
   QS_DEF(Array<char>, str);
   bool single_line = Scanner::isSingleLine(scanner);

   result.clear();

   if (single_line)
   {
      scanner.readLine(str, true);
      int idx = str.find('|');
      int idx2 = 0;

      if (idx >= 0)
      {
         int tmp = str.find(idx + 1, str.size(), '|');

         if (tmp > 0)
            idx2 = tmp + 1;
      }

      BufferScanner scan2(str.ptr() + idx2);

      while (!scan2.isEOF())
      {
         if (isspace(scan2.readChar()))
            break;
      }
      scan2.skipSpace();
      if (!scan2.isEOF())
         scan2.readLine(result, false);
   }
   else
   {
      scanner.readLine(result, false);
      if (result.size() >= 4 && strncmp(result.ptr(), "$RXN", 4) == 0)
         scanner.readLine(result, false);
   }
}
void bingoGetTauCondition (const char *list_ptr, int &aromaticity, Array<int> &label_list)
{
   if (isdigit(*list_ptr))
   {
      if (*list_ptr == '1')
         aromaticity = 1;
      else if (*list_ptr == '0')
         aromaticity = 0;
      else
         throw BingoError("Bad tautomer configuration string format");
      list_ptr++;
   } else {
      aromaticity = -1;
   }

   label_list.clear();

   QS_DEF(Array<char>, buf);
   buf.clear();

   while (*list_ptr != 0)
   {
      if (isalpha((unsigned)*list_ptr))
         buf.push(*list_ptr);
      else if (*list_ptr == ',')
      {
         buf.push(0);
         label_list.push(Element::fromString(buf.ptr()));
         buf.clear();
      } else
         throw BingoError("Bad label list format");
      list_ptr++;
   }

   buf.push(0);
   label_list.push(Element::fromString(buf.ptr()));
}