Coverage Report

Created: 2025-08-03 06:31

/src/openbabel/src/data.cpp
Line
Count
Source (jump to first uncovered line)
1
/**********************************************************************
2
data.cpp - Global data and resource file parsers.
3
4
Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc.
5
Some portions Copyright (C) 2001-2008 by Geoffrey R. Hutchison
6
7
This file is part of the Open Babel project.
8
For more information, see <http://openbabel.org/>
9
10
This program is free software; you can redistribute it and/or modify
11
it under the terms of the GNU General Public License as published by
12
the Free Software Foundation version 2 of the License.
13
14
This program is distributed in the hope that it will be useful,
15
but WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
GNU General Public License for more details.
18
***********************************************************************/
19
20
#ifdef WIN32
21
#pragma warning (disable : 4786)
22
#endif
23
#include <cstdlib>
24
#include <openbabel/babelconfig.h>
25
#include <openbabel/data.h>
26
#include <openbabel/data_utilities.h>
27
#include <openbabel/mol.h>
28
#include <openbabel/atom.h>
29
#include <openbabel/bond.h>
30
#include <openbabel/locale.h>
31
#include <openbabel/oberror.h>
32
#include <openbabel/elements.h>
33
34
// data headers with default parameters
35
#include "types.h"
36
#include "resdata.h"
37
#include "atomizationenergies.h"
38
39
#if !HAVE_STRNCASECMP
40
extern "C" int strncasecmp(const char *s1, const char *s2, size_t n);
41
#endif
42
43
using namespace std;
44
45
namespace OpenBabel
46
{
47
  // Initialize the globals (declared in data.h)
48
  OBTypeTable ttab;
49
  OBResidueData resdat;
50
51
  OBAtomicHeatOfFormationTable::OBAtomicHeatOfFormationTable(void)
52
0
  {
53
0
    _init = false;
54
0
    _dir = BABEL_DATADIR;
55
0
    _envvar = "BABEL_DATADIR";
56
0
    _filename = "atomization-energies.txt";
57
0
    _subdir = "data";
58
0
    _dataptr = AtomicHeatOfFormationData;
59
0
    Init();
60
0
  }
61
62
0
  static double UnitNameToConversionFactor(const char* unit) {
63
0
    const char* p = unit;
64
0
    switch(p[0]) {
65
0
    case 'e':
66
0
      if (p[1]=='V' && p[2]=='\0')
67
0
        return ELECTRONVOLT_TO_KCALPERMOL; // eV
68
0
      if (p[1]=='l' && p[2]=='e' && p[3]=='c' && p[4]=='t' && p[5]=='r' && p[6]=='o' && p[7]=='n' &&
69
0
          p[8]=='v' && p[9]=='o' && p[10]=='l' && p[11]=='t' && p[12]=='\0')
70
0
        return ELECTRONVOLT_TO_KCALPERMOL; // electronvolt
71
0
      break;
72
0
    case 'k':
73
0
      if (p[1]=='J' && p[2]=='/' && p[3]=='m' && p[4]=='o' && p[5]=='l' && p[6]=='\0')
74
0
        return KJPERMOL_TO_KCALPERMOL; // kJ/mol
75
0
      if (p[1]=='c' && p[2]=='a' && p[3]=='l' && p[4]=='/' && p[5]=='m' && p[6]=='o' && p[7]=='l' && p[8]=='\0')
76
0
        return 1.0; // kcal/mol
77
0
      break;
78
0
    case 'H':
79
0
      if (p[1]=='a' && p[2]=='r' && p[3]=='t' && p[4]=='r' && p[5]=='e' && p[6]=='e' && p[7]=='\0')
80
0
        return HARTEE_TO_KCALPERMOL; // Hartree
81
0
      break;
82
0
    case 'J':
83
0
      if (p[1]=='/' && p[2]=='m' && p[3]=='o' && p[4]=='l' && p[5]==' ' && p[6]=='K' && p[7]=='\0')
84
0
        return KJPERMOL_TO_KCALPERMOL; // J/mol K
85
0
      break;
86
0
    case 'R':
87
0
      if (p[1]=='y' && p[2]=='d' && p[3]=='b' && p[4]=='e' && p[5]=='r' && p[6]=='g' && p[7]=='\0')
88
0
        return RYDBERG_TO_KCALPERMOL; // Rydberg
89
0
      break;
90
0
    }
91
92
0
    std::stringstream errorMsg;
93
0
    errorMsg << "WARNING: Unknown energy unit in thermochemistry file\n";
94
0
    obErrorLog.ThrowError(__FUNCTION__, errorMsg.str() , obWarning);
95
96
0
    return 1.0;
97
0
  }
98
99
  void OBAtomicHeatOfFormationTable::ParseLine(const char *line)
100
0
  {
101
0
    char *ptr;
102
0
    vector<string> vs;
103
0
    OBAtomHOF *oba;
104
105
0
    ptr = const_cast<char*>( strchr(line,'#'));
106
0
    if (nullptr != ptr)
107
0
      ptr[0] = '\0';
108
0
    if (strlen(line) > 0)
109
0
      {
110
0
        tokenize(vs,line,"|");
111
0
        if (vs.size() >= 8)
112
0
          {
113
0
              oba = new OBAtomHOF(vs[0],
114
0
                                  atoi(vs[1].c_str()),
115
0
                                  vs[2],
116
0
                                  vs[3],
117
0
                                  atof(vs[4].c_str()),
118
0
                                  atof(vs[5].c_str()),
119
0
                                  atoi(vs[6].c_str()),
120
0
                                  vs[7]);
121
0
            _atomhof.push_back(*oba);
122
0
          }
123
0
      }
124
0
  }
125
126
  int OBAtomicHeatOfFormationTable::GetHeatOfFormation(std::string elem,
127
                                                       int charge,
128
                                                       std::string meth,
129
                                                       double T,
130
                                                       double *dhof0,
131
                                                       double *dhofT,
132
                                                       double *S0T)
133
0
  {
134
0
    int    found;
135
0
    double Ttol = 0.05; /* Kelvin */
136
0
    double Vmodel, Vdhf, S0, HexpT;
137
0
    std::vector<OBAtomHOF>::iterator it;
138
0
    char desc[128];
139
140
0
    found = 0;
141
0
    Vmodel = Vdhf = S0 = HexpT = 0;
142
0
    snprintf(desc,sizeof(desc),"%s(0K)",meth.c_str());
143
144
0
    for(it = _atomhof.begin(); it != _atomhof.end(); ++it)
145
0
    {
146
0
        if ((0 == it->Element().compare(elem)) &&
147
0
            (it->Charge() == charge))
148
0
        {
149
0
            double eFac = UnitNameToConversionFactor(it->Unit().c_str());
150
0
            if (fabs(T - it->T()) < Ttol)
151
0
            {
152
0
                if (0 == it->Method().compare("exp"))
153
0
                {
154
0
                    if (0 == it->Desc().compare("H(0)-H(T)"))
155
0
                    {
156
0
                        HexpT += it->Value()*eFac;
157
0
                        found++;
158
0
                    }
159
0
                    else if (0 == it->Desc().compare("S0(T)"))
160
0
                    {
161
0
                        S0 += it->Value();
162
0
                        found++;
163
0
                    }
164
0
                }
165
0
            }
166
0
            else if (0 == it->T()) 
167
0
            {
168
0
                if ((0 == it->Method().compare(meth)) &&
169
0
                    (0 == it->Desc().compare(desc)))
170
0
                {
171
0
                    Vmodel += it->Value()*eFac;
172
0
                    found++;
173
0
                }
174
0
                if (0 == it->Method().compare("exp"))
175
0
                {
176
0
                    if (0 == it->Desc().compare("DHf(T)"))
177
0
                    {
178
0
                        Vdhf += it->Value()*eFac;
179
0
                        found++;
180
0
                    }
181
0
                }
182
0
            }
183
0
        }
184
0
    }
185
186
0
    if (found == 4)
187
0
    {
188
0
        *dhof0 = Vdhf-Vmodel;
189
0
        *dhofT = Vdhf-Vmodel-HexpT;
190
0
        *S0T   = -S0/4.184;
191
0
        return 1;
192
0
    }
193
0
    return 0;
194
0
  }
195
196
  /** \class OBTypeTable data.h <openbabel/data.h>
197
      \brief Atom Type Translation Table
198
199
      Molecular file formats frequently store information about atoms in an
200
      atom type field. Some formats store only the element for each atom,
201
      while others include hybridization and local environments, such as the
202
      Sybyl mol2 atom type field. The OBTypeTable class acts as a translation
203
      table to convert atom types between a number of different molecular
204
      file formats. The constructor for OBTypeTable automatically reads the
205
      text file types.txt. An instance of
206
      OBTypeTable (ttab) is declared external in data.cpp and is referenced as
207
      extern OBTypeTable ttab in mol.h.  The following code demonstrates how
208
      to use the OBTypeTable class to translate the internal representation
209
      of atom types in an OBMol Internal to Sybyl Mol2 atom types.
210
211
      \code
212
      ttab.SetFromType("INT");
213
      ttab.SetToType("SYB");
214
      OBAtom *atom;
215
      vector<OBAtom*>::iterator i;
216
      string src,dst;
217
      for (atom = mol.BeginAtom(i);atom;atom = mol.EndAtom(i))
218
      {
219
         src = atom->GetType();
220
         ttab.Translate(dst,src);
221
         cout << "atom number " << atom->GetIdx() << "has mol2 type " << dst << endl;
222
      }
223
      \endcode
224
225
      Current atom types include (defined in the top line of the data file types.txt):
226
      - INT (Open Babel internal codes)
227
      - ATN (atomic numbers)
228
      - HYB (hybridization)
229
      - MMD (MacroModel)
230
      - MM2 (MM2 force field)
231
      - XYZ (element symbols from XYZ file format)
232
      - ALC (Alchemy)
233
      - HAD (H added)
234
      - MCML (MacMolecule)
235
      - C3D (Chem3D)
236
      - SYB (Sybyl mol2)
237
      - MOL (Sybyl mol)
238
      - MAP (Gasteiger partial charge types)
239
      - DRE (Dreiding)
240
      - XED (XED format)
241
      - DOK (Dock)
242
      - M3D (Molecular Arts M3D)
243
      - SBN (Sybyl descriptor types for MPD files)
244
      - PCM (PC Model)
245
  */
246
247
  OBTypeTable::OBTypeTable()
248
2
  {
249
2
    _init = false;
250
2
    _dir = BABEL_DATADIR;
251
2
    _envvar = "BABEL_DATADIR";
252
2
    _filename = "types.txt";
253
2
    _subdir = "data";
254
2
    _dataptr = TypesData;
255
2
    _linecount = 0;
256
2
    _from = _to = -1;
257
2
  }
258
259
  void OBTypeTable::ParseLine(const char *buffer)
260
198
  {
261
198
    if (buffer[0] == '#')
262
0
      return; // just a comment line
263
264
198
    if (_linecount == 0) {
265
1
      tokenize(_colnames,buffer);
266
1
      _ncols = _colnames.size();
267
1
    }
268
197
    else
269
197
      {
270
197
        vector<string> vc;
271
197
        tokenize(vc,buffer);
272
197
        if (vc.size() == (unsigned)_ncols)
273
197
          _table.push_back(vc);
274
0
        else
275
0
          {
276
0
            stringstream errorMsg;
277
0
            errorMsg << " Could not parse line in type translation table types.txt -- incorect number of columns";
278
0
            errorMsg << " found " << vc.size() << " expected " << _ncols << ".";
279
0
            obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obInfo);
280
0
          }
281
197
      }
282
198
    _linecount++;
283
198
  }
