rino 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. data/Rakefile +1 -1
  2. data/ext/extconf.rb +1 -24
  3. data/ext/libinchi.so +0 -0
  4. data/ext/src/aux2atom.h +120 -39
  5. data/ext/src/comdef.h +3 -3
  6. data/ext/src/dispstru.c +2547 -0
  7. data/ext/src/dispstru.h +73 -0
  8. data/ext/src/extr_ct.h +5 -2
  9. data/ext/src/ichi.h +27 -11
  10. data/ext/src/ichi_bns.c +1800 -254
  11. data/ext/src/ichi_bns.h +205 -4
  12. data/ext/src/ichican2.c +197 -86
  13. data/ext/src/ichicano.c +8 -13
  14. data/ext/src/ichicano.h +2 -2
  15. data/ext/src/ichicans.c +11 -6
  16. data/ext/src/ichicant.h +2 -2
  17. data/ext/src/ichicomn.h +2 -2
  18. data/ext/src/ichicomp.h +19 -4
  19. data/ext/src/ichidrp.h +9 -5
  20. data/ext/src/ichierr.h +5 -3
  21. data/ext/src/ichiisot.c +2 -2
  22. data/ext/src/ichimain.c +461 -0
  23. data/ext/src/ichimain.h +23 -15
  24. data/ext/src/ichimak2.c +6 -6
  25. data/ext/src/ichimake.c +843 -42
  26. data/ext/src/ichimake.h +4 -2
  27. data/ext/src/ichimap1.c +5 -5
  28. data/ext/src/ichimap2.c +2 -2
  29. data/ext/src/ichimap4.c +34 -21
  30. data/ext/src/ichinorm.c +11 -5
  31. data/ext/src/ichinorm.h +3 -2
  32. data/ext/src/ichiparm.c +2 -2
  33. data/ext/src/ichiparm.h +232 -30
  34. data/ext/src/ichiprt1.c +35 -11
  35. data/ext/src/ichiprt2.c +78 -7
  36. data/ext/src/ichiprt3.c +300 -120
  37. data/ext/src/ichiqueu.c +17 -2
  38. data/ext/src/ichiread.c +6932 -0
  39. data/ext/src/ichiring.c +3 -2
  40. data/ext/src/ichiring.h +2 -2
  41. data/ext/src/ichirvr1.c +4891 -0
  42. data/ext/src/ichirvr2.c +6344 -0
  43. data/ext/src/ichirvr3.c +5499 -0
  44. data/ext/src/ichirvr4.c +3177 -0
  45. data/ext/src/ichirvr5.c +1166 -0
  46. data/ext/src/ichirvr6.c +1287 -0
  47. data/ext/src/ichirvr7.c +2319 -0
  48. data/ext/src/ichirvrs.h +882 -0
  49. data/ext/src/ichisize.h +2 -2
  50. data/ext/src/ichisort.c +5 -5
  51. data/ext/src/ichister.c +281 -86
  52. data/ext/src/ichister.h +9 -3
  53. data/ext/src/ichitaut.c +208 -9
  54. data/ext/src/ichitaut.h +13 -11
  55. data/ext/src/ichitime.h +16 -2
  56. data/ext/src/inchicmp.h +107 -0
  57. data/ext/src/inpdef.h +6 -3
  58. data/ext/src/libinchi_wrap.c +912 -0
  59. data/ext/src/lreadmol.h +34 -31
  60. data/ext/src/mode.h +244 -7
  61. data/ext/src/mol2atom.c +1060 -0
  62. data/ext/src/mol2atom.h +31 -0
  63. data/ext/src/readinch.c +239 -0
  64. data/ext/src/readmol.c +28 -0
  65. data/ext/src/{e_readmol.h → readmol.h} +7 -9
  66. data/ext/src/runichi.c +251 -177
  67. data/ext/src/strutil.c +444 -238
  68. data/ext/src/strutil.h +150 -11
  69. data/ext/src/util.c +176 -118
  70. data/ext/src/util.h +15 -3
  71. data/lib/rino.rb +71 -3
  72. data/test/test.rb +33 -4
  73. metadata +22 -34
  74. data/ext/ruby_inchi_main.so +0 -0
  75. data/ext/src/e_0dstereo.c +0 -3014
  76. data/ext/src/e_0dstereo.h +0 -31
  77. data/ext/src/e_comdef.h +0 -57
  78. data/ext/src/e_ctl_data.h +0 -147
  79. data/ext/src/e_ichi_io.c +0 -498
  80. data/ext/src/e_ichi_io.h +0 -40
  81. data/ext/src/e_ichi_parms.c +0 -37
  82. data/ext/src/e_ichi_parms.h +0 -41
  83. data/ext/src/e_ichicomp.h +0 -50
  84. data/ext/src/e_ichierr.h +0 -40
  85. data/ext/src/e_ichimain.c +0 -593
  86. data/ext/src/e_ichisize.h +0 -43
  87. data/ext/src/e_inchi_atom.c +0 -75
  88. data/ext/src/e_inchi_atom.h +0 -33
  89. data/ext/src/e_inpdef.h +0 -41
  90. data/ext/src/e_mode.h +0 -706
  91. data/ext/src/e_mol2atom.c +0 -649
  92. data/ext/src/e_readinch.c +0 -58
  93. data/ext/src/e_readmol.c +0 -54
  94. data/ext/src/e_readstru.c +0 -251
  95. data/ext/src/e_readstru.h +0 -33
  96. data/ext/src/e_util.c +0 -284
  97. data/ext/src/e_util.h +0 -61
  98. data/ext/src/ichilnct.c +0 -286
  99. data/ext/src/inchi_api.h +0 -670
  100. data/ext/src/inchi_dll.c +0 -1480
  101. data/ext/src/inchi_dll.h +0 -34
  102. data/ext/src/inchi_dll_main.c +0 -23
  103. data/ext/src/inchi_dll_main.h +0 -31
  104. data/ext/src/ruby_inchi_main.c +0 -558
