rino 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +1 -1
- data/ext/extconf.rb +1 -24
- data/ext/libinchi.so +0 -0
- data/ext/src/aux2atom.h +120 -39
- data/ext/src/comdef.h +3 -3
- data/ext/src/dispstru.c +2547 -0
- data/ext/src/dispstru.h +73 -0
- data/ext/src/extr_ct.h +5 -2
- data/ext/src/ichi.h +27 -11
- data/ext/src/ichi_bns.c +1800 -254
- data/ext/src/ichi_bns.h +205 -4
- data/ext/src/ichican2.c +197 -86
- data/ext/src/ichicano.c +8 -13
- data/ext/src/ichicano.h +2 -2
- data/ext/src/ichicans.c +11 -6
- data/ext/src/ichicant.h +2 -2
- data/ext/src/ichicomn.h +2 -2
- data/ext/src/ichicomp.h +19 -4
- data/ext/src/ichidrp.h +9 -5
- data/ext/src/ichierr.h +5 -3
- data/ext/src/ichiisot.c +2 -2
- data/ext/src/ichimain.c +461 -0
- data/ext/src/ichimain.h +23 -15
- data/ext/src/ichimak2.c +6 -6
- data/ext/src/ichimake.c +843 -42
- data/ext/src/ichimake.h +4 -2
- data/ext/src/ichimap1.c +5 -5
- data/ext/src/ichimap2.c +2 -2
- data/ext/src/ichimap4.c +34 -21
- data/ext/src/ichinorm.c +11 -5
- data/ext/src/ichinorm.h +3 -2
- data/ext/src/ichiparm.c +2 -2
- data/ext/src/ichiparm.h +232 -30
- data/ext/src/ichiprt1.c +35 -11
- data/ext/src/ichiprt2.c +78 -7
- data/ext/src/ichiprt3.c +300 -120
- data/ext/src/ichiqueu.c +17 -2
- data/ext/src/ichiread.c +6932 -0
- data/ext/src/ichiring.c +3 -2
- data/ext/src/ichiring.h +2 -2
- data/ext/src/ichirvr1.c +4891 -0
- data/ext/src/ichirvr2.c +6344 -0
- data/ext/src/ichirvr3.c +5499 -0
- data/ext/src/ichirvr4.c +3177 -0
- data/ext/src/ichirvr5.c +1166 -0
- data/ext/src/ichirvr6.c +1287 -0
- data/ext/src/ichirvr7.c +2319 -0
- data/ext/src/ichirvrs.h +882 -0
- data/ext/src/ichisize.h +2 -2
- data/ext/src/ichisort.c +5 -5
- data/ext/src/ichister.c +281 -86
- data/ext/src/ichister.h +9 -3
- data/ext/src/ichitaut.c +208 -9
- data/ext/src/ichitaut.h +13 -11
- data/ext/src/ichitime.h +16 -2
- data/ext/src/inchicmp.h +107 -0
- data/ext/src/inpdef.h +6 -3
- data/ext/src/libinchi_wrap.c +912 -0
- data/ext/src/lreadmol.h +34 -31
- data/ext/src/mode.h +244 -7
- data/ext/src/mol2atom.c +1060 -0
- data/ext/src/mol2atom.h +31 -0
- data/ext/src/readinch.c +239 -0
- data/ext/src/readmol.c +28 -0
- data/ext/src/{e_readmol.h → readmol.h} +7 -9
- data/ext/src/runichi.c +251 -177
- data/ext/src/strutil.c +444 -238
- data/ext/src/strutil.h +150 -11
- data/ext/src/util.c +176 -118
- data/ext/src/util.h +15 -3
- data/lib/rino.rb +71 -3
- data/test/test.rb +33 -4
- metadata +22 -34
- data/ext/ruby_inchi_main.so +0 -0
- data/ext/src/e_0dstereo.c +0 -3014
- data/ext/src/e_0dstereo.h +0 -31
- data/ext/src/e_comdef.h +0 -57
- data/ext/src/e_ctl_data.h +0 -147
- data/ext/src/e_ichi_io.c +0 -498
- data/ext/src/e_ichi_io.h +0 -40
- data/ext/src/e_ichi_parms.c +0 -37
- data/ext/src/e_ichi_parms.h +0 -41
- data/ext/src/e_ichicomp.h +0 -50
- data/ext/src/e_ichierr.h +0 -40
- data/ext/src/e_ichimain.c +0 -593
- data/ext/src/e_ichisize.h +0 -43
- data/ext/src/e_inchi_atom.c +0 -75
- data/ext/src/e_inchi_atom.h +0 -33
- data/ext/src/e_inpdef.h +0 -41
- data/ext/src/e_mode.h +0 -706
- data/ext/src/e_mol2atom.c +0 -649
- data/ext/src/e_readinch.c +0 -58
- data/ext/src/e_readmol.c +0 -54
- data/ext/src/e_readstru.c +0 -251
- data/ext/src/e_readstru.h +0 -33
- data/ext/src/e_util.c +0 -284
- data/ext/src/e_util.h +0 -61
- data/ext/src/ichilnct.c +0 -286
- data/ext/src/inchi_api.h +0 -670
- data/ext/src/inchi_dll.c +0 -1480
- data/ext/src/inchi_dll.h +0 -34
- data/ext/src/inchi_dll_main.c +0 -23
- data/ext/src/inchi_dll_main.h +0 -31
- data/ext/src/ruby_inchi_main.c +0 -558
data/ext/src/ichirvr7.c
ADDED
@@ -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
|