284
285
  bool OBTypeTable::SetFromType(const char* from)
286
1
  {
287
1
    if (!_init)
288
0
      Init();
289
290
1
    string tmp = from;
291
292
1
    unsigned int i;
293
5
    for (i = 0;i < _colnames.size();++i)
294
5
      if (tmp == _colnames[i])
295
1
        {
296
1
          _from = i;
297
1
          return(true);
298
1
        }
299
300
0
    obErrorLog.ThrowError(__FUNCTION__, "Requested type column not found", obInfo);
301
302
0
    return(false);
303
1
  }
304
305
  bool OBTypeTable::SetToType(const char* to)
306
1
  {
307
1
    if (!_init)
308
1
      Init();
309
310
1
    string tmp = to;
311
312
1
    unsigned int i;
313
1
    for (i = 0;i < _colnames.size();++i)
314
1
      if (tmp == _colnames[i])
315
1
        {
316
1
          _to = i;
317
1
          return(true);
318
1
        }
319
320
0
    obErrorLog.ThrowError(__FUNCTION__, "Requested type column not found", obInfo);
321
322
0
    return(false);
323
1
  }
324
325
  //! Translates atom types (to, from), checking for size of destination
326
  //!  string and null-terminating as needed
327
  //! \deprecated Because there is no guarantee on the length of an atom type