@@ -0,0 +1,2319 @@
1
+ /*
2
+ * International Union of Pure and Applied Chemistry (IUPAC)
3
+ * International Chemical Identifier (InChI)
4
+ * Version 1
5
+ * Software version 1.01
6
+ * July 21, 2006
7
+ * Developed at NIST
8
+ */
9
+
10
+ #include <stdio.h>
11
+ #include <stdlib.h>
12
+ #include <string.h>
13
+ #include <ctype.h>
14
+ #include <math.h>
15
+
16
+ /* #define CHECK_WIN32_VC_HEAP */
17
+ #include "mode.h"
18
+
19
+ #if( READ_INCHI_STRING == 1 )
20
+
21
+ #include "ichicomp.h"
22
+ #include "ichi.h"
23
+ #include "ichitime.h"
24
+ #include "ichierr.h"
25
+ #include "util.h"
26
+ #include "strutil.h"
27
+
28
+ /* reverse InChI */
29
+ #include "ichimain.h"
30
+ #include "extr_ct.h"
31
+ #include "ichitaut.h"
32
+ #include "ichister.h"
33
+ #include "strutil.h"
34
+ #include "ichisize.h"
35
+ #include "ichiring.h"
36
+ #include "ichinorm.h"
37
+
38
+ #include "ichirvrs.h"
39
+ #include "inchicmp.h"
40
+
41
+ /******************************************************************************************************/
42
+ int InChI2Atom( ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd, const char *szCurHdr, long num_inp,
43
+ StrFromINChI *pStruct, int iComponent, int iAtNoOffset, int bI2A_Flag, int bHasSomeFixedH, InpInChI *OneInput)
44
+ {
45
+ int iINChI = (bI2A_Flag & I2A_FLAG_RECMET)? INCHI_REC : INCHI_BAS;
46
+ int bMobileH = (bI2A_Flag & I2A_FLAG_FIXEDH)? TAUT_NON : TAUT_YES;
47
+ INChI *pInChI[TAUT_NUM];
48
+ int ret = 0;
49
+
50
+ memset( pInChI, 0, sizeof(pInChI) );
51
+ /* disconnected or reconnected */
52
+ if ( iINChI == INCHI_REC ) {
53
+ if ( !OneInput->nNumComponents[iINChI][TAUT_YES] ) {
54
+ iINChI = INCHI_BAS;
55
+ }
56
+ }
57
+ if ( iComponent >= OneInput->nNumComponents[iINChI][TAUT_YES] ) {
58
+ return 0; /* component does not exist */
59
+ }
60
+ /* mobile or fixed H */
61
+ pStruct->bFixedHExists = 0;
62
+ if ( bMobileH == TAUT_NON ) {
63
+ if ( !OneInput->nNumComponents[iINChI][bMobileH] ) {
64
+ /* only one InChI exists (no mobile H) */
65
+ bMobileH = TAUT_YES;
66
+ }
67
+ }
68
+
69
+ if ( iComponent >= OneInput->nNumComponents[iINChI][bMobileH] ) {
70
+ return 0; /* component does not exist */
71
+ }
72
+ /* pointer to the InChI that is going to be reversed */
73
+ pInChI[0] = &OneInput->pInpInChI[iINChI][bMobileH][iComponent];
74
+ pStruct->bMobileH = bMobileH;
75
+ pStruct->iINCHI = iINChI;
76
+ /* deleted component only in case Mobile-H and compound contains only protons */
77
+ if ( pInChI[0]->bDeleted ) {
78
+ return 0; /* deleted component, presumably H(+) */
79
+ }
80
+
81
+ if ( bMobileH == TAUT_NON && OneInput->nNumProtons[iINChI][TAUT_YES].pNumProtons ) {
82
+ pStruct->nNumRemovedProtonsMobHInChI =
83
+ OneInput->nNumProtons[iINChI][TAUT_YES].pNumProtons[iComponent].nNumRemovedProtons;
84
+ }
85
+
86
+ if ( bMobileH == TAUT_NON || bMobileH == TAUT_YES && OneInput->pInpInChI[iINChI][TAUT_NON] &&
87
+ OneInput->pInpInChI[iINChI][TAUT_NON][iComponent].nNumberOfAtoms > 0 &&
88
+ !OneInput->pInpInChI[iINChI][TAUT_NON][iComponent].bDeleted ) {
89
+ pStruct->bFixedHExists = 1;
90
+ }
91
+ if ( bMobileH == TAUT_NON && iComponent < OneInput->nNumComponents[iINChI][TAUT_YES] &&
92
+ OneInput->pInpInChI[iINChI][TAUT_YES] &&
93
+ OneInput->pInpInChI[iINChI][TAUT_YES][iComponent].nNumberOfAtoms > 0 &&
94
+ !OneInput->pInpInChI[iINChI][TAUT_YES][iComponent].bDeleted ) {
95
+ /* pointer to the Mobile-H InChI if we are reversing Fixed-H InChI */
96
+ pInChI[1] = &OneInput->pInpInChI[iINChI][TAUT_YES][iComponent];
97
+ }
98
+ pStruct->num_inp_actual = OneInput->num_inp;
99
+ ret = OneInChI2Atom( ip, sd, szCurHdr, num_inp, pStruct, iComponent, iAtNoOffset, bHasSomeFixedH, pInChI);
100
+ return ret; /* same interpretation as in ProcessOneStructure ??? */
101
+ }
102
+
103
+ /*******************************************************************/
104
+ void RemoveFixHInChIIdentical2MobH( InpInChI *pOneInput )
105
+ {
106
+ int iInchiRec, cur_num_comp, k;
107
+ /* eliminate Fixed-H InChI that are exactly came as the corresponding Mobile-H structures */
108
+ for ( iInchiRec = 0; iInchiRec < INCHI_NUM; iInchiRec ++ ) {
109
+ cur_num_comp = inchi_min(pOneInput->nNumComponents[iInchiRec][TAUT_YES],
110
+ pOneInput->nNumComponents[iInchiRec][TAUT_NON]);
111
+ for ( k = 0; k < cur_num_comp; k ++ ) {
112
+ if ( !CompareReversedINChI( pOneInput->pInpInChI[iInchiRec][TAUT_YES]+k,
113
+ pOneInput->pInpInChI[iInchiRec][TAUT_NON]+k, NULL, NULL ) ) {
114
+ Free_INChI_Members( pOneInput->pInpInChI[iInchiRec][TAUT_NON]+k );
115
+ memset( pOneInput->pInpInChI[iInchiRec][TAUT_NON]+k, 0, sizeof(pOneInput->pInpInChI[0][0][0]) );
116
+ }
117
+ }
118
+ }
119
+ }
120
+ /*******************************************************************/
121
+ int MarkDisconectedIdenticalToReconnected ( InpInChI *pOneInput )
122
+ {
123
+ /* mark Disconnected InChI components that are exactly came as Reconnected ones */
124
+ /* Disconnected will have a negative number of the reconnected component */
125
+ /* Reconnected will have a positive number of the disconnected component */
126
+ int k1, k2, num_marked = 0;
127
+ for ( k1 = 0; k1 < inchi_max(pOneInput->nNumComponents[INCHI_BAS][TAUT_YES],
128
+ pOneInput->nNumComponents[INCHI_BAS][TAUT_NON]); k1 ++ ) {
129
+ for ( k2 = 0; k2 < inchi_max(pOneInput->nNumComponents[INCHI_REC][TAUT_YES],
130
+ pOneInput->nNumComponents[INCHI_REC][TAUT_NON]); k2 ++ ) {
131
+ int eqM = ( k1 < pOneInput->nNumComponents[INCHI_BAS][TAUT_YES] &&
132
+ k2 < pOneInput->nNumComponents[INCHI_REC][TAUT_YES] &&
133
+ !pOneInput->pInpInChI[INCHI_REC][TAUT_YES][k2].nLink && /* already linked */
134
+ !pOneInput->pInpInChI[INCHI_BAS][TAUT_YES][k1].bDeleted &&
135
+ pOneInput->pInpInChI[INCHI_BAS][TAUT_YES][k1].nNumberOfAtoms &&
136
+ pOneInput->pInpInChI[INCHI_BAS][TAUT_YES][k1].nNumberOfAtoms ==
137
+ pOneInput->pInpInChI[INCHI_REC][TAUT_YES][k2].nNumberOfAtoms &&
138
+ !pOneInput->pInpInChI[INCHI_REC][TAUT_YES][k2].bDeleted &&
139
+ !CompareReversedINChI( pOneInput->pInpInChI[INCHI_REC][TAUT_YES]+k2,
140
+ pOneInput->pInpInChI[INCHI_BAS][TAUT_YES]+k1,
141
+ NULL, NULL ));
142
+ int isF1 = (k1 < pOneInput->nNumComponents[INCHI_BAS][TAUT_NON] &&
143
+ 0 == pOneInput->pInpInChI[INCHI_BAS][TAUT_NON][k1].bDeleted &&
144
+ 0 < pOneInput->pInpInChI[INCHI_BAS][TAUT_NON][k1].nNumberOfAtoms );
145
+ int isF2 = (k2 < pOneInput->nNumComponents[INCHI_REC][TAUT_NON] &&
146
+ 0 == pOneInput->pInpInChI[INCHI_REC][TAUT_NON][k2].bDeleted &&
147
+ 0 < pOneInput->pInpInChI[INCHI_REC][TAUT_NON][k2].nNumberOfAtoms );
148
+ int eqF = isF1 && isF2 &&
149
+ !pOneInput->pInpInChI[INCHI_REC][TAUT_NON][k2].nLink &&
150
+ pOneInput->pInpInChI[INCHI_BAS][TAUT_NON][k1].nNumberOfAtoms ==
151
+ pOneInput->pInpInChI[INCHI_REC][TAUT_NON][k2].nNumberOfAtoms &&
152
+ !CompareReversedINChI( pOneInput->pInpInChI[INCHI_REC][TAUT_NON]+k2,
153
+ pOneInput->pInpInChI[INCHI_BAS][TAUT_NON]+k1,
154
+ NULL, NULL );
155
+ if ( eqM && (!isF1 && !isF2 || eqF ) ) {
156
+ pOneInput->pInpInChI[INCHI_BAS][TAUT_YES][k1].nLink = -(k2+1);
157
+ pOneInput->pInpInChI[INCHI_REC][TAUT_YES][k2].nLink = (k1+1);
158
+ if ( eqF ) {
159
+ pOneInput->pInpInChI[INCHI_BAS][TAUT_NON][k1].nLink = -(k2+1);
160
+ pOneInput->pInpInChI[INCHI_REC][TAUT_NON][k2].nLink = (k1+1);
161
+ }
162
+ num_marked ++;
163
+ break; /* equal InChI has been deleted from the disconnected layer, get next k1 */
164
+ }
165
+ }
166
+ }
167
+ return num_marked;
168
+
169
+ }
170
+ /**************************************************************/
171
+ void SetUpSrm( SRM *pSrm )
172
+ {
173
+ /* structure restore parms !!!!! */
174
+ memset( pSrm, 0, sizeof(pSrm[0]) );
175
+ pSrm->bFixStereoBonds = FIX_STEREO_BOND_ORDER;
176
+ pSrm->nMetal2EndpointMinBondOrder = 1;
177
+ pSrm->nMetal2EndpointInitEdgeFlow = 0;
178
+ if ( METAL_FREE_CHARGE_VAL == 1 ) {
179
+ pSrm->bMetalAddFlower = 1;
180
+ /* the next 3 parameters: */
181
+ /* 0, 0, 0 => all bonds 0, no init radical on metal */
182
+ /* 0, 0, 1 => all bonds 0, init radical on metal */
183
+ /* 0, 1, 0 => wrong */
184
+ /* 0, 1, 1 => all bonds 1, no init radical on metal */
185
+ /* 1, 0, 1 => min bond order 1, all bonds to metal have order 1 */
186
+ /* 1, 1, 0 => wrong */
187
+ /* 1, 1, 1 => wrong */
188
+ pSrm->nMetalMinBondOrder = 0;
189
+ pSrm->nMetalInitEdgeFlow = 1;
190
+ pSrm->nMetalInitBondOrder = 1;
191
+ pSrm->bStereoRemovesMetalFlag = pSrm->bFixStereoBonds;
192
+ pSrm->nMetalFlowerParam_D = 16;
193
+ pSrm->nMetalMaxCharge_D = 16;
194
+ } else {
195
+ pSrm->bMetalAddFlower = 0;
196
+ pSrm->nMetalMinBondOrder = 1;
197
+ pSrm->nMetalInitEdgeFlow = 0;
198
+ pSrm->nMetalInitBondOrder = 1;
199
+ pSrm->bStereoRemovesMetalFlag = pSrm->bFixStereoBonds;
200
+ pSrm->nMetalFlowerParam_D = 16;
201
+ pSrm->nMetalMaxCharge_D = 0;
202
+ }
203
+ /*
204
+ pSrm->nMetalInitBondOrder = pSrm->nMetalMinBondOrder
205
+ + pSrm->nMetalInitEdgeFlow;
206
+ */
207
+ pSrm->nMetal2EndpointInitBondOrder = pSrm->nMetal2EndpointMinBondOrder
208
+ + pSrm->nMetal2EndpointInitEdgeFlow;
209
+
210
+ }
211
+ /**************************************************************************************/
212
+ int MergeStructureComponents( ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd, long num_inp, char *szCurHdr,
213
+ ICHICONST SRM *pSrm, int bReqNonTaut, StrFromINChI *pStruct[INCHI_NUM][TAUT_NUM],
214
+ InpInChI *pOneInput )
215
+ {
216
+ int iInchiRec, iMobileH, iAlternH, num_components, tot_just_atoms, tot_removed_H, tot_atoms, cur_nA, cur_nH;
217
+ int k, i, j, ret, iCurAtomOffs, iNxtAtomOffs, iCurDelHOffs, iNxtDelHOffs, len, len2, iShiftH, icomp;
218
+ int *nAtomOffs=NULL, *nDelHOffs=NULL;
219
+ StrFromINChI *pStruct1;
220
+ inp_ATOM *at=NULL, *a;
221
+
222
+ ret = 0;
223
+ pOneInput->num_atoms = 0;
224
+ /* select highest detail level */
225
+ if ( num_components = pOneInput->nNumComponents[INCHI_REC][TAUT_NON] ) {
226
+ iInchiRec = INCHI_REC;
227
+ iMobileH = TAUT_NON;
228
+ } else
229
+ if ( num_components = pOneInput->nNumComponents[INCHI_REC][TAUT_YES] ) {
230
+ iInchiRec = INCHI_REC;
231
+ iMobileH = TAUT_YES;
232
+ } else
233
+ if ( num_components = pOneInput->nNumComponents[INCHI_BAS][TAUT_NON] ) {
234
+ iInchiRec = INCHI_BAS;
235
+ iMobileH = TAUT_NON;
236
+ } else
237
+ if ( num_components = pOneInput->nNumComponents[INCHI_BAS][TAUT_YES] ) {
238
+ iInchiRec = INCHI_BAS;
239
+ iMobileH = TAUT_YES;
240
+ } else {
241
+ return 0; /* no components available */
242
+ }
243
+
244
+ nAtomOffs = (int*)inchi_malloc((num_components+1) * sizeof(nAtomOffs[0]));
245
+ nDelHOffs = (int*)inchi_malloc((num_components+1) * sizeof(nDelHOffs[0]));
246
+ if ( !nAtomOffs || !nDelHOffs ) {
247
+ ret = RI_ERR_ALLOC;
248
+ goto exit_function;
249
+ }
250
+ /* count number of atoms and removed H */
251
+ tot_just_atoms = tot_removed_H = tot_atoms = 0;
252
+ iAlternH = (iMobileH==TAUT_NON && pOneInput->nNumComponents[iInchiRec][TAUT_YES])? TAUT_YES : -1;
253
+ nAtomOffs[0] = nDelHOffs[0] = 0;
254
+ for ( k = 0; k < num_components; k ++ ) {
255
+ pStruct1 = pStruct[iInchiRec][iMobileH][k].num_atoms? pStruct[iInchiRec][iMobileH]+k :
256
+ iAlternH>=0 &&
257
+ pStruct[iInchiRec][iAlternH][k].num_atoms? pStruct[iInchiRec][iAlternH]+k : NULL;
258
+ if ( !pStruct1 || !pStruct1->at2 || !pStruct1->num_atoms || pStruct1->bDeleted ) {
259
+ cur_nA = cur_nH = 0;
260
+ } else {
261
+ cur_nA = pStruct1->num_atoms;
262
+ cur_nH = pStruct1->num_deleted_H;
263
+ }
264
+ nAtomOffs[k+1] = nAtomOffs[k] + cur_nA;
265
+ nDelHOffs[k+1] = nDelHOffs[k] + cur_nH;
266
+ }
267
+ tot_just_atoms = nAtomOffs[num_components];
268
+ /* shift all H to the end */
269
+ for ( k = 0; k <= num_components; k ++ ) {
270
+ nDelHOffs[k] += tot_just_atoms;
271
+ }
272
+ tot_atoms = nDelHOffs[num_components];
273
+
274
+ /* merge atoms together: 1. Allocate */
275
+ if ( NULL == (at = (inp_ATOM *)inchi_malloc( (tot_atoms+1) * sizeof(at[0]) ) ) ) {
276
+ ret = RI_ERR_ALLOC;
277
+ goto exit_function;
278
+ }
279
+ if ( !tot_atoms ) {
280
+ ret = 0;
281
+ goto exit_function; /* empty structure */
282
+ }
283
+ /* merge atoms together: 2. Copy */
284
+ for ( k = 0; k < num_components; k ++ ) {
285
+ pStruct1 = pStruct[iInchiRec][iMobileH][k].num_atoms? pStruct[iInchiRec][iMobileH]+k :
286
+ iAlternH>=0 &&
287
+ pStruct[iInchiRec][iAlternH][k].num_atoms? pStruct[iInchiRec][iAlternH]+k : NULL;
288
+ if ( len = nAtomOffs[k+1] - nAtomOffs[k] ) {
289
+ memcpy( at + nAtomOffs[k], pStruct1->at2, len * sizeof(at[0]) );
290
+ if ( len2 = nDelHOffs[k+1] - nDelHOffs[k] ) {
291
+ memcpy( at + nDelHOffs[k], pStruct1->at2+len, len2 * sizeof(at[0]) );
292
+ }
293
+ }
294
+ }
295
+ /* merge atoms together: 3. Update atom numbers */
296
+ icomp = 0;
297
+ for ( k = 0; k < num_components; k ++ ) {
298
+ iCurAtomOffs = nAtomOffs[k];
299
+ iNxtAtomOffs = nAtomOffs[k+1];
300
+ iCurDelHOffs = nDelHOffs[k];
301
+ iNxtDelHOffs = nDelHOffs[k+1];
302
+ len = nAtomOffs[k+1] - nAtomOffs[k]; /* number of atoms in a component excluding explicit H */
303
+ iShiftH = iCurDelHOffs - len;
304
+ if ( !len ) {
305
+ continue;
306
+ }
307
+ icomp ++; /* current component number */
308
+ /* update atoms */
309
+ for ( i = iCurAtomOffs; i < iNxtAtomOffs; i ++ ) {
310
+
311
+ a = at+i;
312
+
313
+ a->endpoint = 0;
314
+ a->bAmbiguousStereo = 0;
315
+ a->at_type = 0;
316
+ a->bCutVertex = 0;
317
+ a->bUsed0DParity = 0;
318
+ a->cFlags = 0;
319
+ a->nBlockSystem = 0;
320
+ a->nNumAtInRingSystem = 0;
321
+ a->nRingSystem = 0;
322
+
323
+ for ( j = 0; j < a->valence; j ++ ) {
324
+ if ( a->neighbor[j] < len ) {
325
+ a->neighbor[j] += iCurAtomOffs; /* atom */
326
+ } else {
327
+ a->neighbor[j] += iShiftH; /* explicit H */
328
+ }
329
+ }
330
+ a->orig_at_number += iCurAtomOffs;
331
+ a->component = icomp;
332
+ if ( a->p_parity ) {
333
+ for ( j = 0; j < MAX_NUM_STEREO_ATOM_NEIGH; j ++ ) {
334
+ if ( a->p_orig_at_num[j] <= len ) {
335
+ /* originally, orig_at_num = atom_index+1, therefore <= instead of < */
336
+ a->p_orig_at_num[j] += iCurAtomOffs;
337
+ } else {
338
+ a->p_orig_at_num[j] += iShiftH;
339
+ }
340
+ }
341
+ }
342
+ for ( j = 0; j < MAX_NUM_STEREO_BONDS && a->sb_parity[j]; j ++ ) {
343
+ if ( a->sn_orig_at_num[j] <= len ) {
344
+ /* originally, orig_at_num = atom_index+1, therefore <= instead of < */
345
+ a->sn_orig_at_num[j] += iCurAtomOffs;
346
+ } else {
347
+ a->sn_orig_at_num[j] += iShiftH;
348
+ }
349
+ }
350
+ }
351
+ /* update fixed-H */
352
+ for ( i = iCurDelHOffs; i < iNxtDelHOffs; i ++ ) {
353
+ a = at+i;
354
+ a->neighbor[0] += iCurAtomOffs;
355
+ a->orig_at_number += iShiftH;
356
+
357
+ }
358
+ }
359
+ /* save the results */
360
+ pOneInput->atom = at;
361
+ pOneInput->num_atoms = tot_atoms;
362
+ at = NULL;
363
+
364
+ exit_function:
365
+ if ( at ) inchi_free( at ); /* in case of failure */
366
+ if ( nAtomOffs ) inchi_free( nAtomOffs );
367
+ if ( nDelHOffs ) inchi_free( nDelHOffs );
368
+ return ret;
369
+ }
370
+ #ifndef INCHI_ANSI_ONLY
371
+ static PER_DRAW_PARMS pdp;
372
+ /******************************************************************************************************/
373
+ int DisplayAllRestoredComponents( inp_ATOM *at, int num_at, const char *szCurHdr )
374
+ {
375
+ int ret;
376
+ char szTitle[512];
377
+ DRAW_PARMS dp;
378
+ TBL_DRAW_PARMS tdp;
379
+ if ( num_at <= 0 ) {
380
+ return 0;
381
+ }
382
+ memset( &dp, 0, sizeof(dp));
383
+ memset( &tdp, 0, sizeof(tdp) );
384
+ //memset( &pdp, 0, sizeof(pdp) );
385
+ dp.sdp.tdp = &tdp;
386
+ dp.pdp = &pdp;
387
+ dp.sdp.nFontSize = -9;
388
+ sprintf( szTitle, "All Components of Restored %s Structure", szCurHdr? szCurHdr : "(No structure name)");
389
+ ret = DisplayStructure( at, num_at, 0 /* nNumDeletedH*/, 0 /*bAdd_DT_to_num_H*/,
390
+ 0 /*nNumRemovedProtons*/, NULL /*NUM_H *nNumRemovedProtonsIsotopic*/,
391
+ 1 /*int bIsotopic*/, 0 /*bTautomeric*/,
392
+ NULL /* pINChI */, NULL /* INChI_Aux **cur_INChI_Aux*/,
393
+ 0 /*bAbcNumbers*/, &dp, 0 /*INCHI_MODE nMode*/, szTitle );
394
+ return 0;
395
+ }
396
+ /******************************************************************************************************/
397
+ int DisplayOneRestoredComponent( StrFromINChI *pStruct, inp_ATOM *at,
398
+ int iComponent, int nNumComponents, int bMobileH,
399
+ const char *szCurHdr )
400
+ {
401
+ int ret, k;
402
+ int num_at = pStruct->num_atoms;
403
+ XYZ_COORD *pxyz = pStruct->pXYZ;
404
+ char szTitle[512];
405
+ DRAW_PARMS dp;
406
+ TBL_DRAW_PARMS tdp;
407
+ int iInchiRec = pStruct->iInchiRec;
408
+ int iMobileH = pStruct->iMobileH;
409
+ INChI **pInChI = NULL;
410
+ INChI_Aux **pAux = NULL;
411
+ int nNumRemovedProtons = pAux? pAux[iMobileH]->nNumRemovedProtons : 0;
412
+ NUM_H *nNumRemovedProtonsIsotopic = pAux? pAux[iMobileH]->nNumRemovedIsotopicH : NULL;
413
+
414
+
415
+ if ( num_at <= 0 || !pxyz ) {
416
+ return 0;
417
+ }
418
+ if ( iInchiRec && !pStruct->RevInChI.pINChI_Aux[iInchiRec][0] ) {
419
+ iInchiRec = 0;
420
+ }
421
+ k = iMobileH;
422
+ if ( !bRevInchiComponentExists( pStruct, iInchiRec, k, 0 ) ) {
423
+ k = ALT_TAUT(k);
424
+ }
425
+ pInChI = pStruct->RevInChI.pINChI[iInchiRec][0];
426
+ pAux = pStruct->RevInChI.pINChI_Aux[iInchiRec][0];
427
+
428
+
429
+ memset( &dp, 0, sizeof(dp));
430
+ memset( &tdp, 0, sizeof(tdp) );
431
+ //memset( &pdp, 0, sizeof(pdp) );
432
+ dp.sdp.tdp = &tdp;
433
+ dp.pdp = &pdp;
434
+ dp.sdp.nFontSize = -9;
435
+ sprintf( szTitle, "Restored %s Component %d of %d %c%c",
436
+ szCurHdr? szCurHdr : "(No structure name)", iComponent+1, nNumComponents,
437
+ pStruct->iInchiRec? 'R':'D', pStruct->iMobileH?'M':'F' );
438
+ ret = DisplayStructure( at, num_at, 0 /* nNumDeletedH*/, 0 /*bAdd_DT_to_num_H*/,
439
+ nNumRemovedProtons, /*NULL*/ nNumRemovedProtonsIsotopic,
440
+ 1 /*int bIsotopic*/, k,
441
+ pInChI, pAux,
442
+ 0 /*bAbcNumbers*/, &dp, 0 /*INCHI_MODE nMode*/, szTitle );
443
+ return 0;
444
+ }
445
+ /******************************************************************************************************/
446
+ int DisplayRestoredComponent( StrFromINChI *pStruct, int iComponent, int iAtNoOffset, INChI *pInChI, const char *szCurHdr )
447
+ {
448
+ int i, ret;
449
+ int num_at = pStruct->num_atoms;
450
+ int num_deleted_H = pStruct->num_deleted_H;
451
+ inp_ATOM *atom = pStruct->at2;
452
+ XYZ_COORD *pxyz = pStruct->pXYZ;
453
+ inp_ATOM *at = NULL;
454
+ char szTitle[512];
455
+ DRAW_PARMS dp;
456
+ TBL_DRAW_PARMS tdp;
457
+ if ( !atom || num_at <= 0 || !pxyz ) {
458
+ return 0;
459
+ }
460
+ at = (inp_ATOM *)inchi_calloc( num_at + num_deleted_H, sizeof(at[0]) );
461
+ if ( !at ) {
462
+ return RI_ERR_ALLOC;
463
+ }
464
+ memcpy( at, atom, (num_at + num_deleted_H) * sizeof(at[0]) );
465
+ for ( i = 0; i < num_at; i ++ ) {
466
+ at[i].x = pxyz[i].xyz[0];
467
+ at[i].y = pxyz[i].xyz[1];
468
+ at[i].z = pxyz[i].xyz[2];
469
+ }
470
+ memset( &dp, 0, sizeof(dp));
471
+ memset( &tdp, 0, sizeof(tdp) );
472
+ //memset( &pdp, 0, sizeof(pdp) );
473
+ dp.sdp.tdp = &tdp;
474
+ dp.pdp = &pdp;
475
+ dp.sdp.nFontSize = -9;
476
+ sprintf( szTitle, "DBG Restored %s Component %d %c%c", szCurHdr? szCurHdr : "(No structure name)", iComponent+1, pStruct->iInchiRec? 'R':'D', pStruct->iMobileH?'M':'F' );
477
+ ret = DisplayStructure( at, num_at, 0 /* nNumDeletedH*/, 0 /*bAdd_DT_to_num_H*/,
478
+ 0 /*nNumRemovedProtons*/, NULL /*NUM_H *nNumRemovedProtonsIsotopic*/,
479
+ 1 /*int bIsotopic*/, 0 /*bTautomeric*/,
480
+ &pInChI, NULL /* INChI_Aux **cur_INChI_Aux*/,
481
+ 0 /*bAbcNumbers*/, &dp, 0 /*INCHI_MODE nMode*/, szTitle );
482
+ inchi_free( at );
483
+ return 0;
484
+ }
485
+ /**************************************************************************************/
486
+ int DisplayStructureComponents( ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd, long num_inp, char *szCurHdr,
487
+ ICHICONST SRM *pSrm, int bReqNonTaut, StrFromINChI *pStruct[INCHI_NUM][TAUT_NUM],
488
+ InpInChI *pOneInput )
489
+ {
490
+ int iInchiRec, iMobileH, iCurMobH, iAlternH, num_components, tot_just_atoms, tot_removed_H, tot_atoms, cur_nA, cur_nH;
491
+ int k, i, j, ret, iCurAtomOffs, iNxtAtomOffs, iCurDelHOffs, iNxtDelHOffs, len, len2, iShiftH, icomp;
492
+ int *nAtomOffs=NULL, *nDelHOffs=NULL, bNoCoord=0, iNewCoord=0, nNewCoord=0;
493
+ double x_max=-1.0e16, x_min = 1.0e16, y_max=-1.0e16, y_min=1.0e16, delta = 0.0;
494
+ StrFromINChI *pStruct1;
495
+ inp_ATOM *at=NULL, *a;
496
+
497
+ if (!ip->bDisplayCompositeResults && !ip->bDisplay ) {
498
+ return 0;
499
+ }
500
+
501
+ ret = 0;
502
+ pOneInput->num_atoms = 0;
503
+ /* select highest detail level */
504
+ if ( num_components = pOneInput->nNumComponents[INCHI_REC][TAUT_NON] ) {
505
+ iInchiRec = INCHI_REC;
506
+ iMobileH = TAUT_NON;
507
+ } else
508
+ if ( num_components = pOneInput->nNumComponents[INCHI_REC][TAUT_YES] ) {
509
+ iInchiRec = INCHI_REC;
510
+ iMobileH = TAUT_YES;
511
+ } else
512
+ if ( num_components = pOneInput->nNumComponents[INCHI_BAS][TAUT_NON] ) {
513
+ iInchiRec = INCHI_BAS;
514
+ iMobileH = TAUT_NON;
515
+ } else
516
+ if ( num_components = pOneInput->nNumComponents[INCHI_BAS][TAUT_YES] ) {
517
+ iInchiRec = INCHI_BAS;
518
+ iMobileH = TAUT_YES;
519
+ } else {
520
+ return 0; /* no components available */
521
+ }
522
+ for ( k = 0; k < num_components; k ++ ) {
523
+ if ( pStruct[iInchiRec][iMobileH][k].bDeleted )
524
+ break;
525
+ }
526
+ num_components = k;
527
+
528
+ nAtomOffs = (int*)inchi_malloc((num_components+1) * sizeof(nAtomOffs[0]));
529
+ nDelHOffs = (int*)inchi_malloc((num_components+1) * sizeof(nDelHOffs[0]));
530
+ if ( !nAtomOffs || !nDelHOffs ) {
531
+ ret = RI_ERR_ALLOC;
532
+ goto exit_function;
533
+ }
534
+ /* count number of atoms and removed H */
535
+ tot_just_atoms = tot_removed_H = tot_atoms = 0;
536
+ iAlternH = (iMobileH==TAUT_NON && pOneInput->nNumComponents[iInchiRec][TAUT_YES])? TAUT_YES : -1;
537
+ nAtomOffs[0] = nDelHOffs[0] = 0;
538
+ for ( k = 0; k < num_components; k ++ ) {
539
+ pStruct1 = pStruct[iInchiRec][iMobileH][k].num_atoms? pStruct[iInchiRec][iMobileH]+k :
540
+ iAlternH>=0 &&
541
+ pStruct[iInchiRec][iAlternH][k].num_atoms? pStruct[iInchiRec][iAlternH]+k : NULL;
542
+ if ( !pStruct1 || !pStruct1->at2 || !pStruct1->num_atoms ) {
543
+ cur_nA = cur_nH = 0;
544
+ } else {
545
+ cur_nA = pStruct1->num_atoms;
546
+ cur_nH = pStruct1->num_deleted_H;
547
+ if ( cur_nA && !pStruct1->pXYZ ) {
548
+ if ( !k ) {
549
+ ret = 0; /* no coordinates available */
550
+ goto exit_function;
551
+ } else {
552
+ bNoCoord ++;
553
+ }
554
+ }
555
+ }
556
+ nAtomOffs[k+1] = nAtomOffs[k] + cur_nA;
557
+ nDelHOffs[k+1] = nDelHOffs[k] + cur_nH;
558
+ }
559
+ tot_just_atoms = nAtomOffs[num_components];
560
+ /* shift all H to the end */
561
+ for ( k = 0; k <= num_components; k ++ ) {
562
+ nDelHOffs[k] += tot_just_atoms;
563
+ }
564
+ tot_atoms = nDelHOffs[num_components];
565
+
566
+ /* merge atoms together: 1. Allocate */
567
+ if ( NULL == (at = (inp_ATOM *)inchi_malloc( (tot_atoms+1) * sizeof(at[0]) ) ) ) {
568
+ ret = RI_ERR_ALLOC;
569
+ goto exit_function;
570
+ }
571
+ if ( !tot_atoms ) {
572
+ ret = 0;
573
+ goto exit_function; /* empty structure */
574
+ }
575
+ /* merge atoms together: 2. Copy */
576
+ for ( k = 0; k < num_components; k ++ ) {
577
+ pStruct1 = pStruct[iInchiRec][iMobileH][k].num_atoms? pStruct[iInchiRec][iCurMobH=iMobileH]+k :
578
+ iAlternH>=0 &&
579
+ pStruct[iInchiRec][iAlternH][k].num_atoms? pStruct[iInchiRec][iCurMobH=iAlternH]+k : NULL;
580
+ if ( len = nAtomOffs[k+1] - nAtomOffs[k] ) {
581
+ XYZ_COORD *pxyz = pStruct1->pXYZ;
582
+ len2 = nDelHOffs[k+1] - nDelHOffs[k]; /* do not separate H from the atom: we will not need them */
583
+ iCurAtomOffs = nAtomOffs[k];
584
+ a = at + iCurAtomOffs;
585
+ memcpy( a, pStruct1->at2, (len+len2) * sizeof(at[0]) );
586
+ DisconnectedConnectedH( a, len, len2 );
587
+ if ( pxyz ) {
588
+ for ( i = 0; i < len; i ++ ) {
589
+ a[i].x = pxyz[i].xyz[0];
590
+ x_max = inchi_max( x_max, pxyz[i].xyz[0] );
591
+ x_min = inchi_min( x_min, pxyz[i].xyz[0] );
592
+ a[i].y = pxyz[i].xyz[1];
593
+ y_max = inchi_max( y_max, pxyz[i].xyz[1] );
594
+ y_min = inchi_min( y_min, pxyz[i].xyz[1] );
595
+ a[i].z = pxyz[i].xyz[2];
596
+ nNewCoord ++;
597
+ }
598
+ } else {
599
+ if ( !iNewCoord ) {
600
+ if ( !nNewCoord ) {
601
+ ret = 0;
602
+ goto exit_function; /* empty structure */
603
+ }
604
+ delta = inchi_max(x_max - x_min, y_max - y_min);
605
+ if ( delta == 0.0 ) {
606
+ delta = 0.5 * (x_max+x_min);
607
+ if ( delta == 0.0 )
608
+ delta = 1.0;
609
+ } else {
610
+ delta /= sqrt( (double)(nNewCoord+1) );
611
+ }
612
+ }
613
+ for ( i = 0; i < len; i ++ ) {
614
+ a[i].x = x_max + delta;
615
+ a[i].y = y_max - iNewCoord * delta;
616
+ a[i].z = 0.0;
617
+ iNewCoord ++;
618
+ }
619
+ if ( pStruct1->pXYZ = (XYZ_COORD *)inchi_calloc(len, sizeof(pStruct1->pXYZ[0]) ) ) {
620
+
621
+ for ( i = 0; i < len; i ++ ) {
622
+ pStruct1->pXYZ[i].xyz[0] = a[i].x;
623
+ pStruct1->pXYZ[i].xyz[1] = a[i].y;
624
+ pStruct1->pXYZ[i].xyz[2] = 0.0;
625
+ }
626
+ }
627
+ }
628
+ if ( ip->bDisplay || ip->bDisplayCompositeResults && 1 == num_components ) {
629
+ DisplayOneRestoredComponent( pStruct1, a, k, num_components, iCurMobH, szCurHdr );
630
+ }
631
+ if ( !pxyz && pStruct1->pXYZ ) {
632
+ inchi_free( pStruct1->pXYZ );
633
+ pStruct1->pXYZ = NULL;
634
+ }
635
+ }
636
+ }
637
+ /* merge atoms together: 3. Update atom numbers */
638
+ icomp = 0;
639
+ if ( ip->bDisplayCompositeResults && num_components > 1 ) {
640
+ for ( k = 0; k < num_components; k ++ ) {
641
+ /* display each restored component if requested */
642
+ iCurAtomOffs = nAtomOffs[k];
643
+ iNxtAtomOffs = nAtomOffs[k+1];
644
+ iCurDelHOffs = nDelHOffs[k];
645
+ iNxtDelHOffs = nDelHOffs[k+1];
646
+ len = nAtomOffs[k+1] - nAtomOffs[k]; /* number of atoms in a component excluding explicit H */
647
+ iShiftH = iCurDelHOffs - len;
648
+ if ( !len ) {
649
+ continue;
650
+ }
651
+ icomp ++; /* current component number */
652
+ /* update atoms */
653
+ for ( i = iCurAtomOffs; i < iNxtAtomOffs; i ++ ) {
654
+ a = at+i;
655
+ for ( j = 0; j < a->valence; j ++ ) {
656
+ if ( a->neighbor[j] < len ) {
657
+ a->neighbor[j] += iCurAtomOffs; /* atom */
658
+ } else {
659
+ ret = RI_ERR_PROGR; /* explicit H */
660
+ goto exit_function;
661
+ }
662
+ }
663
+ a->orig_at_number += iCurAtomOffs;
664
+ }
665
+ }
666
+ tot_atoms = nAtomOffs[num_components];
667
+ DisplayAllRestoredComponents( at, tot_atoms, szCurHdr );
668
+
669
+ }
670
+
671
+ exit_function:
672
+ if ( at ) inchi_free( at ); /* in case of failure */
673
+ if ( nAtomOffs ) inchi_free( nAtomOffs );
674
+ if ( nDelHOffs ) inchi_free( nDelHOffs );
675
+ return ret;
676
+ }
677
+ #endif
678
+ /**************************************************************************************/
679
+ int AllInchiToStructure( ICHICONST INPUT_PARMS *ip_inp, STRUCT_DATA *sd_inp, long num_inp, char *szCurHdr,
680
+ ICHICONST SRM *pSrm, int bHasSomeFixedH, StrFromINChI *pStruct[INCHI_NUM][TAUT_NUM],
681
+ InpInChI *pOneInput )
682
+ {
683
+ int iInchiRec, iMobileH, cur_num_comp, bCurI2A_Flag, k, ret, num_err;
684
+ INPUT_PARMS *ip, ip_loc;
685
+ STRUCT_DATA *sd, sd_loc;
686
+ long ulProcessingTime = 0;
687
+ inchiTime ulTStart;
688
+
689
+ InchiTimeGet( &ulTStart );
690
+ ip = &ip_loc;
691
+ *ip = *ip_inp;
692
+ sd = &sd_loc;
693
+ memset( sd, 0, sizeof(*sd));
694
+ sd->ulStructTime = sd_inp->ulStructTime;
695
+ ret = 0;
696
+ num_err = 0;
697
+ for ( iInchiRec = 0; iInchiRec < INCHI_NUM; iInchiRec ++ ) { /* Disconnected/Connected */
698
+ for ( iMobileH = 0; iMobileH < TAUT_NUM; iMobileH ++ ) { /* Mobile/Fixed H */
699
+ cur_num_comp = pOneInput->nNumComponents[iInchiRec][iMobileH];
700
+ if ( !cur_num_comp ) {
701
+ continue;
702
+ }
703
+ /* allocate memory for all existing components */
704
+ pStruct[iInchiRec][iMobileH] = (StrFromINChI *)inchi_calloc( cur_num_comp, sizeof(pStruct[0][0][0]));
705
+ if ( !pStruct[iInchiRec][iMobileH] ) {
706
+ ret = RI_ERR_ALLOC;
707
+ goto exit_error;
708
+ }
709
+ /* set conversion mode */
710
+ bCurI2A_Flag = (iMobileH? 0: I2A_FLAG_FIXEDH) | (iInchiRec? I2A_FLAG_RECMET : 0);
711
+ if ( iMobileH ) {
712
+ ip->nMode &= ~REQ_MODE_BASIC;
713
+ } else {
714
+ ip->nMode |= REQ_MODE_BASIC;
715
+ }
716
+ /* InChI --> structure conversion for all components except duplicated */
717
+ for ( k = 0; k < cur_num_comp; k ++ ) { /* components */
718
+ if ( !iMobileH && !pOneInput->pInpInChI[iInchiRec][iMobileH][k].nNumberOfAtoms ||
719
+ pOneInput->pInpInChI[iInchiRec][iMobileH][k].bDeleted ||
720
+ pOneInput->pInpInChI[iInchiRec][iMobileH][k].nLink < 0 ) {
721
+
722
+ pStruct[iInchiRec][iMobileH][k].nLink = pOneInput->pInpInChI[iInchiRec][iMobileH][k].nLink;
723
+ pStruct[iInchiRec][iMobileH][k].bDeleted = pOneInput->pInpInChI[iInchiRec][iMobileH][k].bDeleted;
724
+ continue; /* do not create a structure out of an unavailable
725
+ Fixed-H InChI or out of the one present in Reconnected layer */
726
+ #ifdef NEVER /* a wrong attempt to process deleted components here */
727
+ if ( pStruct[iInchiRec][iMobileH][k].nLink = pOneInput->pInpInChI[iInchiRec][iMobileH][k].nLink ) {
728
+ continue; /* do not create a structure out of an unavailable
729
+ Fixed-H InChI or out of the one present in Reconnected layer */
730
+ } else
731
+ if ( iMobileH && pOneInput->pInpInChI[iInchiRec][iMobileH][k].nNumberOfAtoms &&
732
+ pOneInput->pInpInChI[iInchiRec][iMobileH][k].bDeleted &&
733
+ pOneInput->pInpInChI[iInchiRec][iMobileH][0].bDeleted ) {
734
+ /* all components are protons */
735
+ ;
736
+ } else {
737
+ continue;
738
+ }
739
+ #endif
740
+ }
741
+ if ( bHasSomeFixedH && iMobileH && k < pOneInput->nNumComponents[iInchiRec][TAUT_NON] &&
742
+ pOneInput->pInpInChI[iInchiRec][TAUT_NON][k].nNumberOfAtoms ) {
743
+ continue; /* do not process Mobile-H if Fixed-H is requested and exists */
744
+ }
745
+ pStruct[iInchiRec][iMobileH][k].pSrm = pSrm;
746
+ pStruct[iInchiRec][iMobileH][k].iInchiRec = iInchiRec;
747
+ pStruct[iInchiRec][iMobileH][k].iMobileH = iMobileH;
748
+
749
+ /****************************************************/
750
+ /* */
751
+ /* Convert InChI of one component into a Structure */
752
+ /* */
753
+ /****************************************************/
754
+
755
+ ret = InChI2Atom( ip, sd, szCurHdr, num_inp, pStruct[iInchiRec][iMobileH]+k, k,
756
+ 0 /* AtNoOffset*/, bCurI2A_Flag, bHasSomeFixedH, pOneInput );
757
+ pStruct[iInchiRec][iMobileH][k].nLink = pOneInput->pInpInChI[iInchiRec][iMobileH][k].nLink;
758
+ if ( ret < 0 ) {
759
+ #if( bRELEASE_VERSION != 1 )
760
+ #ifndef INCHI_LIBRARY
761
+ /* !!! Conversion Error -- Ignore for now !!! */
762
+ fprintf( stdout, "%ld %s Conversion failed: %d, %c%c comp %d\n",
763
+ num_inp, szCurHdr? szCurHdr : "Struct", ret, iInchiRec? 'R':'D', iMobileH? 'M':'F', k+1);
764
+ #endif
765
+ #endif
766
+ if ( ret == CT_USER_QUIT_ERR ) {
767
+ goto exit_error;
768
+ }
769
+ pStruct[iInchiRec][iMobileH][k].nError = ret;
770
+ ret = 0; /* force to ignore the errors for now !!!! */
771
+ num_err ++;
772
+ }
773
+ }
774
+ }
775
+ }
776
+ exit_error:
777
+ ulProcessingTime += InchiTimeElapsed( &ulTStart );
778
+ sd->ulStructTime += ulProcessingTime;
779
+ return ret<0? ret : num_err;
780
+ }
781
+ /**************************************************************************************/
782
+ int AddProtonAndIsoHBalanceToMobHStruct( ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd,
783
+ long num_inp, int bHasSomeFixedH, char *szCurHdr,
784
+ StrFromINChI *pStruct[INCHI_NUM][TAUT_NUM], InpInChI *pOneInput)
785
+ {
786
+ COMPONENT_REM_PROTONS nToBeRemovedByNormFromRevrs[INCHI_NUM];
787
+ int nRemovedByNormFromRevrs[INCHI_NUM];
788
+ int nRemovedByRevrs[INCHI_NUM];
789
+
790
+ int nDeltaFromDisconnected = 0, nRemovedProtonsByNormFromRevrs, nRemovedProtonsByRevrs, num_changes = 0;
791
+ NUM_H nIsoDeltaFromDisconnected[NUM_H_ISOTOPES];
792
+ int iInchiRec, i, k, k1, ret = 0;
793
+ int nChargeInChI, nChargeRevrs;
794
+
795
+ if ( bHasSomeFixedH ) {
796
+ return 0; /* 2005-03-01 */
797
+ }
798
+
799
+ /* num protons removed by InChI Normalization from the original structure */
800
+ for ( i = 0; i < INCHI_NUM; i ++ ) {
801
+ nToBeRemovedByNormFromRevrs[i].nNumRemovedProtons = pOneInput->nNumProtons[i][TAUT_YES].nNumRemovedProtons;
802
+ for ( k = 0; k < NUM_H_ISOTOPES; k ++ ) {
803
+ nToBeRemovedByNormFromRevrs[i].nNumRemovedIsotopicH[k] = pOneInput->nNumProtons[i][TAUT_YES].nNumRemovedIsotopicH[k];
804
+ }
805
+ }
806
+ /* accumulate here num. protons removed by the normalization from the reversed structure */
807
+ nRemovedByNormFromRevrs[INCHI_BAS] =
808
+ nRemovedByNormFromRevrs[INCHI_REC] = 0;
809
+ nRemovedByRevrs[INCHI_REC] =
810
+ nRemovedByRevrs[INCHI_BAS] = 0;
811
+ /* protons added/removed by InChI Normalization to/from Restored Structure might have been added by StructureRestore */
812
+ for ( iInchiRec = 0; iInchiRec < INCHI_NUM; iInchiRec ++ ) {
813
+ for ( k = 0; k < pOneInput->nNumComponents[iInchiRec][TAUT_YES]; k ++ ) {
814
+ if ( !bInpInchiComponentExists( pOneInput, iInchiRec, TAUT_YES, k ) ) {
815
+ continue;
816
+ }
817
+ nRemovedProtonsByNormFromRevrs = 0; /* Num protons removed from the Restored Structure by InChI Normalization */
818
+ nRemovedProtonsByRevrs = 0; /* Num protons removed by the Reconstruction from the Restored Structure */
819
+ if ( iInchiRec == INCHI_REC || iInchiRec == INCHI_BAS && (k1=pStruct[iInchiRec][TAUT_YES][k].nLink) >= 0 ) {
820
+
821
+ REV_INCHI *pRevInChI = &pStruct[iInchiRec][TAUT_YES][k].RevInChI;
822
+ INChI_Aux **pINChI_Aux2 = pRevInChI->pINChI_Aux[iInchiRec][0]; /* component 0*/
823
+ INChI **pINChI_Revr = pRevInChI->pINChI[iInchiRec][0];
824
+ INChI *pINChI_Orig = pOneInput->pInpInChI[iInchiRec][TAUT_YES]+k;
825
+ nChargeRevrs = pINChI_Revr? pINChI_Revr[TAUT_YES]->nTotalCharge : NO_VALUE_INT;
826
+ nChargeInChI = pINChI_Orig->nTotalCharge;
827
+ if ( pINChI_Aux2 ) {
828
+ nRemovedProtonsByNormFromRevrs = pINChI_Aux2[TAUT_YES]->nNumRemovedProtons;
829
+ }
830
+ nRemovedProtonsByRevrs = pStruct[iInchiRec][TAUT_YES][k].nNumRemovedProtonsByRevrs;
831
+ pStruct[iInchiRec][TAUT_YES][k].nChargeRevrs = nChargeRevrs;
832
+ pStruct[iInchiRec][TAUT_YES][k].nChargeInChI = nChargeInChI;
833
+ } else
834
+ if ( 0 <= ( k1 = -(1+pStruct[iInchiRec][TAUT_YES][k].nLink) ) ) {
835
+ REV_INCHI *pRevInChI = &pStruct[INCHI_REC][TAUT_YES][k1].RevInChI;
836
+ INChI_Aux **pINChI_Aux2 = pRevInChI->pINChI_Aux[INCHI_BAS][0]; /* component 0 */
837
+ INChI **pINChI_Revr = pRevInChI->pINChI[INCHI_BAS][0];
838
+ INChI *pINChI_Orig = pOneInput->pInpInChI[INCHI_REC][TAUT_YES]+k1;
839
+ nChargeRevrs = pINChI_Revr? pINChI_Revr[TAUT_YES]->nTotalCharge : NO_VALUE_INT;
840
+ nChargeInChI = pINChI_Orig->nTotalCharge;
841
+ if ( pINChI_Aux2 ) {
842
+ nRemovedProtonsByNormFromRevrs = pINChI_Aux2[TAUT_YES]->nNumRemovedProtons;
843
+ }
844
+ /* this component cannot be disconnected because it is same as in reconnected layer */
845
+ nRemovedProtonsByRevrs = pStruct[INCHI_REC][TAUT_YES][k1].nNumRemovedProtonsByRevrs;
846
+ pStruct[iInchiRec][TAUT_YES][k1].nChargeRevrs = nChargeRevrs;
847
+ pStruct[iInchiRec][TAUT_YES][k1].nChargeInChI = nChargeInChI;
848
+ }
849
+ /* how many protons (to be removed by InChI Normalization) to add =
850
+ (proton balance in InChI} -
851
+ {number of protons known to be removed by InChI Normalization from Reconstructed structure} */
852
+ nToBeRemovedByNormFromRevrs[iInchiRec].nNumRemovedProtons -= nRemovedProtonsByNormFromRevrs;
853
+ nRemovedByNormFromRevrs[iInchiRec] += nRemovedProtonsByNormFromRevrs;
854
+ nRemovedByRevrs[iInchiRec] += nRemovedProtonsByRevrs;
855
+ pStruct[iInchiRec][TAUT_YES][k].nRemovedProtonsByNormFromRevrs = nRemovedProtonsByNormFromRevrs;
856
+ }
857
+ }
858
+
859
+ /* Since fixed-H layer is missing we need to add proton balance to the components */
860
+ memset( nIsoDeltaFromDisconnected, 0, sizeof(nIsoDeltaFromDisconnected) );
861
+ for ( iInchiRec = INCHI_REC; INCHI_BAS <= iInchiRec; iInchiRec -- ) {
862
+ /*
863
+ if ( !pOneInput->nNumComponents[iInchiRec][TAUT_NON] &&
864
+ pOneInput->nNumComponents[iInchiRec][TAUT_YES] ) {
865
+ */
866
+ int bHasRecMobH = (iInchiRec==INCHI_BAS && pOneInput->nNumComponents[INCHI_REC][TAUT_YES]);
867
+ /* bHasRecMobH means all components that could not be disconnected are in reconnected part */
868
+ if ( iInchiRec==INCHI_BAS ) {
869
+ /* second pass: common structures have been changed */
870
+ nToBeRemovedByNormFromRevrs[INCHI_BAS].nNumRemovedProtons += nDeltaFromDisconnected;
871
+ }
872
+ /* after proton removal InChI is recalculated */
873
+
874
+ ret = AddRemProtonsInRestrStruct( ip, sd, num_inp, bHasSomeFixedH, pStruct[iInchiRec][TAUT_YES],
875
+ pOneInput->nNumComponents[iInchiRec][TAUT_YES],
876
+ bHasRecMobH? pStruct[INCHI_REC][TAUT_YES] : NULL,
877
+ bHasRecMobH? pOneInput->nNumComponents[INCHI_REC][TAUT_YES]:0,
878
+ &nToBeRemovedByNormFromRevrs[iInchiRec].nNumRemovedProtons,
879
+ (iInchiRec==INCHI_REC)?&nDeltaFromDisconnected : NULL);
880
+ if ( ret < 0 ) {
881
+ goto exit_function;
882
+ }
883
+ num_changes += ret;
884
+ /*
885
+ }
886
+ */
887
+ }
888
+ /* if fixed-H layer is missing then we need to add isotopic exchangeable proton balance to the components */
889
+ for ( iInchiRec = INCHI_REC; INCHI_BAS <= iInchiRec; iInchiRec -- ) {
890
+ /*
891
+ if ( !pOneInput->nNumComponents[iInchiRec][TAUT_NON] &&
892
+ pOneInput->nNumComponents[iInchiRec][TAUT_YES] ) {
893
+ */
894
+ int bHasRecMobH = (iInchiRec==INCHI_BAS && pOneInput->nNumComponents[INCHI_REC][TAUT_YES]);
895
+ /* bHasRecMobH means all components that could not be disconnected are in reconnected part */
896
+ if ( iInchiRec==INCHI_BAS ) {
897
+ /* second pass: common structures have been changed */
898
+ for ( k = 0; k < NUM_H_ISOTOPES; k ++ ) {
899
+ nToBeRemovedByNormFromRevrs[INCHI_BAS].nNumRemovedIsotopicH[k] += nIsoDeltaFromDisconnected[k];
900
+ }
901
+ }
902
+ /* after proton removal InChI is recalculated */
903
+ ret = AddRemIsoProtonsInRestrStruct( ip, sd, num_inp, bHasSomeFixedH, pStruct[iInchiRec][TAUT_YES],
904
+ pOneInput->nNumComponents[iInchiRec][TAUT_YES],
905
+ bHasRecMobH? pStruct[INCHI_REC][TAUT_YES] : NULL,
906
+ bHasRecMobH? pOneInput->nNumComponents[INCHI_REC][TAUT_YES]:0,
907
+ nToBeRemovedByNormFromRevrs[iInchiRec].nNumRemovedIsotopicH,
908
+ (iInchiRec==INCHI_REC)?nIsoDeltaFromDisconnected : NULL);
909
+ if ( ret < 0 ) {
910
+ goto exit_function;
911
+ }
912
+ num_changes += ret;
913
+ /*
914
+ }
915
+ */
916
+ }
917
+
918
+ exit_function:
919
+ return ret;
920
+ }
921
+
922
+ /*************************************************************/
923
+ void FreeStrFromINChI( StrFromINChI *pStruct[INCHI_NUM][TAUT_NUM], int nNumComponents[INCHI_NUM][TAUT_NUM] )
924
+ {
925
+ int iInchiRec, iMobileH, cur_num_comp, k, j;
926
+ StrFromINChI *pStruct1;
927
+ for ( iInchiRec = 0; iInchiRec < INCHI_NUM; iInchiRec ++ ) {
928
+ for ( iMobileH = 0; iMobileH < TAUT_NUM; iMobileH ++ ) {
929
+ cur_num_comp = nNumComponents[iInchiRec][iMobileH];
930
+ if ( !cur_num_comp || !(pStruct1=pStruct[iInchiRec][iMobileH]) ) {
931
+ continue;
932
+ }
933
+ for ( k = 0; k < cur_num_comp; k ++ ) {
934
+ if ( pStruct1[k].at ) {
935
+ inchi_free(pStruct1[k].at);
936
+ }
937
+ if ( pStruct1[k].at2 ) {
938
+ inchi_free(pStruct1[k].at2);
939
+ }
940
+ if ( pStruct1[k].st ) {
941
+ inchi_free(pStruct1[k].st);
942
+ }
943
+ if ( pStruct1[k].pVA ) {
944
+ inchi_free(pStruct1[k].pVA);
945
+ }
946
+ /*
947
+ if ( pStruct1[k].ti.t_group ) {
948
+ inchi_free( pStruct1[k].ti.t_group );
949
+ }
950
+ */
951
+ if ( pStruct1[k].pXYZ ) {
952
+ inchi_free(pStruct1[k].pXYZ);
953
+ }
954
+ /*==== begin ====*/
955
+ free_t_group_info( &pStruct1[k].ti );
956
+ if ( pStruct1[k].endpoint ) {
957
+ inchi_free(pStruct1[k].endpoint);
958
+ }
959
+ if ( pStruct1[k].fixed_H ) {
960
+ inchi_free(pStruct1[k].fixed_H);
961
+ }
962
+ for ( j = 0; j < TAUT_NUM; j ++ ) {
963
+ if ( pStruct1[k].nAtno2Canon[j] )
964
+ inchi_free( pStruct1[k].nAtno2Canon[j] );
965
+ if ( pStruct1[k].nCanon2Atno[j] )
966
+ inchi_free( pStruct1[k].nCanon2Atno[j] );
967
+ }
968
+ /*===== end ======*/
969
+ /* free INChI memory */
970
+ FreeAllINChIArrays( pStruct1[k].RevInChI.pINChI,
971
+ pStruct1[k].RevInChI.pINChI_Aux,
972
+ pStruct1[k].RevInChI.num_components );
973
+ #ifdef NEVER
974
+ /* don't do that: these are just pointers to OneInput structure members */
975
+ Free_INChI( &pStruct1[k].pINChI );
976
+ Free_INChI_Aux( &pStruct1[k].pINChI_Aux );
977
+ if ( pStruct1[k].inp_norm_data ) {
978
+ FreeInpAtomData( pStruct1[k].inp_norm_data );
979
+ inchi_free( pStruct1[k].inp_norm_data );
980
+ }
981
+ #endif
982
+ }
983
+ inchi_free(pStruct[iInchiRec][iMobileH]);
984
+ pStruct[iInchiRec][iMobileH] = NULL;
985
+ }
986
+ }
987
+ }
988
+ /********************************************************************/
989
+ void FreeInpInChI( InpInChI *pOneInput )
990
+ {
991
+ int iINChI, k, j;
992
+ for ( iINChI = 0; iINChI < INCHI_NUM; iINChI ++ ) {
993
+ for ( j = 0; j < TAUT_NUM; j ++ ) {
994
+ if ( pOneInput->pInpInChI[iINChI][j] ) {
995
+ for ( k = 0; k < pOneInput->nNumComponents[iINChI][j]; k ++ ) {
996
+ Free_INChI_Members( &pOneInput->pInpInChI[iINChI][j][k] );
997
+ }
998
+ inchi_free(pOneInput->pInpInChI[iINChI][j]);
999
+ pOneInput->pInpInChI[iINChI][j] = NULL;
1000
+ }
1001
+ if ( pOneInput->nNumProtons[iINChI][j].pNumProtons ) {
1002
+ inchi_free( pOneInput->nNumProtons[iINChI][j].pNumProtons );
1003
+ pOneInput->nNumProtons[iINChI][j].pNumProtons = NULL;
1004
+ }
1005
+ }
1006
+ }
1007
+ if ( pOneInput->atom ) inchi_free(pOneInput->atom);
1008
+ memset( pOneInput, 0, sizeof(*pOneInput) );
1009
+ }
1010
+
1011
+ /***********************************************************************************************/
1012
+ int CompareAllOrigInchiToRevInChI(StrFromINChI *pStruct[INCHI_NUM][TAUT_NUM], InpInChI *pOneInput, int bReqNonTaut,
1013
+ long num_inp, char *szCurHdr)
1014
+ {
1015
+ int i, iInchiRec, iMobileH, iMobileHpStruct, num_components, iComponent, ret;
1016
+ COMPONENT_REM_PROTONS nCurRemovedProtons, nNumRemovedProtons;
1017
+ INChI *pInChI[TAUT_NUM];
1018
+ INCHI_MODE CompareInchiFlags[TAUT_NUM];
1019
+ memset( pOneInput->CompareInchiFlags[0], 0, sizeof(pOneInput->CompareInchiFlags[0]) );
1020
+ memset( &nNumRemovedProtons, 0, sizeof(nNumRemovedProtons) );
1021
+
1022
+ /* do we have reconnected InChI ?*/
1023
+ iInchiRec = INCHI_REC;
1024
+ iMobileH = TAUT_NON;
1025
+ if ( !pOneInput->nNumComponents[iInchiRec][TAUT_YES] && !pOneInput->nNumComponents[iInchiRec][TAUT_NON] ) {
1026
+ iInchiRec = INCHI_BAS;
1027
+ }
1028
+ /* do we have Mobile or Fixed-H ? */
1029
+ if ( !pOneInput->nNumComponents[iInchiRec][TAUT_NON] || !bReqNonTaut ) {
1030
+ iMobileH = TAUT_YES; /* index for pOneInput */
1031
+ }
1032
+ /* if a restored structure has Fixed-H InChI then its mobile-H restored InChI is in Fixed-H pStruct */
1033
+ num_components = pOneInput->nNumComponents[iInchiRec][iMobileH];
1034
+ for ( iComponent = 0; iComponent < num_components; iComponent ++ ) {
1035
+ int bMobileH = iMobileH;
1036
+ pInChI[0] = pInChI[1] = NULL;
1037
+ if ( pOneInput->pInpInChI[iInchiRec][bMobileH][iComponent].nNumberOfAtoms &&
1038
+ !pOneInput->pInpInChI[iInchiRec][bMobileH][iComponent].bDeleted ) {
1039
+ /* the requested InChI layer exists */
1040
+ pInChI[0] = &pOneInput->pInpInChI[iInchiRec][bMobileH][iComponent];
1041
+ if ( bMobileH == TAUT_NON ) {
1042
+ pInChI[1] = &pOneInput->pInpInChI[iInchiRec][TAUT_YES][iComponent];
1043
+ }
1044
+ } else
1045
+ if ( bMobileH == TAUT_NON &&
1046
+ pOneInput->pInpInChI[iInchiRec][TAUT_YES][iComponent].nNumberOfAtoms &&
1047
+ !pOneInput->pInpInChI[iInchiRec][TAUT_YES][iComponent].bDeleted ) {
1048
+ /* the requested Fixed-H InChI layer does not exist; however, the Mobile-H does exist */
1049
+ bMobileH = TAUT_YES; /* only Mobile-H is available */
1050
+ pInChI[0] = &pOneInput->pInpInChI[iInchiRec][bMobileH][iComponent];
1051
+ }
1052
+ memset( CompareInchiFlags, 0, sizeof(CompareInchiFlags) );
1053
+ memset( &nCurRemovedProtons, 0, sizeof(nCurRemovedProtons) );
1054
+ iMobileHpStruct =
1055
+ #if( bRELEASE_VERSION == 0 )
1056
+ #ifndef INCHI_LIBRARY
1057
+ /* legacy: reproduce old output */
1058
+ OldPrintCompareOneOrigInchiToRevInChI(pStruct[iInchiRec][bMobileH]+iComponent, pInChI, bMobileH,
1059
+ iComponent, num_inp, szCurHdr);
1060
+ #endif
1061
+ #endif
1062
+ /* one component comparison result bits */
1063
+ ret = CompareOneOrigInchiToRevInChI( pStruct[iInchiRec][bMobileH]+iComponent, pInChI, bMobileH, iComponent,
1064
+ num_inp, szCurHdr, &nCurRemovedProtons, CompareInchiFlags);
1065
+ if ( ret >= 0 ) {
1066
+ /* no errors encountered -> accumulate removed protons from individual Mobile-H layers of components */
1067
+ nNumRemovedProtons.nNumRemovedProtons += nCurRemovedProtons.nNumRemovedProtons;
1068
+ for ( i = 0; i < NUM_H_ISOTOPES; i ++ ) {
1069
+ nNumRemovedProtons.nNumRemovedIsotopicH[i] += nCurRemovedProtons.nNumRemovedIsotopicH[i];
1070
+ }
1071
+ /* accumulate compare bits */
1072
+ for ( i = 0; i < TAUT_NUM; i ++ ) {
1073
+ pOneInput->CompareInchiFlags[0][i] |= CompareInchiFlags[i];
1074
+ }
1075
+ } else {
1076
+ goto exit_function;
1077
+ }
1078
+ }
1079
+ if ( iMobileH == TAUT_YES ) {
1080
+ if ( pOneInput->nNumProtons[iInchiRec][iMobileH].pNumProtons ) {
1081
+ ret = RI_ERR_PROGR; /* in Mobile-H case proton balances are split between compoments */
1082
+ } else {
1083
+ /* num removed protons in orig. InChI num removed protons in restored InChi */
1084
+ if ( nNumRemovedProtons.nNumRemovedProtons != pOneInput->nNumProtons[iInchiRec][iMobileH].nNumRemovedProtons ) {
1085
+ /* restored structure InChI has less or more removed protons */
1086
+ pOneInput->CompareInchiFlags[0][TAUT_YES] |= INCHIDIFF_MOBH_PROTONS;
1087
+ #if( bRELEASE_VERSION == 0 )
1088
+ /* debug output only */
1089
+ {
1090
+ int num_H_AddedByRevrs = pOneInput->nNumProtons[iInchiRec][iMobileH].nNumRemovedProtons
1091
+ - nNumRemovedProtons.nNumRemovedProtons;
1092
+ fprintf( stdout, "COMPARE_INCHI: %ld: %s %cM: Proton balance (Diff: %d, RevrsRem=%d)\n",
1093
+ num_inp, szCurHdr? szCurHdr : "Struct", iInchiRec? 'R':'D',
1094
+ pOneInput->nNumProtons[iInchiRec][iMobileH].nNumRemovedProtons,num_H_AddedByRevrs);
1095
+ }
1096
+ #endif
1097
+ }
1098
+ for ( i = 0; i < NUM_H_ISOTOPES; i ++ ) {
1099
+ if ( nNumRemovedProtons.nNumRemovedIsotopicH[i] != pOneInput->nNumProtons[iInchiRec][TAUT_YES].nNumRemovedIsotopicH[i] ) {
1100
+ pOneInput->CompareInchiFlags[0][TAUT_YES] |= INCHIDIFF_MOB_ISO_H;
1101
+ #if( bRELEASE_VERSION == 0 )
1102
+ /* debug output only */
1103
+ {
1104
+ int num_H_AddedByRevrs = pOneInput->nNumProtons[iInchiRec][TAUT_YES].nNumRemovedIsotopicH[i]
1105
+ - nNumRemovedProtons.nNumRemovedIsotopicH[i];
1106
+ fprintf( stdout, "COMPARE_INCHI: %ld: %s %cM: Iso Xchg %dH balance (Diff: %d, RevrsRem=%d)\n",
1107
+ num_inp, szCurHdr? szCurHdr : "Struct", iInchiRec? 'R':'D', i+1,
1108
+ pOneInput->nNumProtons[iInchiRec][TAUT_YES].nNumRemovedIsotopicH[i],num_H_AddedByRevrs);
1109
+ }
1110
+ #endif
1111
+ }
1112
+ }
1113
+ }
1114
+ }
1115
+
1116
+ exit_function:
1117
+ return ret;
1118
+ }
1119
+ /***********************************************************************************************/
1120
+ int CompareAllDisconnectedOrigInchiToRevInChI(StrFromINChI *pStruct[INCHI_NUM][TAUT_NUM],
1121
+ InpInChI *pOneInput, int bHasSomeFixedH,
1122
+ long num_inp, char *szCurHdr)
1123
+ {
1124
+ int i, k, m, n, iInChI, iMobileH, bMobileH, ifk;
1125
+ int num_components_D, num_components_R;
1126
+ int nNumCompHaveSeparateProtons_D, nNumCompHaveSeparateProtons_R;
1127
+ int num_fragments_D, num_fragments_R, num_fragments_DR, num_fragments, iComponent, ret;
1128
+ int ifInChI, ifMobileH, bfMobileH, nLink;
1129
+ COMPONENT_REM_PROTONS nNumRemovedProtons_D; /* removed from the disconnected layer of the Input InChI */
1130
+ COMPONENT_REM_PROTONS nNumRemovedProtons_D_all; /* if only totals are avalable */
1131
+ COMPONENT_REM_PROTONS nNumRemovedProtons_R; /* removed from disconnected layer of the reconstructed struct */
1132
+ COMPONENT_REM_PROTONS nNumRemovedProtons_R_all;
1133
+ INCHI_MODE CompareInchiFlags[TAUT_NUM];
1134
+ StrFromINChI *pStruct1;
1135
+ INChI_Aux *pINChI_Aux;
1136
+ INCHI_SORT *pINChISort1 = NULL; /* from reversed structure */
1137
+ INCHI_SORT *pINChISort2 = NULL; /* original input InChI */
1138
+ int nNumNonTaut1=0, nNumNonTaut2=0;
1139
+
1140
+ ret = 0;
1141
+ memset( pOneInput->CompareInchiFlags[1], 0, sizeof(pOneInput->CompareInchiFlags[1]) );
1142
+
1143
+ /* count components that are not subject to disconnection */
1144
+ if ( !pOneInput->nNumComponents[INCHI_REC][TAUT_YES] &&
1145
+ !pOneInput->nNumComponents[INCHI_REC][TAUT_NON] ) {
1146
+ return 0; /* nothing to do */
1147
+ }
1148
+
1149
+ memset( &nNumRemovedProtons_D, 0, sizeof(nNumRemovedProtons_D) );
1150
+ memset( &nNumRemovedProtons_R, 0, sizeof(nNumRemovedProtons_R) );
1151
+ memset( &nNumRemovedProtons_D_all, 0, sizeof(nNumRemovedProtons_D_all) );
1152
+ memset( &nNumRemovedProtons_R_all, 0, sizeof(nNumRemovedProtons_R_all) );
1153
+ memset( CompareInchiFlags, 0, sizeof(CompareInchiFlags) );
1154
+
1155
+ num_components_D = inchi_max( pOneInput->nNumComponents[INCHI_BAS][TAUT_YES],
1156
+ pOneInput->nNumComponents[INCHI_BAS][TAUT_NON] );
1157
+ num_components_R = inchi_max( pOneInput->nNumComponents[INCHI_REC][TAUT_YES],
1158
+ pOneInput->nNumComponents[INCHI_REC][TAUT_NON] );
1159
+ /***********************************************************************************************/
1160
+ /* InpInChI: count fragments -- disconnected components that do not match reconnected */
1161
+ /* Accumulate removed H and isotopic H from ALL Fixed-H disconnected components except deleted */
1162
+ /* This segment collects info from the original InChI */
1163
+ /***********************************************************************************************/
1164
+ /*---- Original InChI ----*/
1165
+ num_fragments_D = 0;
1166
+ iInChI = INCHI_BAS;
1167
+ iMobileH = bHasSomeFixedH? !pOneInput->nNumComponents[iInChI][TAUT_NON] : TAUT_YES;
1168
+ nNumCompHaveSeparateProtons_D = 0;
1169
+
1170
+ /* in case of Mobile-H components here are the proton totals from the original InChI disconn. layer */
1171
+ nNumRemovedProtons_D.nNumRemovedProtons = pOneInput->nNumProtons[iInChI][TAUT_YES].nNumRemovedProtons;
1172
+ memcpy( nNumRemovedProtons_D.nNumRemovedIsotopicH,
1173
+ pOneInput->nNumProtons[iInChI][TAUT_YES].nNumRemovedIsotopicH,
1174
+ sizeof(nNumRemovedProtons_D.nNumRemovedIsotopicH) ); /* total for the disconnected layer */
1175
+
1176
+ for ( k = 0; k < num_components_D; k ++ ) {
1177
+ bMobileH = iMobileH;
1178
+ if ( !bInpInchiComponentExists( pOneInput, iInChI, bMobileH, k ) ) {
1179
+ if ( bInpInchiComponentExists( pOneInput, iInChI, TAUT_YES, k ) ) {
1180
+ bMobileH = TAUT_YES;
1181
+ } else {
1182
+ continue; /* component is missing ??? */
1183
+ }
1184
+ }
1185
+ if ( 0 > (nLink = pOneInput->pInpInChI[iInChI][bMobileH][k].nLink) ) {
1186
+ /* component in Disconnected layer is linked to the identical one in the Reconnected layer */
1187
+ if ( pOneInput->nNumProtons[INCHI_REC][TAUT_YES].pNumProtons ) {
1188
+ nNumCompHaveSeparateProtons_D ++;
1189
+ nLink = -(1+nLink);
1190
+ nNumRemovedProtons_D.nNumRemovedProtons += pOneInput->nNumProtons[INCHI_REC][TAUT_YES].pNumProtons[nLink].nNumRemovedProtons;
1191
+ for ( m = 0; m < NUM_H_ISOTOPES; m ++ ) {
1192
+ nNumRemovedProtons_D.nNumRemovedIsotopicH[m] += pOneInput->nNumProtons[INCHI_REC][TAUT_YES].pNumProtons[nLink].nNumRemovedIsotopicH[m];
1193
+ }
1194
+ }
1195
+ continue; /* same as reconnected */
1196
+ }
1197
+ /* component in the reconnected layer that was disconnected */
1198
+ nNumNonTaut2 += (bMobileH == TAUT_NON);
1199
+ if ( pOneInput->nNumProtons[iInChI][TAUT_YES].pNumProtons ) {
1200
+ nNumCompHaveSeparateProtons_D ++;
1201
+ nNumRemovedProtons_D.nNumRemovedProtons += pOneInput->nNumProtons[iInChI][TAUT_YES].pNumProtons[k].nNumRemovedProtons;
1202
+ for ( m = 0; m < NUM_H_ISOTOPES; m ++ ) {
1203
+ nNumRemovedProtons_D.nNumRemovedIsotopicH[m] += pOneInput->nNumProtons[iInChI][TAUT_YES].pNumProtons[k].nNumRemovedIsotopicH[m];
1204
+ }
1205
+ }
1206
+ num_fragments_D ++; /* number of disconnected fragments from original reconnected structure */
1207
+ }
1208
+ /* in case of Mobile-H components here are the proton totals from the original InChI */
1209
+ /*
1210
+ nNumRemovedProtons_D_all.nNumRemovedProtons = pOneInput->nNumProtons[iInChI][TAUT_YES].nNumRemovedProtons;
1211
+ memcpy( nNumRemovedProtons_D_all.nNumRemovedIsotopicH,
1212
+ pOneInput->nNumProtons[iInChI][TAUT_YES].nNumRemovedIsotopicH,
1213
+ sizeof(nNumRemovedProtons_D_all.nNumRemovedIsotopicH) );
1214
+
1215
+ */
1216
+ /****************************************************************************************************/
1217
+ /* count fragments in reconstructed reconnected structure */
1218
+ /* accumulate removed H and isotopic H from ALL reconstructed reconnected components except deleted */
1219
+ /* This segment collects info from the reconstructed structure InChI */
1220
+ /****************************************************************************************************/
1221
+ /*---- InChI from the reconstructed reconnected structure ----*/
1222
+ num_fragments_R = 0;
1223
+ iInChI = INCHI_REC;
1224
+ iMobileH = bHasSomeFixedH? !pOneInput->nNumComponents[iInChI][TAUT_NON] : TAUT_YES;
1225
+ nNumCompHaveSeparateProtons_R = 0;
1226
+ for ( k = 0; k < num_components_R; k ++ ) {
1227
+ bMobileH = iMobileH;
1228
+ if ( !bInpInchiComponentExists( pOneInput, iInChI, bMobileH, k ) ) {
1229
+ if ( bInpInchiComponentExists( pOneInput, iInChI, TAUT_YES, k ) ) {
1230
+ bMobileH = TAUT_YES;
1231
+ } else {
1232
+ continue; /* component is missing ??? (Deleted proton in Mobile-H layer) */
1233
+ }
1234
+ }
1235
+ if ( 0 < pOneInput->pInpInChI[iInChI][bMobileH][k].nLink ) {
1236
+ /* this reconstructed reconnected component was NOT DISCONNECTED */
1237
+ /* same component is in the disconnected layer, it has no metal atoms or is an isolated metal atom */
1238
+ pStruct1 = pStruct[iInChI][bMobileH]+k;
1239
+ ifMobileH = TAUT_YES; /* Mobile-H Aux_Info contains number removed protons */
1240
+ ifInChI = INCHI_BAS; /* this component cannot be reconnected */
1241
+ ifk = 0; /* 0th component since it is InChI of a single component */
1242
+ /* The statement in the following line is *WRONG*, component number mixed with bMobileH: */
1243
+ /* in RevInchi, when only Mobile-H is present then its only non-NULL InChI has index 0==TAUT_NON */
1244
+ if ( bRevInchiComponentExists( pStruct1, ifInChI, ifMobileH, ifk ) ) {
1245
+ /* count protons */
1246
+ pINChI_Aux = pStruct1->RevInChI.pINChI_Aux[ifInChI][ifk][ifMobileH];
1247
+ if ( pINChI_Aux ) {
1248
+ nNumRemovedProtons_R.nNumRemovedProtons += pINChI_Aux->nNumRemovedProtons;
1249
+ for ( m = 0; m < NUM_H_ISOTOPES; m ++ ) {
1250
+ nNumRemovedProtons_R.nNumRemovedIsotopicH[m] += pINChI_Aux->nNumRemovedIsotopicH[m];
1251
+ }
1252
+ }
1253
+ }
1254
+ nNumCompHaveSeparateProtons_R += bRevInchiComponentExists( pStruct1, ifInChI, ALT_TAUT(ifMobileH), ifk );
1255
+ continue; /* same as disconnected, has no metal atoms */
1256
+ }
1257
+ /* this reconstructed reconnected component WAS DISCONNECTED; check its fragments */
1258
+ /* it does not have same component in the disconnected layer */
1259
+ pStruct1 = pStruct[iInChI][bMobileH]+k;
1260
+ num_fragments = pStruct1->RevInChI.num_components[INCHI_BAS];
1261
+ ifInChI = INCHI_BAS; /* disconnected layer */
1262
+ ifMobileH = bHasSomeFixedH? TAUT_NON : TAUT_YES;
1263
+ for ( ifk = 0; ifk < num_fragments; ifk ++ ) {
1264
+ bfMobileH = ifMobileH;
1265
+ if ( !bRevInchiComponentExists( pStruct1, ifInChI, bfMobileH, ifk ) ) {
1266
+ if ( bRevInchiComponentExists( pStruct1, ifInChI, TAUT_YES, ifk ) ) {
1267
+ bfMobileH = TAUT_YES;
1268
+ } else {
1269
+ continue; /* fragment does not exist ??? */
1270
+ }
1271
+ }
1272
+ nNumNonTaut1 += (bfMobileH == TAUT_NON);
1273
+ nNumCompHaveSeparateProtons_R += (bfMobileH == TAUT_NON);
1274
+ /* count protons from fragments made by metal disconnection */
1275
+ pINChI_Aux = pStruct1->RevInChI.pINChI_Aux[ifInChI][ifk][TAUT_YES];
1276
+ if ( pINChI_Aux ) {
1277
+ nNumRemovedProtons_R.nNumRemovedProtons += pINChI_Aux->nNumRemovedProtons;
1278
+ for ( m = 0; m < NUM_H_ISOTOPES; m ++ ) {
1279
+ nNumRemovedProtons_R.nNumRemovedIsotopicH[m] += pINChI_Aux->nNumRemovedIsotopicH[m];
1280
+ }
1281
+ }
1282
+ num_fragments_R ++; /* number of disconnected fragments from reconstructed reconnected structure */
1283
+ }
1284
+ }
1285
+ /*---------------- special treatment of the last reconstructed component -----------------*/
1286
+ /*---------------- this may contain separate protons added by the reconstruction ---------*/
1287
+ k = num_components_R - 1;
1288
+ pStruct1 = pStruct[iInChI][iMobileH]+k;
1289
+ if ( iMobileH == TAUT_YES && !bHasSomeFixedH &&
1290
+ bInpInchiComponentDeleted( pOneInput, iInChI, iMobileH, k ) &&
1291
+ (num_fragments = pStruct1->RevInChI.num_components[INCHI_BAS]) ) {
1292
+
1293
+ ifInChI = INCHI_BAS; /* disconnected layer */
1294
+ ifMobileH = TAUT_YES;
1295
+ for ( ifk = 0; ifk < num_fragments; ifk ++ ) {
1296
+ bfMobileH = ifMobileH;
1297
+ if ( !bRevInchiComponentDeleted( pStruct1, ifInChI, bfMobileH, ifk ) ) {
1298
+ continue; /* fragment does exist ??? Should not happen */
1299
+ }
1300
+ /*
1301
+ nNumNonTaut1 += (bfMobileH == TAUT_NON);
1302
+ nNumCompHaveSeparateProtons_R += (bfMobileH == TAUT_NON);
1303
+ */
1304
+ /* count protons from fragments made by metal disconnection */
1305
+ pINChI_Aux = pStruct1->RevInChI.pINChI_Aux[ifInChI][ifk][TAUT_YES];
1306
+ if ( pINChI_Aux ) {
1307
+ nNumRemovedProtons_R.nNumRemovedProtons += pINChI_Aux->nNumRemovedProtons;
1308
+ for ( m = 0; m < NUM_H_ISOTOPES; m ++ ) {
1309
+ nNumRemovedProtons_R.nNumRemovedIsotopicH[m] += pINChI_Aux->nNumRemovedIsotopicH[m];
1310
+ }
1311
+ }
1312
+ /*num_fragments_R ++;*/ /* number of disconnected fragments from reconstructed reconnected structure */
1313
+ }
1314
+ }
1315
+
1316
+
1317
+
1318
+ num_fragments_DR = inchi_max( num_fragments_D, num_fragments_R );
1319
+ /* in case of correct reconstruction, num_fragments_D, num_fragments_R */
1320
+
1321
+ if ( !num_fragments_DR ) {
1322
+ return 0; /* no component was disconnected */
1323
+ }
1324
+ if ( num_fragments_D != num_fragments_R ) {
1325
+ for ( i = 0; i < TAUT_NUM; i ++ ) {
1326
+ if ( pOneInput->nNumComponents[INCHI_BAS][i] ) {
1327
+ pOneInput->CompareInchiFlags[1][i] |= INCHIDIFF_PROBLEM;
1328
+ }
1329
+ }
1330
+ return 1; /* severe error */
1331
+ }
1332
+
1333
+
1334
+ pINChISort1 = (INCHI_SORT *)inchi_calloc(num_fragments_DR, sizeof(pINChISort1[0]));
1335
+ pINChISort2 = (INCHI_SORT *)inchi_calloc(num_fragments_DR, sizeof(pINChISort2[0]));
1336
+ if ( !pINChISort1 || !pINChISort2 ) {
1337
+ ret = RI_ERR_ALLOC;
1338
+ goto exit_function;
1339
+ }
1340
+
1341
+ /* accumulate original InChI of fragments -- disconnected components that do not match reconnected */
1342
+ iInChI = INCHI_BAS;
1343
+ iMobileH = bHasSomeFixedH? !pOneInput->nNumComponents[iInChI][TAUT_NON] : TAUT_YES;
1344
+ for ( k = n = 0; k < num_components_D; k ++ ) {
1345
+ bMobileH = iMobileH;
1346
+ if ( !bInpInchiComponentExists( pOneInput, iInChI, bMobileH, k ) ) {
1347
+ if ( bInpInchiComponentExists( pOneInput, iInChI, TAUT_YES, k ) ) {
1348
+ bMobileH = TAUT_YES;
1349
+ } else {
1350
+ continue; /* component is missing ??? (Deleted proton in Mobile-H layer) */
1351
+ }
1352
+ }
1353
+ if ( 0 > pOneInput->pInpInChI[iInChI][bMobileH][k].nLink ) {
1354
+ continue; /* same as reconnected */
1355
+ }
1356
+ /* the component exists in disconnected layer of the orig. InChI only: it is a fragment */
1357
+ pINChISort2[n].pINChI[bMobileH] = pOneInput->pInpInChI[iInChI][bMobileH] + k;
1358
+ if ( bMobileH == TAUT_NON &&
1359
+ (bInpInchiComponentExists( pOneInput, iInChI, TAUT_YES, k ) ||
1360
+ bInpInchiComponentDeleted( pOneInput, iInChI, TAUT_YES, k ) ) ) {
1361
+ pINChISort2[n].pINChI[TAUT_YES] = pOneInput->pInpInChI[iInChI][TAUT_YES] + k;
1362
+ }
1363
+ /* the last sort key is a number of removed protons */
1364
+ pINChISort2[n].ord_number = pOneInput->nNumProtons[iInChI][TAUT_YES].pNumProtons?
1365
+ pOneInput->nNumProtons[iInChI][TAUT_YES].pNumProtons[k].nNumRemovedProtons : 0;
1366
+ pINChISort2[n].n1 = k; /* orig. InChI disconnected layer component number */
1367
+ pINChISort2[n].n2 = -1; /* no fragment index */
1368
+ n ++;
1369
+ }
1370
+
1371
+ /* accumulate fragments from the reconstructed structure */
1372
+ iInChI = INCHI_REC;
1373
+ iMobileH = bHasSomeFixedH? !pOneInput->nNumComponents[iInChI][TAUT_NON] : TAUT_YES;
1374
+ for ( k = n = 0; k < num_components_R; k ++ ) {
1375
+ bMobileH = iMobileH;
1376
+ if ( !bInpInchiComponentExists( pOneInput, iInChI, bMobileH, k ) ) {
1377
+ if ( bInpInchiComponentExists( pOneInput, iInChI, TAUT_YES, k ) ) {
1378
+ bMobileH = TAUT_YES;
1379
+ } else {
1380
+ continue; /* component is missing ??? (Deleted proton in Mobile-H layer) */
1381
+ }
1382
+ }
1383
+ /* the reconstructed structure */
1384
+ if ( 0 < pOneInput->pInpInChI[iInChI][bMobileH][k].nLink ) {
1385
+ continue; /* same as disconnected, has no metal atoms */
1386
+ }
1387
+ /* this reconstructed structure was disconnected */
1388
+ pStruct1 = pStruct[iInChI][bMobileH]+k;
1389
+ num_fragments = pStruct1->RevInChI.num_components[INCHI_BAS];
1390
+ ifInChI = INCHI_BAS;
1391
+ ifMobileH = bHasSomeFixedH? TAUT_NON : TAUT_YES;
1392
+ for ( i = 0; i < num_fragments; i ++ ) {
1393
+ bfMobileH = ifMobileH;
1394
+ if ( !bRevInchiComponentExists( pStruct1, ifInChI, bfMobileH, i ) ) {
1395
+ if ( bRevInchiComponentExists( pStruct1, ifInChI, TAUT_YES, i ) ) {
1396
+ bfMobileH = TAUT_YES;
1397
+ } else {
1398
+ continue; /* component is missing ??? */
1399
+ }
1400
+ }
1401
+ pINChISort1[n].pINChI[bfMobileH] = pStruct1->RevInChI.pINChI[ifInChI][i][bfMobileH];
1402
+ if ( bfMobileH == TAUT_NON /*&& bRevInchiComponentExists( pStruct1, ifInChI, TAUT_YES, i )*/ ) {
1403
+ pINChISort1[n].pINChI[TAUT_YES] = pStruct1->RevInChI.pINChI[ifInChI][i][TAUT_YES];
1404
+ /* remove Fixed-H InChI if is is identical to Mobile-H */
1405
+ /* do it exactly same way the identical components were removed from InpInChI */
1406
+ if ( !CompareReversedINChI( pINChISort1[n].pINChI[bfMobileH],
1407
+ pINChISort1[n].pINChI[TAUT_YES], NULL, NULL ) ) {
1408
+ pINChISort1[n].pINChI[bfMobileH] = NULL; /* remove Fixed-H layer */
1409
+ } else {
1410
+ pINChISort1[n].ord_number = pStruct1->RevInChI.pINChI_Aux[ifInChI][i][TAUT_YES]->nNumRemovedProtons;
1411
+ }
1412
+ }
1413
+
1414
+ pINChISort1[n].n1 = k; /* reconstructed reconnected structure component index */
1415
+ pINChISort1[n].n2 = i; /* index of a fragment made out of this component */
1416
+ n ++;
1417
+ }
1418
+ }
1419
+
1420
+ /* sort fragment InChI before comparing them */
1421
+ qsort( pINChISort1, num_fragments_D, sizeof(pINChISort1[0]), CompINChITaut2 );
1422
+ qsort( pINChISort2, num_fragments_R, sizeof(pINChISort2[0]), CompINChITaut2 );
1423
+
1424
+ /* compare fragments -- components present in disconnected layer only */
1425
+ for ( iComponent = 0; iComponent < num_fragments_DR; iComponent ++ ) {
1426
+ INChI *pInChI1[TAUT_NUM]; /* from reversed structure */
1427
+ INChI *pInChI2[TAUT_NUM]; /* original input InChI */
1428
+ for ( i = 0; i < TAUT_NUM; i ++ ) {
1429
+ pInChI1[i] = pINChISort1[iComponent].pINChI[i];
1430
+ pInChI2[i] = pINChISort2[iComponent].pINChI[i];
1431
+ }
1432
+ CompareTwoPairsOfInChI( pInChI1, pInChI2, !bHasSomeFixedH, CompareInchiFlags );
1433
+ }
1434
+
1435
+ if ( /*nNumNonTaut1 && nNumNonTaut2 &&*/ bHasSomeFixedH ) {
1436
+ if ( nNumCompHaveSeparateProtons_D || nNumCompHaveSeparateProtons_R ) {
1437
+ /* for each component, compare number removed protons */
1438
+ /* comparison does not make sense if Disconnected Fixed-H layer is not present */
1439
+ for ( iComponent = 0; iComponent < num_fragments_DR; iComponent ++ ) {
1440
+ NUM_H nNumRemovedIsotopicH1[NUM_H_ISOTOPES];
1441
+ NUM_H nNumRemovedIsotopicH2[NUM_H_ISOTOPES];
1442
+
1443
+ memset( nNumRemovedIsotopicH1, 0, sizeof(nNumRemovedIsotopicH1) );
1444
+ memset( nNumRemovedIsotopicH2, 0, sizeof(nNumRemovedIsotopicH2) );
1445
+ /* compare removed protons */
1446
+ if ( pINChISort1[iComponent].ord_number != pINChISort2[iComponent].ord_number ) {
1447
+ CompareInchiFlags[TAUT_YES] |= INCHIDIFF_MOBH_PROTONS; /* diff number of removed protons */
1448
+ }
1449
+ /* also compare removed isotopic atoms H */
1450
+ k = pINChISort2[iComponent].n1; /* input InChI, OneInput */
1451
+ if ( pOneInput->nNumProtons[INCHI_BAS][TAUT_YES].pNumProtons ) {
1452
+ memcpy( nNumRemovedIsotopicH2,
1453
+ pOneInput->nNumProtons[INCHI_BAS][TAUT_YES].pNumProtons[k].nNumRemovedIsotopicH,
1454
+ sizeof( nNumRemovedIsotopicH2 ) );
1455
+ }
1456
+ /* get fragments of reconstructed structure removed protons info */
1457
+ k = pINChISort1[iComponent].n1; /* restored component number */
1458
+ i = pINChISort1[iComponent].n2; /* subcomponent number */
1459
+ iInChI = INCHI_REC;
1460
+ iMobileH = bHasSomeFixedH? !pOneInput->nNumComponents[iInChI][TAUT_NON] : TAUT_YES;
1461
+ bMobileH = iMobileH;
1462
+ if ( !bInpInchiComponentExists( pOneInput, iInChI, bMobileH, k ) ) {
1463
+ if ( bInpInchiComponentExists( pOneInput, iInChI, TAUT_YES, k ) ) {
1464
+ bMobileH = TAUT_YES;
1465
+ } else {
1466
+ goto compare_iso_H;
1467
+ }
1468
+ }
1469
+ if ( pOneInput->pInpInChI[iInChI][bMobileH][k].nLink ) {
1470
+ continue;
1471
+ /*
1472
+ ret = RI_ERR_PROGR;
1473
+ goto exit_function;
1474
+ */
1475
+ }
1476
+ pStruct1 = pStruct[iInChI][bMobileH]+k;
1477
+ num_fragments = pStruct1->RevInChI.num_components[INCHI_BAS];
1478
+ ifInChI = INCHI_BAS;
1479
+ ifMobileH = bHasSomeFixedH? TAUT_NON : TAUT_YES;
1480
+ if ( i < num_fragments ) {
1481
+ bfMobileH = ifMobileH;
1482
+ if ( !bRevInchiComponentExists( pStruct1, ifInChI, bfMobileH, i ) ) {
1483
+ if ( bRevInchiComponentExists( pStruct1, ifInChI, TAUT_YES, i ) ) {
1484
+ bfMobileH = TAUT_YES;
1485
+ } else {
1486
+ goto compare_iso_H;
1487
+ }
1488
+ }
1489
+ memcpy( nNumRemovedIsotopicH1,
1490
+ pStruct1->RevInChI.pINChI_Aux[ifInChI][i][TAUT_YES]->nNumRemovedIsotopicH,
1491
+ sizeof( nNumRemovedIsotopicH1 ) );
1492
+ }
1493
+ compare_iso_H:
1494
+ if ( memcmp( nNumRemovedIsotopicH1, nNumRemovedIsotopicH2, sizeof( nNumRemovedIsotopicH1 ) ) ) {
1495
+ CompareInchiFlags[TAUT_YES] |= INCHIDIFF_REM_ISO_H;
1496
+ }
1497
+ }
1498
+ }
1499
+ } else
1500
+ /*if ( !nNumNonTaut1 && !nNumNonTaut2 || !bHasSomeFixedH )*/ {
1501
+ /* compare totals for removed protons and isotopic H */
1502
+ if ( pOneInput->nNumProtons[INCHI_BAS][TAUT_YES].nNumRemovedProtons !=
1503
+ nNumRemovedProtons_R.nNumRemovedProtons ) {
1504
+ CompareInchiFlags[TAUT_YES] |= INCHIDIFF_MOBH_PROTONS;
1505
+ }
1506
+ if ( memcmp( pOneInput->nNumProtons[INCHI_BAS][TAUT_YES].nNumRemovedIsotopicH,
1507
+ nNumRemovedProtons_R.nNumRemovedIsotopicH,
1508
+ sizeof( nNumRemovedProtons_R.nNumRemovedIsotopicH ) ) ) {
1509
+ CompareInchiFlags[TAUT_YES] |= INCHIDIFF_REM_ISO_H;
1510
+ }
1511
+ }
1512
+
1513
+ if ( !nNumNonTaut1 == !nNumNonTaut2 ) {
1514
+ ; /* difference if(nNumNonTaut1 != nNumNonTaut2) will be caught in InChI comparison */
1515
+ } else
1516
+ if ( nNumNonTaut1 ) {
1517
+ /* reconstructed has Fixed-H while the original has not: extra Fixed-H layer */
1518
+ CompareInchiFlags[TAUT_YES] |= INCHIDIFF_WRONG_TAUT;
1519
+ } else {
1520
+ /* the original InChI has Fixed-H while the reconstructed one has not: missing Fixed-H layer */
1521
+ CompareInchiFlags[TAUT_YES] |= INCHIDIFF_NO_TAUT;
1522
+ }
1523
+ for ( i = 0; i < TAUT_NUM; i ++ ) {
1524
+ pOneInput->CompareInchiFlags[1][i] |= CompareInchiFlags[i];
1525
+ }
1526
+
1527
+ /* compare totals */
1528
+ if ( nNumRemovedProtons_R.nNumRemovedProtons != nNumRemovedProtons_D.nNumRemovedProtons ) {
1529
+ CompareInchiFlags[TAUT_YES] |= INCHIDIFF_MOBH_PROTONS; /* diff number of removed protons */
1530
+ }
1531
+ if ( memcmp( nNumRemovedProtons_R.nNumRemovedIsotopicH,
1532
+ nNumRemovedProtons_D.nNumRemovedIsotopicH,
1533
+ sizeof( nNumRemovedProtons_D.nNumRemovedIsotopicH ) ) ) {
1534
+ CompareInchiFlags[TAUT_YES] |= INCHIDIFF_REM_ISO_H;
1535
+ }
1536
+
1537
+ exit_function:
1538
+
1539
+ if ( pINChISort1 ) inchi_free( pINChISort1 );
1540
+ if ( pINChISort2 ) inchi_free( pINChISort2 );
1541
+
1542
+ return ret;
1543
+ }
1544
+ /******************************************************************************************************/
1545
+ int CompareTwoPairsOfInChI( INChI *pInChI1[TAUT_NUM], INChI *pInChI2[TAUT_NUM],
1546
+ int bMobileH, INCHI_MODE CompareInchiFlags[] )
1547
+ {
1548
+ int iMobileH, err=0;
1549
+ INCHI_MODE cmp;
1550
+ for ( iMobileH = 0; iMobileH < TAUT_NUM; iMobileH ++ ) {
1551
+ if ( !pInChI1[iMobileH] != !pInChI2[iMobileH] ) {
1552
+ if ( iMobileH == TAUT_NON &&
1553
+ pInChI1[TAUT_YES] && pInChI1[TAUT_YES] ) {
1554
+ CompareInchiFlags[iMobileH] |= INCHIDIFF_COMP_HLAYER;
1555
+ } else {
1556
+ CompareInchiFlags[iMobileH] |= INCHIDIFF_COMP_NUMBER;
1557
+ }
1558
+ continue;
1559
+ }
1560
+ if ( pInChI1[iMobileH] && pInChI2[iMobileH] ) {
1561
+ cmp = CompareReversedINChI3( pInChI1[iMobileH], pInChI2[iMobileH], NULL, NULL, &err );
1562
+ if ( cmp ) {
1563
+ CompareInchiFlags[iMobileH] |= cmp;
1564
+ }
1565
+ }
1566
+ }
1567
+ return err;
1568
+ }
1569
+ /******************************************************************************************************/
1570
+ int CompareOneOrigInchiToRevInChI(StrFromINChI *pStruct, INChI *pInChI[TAUT_NUM], int bMobileH, int iComponent,
1571
+ long num_inp, char *szCurHdr,
1572
+ COMPONENT_REM_PROTONS *nCurRemovedProtons, INCHI_MODE CompareInchiFlags[])
1573
+ {
1574
+ int ret = pStruct->RevInChI.nRetVal, err=0;
1575
+ INCHI_MODE cmp;
1576
+ if ( ret == _IS_OKAY || ret == _IS_WARNING ) {
1577
+ /* ignore bMobileH for now */
1578
+ int i, i0, b /* created type */, b0 /* requested type*/, j, k;
1579
+ /* pINChI[iINCHI][iComponent][bTaut] */
1580
+ /* i0 = requested Rec/Disconnected: 1/0 */
1581
+ /* i = what InChI creaded out of the restored structure */
1582
+ /* b0 = requested Mobile/Fixed-H: 1/0 */
1583
+ /* b = what InChI creaded out of the restored structure */
1584
+ i = i0 = pStruct->iINCHI;
1585
+ b = b0 = pStruct->iMobileH;
1586
+ if ( i == INCHI_REC && !pStruct->RevInChI.num_components[i] ) {
1587
+ i = INCHI_BAS;
1588
+ }
1589
+ if ( b == TAUT_NON && (!pStruct->RevInChI.pINChI[i] ||
1590
+ !pStruct->RevInChI.pINChI[i][0][b] ||
1591
+ !pStruct->RevInChI.pINChI[i][0][b]->nNumberOfAtoms ) ) {
1592
+ b = TAUT_YES;
1593
+ }
1594
+ if ( pStruct->bDeleted && (!pInChI[0] || pInChI[0]->bDeleted ) ) {
1595
+ return 0;
1596
+ }
1597
+
1598
+ if ( pStruct->RevInChI.num_components[i] > 1 &&
1599
+ !pStruct->RevInChI.pINChI[i][1][b]->bDeleted ||
1600
+ pStruct->RevInChI.num_components[i] < 1 ) {
1601
+ CompareInchiFlags[bMobileH] |= INCHIDIFF_COMP_NUMBER;
1602
+ }
1603
+ if ( b != b0 || b != bMobileH || b0 != bMobileH || i > i0 ) {
1604
+ /* do not print messages about TAUT_YES instead of TAUT_NON */
1605
+ CompareInchiFlags[bMobileH] |= INCHIDIFF_COMP_HLAYER;
1606
+ }
1607
+
1608
+ if ( pStruct->RevInChI.num_components[i] ) {
1609
+ /* compare InChI from restored structure; '0' in [i][0][b] is the first component */
1610
+ if ( b == TAUT_YES && pStruct->RevInChI.pINChI[i][0][b]->bDeleted && (!pInChI[0] || pInChI[0]->bDeleted ) ) {
1611
+ /* the 1st component is made out of proton(s) and the input component is missing or also a proton */
1612
+ cmp = 0;
1613
+ } else {
1614
+ cmp = CompareReversedINChI3( pStruct->RevInChI.pINChI[i][0][b], pInChI[0], NULL, NULL, &err );
1615
+ if ( cmp ) {
1616
+ CompareInchiFlags[bMobileH] |= cmp;
1617
+ }
1618
+ }
1619
+ if ( b == b0 && b == TAUT_NON ) {
1620
+ if ( pStruct->RevInChI.pINChI[i][0][TAUT_YES] &&
1621
+ !pStruct->RevInChI.pINChI[i][0][TAUT_YES]->bDeleted ||
1622
+ pInChI[1] && !pInChI[1]->bDeleted ) {
1623
+
1624
+ /* in addition to fixed-H also compare mobile-H InChI */
1625
+ cmp = CompareReversedINChI3( pStruct->RevInChI.pINChI[i][0][TAUT_YES], pInChI[1], NULL, NULL, &err );
1626
+ if ( cmp ) {
1627
+ CompareInchiFlags[TAUT_YES] |= cmp;
1628
+ }
1629
+ }
1630
+ /* compare removed H */
1631
+ if ( pStruct->nNumRemovedProtonsMobHInChI != pStruct->RevInChI.pINChI_Aux[i][0][TAUT_YES]->nNumRemovedProtons ) {
1632
+ CompareInchiFlags[TAUT_YES] |= INCHIDIFF_MOBH_PROTONS;
1633
+ }
1634
+ }
1635
+ memset( nCurRemovedProtons, 0, sizeof(*nCurRemovedProtons) );
1636
+ for ( k = 0; k < pStruct->RevInChI.num_components[i]; k ++ ) {
1637
+ if ( !k || pStruct->RevInChI.pINChI[i][k][TAUT_YES]->bDeleted ) {
1638
+ /* get removed protons from the 1st component; add othere only if they are deleted protons */
1639
+ nCurRemovedProtons->nNumRemovedProtons += pStruct->RevInChI.pINChI_Aux[i][k][TAUT_YES]->nNumRemovedProtons;
1640
+ for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
1641
+ nCurRemovedProtons->nNumRemovedIsotopicH[j] += pStruct->RevInChI.pINChI_Aux[i][k][TAUT_YES]->nNumRemovedIsotopicH[j];
1642
+ }
1643
+ }
1644
+ }
1645
+ }
1646
+ } else {
1647
+ CompareInchiFlags[bMobileH] |= INCHIDIFF_STR2INCHI_ERR;
1648
+ }
1649
+ return err;
1650
+ }
1651
+ /*************************************************************************************/
1652
+ INCHI_MODE CompareReversedStereoINChI3( INChI_Stereo *s1/* InChI from reversed struct */, INChI_Stereo *s2 /* input InChI */, ICR *picr)
1653
+ {
1654
+ int ret = 0;
1655
+ int j1, j2, num_eq, num_dif, num_extra_undf, num_miss_undf, num_in1_only, num_in2_only;
1656
+ int bAddSb = !(picr->num_sb_undef_in1_only + picr->num_sb_in1_only + picr->num_sb_in2_only);
1657
+ int bAddSc = !(picr->num_sc_undef_in1_only + picr->num_sc_in1_only + picr->num_sc_in2_only);
1658
+
1659
+ int nNumSc1 = s1? s1->nNumberOfStereoCenters : 0;
1660
+ int nNumSc2 = s2? s2->nNumberOfStereoCenters : 0;
1661
+ int nNumSb1 = s1? s1->nNumberOfStereoBonds : 0;
1662
+ int nNumSb2 = s2? s2->nNumberOfStereoBonds : 0;
1663
+
1664
+ if ( (nNumSc1 || nNumSc1) &&
1665
+ ( nNumSc1 != nNumSc2 ||
1666
+ memcmp( s1->nNumber, s2->nNumber, nNumSc1*sizeof(s1->nNumber[0] ) ) ||
1667
+ memcmp( s1->t_parity, s2->t_parity, nNumSc1*sizeof(s1->t_parity[0]) ) ) ) {
1668
+
1669
+ num_eq = num_dif = num_extra_undf = num_miss_undf = num_in1_only = num_in2_only = 0;
1670
+ for ( j1 = j2 = 0; j1 < nNumSc1 && j2 < nNumSc2; ) {
1671
+ if ( s1->nNumber[j1] == s2->nNumber[j2] ) {
1672
+ if ( s1->t_parity[j1] == s2->t_parity[j2] ) {
1673
+ num_eq ++;
1674
+ } else {
1675
+ num_dif ++;
1676
+ }
1677
+ j1 ++;
1678
+ j2 ++;
1679
+ } else
1680
+ if ( s1->nNumber[j1] < s2->nNumber[j2] ) {
1681
+ num_in1_only ++;
1682
+ if ( s1->t_parity[j1] == AB_PARITY_UNDF ) {
1683
+ num_extra_undf ++;
1684
+ }
1685
+ if ( bAddSc ) {
1686
+ if ( picr->num_sc_in1_only < ICR_MAX_SC_IN1_ONLY )
1687
+ picr->sc_in1_only[picr->num_sc_in1_only ++] = j1;
1688
+ if ( s1->t_parity[j1] == AB_PARITY_UNDF ) {
1689
+ if ( picr->num_sc_undef_in1_only < ICR_MAX_SC_UNDF )
1690
+ picr->sc_undef_in1_only[picr->num_sc_undef_in1_only ++] = j1;
1691
+ }
1692
+ }
1693
+ j1 ++;
1694
+ } else {
1695
+ num_in2_only ++;
1696
+ if ( s2->t_parity[j2] == AB_PARITY_UNDF ) {
1697
+ num_miss_undf ++;
1698
+ }
1699
+ if ( bAddSc ) {
1700
+ if ( picr->num_sc_in2_only < ICR_MAX_SC_IN2_ONLY )
1701
+ picr->sc_in2_only[picr->num_sc_in2_only ++] = j2;
1702
+ if ( s2->t_parity[j2] == AB_PARITY_UNDF ) {
1703
+ if ( picr->num_sc_undef_in2_only < ICR_MAX_SC_UNDF )
1704
+ picr->sc_undef_in2_only[picr->num_sc_undef_in2_only ++] = j1;
1705
+ }
1706
+ }
1707
+ j2 ++;
1708
+ }
1709
+ }
1710
+ while ( j1 < nNumSc1 ) {
1711
+ if ( s1->t_parity[j1] == AB_PARITY_UNDF ) {
1712
+ num_extra_undf ++;
1713
+ }
1714
+ num_in1_only ++;
1715
+ if ( bAddSc ) {
1716
+ if ( picr->num_sc_in1_only < ICR_MAX_SC_IN1_ONLY )
1717
+ picr->sc_in1_only[picr->num_sc_in1_only ++] = j1;
1718
+ if ( s1->t_parity[j1] == AB_PARITY_UNDF ) {
1719
+ if ( picr->num_sc_undef_in1_only < ICR_MAX_SC_UNDF )
1720
+ picr->sc_undef_in1_only[picr->num_sc_undef_in1_only ++] = j1;
1721
+ }
1722
+ }
1723
+ j1 ++;
1724
+ }
1725
+ while ( j2 < nNumSc2 ) {
1726
+ if ( s2->t_parity[j2] == AB_PARITY_UNDF ) {
1727
+ num_miss_undf ++;
1728
+ }
1729
+ num_in2_only ++;
1730
+ if ( bAddSc ) {
1731
+ if ( picr->num_sc_in2_only < ICR_MAX_SC_IN2_ONLY )
1732
+ picr->sc_in2_only[picr->num_sc_in2_only ++] = j2;
1733
+ }
1734
+ j2 ++;
1735
+ }
1736
+ if ( num_dif ) {
1737
+ ret |= INCHIDIFF_SC_PARITY;
1738
+ }
1739
+ if ( num_in1_only ) {
1740
+ if ( num_extra_undf ) {
1741
+ ret |= INCHIDIFF_SC_EXTRA_UNDF;
1742
+ }
1743
+ if ( num_in1_only != num_extra_undf ) {
1744
+ ret |= INCHIDIFF_SC_EXTRA;
1745
+ }
1746
+ }
1747
+ if ( num_in2_only ) {
1748
+ if ( num_miss_undf ) {
1749
+ ret |= INCHIDIFF_SC_MISS_UNDF;
1750
+ }
1751
+ if ( num_in2_only != num_miss_undf ) {
1752
+ ret |= INCHIDIFF_SC_MISS;
1753
+ }
1754
+ }
1755
+ }
1756
+ if ( s1 && s2 && s1->nCompInv2Abs != s2->nCompInv2Abs && s1->nCompInv2Abs && s2->nCompInv2Abs ) {
1757
+ ret |= INCHIDIFF_SC_INV;
1758
+ }
1759
+
1760
+ if ( (nNumSb1 || nNumSb2 ) &&
1761
+ (nNumSb1 != nNumSb2 ||
1762
+ memcmp( s1->nBondAtom1, s2->nBondAtom1, nNumSb1*sizeof(s1->nBondAtom1[0]) ) ||
1763
+ memcmp( s1->nBondAtom2, s2->nBondAtom2, nNumSb1*sizeof(s1->nBondAtom2[0]) ) ||
1764
+ memcmp( s1->b_parity, s2->b_parity, nNumSb1*sizeof(s1->b_parity[0]) ) ) ) {
1765
+
1766
+ num_eq = num_dif = num_extra_undf = num_miss_undf = num_in1_only = num_in2_only = 0;
1767
+ for ( j1 = j2 = 0; j1 < nNumSb1 && j2 < nNumSb2; ) {
1768
+ if ( s1->nBondAtom1[j1] == s2->nBondAtom1[j2] &&
1769
+ s1->nBondAtom2[j1] == s2->nBondAtom2[j2] ) {
1770
+ if ( s1->b_parity[j1] == s2->b_parity[j2] ) {
1771
+ num_eq ++;
1772
+ } else {
1773
+ num_dif ++;
1774
+ }
1775
+ j1 ++;
1776
+ j2 ++;
1777
+ } else
1778
+ if ( s1->nBondAtom1[j1] < s2->nBondAtom1[j2] ||
1779
+ s1->nBondAtom1[j1] == s2->nBondAtom1[j2] && s1->nBondAtom2[j1] < s2->nBondAtom2[j2]) {
1780
+ num_in1_only ++;
1781
+ if ( s1->b_parity[j1] == AB_PARITY_UNDF ) {
1782
+ num_extra_undf ++;
1783
+ }
1784
+ if ( bAddSb ) {
1785
+ if ( picr->num_sb_in1_only < ICR_MAX_SB_IN1_ONLY )
1786
+ picr->sb_in1_only[picr->num_sb_in1_only ++] = j1;
1787
+ if ( s1->b_parity[j1] == AB_PARITY_UNDF ) {
1788
+ if ( picr->num_sb_undef_in1_only < ICR_MAX_SB_UNDF )
1789
+ picr->sb_undef_in1_only[picr->num_sb_undef_in1_only ++] = j1;
1790
+ }
1791
+ }
1792
+ j1 ++;
1793
+ } else {
1794
+ num_in2_only ++;
1795
+ if ( s2->b_parity[j2] == AB_PARITY_UNDF ) {
1796
+ num_miss_undf ++;
1797
+ }
1798
+ if ( bAddSb ) {
1799
+ if ( picr->num_sb_in2_only < ICR_MAX_SB_IN2_ONLY )
1800
+ picr->sb_in2_only[picr->num_sb_in2_only ++] = j2;
1801
+ if ( s2->b_parity[j2] == AB_PARITY_UNDF ) {
1802
+ if ( picr->num_sb_undef_in2_only < ICR_MAX_SB_UNDF )
1803
+ picr->sb_undef_in2_only[picr->num_sb_undef_in2_only ++] = j1;
1804
+ }
1805
+ }
1806
+ j2 ++;
1807
+ }
1808
+ }
1809
+ while ( j1 < nNumSb1 ) {
1810
+ num_in1_only ++;
1811
+ if ( s1->b_parity[j1] == AB_PARITY_UNDF ) {
1812
+ num_extra_undf ++;
1813
+ }
1814
+ if ( bAddSb ) {
1815
+ if ( picr->num_sb_in1_only < ICR_MAX_SB_IN1_ONLY )
1816
+ picr->sb_in1_only[picr->num_sb_in1_only ++] = j1;
1817
+ if ( s1->b_parity[j1] == AB_PARITY_UNDF ) {
1818
+ if ( picr->num_sb_undef_in1_only < ICR_MAX_SB_UNDF )
1819
+ picr->sb_undef_in1_only[picr->num_sb_undef_in1_only ++] = j1;
1820
+ }
1821
+ }
1822
+ j1 ++;
1823
+ }
1824
+ while ( j2 < nNumSb2 ) {
1825
+ num_in2_only ++;
1826
+ if ( s2->b_parity[j2] == AB_PARITY_UNDF ) {
1827
+ num_miss_undf ++;
1828
+ }
1829
+ if ( bAddSb ) {
1830
+ if ( picr->num_sb_in2_only < ICR_MAX_SB_IN2_ONLY )
1831
+ picr->sb_in2_only[picr->num_sb_in2_only ++] = j2;
1832
+ if ( s2->b_parity[j2] == AB_PARITY_UNDF ) {
1833
+ if ( picr->num_sb_undef_in2_only < ICR_MAX_SB_UNDF )
1834
+ picr->sb_undef_in2_only[picr->num_sb_undef_in2_only ++] = j1;
1835
+ }
1836
+ }
1837
+ j2 ++;
1838
+ }
1839
+ if ( num_dif ) {
1840
+ ret |= INCHIDIFF_SB_PARITY;
1841
+ }
1842
+ if ( num_in1_only ) {
1843
+ if ( num_extra_undf ) {
1844
+ ret |= INCHIDIFF_SB_EXTRA_UNDF;
1845
+ }
1846
+ if ( num_in1_only != num_extra_undf ) {
1847
+ ret |= INCHIDIFF_SB_EXTRA;
1848
+ }
1849
+ }
1850
+ if ( num_in2_only ) {
1851
+ if ( num_miss_undf ) {
1852
+ ret |= INCHIDIFF_SB_MISS_UNDF;
1853
+ }
1854
+ if ( num_in2_only != num_miss_undf ) {
1855
+ ret |= INCHIDIFF_SB_MISS;
1856
+ }
1857
+ }
1858
+ }
1859
+
1860
+ return ret;
1861
+ }
1862
+ /*********************************************************************************************************/
1863
+ INCHI_MODE CompareReversedINChI3( INChI *i1 /* InChI from reversed struct */, INChI *i2 /* input InChI */,
1864
+ INChI_Aux *a1, INChI_Aux *a2, int *err )
1865
+ {
1866
+ INCHI_MODE ret = 0;
1867
+ INChI_Stereo *Stereo1=NULL, *Stereo2=NULL;
1868
+ int n1, n2, m, j, j1, j2, ret2, num_H1, num_H2;
1869
+ ICR icr;
1870
+ ICR *picr = &icr;
1871
+
1872
+ *err = 0;
1873
+
1874
+ memset( picr, 0, sizeof(*picr) );
1875
+
1876
+ if ( i1 == NULL && i2 == NULL )
1877
+ return 0;
1878
+ if ( (i1 == NULL) ^ (i2 == NULL) ) {
1879
+ ret |= INCHIDIFF_PROBLEM; /* one InChI exists while another doesn't */
1880
+ goto exit_function;
1881
+ }
1882
+
1883
+ if ( i1->nErrorCode == i2->nErrorCode ) {
1884
+ if ( i1->nErrorCode ) {
1885
+ ret |= INCHIDIFF_PROBLEM; /* both InChI have same error codes */
1886
+ goto exit_function;
1887
+ }
1888
+ } else {
1889
+ ret |= INCHIDIFF_PROBLEM; /* at least one InChI has an error code */
1890
+ goto exit_function;
1891
+ }
1892
+
1893
+ if ( i1->nNumberOfAtoms != i2->nNumberOfAtoms ) {
1894
+ ret |= INCHIDIFF_NUM_AT;
1895
+ goto exit_function;
1896
+ }
1897
+ if ( i1->nNumberOfAtoms > 0 ) {
1898
+ if ( memcmp( i1->nAtom, i2->nAtom, i1->nNumberOfAtoms*sizeof(i1->nAtom[0]) ) ) {
1899
+ ret |= INCHIDIFF_ATOMS;
1900
+ goto exit_function;
1901
+ }
1902
+ /* INCHIDIFF_NON_TAUT_H, INCHIDIFF_MORE_FH, INCHIDIFF_LESS_FH */
1903
+ if ( memcmp( i1->nNum_H, i2->nNum_H, i1->nNumberOfAtoms*sizeof(i1->nNum_H[0]) ) ) {
1904
+ ret |= INCHIDIFF_POSITION_H;
1905
+ for ( j1 = 0; j1 < i1->nNumberOfAtoms; j1 ++ ) {
1906
+ if ( i1->nNum_H[j1] != i2->nNum_H[j1] && picr->num_diff_pos_H < ICR_MAX_DIFF_FIXED_H ) {
1907
+ picr->diff_pos_H_at[picr->num_diff_pos_H] = j1;
1908
+ picr->diff_pos_H_nH[picr->num_diff_pos_H] = i1->nNum_H[j1] - i2->nNum_H[j1];
1909
+ picr->num_diff_pos_H ++;
1910
+ }
1911
+ }
1912
+ }
1913
+ /* fixed H */
1914
+ if ( i1->nNum_H_fixed || i2->nNum_H_fixed ) {
1915
+ int bHasFixedH1 = 0, bHasFixedH2 = 0, i;
1916
+ if ( i1->nNum_H_fixed ) {
1917
+ for ( i = 0; i < i1->nNumberOfAtoms; i ++ ) {
1918
+ if ( i1->nNum_H_fixed[i] ) {
1919
+ bHasFixedH1 ++;
1920
+ }
1921
+ }
1922
+ }
1923
+ if ( i2->nNum_H_fixed ) {
1924
+ for ( i = 0; i < i2->nNumberOfAtoms; i ++ ) {
1925
+ if ( i2->nNum_H_fixed[i] ) {
1926
+ bHasFixedH2 ++;
1927
+ }
1928
+ }
1929
+ }
1930
+ if ( bHasFixedH1 && !bHasFixedH2 ) {
1931
+ for ( i = j = 0; i < i1->nNumberOfAtoms; i ++ ) {
1932
+ if ( i1->nNum_H_fixed[i] ) {
1933
+ if ( j < ICR_MAX_DIFF_FIXED_H ) {
1934
+ picr->fixed_H_at1_more[j] = i;
1935
+ picr->fixed_H_nH1_more[j] = i1->nNum_H_fixed[i];
1936
+ j ++;
1937
+ }
1938
+ }
1939
+ }
1940
+ picr->num_fixed_H1_more = j;
1941
+ ret |= INCHIDIFF_MORE_FH; /* Extra Fixed-H */
1942
+ } else
1943
+ if ( !bHasFixedH1 && bHasFixedH2 ) {
1944
+ for ( i = j = 0; i < i2->nNumberOfAtoms; i ++ ) {
1945
+ if ( i2->nNum_H_fixed[i] ) {
1946
+ if ( j < ICR_MAX_DIFF_FIXED_H ) {
1947
+ picr->fixed_H_at2_more[j] = i;
1948
+ picr->fixed_H_nH2_more[j] = i2->nNum_H_fixed[i];
1949
+ j ++;
1950
+ }
1951
+ }
1952
+ }
1953
+ picr->num_fixed_H2_more = j;
1954
+ ret |= INCHIDIFF_LESS_FH; /* Missed Fixed-H */
1955
+ } else
1956
+ if ( bHasFixedH1 && bHasFixedH2 &&
1957
+ memcmp( i1->nNum_H_fixed, i2->nNum_H_fixed, i1->nNumberOfAtoms*sizeof(i1->nNum_H_fixed[0]) ) ) {
1958
+ for ( i = j1 = j2 = 0; i < i1->nNumberOfAtoms; i ++ ) {
1959
+ if ( i1->nNum_H_fixed[i] > i2->nNum_H_fixed[i] ) {
1960
+ if ( j1 < ICR_MAX_DIFF_FIXED_H ) {
1961
+ picr->fixed_H_at1_more[j1] = i;
1962
+ picr->fixed_H_nH1_more[j1] = i1->nNum_H_fixed[i] - i2->nNum_H_fixed[i];
1963
+ j1 ++;
1964
+ }
1965
+ } else
1966
+ if ( i1->nNum_H_fixed[i] < i2->nNum_H_fixed[i] ) {
1967
+ if ( j2 < ICR_MAX_DIFF_FIXED_H ) {
1968
+ picr->fixed_H_at2_more[j2] = i;
1969
+ picr->fixed_H_nH2_more[j2] = i2->nNum_H_fixed[i] - i1->nNum_H_fixed[i];
1970
+ j2 ++;
1971
+ }
1972
+ }
1973
+ }
1974
+ ret |= (j1? INCHIDIFF_MORE_FH:0) | (j2? INCHIDIFF_LESS_FH:0);
1975
+ picr->num_fixed_H1_more = j1;
1976
+ picr->num_fixed_H2_more = j2;
1977
+ }
1978
+ }
1979
+ }
1980
+ /* compare formulas and H */
1981
+ num_H1 = 0;
1982
+ num_H2 = 0;
1983
+ ret2 = CompareHillFormulasNoH( i1->szHillFormula, i2->szHillFormula, &num_H1, &num_H2 );
1984
+ picr->tot_num_H1 = num_H1;
1985
+ picr->tot_num_H2 = num_H2;
1986
+ if ( ret2 ) {
1987
+ ret |= INCHIDIFF_NUM_EL;
1988
+ goto exit_function;
1989
+ }
1990
+ if ( num_H1 > num_H2 ) {
1991
+ ret |= INCHIDIFF_MORE_H;
1992
+ }
1993
+ if ( num_H1 < num_H2 ) {
1994
+ ret |= INCHIDIFF_LESS_H;
1995
+ }
1996
+
1997
+ if ( i1->lenConnTable != i2->lenConnTable ) {
1998
+ ret |= INCHIDIFF_CON_LEN;
1999
+ goto exit_function;
2000
+ } else
2001
+ if ( i1->lenConnTable > 0 && memcmp( i1->nConnTable, i2->nConnTable, i1->lenConnTable*sizeof(i1->nConnTable[0]) ) ) {
2002
+ ret |= INCHIDIFF_CON_TBL;
2003
+ goto exit_function;
2004
+ }
2005
+ /* output special cases: different number of t-groups, different sizes of t-groups, different endpoints */
2006
+ /* in isotopic or deprotonated cases i1->lenTautomer == 1 && i1->nTautomer[0] = 0 */
2007
+ /*
2008
+ if ( i1->lenTautomer != i2->lenTautomer && (i1->lenTautomer > 1 || i2->lenTautomer > 1) ) {
2009
+ ret |= INCHIDIFF_TAUT_LEN;
2010
+ }
2011
+ */
2012
+ /* compare number of t-groups */
2013
+ n1 = i1->lenTautomer? i1->nTautomer[0] : 0;
2014
+ n2 = i2->lenTautomer? i2->nTautomer[0] : 0;
2015
+ if ( !n1 && n2 ) {
2016
+ ret |= INCHIDIFF_NO_TAUT;
2017
+ } else
2018
+ if ( n1 && !n2 ) {
2019
+ ret |= INCHIDIFF_WRONG_TAUT;
2020
+ } else
2021
+ if ( n1 == 1 && n2 > 1 ) {
2022
+ ret |= INCHIDIFF_SINGLE_TG;
2023
+ } else
2024
+ if ( n1 > 1 && n2 == 1 ) {
2025
+ ret |= INCHIDIFF_MULTIPLE_TG;
2026
+ } else
2027
+ if ( n1 != n2 ) {
2028
+ ret |= INCHIDIFF_NUM_TG;
2029
+ }
2030
+ if ( n1 || n2 ) {
2031
+ /* number of endpoints */
2032
+ int num1 = 0, num2 = 0, num_M1=0, num_M2=0;
2033
+ int len, num_eq, num_in1_only, num_in2_only;
2034
+ AT_NUMB *pe1 = (AT_NUMB *)inchi_malloc( (i1->lenTautomer+1) * sizeof(pe1[0]) );
2035
+ AT_NUMB *pe2 = (AT_NUMB *)inchi_malloc( (i2->lenTautomer+1) * sizeof(pe2[0]) );
2036
+ num_H1 = num_H2=0;
2037
+ /* collect endpoints, H, (-) */
2038
+ if ( !pe1 || !pe2 ) {
2039
+ if ( pe1 ) inchi_free( pe1 );
2040
+ if ( pe2 ) inchi_free( pe2 );
2041
+ *err = RI_ERR_ALLOC; /* allocation error */
2042
+ goto exit_function;
2043
+ }
2044
+ for ( m = 1; m < i1->lenTautomer; m += len ) {
2045
+ len = i1->nTautomer[m ++];
2046
+ num_H1 += i1->nTautomer[m];
2047
+ num_M1 += i1->nTautomer[m+1];
2048
+ for ( j = 2; j < len; j ++ ) {
2049
+ pe1[num1 ++] = i1->nTautomer[m + j];
2050
+ }
2051
+ }
2052
+ for ( m = 1; m < i2->lenTautomer; m += len ) {
2053
+ len = i2->nTautomer[m ++];
2054
+ num_H2 += i2->nTautomer[m];
2055
+ num_M2 += i2->nTautomer[m+1];
2056
+ for ( j = 2; j < len; j ++ ) {
2057
+ pe2[num2 ++] = i2->nTautomer[m + j];
2058
+ }
2059
+ }
2060
+ picr->num_taut_H1 = num_H1;
2061
+ picr->num_taut_H2 = num_H2;
2062
+ picr->num_taut_M1 = num_M1;
2063
+ picr->num_taut_M2 = num_M2;
2064
+ /* sort endpoints */
2065
+ insertions_sort_AT_NUMB( pe1, num1 );
2066
+ insertions_sort_AT_NUMB( pe2, num2 );
2067
+ /* compare */
2068
+ /*
2069
+ if ( num1 < num2 ) {
2070
+ ret |= INCHIDIFF_LESS_TG_ENDP;
2071
+ } else
2072
+ if ( num1 > num2 ) {
2073
+ ret |= INCHIDIFF_MORE_TG_ENDP;
2074
+ }
2075
+ */
2076
+ /* compare all */
2077
+ num_eq = num_in1_only = num_in2_only = 0;
2078
+ for ( j1 = j2 = 0; j1 < num1 && j2 < num2; ) {
2079
+ if( pe1[j1] == pe2[j2] ) {
2080
+ j1 ++;
2081
+ j2 ++;
2082
+ num_eq ++;
2083
+ } else
2084
+ if ( pe1[j1] < pe2[j1] ) {
2085
+ if ( picr->num_endp_in1_only < ICR_MAX_ENDP_IN1_ONLY ) {
2086
+ picr->endp_in1_only[picr->num_endp_in1_only ++] = pe1[j1];
2087
+ }
2088
+ j1 ++;
2089
+ num_in1_only ++;
2090
+ } else {
2091
+ if ( picr->num_endp_in2_only < ICR_MAX_ENDP_IN2_ONLY ) {
2092
+ picr->endp_in2_only[picr->num_endp_in2_only ++] = pe2[j2];
2093
+ }
2094
+ j2 ++;
2095
+ num_in2_only ++;
2096
+ }
2097
+ }
2098
+ while ( j1 < num1 ) {
2099
+ if ( picr->num_endp_in1_only < ICR_MAX_ENDP_IN1_ONLY ) {
2100
+ picr->endp_in1_only[picr->num_endp_in1_only ++] = pe1[j1];
2101
+ }
2102
+ j1 ++;
2103
+ num_in1_only ++;
2104
+ }
2105
+ while ( j2 < num2 ) {
2106
+ if ( picr->num_endp_in2_only < ICR_MAX_ENDP_IN2_ONLY ) {
2107
+ picr->endp_in2_only[picr->num_endp_in2_only ++] = pe2[j2];
2108
+ }
2109
+ j2 ++;
2110
+ num_in2_only ++;
2111
+ }
2112
+ if ( num_in1_only ) {
2113
+ ret |= INCHIDIFF_EXTRA_TG_ENDP;
2114
+ }
2115
+ if ( num_in2_only ) {
2116
+ ret |= INCHIDIFF_MISS_TG_ENDP;
2117
+ }
2118
+ if ( !num_in1_only && !num_in2_only && num_eq ) {
2119
+ ; /* same t-groups endpoints */
2120
+ } else {
2121
+ ret |= INCHIDIFF_DIFF_TG_ENDP;
2122
+ }
2123
+ inchi_free( pe1 );
2124
+ inchi_free( pe2 );
2125
+
2126
+ }
2127
+
2128
+ if ( (i1->lenTautomer > 1 && i2->lenTautomer > 1) &&
2129
+ ( i1->lenTautomer != i2->lenTautomer ||
2130
+ memcmp( i1->nTautomer, i2->nTautomer, i1->lenTautomer*sizeof(i1->nTautomer[0]) ) ) )
2131
+ ret |= INCHIDIFF_TG;
2132
+
2133
+ if ( i1->nNumberOfIsotopicAtoms != i2->nNumberOfIsotopicAtoms ) {
2134
+ ret |= INCHIDIFF_NUM_ISO_AT;
2135
+ } else
2136
+ if ( i1->nNumberOfIsotopicAtoms > 0 && memcmp( i1->IsotopicAtom, i2->IsotopicAtom, i1->nNumberOfIsotopicAtoms*sizeof(i1->IsotopicAtom[0]) ) )
2137
+ ret |= INCHIDIFF_ISO_AT;
2138
+ if ( i1->nTotalCharge != i2->nTotalCharge )
2139
+ ret |= INCHIDIFF_CHARGE;
2140
+ if ( a1 && a1->nNumRemovedProtons && (!a2 || a2->nNumRemovedProtons != a1->nNumRemovedProtons) ) {
2141
+ ret |= INCHIDIFF_REM_PROT;
2142
+ }
2143
+ if ( a1 && (!a2 ||
2144
+ a2->nNumRemovedIsotopicH[0] != a1->nNumRemovedIsotopicH[0] ||
2145
+ a2->nNumRemovedIsotopicH[1] != a1->nNumRemovedIsotopicH[1] ||
2146
+ a2->nNumRemovedIsotopicH[2] != a1->nNumRemovedIsotopicH[2]) ) {
2147
+ ret |= INCHIDIFF_REM_ISO_H;
2148
+ }
2149
+
2150
+ /*
2151
+ if ( i1->nPossibleLocationsOfIsotopicH && i2->nPossibleLocationsOfIsotopicH ) {
2152
+ if ( i1->nPossibleLocationsOfIsotopicH[0] != i2->nPossibleLocationsOfIsotopicH[0] ||
2153
+ memcmp(i1->nPossibleLocationsOfIsotopicH, i2->nPossibleLocationsOfIsotopicH,
2154
+ sizeof(i1->nPossibleLocationsOfIsotopicH[0])*i1->nPossibleLocationsOfIsotopicH[0]) )
2155
+ return 18;
2156
+ } else
2157
+ if ( !i1->nPossibleLocationsOfIsotopicH != !i2->nPossibleLocationsOfIsotopicH ) {
2158
+ return 19;
2159
+ }
2160
+ */
2161
+ if ( i1->StereoIsotopic &&
2162
+ i1->StereoIsotopic->nNumberOfStereoBonds + i1->StereoIsotopic->nNumberOfStereoCenters ) {
2163
+ Stereo1 = i1->StereoIsotopic;
2164
+ } else {
2165
+ Stereo1 = i1->Stereo;
2166
+ }
2167
+ if ( i2->StereoIsotopic &&
2168
+ i2->StereoIsotopic->nNumberOfStereoBonds + i2->StereoIsotopic->nNumberOfStereoCenters ) {
2169
+ Stereo2 = i2->StereoIsotopic;
2170
+ } else {
2171
+ Stereo2 = i2->Stereo;
2172
+ }
2173
+ ret |= CompareReversedStereoINChI3( Stereo1, Stereo2, picr );
2174
+
2175
+ exit_function:
2176
+
2177
+ picr->flags = ret;
2178
+
2179
+ return ret;
2180
+ }
2181
+ /* message group names */
2182
+ CMP_INCHI_MSG_GROUP CompareInchiMsgsGroup[] = {
2183
+ {IDGRP_ERR, " Error:"},
2184
+ {IDGRP_H, " Hydrogens:"},
2185
+ {IDGRP_MOB_GRP, " Mobile-H groups:"},
2186
+ {IDGRP_ISO_AT, " Isotopic:"},
2187
+ {IDGRP_CHARGE, " Charge(s):"},
2188
+ {IDGRP_PROTONS, " Proton balance:"},
2189
+ {IDGRP_ISO_H, " Exchangeable isotopic H:"},
2190
+ {IDGRP_SC, " Stereo centers/allenes:"},
2191
+ {IDGRP_SB, " Stereobonds/cumulenes:"},
2192
+ {IDGRP_HLAYER, " Fixed-H layer:"},
2193
+ {IDGRP_COMP, " Number of components:"},
2194
+ {IDGRP_CONV_ERR," Conversion encountered:"},
2195
+ {IDGRP_ZERO, ""}
2196
+ };
2197
+ /* messages */
2198
+ CMP_INCHI_MSG CompareInchiMsgs[] = {
2199
+ {INCHIDIFF_PROBLEM ,IDGRP_ERR, " Wrong result" }, /*0x00000001, severe: at least one InChI does not exist */
2200
+ {INCHIDIFF_POSITION_H ,IDGRP_H, " Locations or number" }, /*0x00000002, difference in non-taut {Mobile-H} or all H {Fixed-H} location/number */
2201
+ {INCHIDIFF_MORE_FH ,IDGRP_H, " Fixed-H" }, /*0x00000004, extra fixed H */
2202
+ {INCHIDIFF_LESS_FH ,IDGRP_H, " Fixed-H" }, /*0x00000004, missing fixed H */
2203
+ {INCHIDIFF_MORE_H ,IDGRP_H, " Number" }, /*0x00000008, formulas differ in number of H */
2204
+ {INCHIDIFF_LESS_H ,IDGRP_H, " Number" }, /*0x00000008, formulas differ in number of H */
2205
+ {INCHIDIFF_NO_TAUT ,IDGRP_MOB_GRP, " Missing" }, /*0x00000010, restored structure has no taut groups while the original InChI has some */
2206
+ {INCHIDIFF_WRONG_TAUT ,IDGRP_MOB_GRP, " Falsely present" }, /*0x00000020, restored has tautomerism while the original does not have it */
2207
+ {INCHIDIFF_SINGLE_TG ,IDGRP_MOB_GRP, " One instead of multiple" }, /*0x00000040, restored has 1 taut. group while the original InChI has multiple tg */
2208
+ {INCHIDIFF_MULTIPLE_TG ,IDGRP_MOB_GRP, " Multiple instead of one" }, /*0x00000080, restored has multiple tg while the original InChI has only one tg */
2209
+ {INCHIDIFF_EXTRA_TG_ENDP,IDGRP_MOB_GRP, " Attachment points" }, /*0x00000100, extra tautomeric endpoint{s} in restored structure */
2210
+ {INCHIDIFF_MISS_TG_ENDP ,IDGRP_MOB_GRP, " Attachment points" }, /*0x00000100, one or more tg endpoint is not in the restored structure */
2211
+ {INCHIDIFF_DIFF_TG_ENDP ,IDGRP_MOB_GRP, " Attachment points" }, /*0x00000100, lists of tg endpoints are different */
2212
+ {INCHIDIFF_NUM_TG ,IDGRP_MOB_GRP, " Number" }, /*0x00000200, different number of tautomeric groups */
2213
+ {INCHIDIFF_TG ,IDGRP_MOB_GRP, " Do not match" }, /*0x00000200, different tautomeric groups */
2214
+ {INCHIDIFF_NUM_ISO_AT ,IDGRP_ISO_AT, " Atoms do not match" }, /*0x00000400, ?severe: restored struct. has different number of isotopic atoms */
2215
+ {INCHIDIFF_ISO_AT ,IDGRP_ISO_AT, " Atoms do not match" }, /*0x00000400, ?severe: restored struct. has different locations/isotopes of isotopic atoms */
2216
+ {INCHIDIFF_REM_ISO_H ,IDGRP_ISO_H, " Does not match for a component" }, /*0x00000800, isotopic H removed */
2217
+ {INCHIDIFF_MOB_ISO_H ,IDGRP_ISO_H, " Do not match" }, /*0x00001000, different number of mobile exchangeable isotopic H */
2218
+ {INCHIDIFF_CHARGE ,IDGRP_CHARGE, " Do not match" }, /*0x00002000, restored structure has different charge */
2219
+ {INCHIDIFF_REM_PROT ,IDGRP_PROTONS, " Does not match for a component" }, /*0x00004000, proton{s} removed/added from the restored structure */
2220
+ {INCHIDIFF_MOBH_PROTONS ,IDGRP_PROTONS, " Does not match" }, /*0x00008000, different proton balance */
2221
+ {INCHIDIFF_SC_INV ,IDGRP_SC, " Falsely inverted" }, /*0x00010000, restores structure has different inversion stereocenter mark */
2222
+ {INCHIDIFF_SC_PARITY ,IDGRP_SC, " Wrong parity" }, /*0x00020000, restored structure has stereoatoms or allenes with different parity */
2223
+ {INCHIDIFF_SC_EXTRA_UNDF,IDGRP_SC, " Extra undefined" }, /*0x00040000, restored structure has extra undefined stereocenter{s} */
2224
+ {INCHIDIFF_SC_EXTRA ,IDGRP_SC, " Extra known" }, /*0x00080000, restored structure has extra stereocenter{s} */
2225
+ {INCHIDIFF_SC_MISS_UNDF ,IDGRP_SC, " Missing undefined" }, /*0x00100000, restored structure has not some undefined stereocenter{s} */
2226
+ {INCHIDIFF_SC_MISS ,IDGRP_SC, " Missing known" }, /*0x00200000, restored structure has not some stereocenters that are not undefined */
2227
+ {INCHIDIFF_SB_PARITY ,IDGRP_SB, " Wrong parity" }, /*0x00400000, restored structure has stereobonds or cumulenes with different parity */
2228
+ {INCHIDIFF_SB_EXTRA_UNDF,IDGRP_SB, " Extra undefined" }, /*0x00800000, restored structure has extra undefined stereobond{s} */
2229
+ {INCHIDIFF_SB_EXTRA ,IDGRP_SB, " Missing known" }, /*0x01000000, restored structure has extra stereobond{s} */
2230
+ {INCHIDIFF_SB_MISS_UNDF ,IDGRP_SB, " Missing undefined" }, /*0x02000000, restored structure has not some undefined stereocenters */
2231
+ {INCHIDIFF_SB_MISS ,IDGRP_SB, " Missing known" }, /*0x04000000, restored structure has not some stereobonds that are not undefined */
2232
+ {INCHIDIFF_COMP_HLAYER ,IDGRP_HLAYER, " Missing or extra" }, /*0x08000000, Restored component has Mobile-H layer instead of both Mobile-H & Fixed-H or both instead of one */
2233
+ {INCHIDIFF_COMP_NUMBER ,IDGRP_COMP, " Does not match" }, /*0x10000000, wrong number of components */
2234
+ {INCHIDIFF_STR2INCHI_ERR,IDGRP_CONV_ERR," Error" }, /*0x20000000 Restored structure to InChI conversion error */
2235
+ {INCHIDIFF_ZERO ,IDGRP_ZERO, "" }
2236
+ };
2237
+
2238
+ /*************************************************************************/
2239
+ int AddOneMsg( char *szMsg, int used_len, int tot_len, const char *szAddMsg, const char *szDelim )
2240
+ {
2241
+ const char ellip[] = "...";
2242
+ int len = strlen( szAddMsg );
2243
+ int len_delim = (used_len && szDelim)? strlen(szDelim) : 0;
2244
+ int len_to_copy;
2245
+ if ( len + len_delim + used_len < tot_len ) {
2246
+ if ( len_delim ) {
2247
+ strcpy( szMsg+used_len, szDelim );
2248
+ used_len += len_delim;
2249
+ }
2250
+ strcpy( szMsg+used_len, szAddMsg );
2251
+ used_len += len;
2252
+ } else
2253
+ if ( (len_to_copy = (tot_len - used_len - len_delim - (int)sizeof(ellip))) > 10 ) {
2254
+ if ( len_delim ) {
2255
+ strcpy( szMsg+used_len, szDelim );
2256
+ used_len += len_delim;
2257
+ }
2258
+ strncpy( szMsg+used_len, szAddMsg, len_to_copy );
2259
+ used_len += len_to_copy;
2260
+ strcpy( szMsg+used_len, ellip );
2261
+ used_len += sizeof( ellip ) - 1;
2262
+ }
2263
+ return used_len;
2264
+ }
2265
+ /*************************************************************************/
2266
+ int FillOutCompareMessage( char *szMsg, int nLenMsg, INCHI_MODE bits[] )
2267
+ {
2268
+ int bMobileH, k, n, len = strlen( szMsg );
2269
+ int iPrevGrpIdx, iCurGrpIdx, bFound;
2270
+ INCHI_MODE bit;
2271
+ static const char *hdr = " Problems/mismatches:";
2272
+ char szOneMsg[256];
2273
+ if ( bits[TAUT_YES] || bits[TAUT_NON] ) {
2274
+ if ( !strstr( szMsg, hdr ) ) {
2275
+ len = AddOneMsg( szMsg, len, nLenMsg, hdr, NULL );
2276
+ }
2277
+ for ( bMobileH = TAUT_YES; 0 <= bMobileH; bMobileH -- ) {
2278
+ if ( bits[bMobileH] ) {
2279
+ strcpy( szOneMsg, bMobileH==TAUT_YES? " Mobile-H(" : " Fixed-H(" );
2280
+ len = AddOneMsg( szMsg, len, nLenMsg, szOneMsg, NULL );
2281
+ }
2282
+ bit = 1;
2283
+ iPrevGrpIdx = -1;
2284
+ do {
2285
+ if ( bit & bits[bMobileH] ) {
2286
+ /* search for the message */
2287
+ bFound = 0;
2288
+ for ( k = 0; CompareInchiMsgs[k].nBit != INCHIDIFF_ZERO && !bFound; k ++ ) {
2289
+ if ( bit & (INCHI_MODE)CompareInchiMsgs[k].nBit ) {
2290
+ /* message found */
2291
+ for ( n = 0; CompareInchiMsgsGroup[n].nGroupID != IDGRP_ZERO; n ++ ) {
2292
+ if ( CompareInchiMsgsGroup[n].nGroupID == CompareInchiMsgs[k].nGroupID ) {
2293
+ iCurGrpIdx = n;
2294
+ if ( iCurGrpIdx != iPrevGrpIdx ) {
2295
+ if ( iPrevGrpIdx >= 0 ) {
2296
+ len = AddOneMsg( szMsg, len, nLenMsg, ";", NULL );
2297
+ }
2298
+ len = AddOneMsg( szMsg, len, nLenMsg, CompareInchiMsgsGroup[iCurGrpIdx].szGroupName, NULL );
2299
+ }
2300
+ len = AddOneMsg( szMsg, len, nLenMsg, CompareInchiMsgs[k].szMsg, iCurGrpIdx == iPrevGrpIdx? ",":NULL );
2301
+ iPrevGrpIdx = iCurGrpIdx;
2302
+ bFound = 1;
2303
+ break;
2304
+ }
2305
+ }
2306
+ }
2307
+ }
2308
+ }
2309
+ bit <<= 1;
2310
+ } while ( bit );
2311
+ if ( bits[bMobileH] ) {
2312
+ len = AddOneMsg( szMsg, len, nLenMsg, ")", NULL );
2313
+ }
2314
+ }
2315
+ }
2316
+ return len;
2317
+ }
2318
+
2319
+ #endif