1 /**********************************************************************
2 Copyright (C) 2000 by OpenEye Scientific Software, Inc.
3 Some portions Copyright (C) 2001-2006 by Geoffrey R. Hutchison
4 Some portions Copyright (C) 2004 by Chris Morley
5 
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation version 2 of the License.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 ***********************************************************************/
15 #include <openbabel/babelconfig.h>
16 
17 #include <openbabel/obmolecformat.h>
18 #include <openbabel/mol.h>
19 #include <openbabel/atom.h>
20 #include <openbabel/bond.h>
21 #include <openbabel/obiter.h>
22 #include <openbabel/elements.h>
23 
24 #include <cstdlib>
25 
26 using namespace std;
27 namespace OpenBabel
28 {
29 
30   class HINFormat : public OBMoleculeFormat
31   {
32   public:
33     //Register this format type ID
HINFormat()34     HINFormat()
35     {
36       OBConversion::RegisterFormat("hin",this, "chemical/x-hin");
37     }
38 
Description()39     virtual const char* Description() //required
40     {
41       return "HyperChem HIN format\n"
42              "No comments yet\n";
43     };
44 
SpecificationURL()45     virtual const char* SpecificationURL()
46     { return "";}; //optional
47 
GetMIMEType()48     virtual const char* GetMIMEType()
49     { return "chemical/x-hin";}; //optional
50 
51     //*** This section identical for most OBMol conversions ***
52     ////////////////////////////////////////////////////
53     /// The "API" interface functions
54     virtual bool ReadMolecule(OBBase* pOb, OBConversion* pConv);
55     virtual bool WriteMolecule(OBBase* pOb, OBConversion* pConv);
56   };
57   //***
58 
59   //Make an instance of the format class
60   HINFormat theHINFormat;
61 
62   /////////////////////////////////////////////////////////////////
ReadMolecule(OBBase * pOb,OBConversion * pConv)63   bool HINFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv)
64   {
65 
66     OBMol* pmol = pOb->CastAndClear<OBMol>();
67     if (pmol == nullptr)
68       return false;
69 
70     //Define some references so we can use the old parameter names
71     istream &ifs = *pConv->GetInStream();
72     OBMol &mol = *pmol;
73     const char* title = pConv->GetTitle();
74 
75     // Right now only read in the first molecule
76     int i;
77     int max, bo;
78     char buffer[BUFF_SIZE];
79     string str,str1;
80     double x,y,z;
81     OBAtom *atom;
82     vector<string> vs;
83 
84     ifs.getline(buffer, BUFF_SIZE);
85     while (ifs.good() && (strstr(buffer, "mol") == nullptr || buffer[0] == ';')) //The "mol" in comment line should be ignored.
86       {
87         ifs.getline(buffer, BUFF_SIZE);
88         if (ifs.peek() == EOF || !ifs.good())
89           return false;
90       }
91     ifs.getline(buffer, BUFF_SIZE);
92     if (!ifs.good())
93       return false; // ended early
94 
95     mol.BeginModify();
96     while (ifs.good() && strstr(buffer, "endmol") == nullptr)
97       {
98 	if(buffer[0]==';'){
99 		 ifs.getline(buffer, BUFF_SIZE);
100 		 continue; //The comment Line in HIN should be ignored.
101 	}
102 
103         tokenize(vs,buffer); // Don't really know how long it'll be
104         if (vs.size() < 11)
105           {
106             ifs.getline(buffer, BUFF_SIZE);
107             continue;
108           }
109 
110         atom = mol.NewAtom();
111         atom->SetAtomicNum(OBElements::GetAtomicNum(vs[3].c_str()));
112         atom->SetPartialCharge(atof(vs[6].c_str()));
113         x = atof((char*)vs[7].c_str());
114         y = atof((char*)vs[8].c_str());
115         z = atof((char*)vs[9].c_str());
116         atom->SetVector(x,y,z);
117 
118         max = 11 + 2 * atoi((char *)vs[10].c_str());
119         for (i = 11; i < max; i+=2)
120           {
121             switch(((char*)vs[i+1].c_str())[0]) // First char in next token
122               {
123               case 's':
124                 bo = 1;
125                 break;
126               case 'd':
127                 bo = 2;
128                 break;
129               case 't':
130                 bo = 3;
131                 break;
132               case 'a':
133                 bo = 5;
134                 break;
135               default :
136                 bo = 1;
137                 break;
138               }
139             mol.AddBond(mol.NumAtoms(), atoi((char *)vs[i].c_str()), bo);
140           }
141         ifs.getline(buffer, BUFF_SIZE);
142       }
143 
144     // clean out remaining blank lines
145     // blank lines cleaning codes rewritten for avoiding peek() and tellg() bugs
146     // https://github.com/openbabel/openbabel/issues/1569
147     std::streampos ipos;
148     do
149     {
150       ipos = ifs.tellg();
151       ifs.getline(buffer,BUFF_SIZE);
152     }
153     while(strlen(buffer) == 0 && !ifs.eof() );
154     ifs.seekg(ipos);
155 
156 
157     mol.EndModify();
158 
159     mol.SetTitle(title);
160     mol.SetPartialChargesPerceived();
161 
162     return(true);
163   }
164 
165   ////////////////////////////////////////////////////////////////
166 
WriteMolecule(OBBase * pOb,OBConversion * pConv)167   bool HINFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv)
168   {
169     OBMol* pmol = dynamic_cast<OBMol*>(pOb);
170     if (pmol == nullptr)
171       return false;
172 
173     //Define some references so we can use the old parameter names
174     ostream &ofs = *pConv->GetOutStream();
175     OBMol &mol = *pmol;
176 
177     unsigned int i, file_num = 1;
178     string str,str1;
179     char buffer[BUFF_SIZE];
180     OBAtom *atom;
181     OBBond *bond;
182     vector<OBBond*>::iterator j;
183     char bond_char;
184 
185     // make sure to escape titles in double quotes
186     // PR#1501694
187     ofs << "mol " << file_num << " \"" << mol.GetTitle() << "\"\n";
188 
189     for(i = 1;i <= mol.NumAtoms(); i++)
190       {
191         atom = mol.GetAtom(i);
192         snprintf(buffer, BUFF_SIZE, "atom %d - %-3s **  - %8.5f %8.5f  %8.5f  %8.5f %d ",
193                 i,
194                 OBElements::GetSymbol(atom->GetAtomicNum()),
195                 atom->GetPartialCharge(),
196                 atom->GetX(),
197                 atom->GetY(),
198                 atom->GetZ(),
199                 atom->GetExplicitDegree());
200         ofs << buffer;
201         for (bond = atom->BeginBond(j); bond; bond = atom->NextBond(j))
202           {
203             switch(bond->GetBondOrder())
204               {
205               case 1 :
206                 bond_char = 's';
207                 break;
208               case 2 :
209                 bond_char = 'd';
210                 break;
211               case 3 :
212                 bond_char = 't';
213                 break;
214               case 5 :
215                 bond_char = 'a';
216                 break;
217               default:
218                 bond_char = 's';
219                 break;
220               }
221             if (bond->IsAromatic())
222               bond_char = 'a';
223 
224             snprintf(buffer,BUFF_SIZE, "%d %c ", (bond->GetNbrAtom(atom))->GetIdx(), bond_char);
225             ofs << buffer;
226           }
227         ofs << endl;
228       }
229     ofs << "endmol " << file_num << endl;
230     return(true);
231   }
232 
233 } //namespace OpenBabel
234