328
  //!  you should consider using std::string instead
329
  OB_DEPRECATED_MSG("you should consider using std::string instead")
330
  bool OBTypeTable::Translate(char *to, const char *from)
331
0
  {
332
0
    if (!_init)
333
0
      Init();
334
335
0
    bool rval;
336
0
    string sto,sfrom;
337
0
    sfrom = from;
338
0
    rval = Translate(sto,sfrom);
339
0
    strncpy(to,(char*)sto.c_str(), OBATOM_TYPE_LEN - 1);
340
0
    to[OBATOM_TYPE_LEN - 1] = '\0';
341
342
0
    return(rval);
343
0
  }
344
345
  bool OBTypeTable::Translate(string &to, const string &from)
346
0
  {
347
0
    if (!_init)
348
0
      Init();
349
350
0
    if (from == "")
351
0
      return(false);
352
353
0
    if (_from >= 0 && _to >= 0 &&
354
0
        _from < (signed)_table.size() && _to < (signed)_table.size())
355
0
      {
356
0
        vector<vector<string> >::iterator i;
357
0
        for (i = _table.begin();i != _table.end();++i)
358
0
          if ((signed)(*i).size() > _from &&  (*i)[_from] == from)
359
0
            {
360
0
              to = (*i)[_to];
361
0
              return(true);
362
0
            }
363
0
      }
364
365
    // Throw an error, copy the string and return false
366
0
    obErrorLog.ThrowError(__FUNCTION__, "Cannot perform atom type translation: table cannot find requested types.", obWarning);
367
0
    to = from;
368
0
    return(false);
369
0
  }
370
371
  std::string OBTypeTable::Translate(const string &from)
372
0
  {
373
0
    if (!_init)
374
0
      Init();
375
376
0
    if (from.empty())
377
0
      return("");
378
379
0
    if (_from >= 0 && _to >= 0 &&
380
0
        _from < (signed)_table.size() && _to < (signed)_table.size())
381
0
      {
382
0
        vector<vector<string> >::iterator i;
383
0
        for (i = _table.begin();i != _table.end();++i)
384
0
          if ((signed)(*i).size() > _from &&  (*i)[_from] == from)
385
0
            {
386
0
              return (*i)[_to];
387
0
            }
388
0
      }
389
390
    // Throw an error, copy the string and return false
391
0
    obErrorLog.ThrowError(__FUNCTION__, "Cannot perform atom type translation: table cannot find requested types.", obWarning);
392
0
    return("");
393
0
  }
394
395
  std::string OBTypeTable::GetFromType()
396
0
  {
397
0
    if (!_init)
398
0
      Init();
399
400
0
    if (_from > 0 && _from < (signed)_table.size())
401
0
      return( _colnames[_from] );
402
0
    else
403
0
      return( _colnames[0] );
404
0
  }
405
406
  std::string OBTypeTable::GetToType()
407
0
  {
408
0
    if (!_init)
409
0
      Init();
410
411
0
    if (_to > 0 && _to < (signed)_table.size())
412
0
      return( _colnames[_to] );
413
0
    else
414
0
      return( _colnames[0] );
415
0
  }
416
417
  void Toupper(string &s)
418
0
  {
419
0
    unsigned int i;
420
0
    for (i = 0;i < s.size();++i)
421
0
      s[i] = toupper(s[i]);
422
0
  }
423
424
  void Tolower(string &s)
425
0
  {
426
0
    unsigned int i;
427
0
    for (i = 0;i < s.size();++i)
428
0
      s[i] = tolower(s[i]);
429
0
  }
430
431
  ///////////////////////////////////////////////////////////////////////
432
  OBResidueData::OBResidueData()
433
2
  {
434
2
    _init = false;
435
2
    _dir = BABEL_DATADIR;
436
2
    _envvar = "BABEL_DATADIR";
437
2
    _filename = "resdata.txt";
438
2
    _subdir = "data";
439
2
    _dataptr = ResidueData;
440
2
  }
441
442
  bool OBResidueData::AssignBonds(OBMol &mol)
443
0
  {
444
0
    if (!_init)
445
0
      Init();
446
447
0
    OBAtom *a1,*a2;
448
0
    OBResidue *r1,*r2;
449
0
    vector<OBAtom*>::iterator i,j;
450
0
    vector3 v;
451
452
0
    int bo;
453
0
    string skipres = ""; // Residue Number to skip
454
0
    string rname = "";
455
    //assign residue bonds
456
0
    for (a1 = mol.BeginAtom(i);a1;a1 = mol.NextAtom(i))
457
0
      {
458
0
        r1 = a1->GetResidue();
459
0
        if (r1 == nullptr) // atoms may not have residues
460
0
          continue;
461
462
0
        if (skipres.length() && r1->GetNumString() == skipres)
463
0
          continue;
464
465
0
        if (r1->GetName() != rname)
466
0
          {
467
0
            skipres = SetResName(r1->GetName()) ? "" : r1->GetNumString();
468
0
            rname = r1->GetName();
469
0
          }
470
        //assign bonds for each atom
471
0
        for (j=i,a2 = mol.NextAtom(j);a2;a2 = mol.NextAtom(j))
472
0
          {
473
0
            r2 = a2->GetResidue();
474
0
            if (r2 == nullptr) // atoms may not have residues
475
0
              continue;
476
477
0
            if (r1->GetNumString() != r2->GetNumString())
478
0
              break;
479
0
            if (r1->GetName() != r2->GetName())
480
0
              break;
481
0
            if (r1->GetChain() != r2->GetChain())
482
0
              break; // Fixes PR#2889763 - Fabian
483
484
0
            if ((bo = LookupBO(r1->GetAtomID(a1),r2->GetAtomID(a2))))
485
0
              {
486
                // Suggested by Liu Zhiguo 2007-08-13
487
                // for predefined residues, don't perceive connection
488
                // by distance
489
                //                v = a1->GetVector() - a2->GetVector();
490
                //                if (v.length_2() < 3.5) //check by distance
491
0
                  mol.AddBond(a1->GetIdx(),a2->GetIdx(),bo);
492
0
              }
493
0
          }
494
0
      }
495
496
0
    int hyb;
497
0
    string type;
498
499
    //types and hybridization
500
0
    rname = ""; // name of current residue
501
0
    skipres = ""; // don't skip any residues right now
502
0
    for (a1 = mol.BeginAtom(i);a1;a1 = mol.NextAtom(i))
503
0
      {
504
0
        if (a1->GetAtomicNum() == OBElements::Oxygen && !a1->GetExplicitDegree())
505
0
          {
506
0
            a1->SetType("O3");
507
0
            continue;
508
0
          }
509
0
        if (a1->GetAtomicNum() == OBElements::Hydrogen)
510
0
          {
511
0
            a1->SetType("H");
512
0
            continue;
513
0
          }
514
515
        //***valence rule for O-
516
0
        if (a1->GetAtomicNum() == OBElements::Oxygen && a1->GetExplicitDegree() == 1)
517
0
          {
518
0
            OBBond *bond;
519
0
            bond = (OBBond*)*(a1->BeginBonds());
520
0
            if (bond->GetBondOrder() == 2)
521
0
              {
522
0
                a1->SetType("O2");
523
0
                a1->SetHyb(2);
524
0
              }
525
0
            else if (bond->GetBondOrder() == 1)
526
0
              {
527
                // Leave the protonation/deprotonation to phmodel.txt
528
0
                a1->SetType("O3");
529
0
                a1->SetHyb(3);
530
                // PR#3203039 -- Fix from Magnus Lundborg
531
                //                a1->SetFormalCharge(0);
532
0
              }
533
0
            continue;
534
0
          }
535
536
0
        r1 = a1->GetResidue();
537
0
        if (r1 == nullptr) continue; // atoms may not have residues
538
0
        if (skipres.length() && r1->GetNumString() == skipres)
539
0
          continue;
540
541
0
        if (r1->GetName() != rname)
542
0
          {
543
            // if SetResName fails, skip this residue
544
0
            skipres = SetResName(r1->GetName()) ? "" : r1->GetNumString();
545
0
            rname = r1->GetName();
546
0
          }
547
548
0
        if (LookupType(r1->GetAtomID(a1),type,hyb))
549
0
          {
550
0
            a1->SetType(type);
551
0
            a1->SetHyb(hyb);
552
0
          }
553
0
        else // try to figure it out by bond order ???
554
0
          {}
555
0
      }
556
557
0
    return(true);
558
0
  }
559
560
  void OBResidueData::ParseLine(const char *buffer)
561
0
  {
562
0
    int bo;
563
0
    string s;
564
0
    vector<string> vs;
565
566
0
    if (buffer[0] == '#')
567
0
      return;
568
569
0
    tokenize(vs,buffer);
570
0
    if (!vs.empty())
571
0
      {
572
0
        if (vs[0] == "BOND")
573
0
          {
574
0
            s = (vs[1] < vs[2]) ? vs[1] + " " + vs[2] :
575
0
              vs[2] + " " + vs[1];
576
0
            bo = atoi(vs[3].c_str());
577
0
            _vtmp.push_back(pair<string,int> (s,bo));
578
0
          }
579
580
0
        if (vs[0] == "ATOM" && vs.size() == 4)
581
0
          {
582
0
            _vatmtmp.push_back(vs[1]);
583
0
            _vatmtmp.push_back(vs[2]);
584
0
            _vatmtmp.push_back(vs[3]);
585
0
          }
586
587
0
        if (vs[0] == "RES")
588
0
          _resname.push_back(vs[1]);
589
590
0
        if (vs[0]== "END")
591
0
          {
592
0
            _resatoms.push_back(_vatmtmp);
593
0
            _resbonds.push_back(_vtmp);
594
0
            _vtmp.clear();
595
0
            _vatmtmp.clear();
596
0
          }
597
0
      }
598
0
  }
599
600
  bool OBResidueData::SetResName(const string &s)
601
0
  {
602
0
    if (!_init)
603
0
      Init();
604
605
0
    unsigned int i;
606
607
0
    for (i = 0;i < _resname.size();++i)
608
0
      if (_resname[i] == s)
609
0
        {
610
0
          _resnum = i;
611
0
          return(true);
612
0
        }
613
614
0
    _resnum = -1;
615
0
    return(false);
616
0
  }
617
618
  int OBResidueData::LookupBO(const string &s)
619
0
  {
620
0
    if (_resnum == -1)
621
0
      return(0);
622
623
0
    unsigned int i;
624
0
    for (i = 0;i < _resbonds[_resnum].size();++i)
625
0
      if (_resbonds[_resnum][i].first == s)
626
0
        return(_resbonds[_resnum][i].second);
627
628
0
    return(0);
629
0
  }
630
631
  int OBResidueData::LookupBO(const string &s1, const string &s2)
632
0
  {
633
0
    if (_resnum == -1)
634
0
      return(0);
635
0
    string s;
636
637
0
    s = (s1 < s2) ? s1 + " " + s2 : s2 + " " + s1;
638
639
0
    unsigned int i;
640
0
    for (i = 0;i < _resbonds[_resnum].size();++i)
641
0
      if (_resbonds[_resnum][i].first == s)
642
0
        return(_resbonds[_resnum][i].second);
643
644
0
    return(0);
645
0
  }
646
647
  bool OBResidueData::LookupType(const string &atmid,string &type,int &hyb)
648
0
  {
649
0
    if (_resnum == -1)
650
0
      return(false);
651
652
0
    string s;
653
0
    vector<string>::iterator i;
654
655
0
    for (i = _resatoms[_resnum].begin();i != _resatoms[_resnum].end();i+=3)
656
0
      if (atmid == *i)
657
0
        {
658
0
          ++i;
659
0
          type = *i;
660
0
          ++i;
661
0
          hyb = atoi((*i).c_str());
662
0
          return(true);
663
0
        }
664
665
0
    return(false);
666
0
  }
667
668
  void OBGlobalDataBase::Init()
669
3
  {
670
3
    if (_init)
671
0
      return;
672
3
    _init = true;
673
674
3
    ifstream ifs;
675
3
    char charBuffer[BUFF_SIZE];
676
677
    // Set the locale for number parsing to avoid locale issues: PR#1785463
678
3
    obLocale.SetLocale();
679
680
    // Check return value from OpenDatafile
681
    // Suggestion from Zhiguo Liu
682
3
    string fn_open = OpenDatafile(ifs, _filename, _envvar);
683
    
684
    // Check _subdir directory
685
3
    if (fn_open == "")
686
3
      string fn_open = OpenDatafile(ifs, _filename, _subdir);
687
688
3
    if (fn_open != "" && (ifs))
689
0
      {
690
0
        while(ifs.getline(charBuffer,BUFF_SIZE))
691
0
          ParseLine(charBuffer);
692
0
      }
693
694
3
    else
695
      // If all else fails, use the compiled in values
696
3
      if (_dataptr)
697
3
        {
698
3
          obErrorLog.ThrowError(__FUNCTION__, "Cannot open " + _filename + " defaulting to compiled data.", obDebug);
699
700
3
          const char *p1,*p2;
701
15.9k
          for (p1 = p2 = _dataptr;*p2 != '\0';++p2)
702
15.9k
            if (*p2 == '\n')
703
295
              {
704
295
                strncpy(charBuffer, p1, (p2 - p1));
705
295
                charBuffer[(p2 - p1)] = '\0';
706
295
                ParseLine(charBuffer);
707
295
                p1 = p2 + 1;
708
295
              }
709
3
        }
710
0
      else
711
0
        {
712
0
          string s = "Unable to open data file '";
713
0
          s += _filename;
714
0
          s += "'";
715
0
          obErrorLog.ThrowError(__FUNCTION__, s, obWarning);
716
0
        }
717
718
    // return the locale to the original one
719
3
    obLocale.RestoreLocale();
720
721
3
    if (ifs)
722
0
      ifs.close();
723
724
3
    if (GetSize() == 0)
725
0
      {
726
0
        string s = "Cannot initialize database '";
727
0
        s += _filename;
728
0
        s += "' which may cause further errors.";
729
0
        obErrorLog.ThrowError(__FUNCTION__, s, obWarning);
730
0
      }
731
732
3
  }
733
734
} // end namespace OpenBabel
735
736
//! \file data.cpp
737
//! \brief Global data and resource file parsers.