rino 0.1.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/README +44 -0
- data/Rakefile +123 -0
- data/ext/extconf.rb +26 -0
- data/ext/ruby_inchi_main.so +0 -0
- data/ext/src/aux2atom.h +2786 -0
- data/ext/src/comdef.h +148 -0
- data/ext/src/e_0dstereo.c +3014 -0
- data/ext/src/e_0dstereo.h +31 -0
- data/ext/src/e_comdef.h +57 -0
- data/ext/src/e_ctl_data.h +147 -0
- data/ext/src/e_ichi_io.c +498 -0
- data/ext/src/e_ichi_io.h +40 -0
- data/ext/src/e_ichi_parms.c +37 -0
- data/ext/src/e_ichi_parms.h +41 -0
- data/ext/src/e_ichicomp.h +50 -0
- data/ext/src/e_ichierr.h +40 -0
- data/ext/src/e_ichimain.c +593 -0
- data/ext/src/e_ichisize.h +43 -0
- data/ext/src/e_inchi_atom.c +75 -0
- data/ext/src/e_inchi_atom.h +33 -0
- data/ext/src/e_inpdef.h +41 -0
- data/ext/src/e_mode.h +706 -0
- data/ext/src/e_mol2atom.c +649 -0
- data/ext/src/e_readinch.c +58 -0
- data/ext/src/e_readmol.c +54 -0
- data/ext/src/e_readmol.h +180 -0
- data/ext/src/e_readstru.c +251 -0
- data/ext/src/e_readstru.h +33 -0
- data/ext/src/e_util.c +284 -0
- data/ext/src/e_util.h +61 -0
- data/ext/src/extr_ct.h +251 -0
- data/ext/src/ichi.h +206 -0
- data/ext/src/ichi_bns.c +7999 -0
- data/ext/src/ichi_bns.h +231 -0
- data/ext/src/ichican2.c +5000 -0
- data/ext/src/ichicano.c +2195 -0
- data/ext/src/ichicano.h +49 -0
- data/ext/src/ichicans.c +1625 -0
- data/ext/src/ichicant.h +379 -0
- data/ext/src/ichicomn.h +260 -0
- data/ext/src/ichicomp.h +50 -0
- data/ext/src/ichidrp.h +119 -0
- data/ext/src/ichierr.h +124 -0
- data/ext/src/ichiisot.c +101 -0
- data/ext/src/ichilnct.c +286 -0
- data/ext/src/ichimain.h +132 -0
- data/ext/src/ichimak2.c +1189 -0
- data/ext/src/ichimake.c +3812 -0
- data/ext/src/ichimake.h +205 -0
- data/ext/src/ichimap1.c +851 -0
- data/ext/src/ichimap2.c +2856 -0
- data/ext/src/ichimap4.c +1609 -0
- data/ext/src/ichinorm.c +741 -0
- data/ext/src/ichinorm.h +67 -0
- data/ext/src/ichiparm.c +45 -0
- data/ext/src/ichiparm.h +1441 -0
- data/ext/src/ichiprt1.c +3612 -0
- data/ext/src/ichiprt2.c +1511 -0
- data/ext/src/ichiprt3.c +3011 -0
- data/ext/src/ichiqueu.c +1003 -0
- data/ext/src/ichiring.c +326 -0
- data/ext/src/ichiring.h +49 -0
- data/ext/src/ichisize.h +35 -0
- data/ext/src/ichisort.c +539 -0
- data/ext/src/ichister.c +3538 -0
- data/ext/src/ichister.h +35 -0
- data/ext/src/ichitaut.c +3843 -0
- data/ext/src/ichitaut.h +387 -0
- data/ext/src/ichitime.h +74 -0
- data/ext/src/inchi_api.h +670 -0
- data/ext/src/inchi_dll.c +1480 -0
- data/ext/src/inchi_dll.h +34 -0
- data/ext/src/inchi_dll_main.c +23 -0
- data/ext/src/inchi_dll_main.h +31 -0
- data/ext/src/inpdef.h +328 -0
- data/ext/src/lreadmol.h +1246 -0
- data/ext/src/mode.h +706 -0
- data/ext/src/ruby_inchi_main.c +558 -0
- data/ext/src/runichi.c +4179 -0
- data/ext/src/strutil.c +3861 -0
- data/ext/src/strutil.h +182 -0
- data/ext/src/util.c +1130 -0
- data/ext/src/util.h +85 -0
- data/lib/clean_tempfile.rb +220 -0
- data/lib/rino.rb +111 -0
- data/test/test.rb +386 -0
- metadata +130 -0
data/ext/src/ichiprt2.c
ADDED
@@ -0,0 +1,1511 @@
|
|
1
|
+
/*
|
2
|
+
* International Union of Pure and Applied Chemistry (IUPAC)
|
3
|
+
* International Chemical Identifier (InChI)
|
4
|
+
* Version 1
|
5
|
+
* Software version 1.00
|
6
|
+
* April 13, 2005
|
7
|
+
* Developed at NIST
|
8
|
+
*/
|
9
|
+
|
10
|
+
#include <stdio.h>
|
11
|
+
#include <stdlib.h>
|
12
|
+
#include <string.h>
|
13
|
+
#include <ctype.h>
|
14
|
+
|
15
|
+
#include "mode.h"
|
16
|
+
|
17
|
+
#include "inpdef.h"
|
18
|
+
#include "ichi.h"
|
19
|
+
#include "strutil.h"
|
20
|
+
#include "util.h"
|
21
|
+
#include "extr_ct.h"
|
22
|
+
#include "ichitaut.h"
|
23
|
+
#include "ichinorm.h"
|
24
|
+
#include "ichicant.h"
|
25
|
+
#include "ichicano.h"
|
26
|
+
#include "ichicomn.h"
|
27
|
+
|
28
|
+
#include "ichicomp.h"
|
29
|
+
#include "ichimain.h"
|
30
|
+
#include "ichimake.h"
|
31
|
+
|
32
|
+
/*****************************************************************************************/
|
33
|
+
int Eql_INChI_Stereo( INChI_Stereo *s1, int eql1, INChI_Stereo *s2, int eql2, int bRelRac )
|
34
|
+
{
|
35
|
+
int inv1=0, inv2=0, len;
|
36
|
+
|
37
|
+
if ( !s1 ) {
|
38
|
+
return 0;
|
39
|
+
}
|
40
|
+
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
|
41
|
+
#else
|
42
|
+
bRelRac = 0;
|
43
|
+
#endif
|
44
|
+
|
45
|
+
if( EQL_SP2 == eql1 ) {
|
46
|
+
if ( (len=s1->nNumberOfStereoBonds) > 0 && s1->b_parity && s1->nBondAtom1 && s1->nBondAtom2 ) {
|
47
|
+
if ( !s2 ) {
|
48
|
+
if ( EQL_EXISTS == eql2 ) {
|
49
|
+
/* find whether double bond stereo exists*/
|
50
|
+
return 1;
|
51
|
+
}
|
52
|
+
return 0;
|
53
|
+
}
|
54
|
+
if ( EQL_SP2 == eql2 &&
|
55
|
+
len == s2->nNumberOfStereoBonds && s2->b_parity && s2->nBondAtom1 && s2->nBondAtom2 &&
|
56
|
+
!memcmp( s1->nBondAtom1, s2->nBondAtom1, len * sizeof(s1->nBondAtom1[0])) &&
|
57
|
+
!memcmp( s1->nBondAtom2, s2->nBondAtom2, len * sizeof(s1->nBondAtom2[0])) &&
|
58
|
+
!memcmp( s1->b_parity, s2->b_parity, len * sizeof(s1->b_parity[0])) ) {
|
59
|
+
return 1;
|
60
|
+
}
|
61
|
+
}
|
62
|
+
return 0;
|
63
|
+
} else
|
64
|
+
if ( (eql1 == EQL_SP3 || (inv1 = (eql1 == EQL_SP3_INV))) &&
|
65
|
+
(len=s1->nNumberOfStereoCenters) > (bRelRac? 1 : 0) ) {
|
66
|
+
|
67
|
+
S_CHAR *t_parity1, *t_parity2;
|
68
|
+
AT_NUMB *nNumber1, *nNumber2;
|
69
|
+
if ( inv1 ) {
|
70
|
+
if ( s1->nCompInv2Abs ) {
|
71
|
+
t_parity1 = s1->t_parityInv;
|
72
|
+
nNumber1 = s1->nNumberInv;
|
73
|
+
} else {
|
74
|
+
return 0;
|
75
|
+
}
|
76
|
+
} else {
|
77
|
+
t_parity1 = s1->t_parity;
|
78
|
+
nNumber1 = s1->nNumber;
|
79
|
+
}
|
80
|
+
|
81
|
+
if ( t_parity1 && nNumber1 ) {
|
82
|
+
if ( !s2 ) {
|
83
|
+
if ( EQL_EXISTS == eql2 && (!inv1 || s1->nCompInv2Abs) ) {
|
84
|
+
/* the 1st sp3 (inverted if requested) stereo exists*/
|
85
|
+
return 1;
|
86
|
+
}
|
87
|
+
return 0; /* both sp3 do not exist */
|
88
|
+
}
|
89
|
+
if( (eql2 == EQL_SP3 || (inv2 = (eql2 == EQL_SP3_INV))) &&
|
90
|
+
len == s2->nNumberOfStereoCenters ) {
|
91
|
+
if ( inv2 ) {
|
92
|
+
if ( s2->nCompInv2Abs && s1->nCompInv2Abs ) {
|
93
|
+
t_parity2 = s2->t_parityInv;
|
94
|
+
nNumber2 = s2->nNumberInv;
|
95
|
+
} else {
|
96
|
+
/* if one sp3 is inverted then another should have non-trivial inverted stereo */
|
97
|
+
return 0;
|
98
|
+
}
|
99
|
+
} else {
|
100
|
+
if ( inv1 && !s2->nCompInv2Abs ) {
|
101
|
+
/* if one sp3 is inverted then another should have non-trivial inverted stereo */
|
102
|
+
return 0;
|
103
|
+
}
|
104
|
+
t_parity2 = s2->t_parity;
|
105
|
+
nNumber2 = s2->nNumber;
|
106
|
+
}
|
107
|
+
if ( t_parity2 && nNumber2 ) {
|
108
|
+
if ( inv1 ^ inv2 ) {
|
109
|
+
int i, num_inv;
|
110
|
+
for ( i = 0, num_inv = 0; i < len; i ++ ) {
|
111
|
+
if ( nNumber1[i] != nNumber2[i] )
|
112
|
+
break;
|
113
|
+
if ( ATOM_PARITY_WELL_DEF(t_parity1[i]) &&
|
114
|
+
ATOM_PARITY_WELL_DEF(t_parity2[i]) ) {
|
115
|
+
if ( 3 == t_parity1[i] + t_parity2[i] ) {
|
116
|
+
num_inv ++;
|
117
|
+
} else {
|
118
|
+
break;
|
119
|
+
}
|
120
|
+
} else
|
121
|
+
if ( t_parity1[i] != t_parity2[i] ) {
|
122
|
+
break;
|
123
|
+
}
|
124
|
+
}
|
125
|
+
return (len == i && num_inv > 0);
|
126
|
+
} else {
|
127
|
+
return !memcmp( t_parity1, t_parity2, len*sizeof(t_parity1[0])) &&
|
128
|
+
!memcmp( nNumber1, nNumber2, len*sizeof(nNumber1[0]));
|
129
|
+
}
|
130
|
+
}
|
131
|
+
}
|
132
|
+
}
|
133
|
+
}
|
134
|
+
return 0;
|
135
|
+
}
|
136
|
+
/**********************************************************************************************/
|
137
|
+
int Eql_INChI_Isotopic( INChI *i1, INChI *i2 )
|
138
|
+
{
|
139
|
+
int eq = i1 && i2 && !i1->bDeleted && !i2->bDeleted &&
|
140
|
+
( i1->nNumberOfIsotopicAtoms > 0 || i1->nNumberOfIsotopicTGroups > 0 ) &&
|
141
|
+
i1->nNumberOfIsotopicAtoms == i2->nNumberOfIsotopicAtoms &&
|
142
|
+
i1->nNumberOfIsotopicTGroups == i2->nNumberOfIsotopicTGroups &&
|
143
|
+
( !i1->nNumberOfIsotopicAtoms ||
|
144
|
+
i1->IsotopicAtom && i2->IsotopicAtom &&
|
145
|
+
!memcmp( i1->IsotopicAtom, i2->IsotopicAtom,
|
146
|
+
i1->nNumberOfIsotopicAtoms * sizeof(i1->IsotopicAtom[0]) ) ) &&
|
147
|
+
( !i1->nNumberOfIsotopicTGroups ||
|
148
|
+
i1->IsotopicTGroup && i2->IsotopicTGroup &&
|
149
|
+
!memcmp( i1->IsotopicTGroup, i2->IsotopicTGroup,
|
150
|
+
i1->nNumberOfIsotopicTGroups * sizeof(i1->IsotopicAtom[0]) ) );
|
151
|
+
return eq;
|
152
|
+
|
153
|
+
}
|
154
|
+
/**********************************************************************************************/
|
155
|
+
int Eql_INChI_Aux_Equ( INChI_Aux *a1, int eql1, INChI_Aux *a2, int eql2 )
|
156
|
+
{
|
157
|
+
int t1=0, t2=0, len;
|
158
|
+
AT_NUMB *n1=NULL, *n2=NULL;
|
159
|
+
if ( !a1 || !a2 ) {
|
160
|
+
return 0;
|
161
|
+
}
|
162
|
+
t1 = (eql1 & EQL_EQU_TG);
|
163
|
+
t2 = (eql2 & EQL_EQU_TG);
|
164
|
+
if ( t1 && t2 ) {
|
165
|
+
if ( (len = a1->nNumberOfTGroups) > 0 && len == a2->nNumberOfTGroups && !a1->bDeleted && !a2->bDeleted ) {
|
166
|
+
if (eql1 & EQL_EQU_ISO) {
|
167
|
+
if ( a1->bIsIsotopic ) {
|
168
|
+
n1 = a1->nConstitEquIsotopicTGroupNumbers;
|
169
|
+
}
|
170
|
+
} else {
|
171
|
+
n1 = a1->nConstitEquTGroupNumbers;
|
172
|
+
}
|
173
|
+
if (eql2 & EQL_EQU_ISO) {
|
174
|
+
if ( a2->bIsIsotopic ) {
|
175
|
+
n2 = a2->nConstitEquIsotopicTGroupNumbers;
|
176
|
+
}
|
177
|
+
} else {
|
178
|
+
n2 = a2->nConstitEquTGroupNumbers;
|
179
|
+
}
|
180
|
+
}
|
181
|
+
} else
|
182
|
+
if ( !t1 && !t2 ) {
|
183
|
+
if ( (len = a1->nNumberOfAtoms) > 0 && len == a2->nNumberOfAtoms && !a1->bDeleted && !a2->bDeleted ) {
|
184
|
+
if (eql1 & EQL_EQU_ISO) {
|
185
|
+
if ( a1->bIsIsotopic ) {
|
186
|
+
n1 = a1->nConstitEquIsotopicNumbers;
|
187
|
+
}
|
188
|
+
} else {
|
189
|
+
n1 = a1->nConstitEquNumbers;
|
190
|
+
}
|
191
|
+
if (eql2 & EQL_EQU_ISO) {
|
192
|
+
if ( a2->bIsIsotopic ) {
|
193
|
+
n2 = a2->nConstitEquIsotopicNumbers;
|
194
|
+
}
|
195
|
+
} else {
|
196
|
+
n2 = a2->nConstitEquNumbers;
|
197
|
+
}
|
198
|
+
}
|
199
|
+
}
|
200
|
+
if ( n1 && n2 && !memcmp(n1, n2, len*sizeof(n1[0])) && bHasEquString( n1, len) ) {
|
201
|
+
return 1;
|
202
|
+
}
|
203
|
+
return 0;
|
204
|
+
}
|
205
|
+
/**********************************************************************************************/
|
206
|
+
int Eql_INChI_Aux_Num( INChI_Aux *a1, int eql1, INChI_Aux *a2, int eql2 )
|
207
|
+
{
|
208
|
+
int len;
|
209
|
+
AT_NUMB *n1=NULL, *n2=NULL;
|
210
|
+
if ( !a1 || !a2 ) {
|
211
|
+
return 0;
|
212
|
+
}
|
213
|
+
if ( (len = a1->nNumberOfAtoms) <= 0 || len != a2->nNumberOfAtoms || a1->bDeleted || a2->bDeleted ) {
|
214
|
+
return 0;
|
215
|
+
}
|
216
|
+
if ( (eql1 & EQL_NUM_ISO) && !a1->bIsIsotopic ||
|
217
|
+
(eql2 & EQL_NUM_ISO) && !a2->bIsIsotopic ) {
|
218
|
+
return 0;
|
219
|
+
}
|
220
|
+
|
221
|
+
switch ( eql1 ) {
|
222
|
+
case EQL_NUM:
|
223
|
+
n1 = a1->nOrigAtNosInCanonOrd;
|
224
|
+
break;
|
225
|
+
case EQL_NUM_ISO:
|
226
|
+
n1 = a1->nIsotopicOrigAtNosInCanonOrd;
|
227
|
+
break;
|
228
|
+
case EQL_NUM_INV:
|
229
|
+
n1 = a1->nOrigAtNosInCanonOrdInv;
|
230
|
+
break;
|
231
|
+
case ( EQL_NUM_INV | EQL_NUM_ISO ):
|
232
|
+
n1 = a1->nIsotopicOrigAtNosInCanonOrdInv;
|
233
|
+
break;
|
234
|
+
default:
|
235
|
+
return 0;
|
236
|
+
}
|
237
|
+
|
238
|
+
switch ( eql2 ) {
|
239
|
+
case EQL_NUM:
|
240
|
+
n2 = a2->nOrigAtNosInCanonOrd;
|
241
|
+
break;
|
242
|
+
case EQL_NUM_ISO:
|
243
|
+
n2 = a2->nIsotopicOrigAtNosInCanonOrd;
|
244
|
+
break;
|
245
|
+
case EQL_NUM_INV:
|
246
|
+
n2 = a2->nOrigAtNosInCanonOrdInv;
|
247
|
+
break;
|
248
|
+
case ( EQL_NUM_INV | EQL_NUM_ISO ):
|
249
|
+
n2 = a2->nIsotopicOrigAtNosInCanonOrdInv;
|
250
|
+
break;
|
251
|
+
default:
|
252
|
+
return 0;
|
253
|
+
}
|
254
|
+
|
255
|
+
if ( n1 && n2 && !memcmp( n1, n2, len*sizeof(n1[0])) ) {
|
256
|
+
return 1;
|
257
|
+
}
|
258
|
+
return 0;
|
259
|
+
}
|
260
|
+
/**********************************************************************************************/
|
261
|
+
int bHasOrigInfo( ORIG_INFO *OrigInfo, int num_atoms )
|
262
|
+
{
|
263
|
+
int i, bFound = 0;
|
264
|
+
if ( OrigInfo && num_atoms > 0 ) {
|
265
|
+
for ( i = 0; !bFound && i < num_atoms; i ++ ) {
|
266
|
+
bFound |= (0 != OrigInfo[i].cCharge) ||
|
267
|
+
(0 != OrigInfo[i].cRadical) ||
|
268
|
+
(0 != OrigInfo[i].cUnusualValence);
|
269
|
+
|
270
|
+
}
|
271
|
+
}
|
272
|
+
return bFound;
|
273
|
+
}
|
274
|
+
/**********************************************************************************************/
|
275
|
+
int EqlOrigInfo( INChI_Aux *a1, INChI_Aux *a2 )
|
276
|
+
{
|
277
|
+
int ret = a1 && a2 && a1->nNumberOfAtoms == a2->nNumberOfAtoms &&
|
278
|
+
bHasOrigInfo( a1->OrigInfo, a1->nNumberOfAtoms ) && a2->OrigInfo &&
|
279
|
+
!memcmp( a1->OrigInfo, a2->OrigInfo, a1->nNumberOfAtoms * sizeof(a1->OrigInfo[0]) );
|
280
|
+
return ret;
|
281
|
+
|
282
|
+
}
|
283
|
+
|
284
|
+
/**********************************************************************************************/
|
285
|
+
int bHasEquString( AT_NUMB *LinearCT, int nLenCT )
|
286
|
+
{
|
287
|
+
/* produce output string; */
|
288
|
+
int i, k;
|
289
|
+
if ( !LinearCT )
|
290
|
+
return 0;
|
291
|
+
for ( k = 0; k < nLenCT; k ++ ) {
|
292
|
+
/* find the first equivalence number */
|
293
|
+
if ( k != (int)LinearCT[k] - 1 )
|
294
|
+
continue;
|
295
|
+
for ( i = k; i < nLenCT; i ++ ) {
|
296
|
+
if ( k != (int)LinearCT[i]-1 )
|
297
|
+
continue;
|
298
|
+
if ( k < i ) {
|
299
|
+
return 1;
|
300
|
+
}
|
301
|
+
}
|
302
|
+
}
|
303
|
+
return 0;
|
304
|
+
}
|
305
|
+
/********************************************************************************************/
|
306
|
+
int MakeMult( int mult, const char *szTailingDelim, char *szLinearCT, int nLen_szLinearCT, int nCtMode, int *bOverflow)
|
307
|
+
{
|
308
|
+
char szValue[16];
|
309
|
+
int len = 0, len_delim;
|
310
|
+
if ( mult == 1 || *bOverflow )
|
311
|
+
return 0;
|
312
|
+
if ( nCtMode & CT_MODE_ABC_NUMBERS ) {
|
313
|
+
len += MakeAbcNumber( szValue, (int)sizeof(szValue), NULL, mult );
|
314
|
+
} else {
|
315
|
+
len += MakeDecNumber( szValue, (int)sizeof(szValue), NULL, mult );
|
316
|
+
}
|
317
|
+
len_delim = strlen(szTailingDelim);
|
318
|
+
if ( len + len_delim < (int)sizeof(szValue) ) {
|
319
|
+
strcpy( szValue+len, szTailingDelim );
|
320
|
+
len += len_delim;
|
321
|
+
if ( len < nLen_szLinearCT ) {
|
322
|
+
strcpy( szLinearCT, szValue );
|
323
|
+
return len;
|
324
|
+
}
|
325
|
+
}
|
326
|
+
*bOverflow |= 1;
|
327
|
+
return 0;
|
328
|
+
}
|
329
|
+
/********************************************************************************************/
|
330
|
+
int MakeDelim( const char *szTailingDelim, char *szLinearCT, int nLen_szLinearCT, int *bOverflow)
|
331
|
+
{
|
332
|
+
int len_delim;
|
333
|
+
if ( !szTailingDelim || !*szTailingDelim || *bOverflow )
|
334
|
+
return 0;
|
335
|
+
len_delim = strlen(szTailingDelim);
|
336
|
+
if ( len_delim < nLen_szLinearCT ) {
|
337
|
+
strcpy( szLinearCT, szTailingDelim );
|
338
|
+
return len_delim;
|
339
|
+
}
|
340
|
+
*bOverflow |= 1;
|
341
|
+
return 0;
|
342
|
+
}
|
343
|
+
/********************************************************************************************/
|
344
|
+
int MakeEqStr( const char *szTailingDelim, int mult, char *szLinearCT, int nLen_szLinearCT, int *bOverflow)
|
345
|
+
{
|
346
|
+
int len = 0, len_delim;
|
347
|
+
char szValue[16];
|
348
|
+
if ( !szTailingDelim || !*szTailingDelim || *bOverflow )
|
349
|
+
return 0;
|
350
|
+
if ( mult != 1 ) {
|
351
|
+
len = MakeDecNumber( szValue, (int)sizeof(szValue), NULL, mult );
|
352
|
+
}
|
353
|
+
len_delim = strlen(szTailingDelim);
|
354
|
+
if ( len_delim + len < nLen_szLinearCT ) {
|
355
|
+
if ( len > 0 ) {
|
356
|
+
memcpy( szLinearCT, szValue, len );
|
357
|
+
}
|
358
|
+
strcpy( szLinearCT+len, szTailingDelim );
|
359
|
+
return len + len_delim;
|
360
|
+
}
|
361
|
+
*bOverflow |= 1;
|
362
|
+
return 0;
|
363
|
+
}
|
364
|
+
/**********************************************************************************************
|
365
|
+
* nCtMode = 0: full
|
366
|
+
* 1: censored CT (no orphans)
|
367
|
+
* 2: compressed CT (Abs numbers)
|
368
|
+
**********************************************************************************************/
|
369
|
+
int MakeCtStringNew( AT_NUMB *LinearCT, int nLenCT, int bAddDelim,
|
370
|
+
S_CHAR *nNum_H, int num_atoms,
|
371
|
+
char *szLinearCT, int nLen_szLinearCT, int nCtMode, int *bOverflow)
|
372
|
+
{
|
373
|
+
/* produce output string; */
|
374
|
+
int nLen = 0, len, i, bOvfl = *bOverflow;
|
375
|
+
char szValue[16];
|
376
|
+
int nValue, nDelim, num_H;
|
377
|
+
AT_NUMB *nDfsOrderCT = NULL;
|
378
|
+
int bNoNum_H = (NULL == nNum_H);
|
379
|
+
int nNumRingClosures;
|
380
|
+
int bAbcNumbers = (0 != ( nCtMode & CT_MODE_ABC_NUMBERS ));
|
381
|
+
int bPredecessors = (0 != ( nCtMode & CT_MODE_PREDECESSORS ));
|
382
|
+
int bCountRingClosures = bAbcNumbers && bPredecessors && (nCtMode & CT_MODE_ABC_NUM_CLOSURES);
|
383
|
+
if ( nLenCT <= 1 ) {
|
384
|
+
return 0; /* no atoms or a single atom: no connection table */
|
385
|
+
}
|
386
|
+
/* make array containing connection string data */
|
387
|
+
if ( !(nDfsOrderCT = GetDfsOrder4CT( LinearCT, nLenCT, nNum_H, num_atoms, nCtMode ) ) ) {
|
388
|
+
(*bOverflow) ++;
|
389
|
+
return 0;
|
390
|
+
}
|
391
|
+
|
392
|
+
/* add connection table string */
|
393
|
+
if ( !bOvfl && bAddDelim ) {
|
394
|
+
if ( nLen_szLinearCT > 1 ) {
|
395
|
+
strcpy( szLinearCT, "," );
|
396
|
+
nLen ++;
|
397
|
+
} else {
|
398
|
+
bOvfl = 1;
|
399
|
+
}
|
400
|
+
}
|
401
|
+
|
402
|
+
if ( !bOvfl ) {
|
403
|
+
nNumRingClosures = 0;
|
404
|
+
for ( i = 0; nDfsOrderCT[i] && nLen < nLen_szLinearCT; i += 3 ) {
|
405
|
+
nValue = (nDfsOrderCT[i] > MAX_ATOMS)? 0 : nDfsOrderCT[i];
|
406
|
+
num_H = nDfsOrderCT[i+1]? nDfsOrderCT[i+1]-16:0;
|
407
|
+
nDelim = nDfsOrderCT[i+2];
|
408
|
+
len = 0;
|
409
|
+
/* delimiter */
|
410
|
+
if ( bPredecessors ) {
|
411
|
+
if ( bCountRingClosures ) {
|
412
|
+
if ( nDelim == '-' && i > 3 && bNoNum_H ) {
|
413
|
+
if ( !nNumRingClosures ) {
|
414
|
+
int j;
|
415
|
+
for ( j = i; nDfsOrderCT[j] && '-' == nDfsOrderCT[j+2]; j += 3 ) {
|
416
|
+
nNumRingClosures ++;
|
417
|
+
}
|
418
|
+
if ( nNumRingClosures ) {
|
419
|
+
len += MakeDecNumber( szValue+len, (int)sizeof(szValue)-len, NULL, nNumRingClosures );
|
420
|
+
}
|
421
|
+
nNumRingClosures --;
|
422
|
+
} else {
|
423
|
+
nNumRingClosures --;
|
424
|
+
}
|
425
|
+
} else {
|
426
|
+
nNumRingClosures = 0;
|
427
|
+
}
|
428
|
+
} else
|
429
|
+
if ( nDelim && !( bAbcNumbers && nDelim == ',' ) ) {
|
430
|
+
if ( nNum_H || i > 3 ) {
|
431
|
+
szValue[len ++] = nDelim;
|
432
|
+
}
|
433
|
+
}
|
434
|
+
} else {
|
435
|
+
if ( nDelim && !( bAbcNumbers && nDelim == '-' ) ) {
|
436
|
+
szValue[len ++] = nDelim;
|
437
|
+
}
|
438
|
+
}
|
439
|
+
if ( bAbcNumbers ) {
|
440
|
+
if ( nValue || i ) { /* the 1st value may be zero in case of presdecessor list */
|
441
|
+
len += MakeAbcNumber( szValue+len, (int)sizeof(szValue)-len, NULL, nValue );
|
442
|
+
}
|
443
|
+
if ( num_H ) {
|
444
|
+
len += MakeDecNumber( szValue+len, (int)sizeof(szValue)-len, NULL, num_H );
|
445
|
+
}
|
446
|
+
} else {
|
447
|
+
if ( nValue || i ) { /* the 1st value may be zero in case of presdecessor list */
|
448
|
+
len += MakeDecNumber( szValue+len, (int)sizeof(szValue)-len, NULL, nValue );
|
449
|
+
}
|
450
|
+
if ( num_H ) {
|
451
|
+
szValue[len] = 'H';
|
452
|
+
len ++;
|
453
|
+
if ( num_H > 1 ) {
|
454
|
+
len += MakeDecNumber( szValue+len, (int)sizeof(szValue)-len, NULL, num_H );
|
455
|
+
}
|
456
|
+
}
|
457
|
+
}
|
458
|
+
if ( 0 <= len && nLen+len < nLen_szLinearCT ) {
|
459
|
+
if ( len ) {
|
460
|
+
strcpy( szLinearCT+nLen, szValue );
|
461
|
+
nLen += len;
|
462
|
+
}
|
463
|
+
} else {
|
464
|
+
bOvfl = 1;
|
465
|
+
break;
|
466
|
+
}
|
467
|
+
}
|
468
|
+
}
|
469
|
+
*bOverflow |= bOvfl;
|
470
|
+
if ( nDfsOrderCT )
|
471
|
+
inchi_free( nDfsOrderCT );
|
472
|
+
return nLen;
|
473
|
+
}
|
474
|
+
/**********************************************************************************************
|
475
|
+
* nCtMode = 0: full
|
476
|
+
* 1: censored CT (no orphans)
|
477
|
+
* 2: compressed CT (Abs numbers)
|
478
|
+
**********************************************************************************************/
|
479
|
+
int MakeCtStringOld( AT_NUMB *LinearCT, int nLenCT, int bAddDelim,
|
480
|
+
char *szLinearCT, int nLen_szLinearCT, int nCtMode, int *bOverflow)
|
481
|
+
{
|
482
|
+
/* produce output string; */
|
483
|
+
int nLen = 0, len, i, bLessThanPrev, bOvfl = *bOverflow;
|
484
|
+
AT_NUMB nMax = 0;
|
485
|
+
char szValue[16];
|
486
|
+
int nValue, bNext = 0;
|
487
|
+
/* add connection table string */
|
488
|
+
if ( !( nCtMode & CT_MODE_ABC_NUMBERS ) && !bOvfl && bAddDelim ) {
|
489
|
+
if ( nLen_szLinearCT > 1 ) {
|
490
|
+
strcpy( szLinearCT, "," );
|
491
|
+
nLen ++;
|
492
|
+
} else {
|
493
|
+
bOvfl = 1;
|
494
|
+
}
|
495
|
+
}
|
496
|
+
if ( !bOvfl ) {
|
497
|
+
for ( i = 0; i < nLenCT && nLen < nLen_szLinearCT; i ++ ) {
|
498
|
+
bLessThanPrev = 0;
|
499
|
+
if ( !(nCtMode & CT_MODE_NO_ORPHANS) || ((bLessThanPrev=LinearCT[i] < nMax) ||
|
500
|
+
i+1 < nLenCT && LinearCT[i+1] < (nMax=LinearCT[i])) ) {
|
501
|
+
nValue = LinearCT[i];
|
502
|
+
if ( nCtMode & CT_MODE_ABC_NUMBERS ) {
|
503
|
+
len = MakeAbcNumber( szValue, (int)sizeof(szValue), (!bNext && bAddDelim)? ITEM_DELIMETER : NULL, nValue );
|
504
|
+
} else
|
505
|
+
if ( nCtMode & CT_MODE_NO_ORPHANS ) { /* censored CT */
|
506
|
+
/* output '-' as a delimiter to show a bonding for decimal output of the connection table */
|
507
|
+
len = MakeDecNumber( szValue, (int)sizeof(szValue), bLessThanPrev? "-":ITEM_DELIMETER, nValue );
|
508
|
+
} else {
|
509
|
+
len = MakeDecNumber( szValue, (int)sizeof(szValue), i? ITEM_DELIMETER:NULL, nValue );
|
510
|
+
}
|
511
|
+
if ( 0 <= len && nLen+len < nLen_szLinearCT ) {
|
512
|
+
if ( len ) {
|
513
|
+
strcpy( szLinearCT+nLen, szValue );
|
514
|
+
nLen += len;
|
515
|
+
bNext ++;
|
516
|
+
}
|
517
|
+
} else {
|
518
|
+
bOvfl = 1;
|
519
|
+
break;
|
520
|
+
}
|
521
|
+
}
|
522
|
+
}
|
523
|
+
}
|
524
|
+
*bOverflow |= bOvfl;
|
525
|
+
return nLen;
|
526
|
+
}
|
527
|
+
/**********************************************************************************************
|
528
|
+
* nCtMode = 0: decimal
|
529
|
+
* 2: compressed CT (Abs numbers)
|
530
|
+
**********************************************************************************************/
|
531
|
+
int MakeHString( int bAddDelim, S_CHAR *LinearCT, int nLenCT,
|
532
|
+
char *szLinearCT, int nLen_szLinearCT, int nCtMode, int *bOverflow )
|
533
|
+
{
|
534
|
+
#define INIT_MIN_NUM_H (-4)
|
535
|
+
#define INIT_MAX_NUM_H 16
|
536
|
+
#define INIT_LEN_NUM_H (INIT_MAX_NUM_H - INIT_MIN_NUM_H + 1)
|
537
|
+
|
538
|
+
/* produce output string; */
|
539
|
+
int nLen = 0, len, i, iFirst, nVal, bOvfl = *bOverflow;
|
540
|
+
char szValue[32];
|
541
|
+
const char *pH;
|
542
|
+
int bNext = 0;
|
543
|
+
/* add connection table string */
|
544
|
+
if ( !( nCtMode & CT_MODE_ABC_NUMBERS ) && !bOvfl && bAddDelim ) {
|
545
|
+
if ( nLen_szLinearCT > 1 ) {
|
546
|
+
strcpy( szLinearCT, "," );
|
547
|
+
nLen ++;
|
548
|
+
} else {
|
549
|
+
bOvfl = 1;
|
550
|
+
}
|
551
|
+
}
|
552
|
+
if ( !bOvfl && 0 < nLenCT && LinearCT ) {
|
553
|
+
if ( nCtMode & CT_MODE_EQL_H_TOGETHER ) {
|
554
|
+
int curMinH = INIT_MIN_NUM_H;
|
555
|
+
int curMaxH = INIT_MAX_NUM_H;
|
556
|
+
int curLenH = INIT_LEN_NUM_H;
|
557
|
+
int nInitNumH[INIT_LEN_NUM_H];
|
558
|
+
int *nNumH = nInitNumH;
|
559
|
+
int numAt, curNumH;
|
560
|
+
int j, bOutOfRange, tot_num_no_H;
|
561
|
+
/* count atoms H */
|
562
|
+
do {
|
563
|
+
bOutOfRange = 0;
|
564
|
+
tot_num_no_H = 0; /* number of atoms that have no H */
|
565
|
+
memset( nNumH, 0, curLenH*sizeof(nNumH[0]) );
|
566
|
+
for ( i = 0; i < nLenCT; i ++ ) {
|
567
|
+
curNumH = LinearCT[i];
|
568
|
+
if ( curNumH < curMinH ) {
|
569
|
+
curMinH = curNumH;
|
570
|
+
bOutOfRange ++;
|
571
|
+
} else
|
572
|
+
if ( curNumH > curMaxH ) {
|
573
|
+
curMaxH = curNumH;
|
574
|
+
bOutOfRange ++;
|
575
|
+
} else
|
576
|
+
if ( !bOutOfRange ) {
|
577
|
+
nNumH[curNumH-curMinH] ++;
|
578
|
+
}
|
579
|
+
tot_num_no_H += !curNumH;
|
580
|
+
}
|
581
|
+
if ( tot_num_no_H == nLenCT ) {
|
582
|
+
return nLen; /* empty string */
|
583
|
+
}
|
584
|
+
if ( bOutOfRange ) {
|
585
|
+
/* for debug only */
|
586
|
+
if ( nNumH != nInitNumH ) {
|
587
|
+
*bOverflow |= 1;
|
588
|
+
inchi_free( nNumH );
|
589
|
+
return nLen;
|
590
|
+
}
|
591
|
+
/* end debug */
|
592
|
+
curLenH = curMaxH - curMinH + 1;
|
593
|
+
nNumH = (int*)inchi_malloc( curLenH * sizeof(nNumH[0]) );
|
594
|
+
if ( !nNumH ) {
|
595
|
+
*bOverflow |= 1;
|
596
|
+
return nLen;
|
597
|
+
}
|
598
|
+
}
|
599
|
+
} while ( bOutOfRange ); /* the loop may be executed 1 or 2 times only */
|
600
|
+
|
601
|
+
for ( curNumH = curMinH; curNumH <= curMaxH; curNumH ++ ) {
|
602
|
+
numAt = nNumH[curNumH-curMinH]; /* number of atoms that have curNumH atoms H */
|
603
|
+
if ( !numAt || !curNumH ) {
|
604
|
+
continue; /* no atom has this number of H or number of H = 0 */
|
605
|
+
}
|
606
|
+
j = 0;
|
607
|
+
while ( j < nLenCT && numAt ) {
|
608
|
+
if ( curNumH == LinearCT[j] ) {
|
609
|
+
iFirst = ++j;
|
610
|
+
numAt --;
|
611
|
+
for ( ; j < nLenCT && curNumH == LinearCT[j] && numAt; j ++ ) {
|
612
|
+
numAt --;
|
613
|
+
}
|
614
|
+
if ( nCtMode & CT_MODE_ABC_NUMBERS ) {
|
615
|
+
len = MakeAbcNumber( szValue, (int)sizeof(szValue), NULL, iFirst );
|
616
|
+
} else {
|
617
|
+
len = MakeDecNumber( szValue, (int)sizeof(szValue), bNext?ITEM_DELIMETER:NULL, iFirst );
|
618
|
+
bNext ++; /* add a delimiter (comma) before all except the first */
|
619
|
+
}
|
620
|
+
if ( iFirst < j ) {
|
621
|
+
/* output last canonical number */
|
622
|
+
if ( nCtMode & CT_MODE_ABC_NUMBERS ) {
|
623
|
+
len += MakeAbcNumber( szValue+len, (int)sizeof(szValue), NULL, j );
|
624
|
+
} else {
|
625
|
+
len += MakeDecNumber( szValue+len, (int)sizeof(szValue)-len, "-", j );
|
626
|
+
}
|
627
|
+
}
|
628
|
+
if ( !numAt || ( nCtMode & CT_MODE_ABC_NUMBERS ) ) {
|
629
|
+
/* add number of H */
|
630
|
+
/* output number of H */
|
631
|
+
nVal = curNumH;
|
632
|
+
if ( nCtMode & CT_MODE_ABC_NUMBERS ) {
|
633
|
+
len += MakeDecNumber( szValue+len, (int)sizeof(szValue)-len, NULL, nVal );
|
634
|
+
} else {
|
635
|
+
pH = nVal > 0? "H":"h";
|
636
|
+
nVal = abs(nVal);
|
637
|
+
if ( nVal > 1 ) {
|
638
|
+
len += MakeDecNumber( szValue+len, (int)sizeof(szValue)-len, pH, nVal );
|
639
|
+
} else {
|
640
|
+
strcpy( szValue+len, pH );
|
641
|
+
len ++;
|
642
|
+
}
|
643
|
+
}
|
644
|
+
}
|
645
|
+
/* add to the output */
|
646
|
+
if ( 0 <= len && nLen+len < nLen_szLinearCT ) {
|
647
|
+
if ( len ) {
|
648
|
+
strcpy( szLinearCT+nLen, szValue );
|
649
|
+
nLen += len;
|
650
|
+
bNext ++;
|
651
|
+
}
|
652
|
+
} else {
|
653
|
+
bOvfl = 1;
|
654
|
+
break;
|
655
|
+
}
|
656
|
+
} else {
|
657
|
+
j ++;
|
658
|
+
}
|
659
|
+
}
|
660
|
+
}
|
661
|
+
if ( nNumH != nInitNumH ) {
|
662
|
+
inchi_free( nNumH );
|
663
|
+
}
|
664
|
+
} else {
|
665
|
+
iFirst = 0;
|
666
|
+
for ( i = iFirst+1; i <= nLenCT && nLen < nLen_szLinearCT; i ++ ) {
|
667
|
+
if ( i < nLenCT && LinearCT[i] == LinearCT[iFirst] ) {
|
668
|
+
continue;
|
669
|
+
}
|
670
|
+
/* output identical values located at i = iFirst..i-1 */
|
671
|
+
if ( LinearCT[iFirst] ) { /* output only non-zero values */
|
672
|
+
/* first canonical number */
|
673
|
+
nVal = LinearCT[iFirst];
|
674
|
+
iFirst ++;
|
675
|
+
if ( nCtMode & CT_MODE_ABC_NUMBERS ) {
|
676
|
+
len = MakeAbcNumber( szValue, (int)sizeof(szValue), NULL, iFirst );
|
677
|
+
} else {
|
678
|
+
len = MakeDecNumber( szValue, (int)sizeof(szValue), bNext?ITEM_DELIMETER:NULL, iFirst );
|
679
|
+
}
|
680
|
+
if ( iFirst < i ) {
|
681
|
+
/* output last canonical number */
|
682
|
+
if ( nCtMode & CT_MODE_ABC_NUMBERS ) {
|
683
|
+
len += MakeAbcNumber( szValue+len, (int)sizeof(szValue), NULL, i );
|
684
|
+
} else {
|
685
|
+
len += MakeDecNumber( szValue+len, (int)sizeof(szValue)-len, "-", i );
|
686
|
+
}
|
687
|
+
}
|
688
|
+
/* output number of H */
|
689
|
+
if ( nCtMode & CT_MODE_ABC_NUMBERS ) {
|
690
|
+
len += MakeDecNumber( szValue+len, (int)sizeof(szValue)-len, NULL, nVal );
|
691
|
+
} else {
|
692
|
+
pH = nVal > 0? "H":"h";
|
693
|
+
nVal = abs(nVal);
|
694
|
+
if ( nVal > 1 ) {
|
695
|
+
len += MakeDecNumber( szValue+len, (int)sizeof(szValue)-len, pH, nVal );
|
696
|
+
} else {
|
697
|
+
strcpy( szValue+len, pH );
|
698
|
+
len ++;
|
699
|
+
}
|
700
|
+
}
|
701
|
+
if ( 0 <= len && nLen+len < nLen_szLinearCT ) {
|
702
|
+
if ( len ) {
|
703
|
+
strcpy( szLinearCT+nLen, szValue );
|
704
|
+
nLen += len;
|
705
|
+
bNext ++;
|
706
|
+
}
|
707
|
+
} else {
|
708
|
+
bOvfl = 1;
|
709
|
+
break;
|
710
|
+
}
|
711
|
+
}
|
712
|
+
iFirst = i;
|
713
|
+
}
|
714
|
+
}
|
715
|
+
}
|
716
|
+
|
717
|
+
*bOverflow |= bOvfl;
|
718
|
+
return nLen;
|
719
|
+
|
720
|
+
#undef INIT_MIN_NUM_H
|
721
|
+
#undef INIT_MAX_NUM_H
|
722
|
+
#undef INIT_LEN_NUM_H
|
723
|
+
}
|
724
|
+
/**********************************************************************************************
|
725
|
+
* nCtMode = 0: full
|
726
|
+
* 1: censored CT (no orphans, that CT should have only atoms with neighbors)
|
727
|
+
* 2: compressed CT (Abc numbers)
|
728
|
+
**********************************************************************************************/
|
729
|
+
int MakeCtString( AT_NUMB *LinearCT, int nLenCT, int bAddDelim,
|
730
|
+
S_CHAR *nNum_H, int num_atoms, /* both parameters are not used here */
|
731
|
+
char *szLinearCT, int nLen_szLinearCT, int nCtMode, int *bOverflow)
|
732
|
+
{
|
733
|
+
|
734
|
+
if ( !nNum_H || !(nCtMode & CT_MODE_NO_ORPHANS) ) {
|
735
|
+
return MakeCtStringOld( LinearCT, nLenCT, bAddDelim,
|
736
|
+
szLinearCT, nLen_szLinearCT, nCtMode, bOverflow);
|
737
|
+
} else {
|
738
|
+
return MakeCtStringNew( LinearCT, nLenCT, bAddDelim,
|
739
|
+
nNum_H, num_atoms,
|
740
|
+
szLinearCT, nLen_szLinearCT, nCtMode, bOverflow);
|
741
|
+
}
|
742
|
+
}
|
743
|
+
|
744
|
+
|
745
|
+
|
746
|
+
/**********************************************************************************************
|
747
|
+
* nCtMode = 0: full: decimal-only, with parentheses around t-groups
|
748
|
+
* 2: compressed CT: do not add comma before the output string if bAddDelim != 0
|
749
|
+
* do not add parentheses around t-groups
|
750
|
+
* atom canon numbers an Abc
|
751
|
+
* LinearCT format:
|
752
|
+
* N = number of tautomeric groups
|
753
|
+
* n = number of endpoints + 1 in a tautomeric group #1
|
754
|
+
* next INCHI_T_NUM_MOVABLE lines (any after the first non-zero):
|
755
|
+
* h = number of hydrogen atoms in the tautomeric group
|
756
|
+
* m = number of negative charges
|
757
|
+
* ... (the rest of the INCHI_T_NUM_MOVABLE has not been established, ignore them)
|
758
|
+
* c(1) = canonical number of the first atom in the t-group
|
759
|
+
* ...
|
760
|
+
* c(n-1) = canonical number of the last atom in the t-group
|
761
|
+
*
|
762
|
+
**********************************************************************************************/
|
763
|
+
|
764
|
+
int MakeTautString( AT_NUMB *LinearCT, int nLenCT, int bAddDelim,
|
765
|
+
char *szLinearCT, int nLen_szLinearCT, int nCtMode, int *bOverflow)
|
766
|
+
{
|
767
|
+
/* produce output string; */
|
768
|
+
int nLen = 0, len, i, bOvfl = *bOverflow;
|
769
|
+
char szValue[16];
|
770
|
+
const char *p;
|
771
|
+
int nValue, nGroupLen, iGroupOutputCount, bCompressed;
|
772
|
+
/* make tautomer string */
|
773
|
+
if ( !nLenCT || !LinearCT || !*LinearCT ) {
|
774
|
+
return nLen;
|
775
|
+
}
|
776
|
+
bCompressed = ( nCtMode & CT_MODE_ABC_NUMBERS );
|
777
|
+
if ( !bCompressed && !bOvfl && bAddDelim ) {
|
778
|
+
if ( nLen_szLinearCT > 1+LEN_EXTRA_SPACE ) {
|
779
|
+
strcpy( szLinearCT, COMMA_EXTRA_SPACE);
|
780
|
+
nLen += 1+LEN_EXTRA_SPACE;
|
781
|
+
} else {
|
782
|
+
bOvfl = 1;
|
783
|
+
}
|
784
|
+
}
|
785
|
+
LinearCT ++; /* bypass number of tautomeric groups */
|
786
|
+
nLenCT --;
|
787
|
+
|
788
|
+
if ( !bOvfl ) {
|
789
|
+
for ( i = nGroupLen = iGroupOutputCount = 0; i < nLenCT && nLen < nLen_szLinearCT; i ++ ) {
|
790
|
+
nValue = (int)LinearCT[i];
|
791
|
+
if ( nGroupLen == iGroupOutputCount ) {
|
792
|
+
nGroupLen = nValue;
|
793
|
+
iGroupOutputCount = 0;
|
794
|
+
/* group delimiter (uncompressed) */
|
795
|
+
if ( !bCompressed ) {
|
796
|
+
if ( !i ) {
|
797
|
+
strcpy( szValue, "(" );
|
798
|
+
len = 1;
|
799
|
+
} else {
|
800
|
+
strcpy( szValue, ")(" );
|
801
|
+
len = 2;
|
802
|
+
}
|
803
|
+
} else {
|
804
|
+
len = 0;
|
805
|
+
}
|
806
|
+
} else
|
807
|
+
if ( bCompressed && iGroupOutputCount >= INCHI_T_NUM_MOVABLE ) {
|
808
|
+
/* compressed canon number in Abc */
|
809
|
+
len = MakeAbcNumber( szValue, (int)sizeof(szValue), NULL, nValue );
|
810
|
+
iGroupOutputCount ++;
|
811
|
+
} else {
|
812
|
+
/* always output number of hydrogen atoms as a decimal */
|
813
|
+
/* output leading space if: */
|
814
|
+
/* (a) this is the first output value in compressed mode (i==1 && bCompressed) */
|
815
|
+
/* (b) this is not the first output value in non-compressed mode ( iGroupOutputCount && !bCompressed) */
|
816
|
+
if ( bCompressed ) {
|
817
|
+
p = NULL;
|
818
|
+
len = 0;
|
819
|
+
switch( iGroupOutputCount ) {
|
820
|
+
case 0:
|
821
|
+
len = MakeDecNumber( szValue, (int)sizeof(szValue), (i == 1)? ITEM_DELIMETER:NULL, nValue );
|
822
|
+
break;
|
823
|
+
case 1:
|
824
|
+
p = "-";
|
825
|
+
break;
|
826
|
+
case 2:
|
827
|
+
p = "+";
|
828
|
+
break;
|
829
|
+
}
|
830
|
+
if ( p ) {
|
831
|
+
switch( nValue ) {
|
832
|
+
case 0:
|
833
|
+
len = 0;
|
834
|
+
break;
|
835
|
+
case 1:
|
836
|
+
strcpy(szValue, p);
|
837
|
+
len = strlen(szValue);
|
838
|
+
break;
|
839
|
+
default:
|
840
|
+
len = MakeDecNumber( szValue, (int)sizeof(szValue), p, nValue );
|
841
|
+
break;
|
842
|
+
}
|
843
|
+
}
|
844
|
+
} else {
|
845
|
+
if ( iGroupOutputCount >= INCHI_T_NUM_MOVABLE ) {
|
846
|
+
/* canonical number of the atom in the tautomeric group */
|
847
|
+
len = MakeDecNumber( szValue, (int)sizeof(szValue), ITEM_DELIMETER, nValue );
|
848
|
+
} else {
|
849
|
+
p = NULL;
|
850
|
+
len = 0;
|
851
|
+
if ( nValue ) {
|
852
|
+
switch( iGroupOutputCount ) {
|
853
|
+
case 0:
|
854
|
+
p = "H";
|
855
|
+
break;
|
856
|
+
case 1:
|
857
|
+
p = "-";
|
858
|
+
break;
|
859
|
+
case 2:
|
860
|
+
p = "+";
|
861
|
+
break;
|
862
|
+
}
|
863
|
+
if ( p ) {
|
864
|
+
/* number of hydrogens */
|
865
|
+
if ( nValue == 1 ) {
|
866
|
+
strcpy(szValue, p);
|
867
|
+
len = strlen(szValue);
|
868
|
+
} else {
|
869
|
+
len = MakeDecNumber( szValue, (int)sizeof(szValue), p, nValue );
|
870
|
+
}
|
871
|
+
}
|
872
|
+
}
|
873
|
+
}
|
874
|
+
}
|
875
|
+
iGroupOutputCount ++;
|
876
|
+
}
|
877
|
+
if ( 0 <= len && nLen+len < nLen_szLinearCT ) {
|
878
|
+
if ( len ) {
|
879
|
+
strcpy( szLinearCT+nLen, szValue );
|
880
|
+
nLen += len;
|
881
|
+
}
|
882
|
+
} else {
|
883
|
+
bOvfl = 1;
|
884
|
+
break;
|
885
|
+
}
|
886
|
+
}
|
887
|
+
if ( !bOvfl && !bCompressed && i ) {
|
888
|
+
if ( nLen + 1 < nLen_szLinearCT ) {
|
889
|
+
strcpy( szLinearCT+nLen, ")" );
|
890
|
+
nLen ++;
|
891
|
+
} else {
|
892
|
+
bOvfl = 1;
|
893
|
+
}
|
894
|
+
}
|
895
|
+
}
|
896
|
+
*bOverflow |= bOvfl;
|
897
|
+
return nLen;
|
898
|
+
}
|
899
|
+
/**********************************************************************************************
|
900
|
+
* nCtMode = 0: full
|
901
|
+
* 2: compressed CT
|
902
|
+
* 22+3s3: 22=canon. number; +3=charge; s=singlet (d=doublet, t=triplet, s is omitted if valence=0), 3 = valence
|
903
|
+
* 22+3.3, (charge, valence) 22.3 (valence) 22t3 (triplet, valence)
|
904
|
+
* Ab+3t4: Ab=canon. number; +3=charge or "." t=triplet (or s, d), 4=valence
|
905
|
+
**********************************************************************************************/
|
906
|
+
int MakeCRVString( ORIG_INFO *OrigInfo, int nLenCT, int bAddDelim,
|
907
|
+
char *szLinearCT, int nLen_szLinearCT, int nCtMode, int *bOverflow)
|
908
|
+
{
|
909
|
+
/* produce output string; */
|
910
|
+
int nLen = 0, len, k, bAbcNumbers;
|
911
|
+
int bOvfl = *bOverflow;
|
912
|
+
char szValue[32];
|
913
|
+
int bNext=0;
|
914
|
+
bAbcNumbers = ( nCtMode & CT_MODE_ABC_NUMBERS );
|
915
|
+
/* add connection table string */
|
916
|
+
if ( !bOvfl && bAddDelim ) {
|
917
|
+
if ( nLen_szLinearCT > 2 ) {
|
918
|
+
strcpy( szLinearCT, ", " );
|
919
|
+
nLen += 2;
|
920
|
+
} else {
|
921
|
+
bOvfl = 1;
|
922
|
+
}
|
923
|
+
}
|
924
|
+
for ( k = 0; !bOvfl && k < nLenCT && nLen < nLen_szLinearCT; k ++ ) {
|
925
|
+
/* find the next non-empty entry */
|
926
|
+
if ( OrigInfo[k].cCharge || OrigInfo[k].cRadical || OrigInfo[k].cUnusualValence ) {
|
927
|
+
if ( bAbcNumbers ) {
|
928
|
+
/*
|
929
|
+
3 items: Ad+3d4 (canon. numb=Ad, charge=+3, doublet, valence = 4
|
930
|
+
2 items: Ad.d4 Ad+3.4 Ad+3d
|
931
|
+
1 item: Ad+3 Ad.d Ad4
|
932
|
+
|
933
|
+
dot output before radical: no charge, radical is present
|
934
|
+
dot before valence: charge is present, no radical, valence is present
|
935
|
+
*/
|
936
|
+
len = MakeAbcNumber( szValue, (int)sizeof(szValue), NULL, k+1 );
|
937
|
+
|
938
|
+
/* charge */
|
939
|
+
if ( OrigInfo[k].cCharge ) {
|
940
|
+
if ( OrigInfo[k].cCharge > 0 ) {
|
941
|
+
len += MakeDecNumber( szValue+len, (int)sizeof(szValue)-len, "+", OrigInfo[k].cCharge );
|
942
|
+
} else {
|
943
|
+
len += MakeDecNumber( szValue+len, (int)sizeof(szValue)-len, NULL, OrigInfo[k].cCharge );
|
944
|
+
}
|
945
|
+
}
|
946
|
+
/* radical */
|
947
|
+
if ( OrigInfo[k].cRadical ) {
|
948
|
+
if ( !OrigInfo[k].cCharge ) {
|
949
|
+
szValue[len ++] = '.';
|
950
|
+
}
|
951
|
+
switch( OrigInfo[k].cRadical ) {
|
952
|
+
case 1:
|
953
|
+
szValue[len ++] = 'd';
|
954
|
+
break;
|
955
|
+
case 2:
|
956
|
+
szValue[len ++] = 't';
|
957
|
+
break;
|
958
|
+
default:
|
959
|
+
szValue[len ++] = 'u';
|
960
|
+
break;
|
961
|
+
}
|
962
|
+
}
|
963
|
+
/* valence */
|
964
|
+
if ( OrigInfo[k].cUnusualValence ) {
|
965
|
+
if ( OrigInfo[k].cCharge && !OrigInfo[k].cRadical ) {
|
966
|
+
szValue[len ++] = '.';
|
967
|
+
}
|
968
|
+
len += MakeDecNumber( szValue+len, (int)sizeof(szValue)-len, NULL, OrigInfo[k].cUnusualValence );
|
969
|
+
}
|
970
|
+
} else {
|
971
|
+
/*
|
972
|
+
3 items: 22+3d4 (canon. numb=22, charge=+3, doublet, valence = 4
|
973
|
+
2 items: 22d4 22+3.4 22+3d
|
974
|
+
1 item: 22+3 22d 22.4
|
975
|
+
|
976
|
+
dot output before valence:
|
977
|
+
(a) charge, no radical, valence
|
978
|
+
(b) no charge, no radical, valence
|
979
|
+
that is, whenever valence is present and no radical
|
980
|
+
*/
|
981
|
+
len = MakeDecNumber( szValue, (int)sizeof(szValue), bNext? ITEM_DELIMETER:NULL, k+1 );
|
982
|
+
/* charge */
|
983
|
+
if ( OrigInfo[k].cCharge ) {
|
984
|
+
if ( OrigInfo[k].cCharge > 0 ) {
|
985
|
+
len += MakeDecNumber( szValue+len, (int)sizeof(szValue)-len, "+", OrigInfo[k].cCharge );
|
986
|
+
} else {
|
987
|
+
len += MakeDecNumber( szValue+len, (int)sizeof(szValue)-len, NULL, OrigInfo[k].cCharge );
|
988
|
+
}
|
989
|
+
}
|
990
|
+
/* radical */
|
991
|
+
if ( OrigInfo[k].cRadical ) {
|
992
|
+
switch( OrigInfo[k].cRadical ) {
|
993
|
+
case 1:
|
994
|
+
szValue[len ++] = 'd';
|
995
|
+
break;
|
996
|
+
case 2:
|
997
|
+
szValue[len ++] = 't';
|
998
|
+
break;
|
999
|
+
default:
|
1000
|
+
szValue[len ++] = 'u';
|
1001
|
+
break;
|
1002
|
+
}
|
1003
|
+
}
|
1004
|
+
/* valence */
|
1005
|
+
if ( OrigInfo[k].cUnusualValence ) {
|
1006
|
+
if ( !OrigInfo[k].cRadical ) {
|
1007
|
+
szValue[len ++] = '.';
|
1008
|
+
}
|
1009
|
+
len += MakeDecNumber( szValue+len, (int)sizeof(szValue)-len, NULL, OrigInfo[k].cUnusualValence );
|
1010
|
+
}
|
1011
|
+
}
|
1012
|
+
} else {
|
1013
|
+
len = 0;
|
1014
|
+
}
|
1015
|
+
if ( len && nLen+len < nLen_szLinearCT ) {
|
1016
|
+
strcpy( szLinearCT+nLen, szValue );
|
1017
|
+
nLen += len;
|
1018
|
+
bNext ++;
|
1019
|
+
} else
|
1020
|
+
if ( len ) {
|
1021
|
+
bOvfl = 1;
|
1022
|
+
break;
|
1023
|
+
}
|
1024
|
+
}
|
1025
|
+
*bOverflow |= bOvfl;
|
1026
|
+
return nLen;
|
1027
|
+
}
|
1028
|
+
|
1029
|
+
/**********************************************************************************************
|
1030
|
+
* nCtMode = 0: full
|
1031
|
+
* 2: compressed CT
|
1032
|
+
**********************************************************************************************/
|
1033
|
+
int MakeEquString( AT_NUMB *LinearCT, int nLenCT, int bAddDelim,
|
1034
|
+
char *szLinearCT, int nLen_szLinearCT, int nCtMode, int *bOverflow)
|
1035
|
+
{
|
1036
|
+
/* produce output string; */
|
1037
|
+
int nLen = 0, len, i, k, bAbcNumbers;
|
1038
|
+
int bOvfl = *bOverflow;
|
1039
|
+
char szValue[16];
|
1040
|
+
int bNext=0;
|
1041
|
+
bAbcNumbers = ( nCtMode & CT_MODE_ABC_NUMBERS );
|
1042
|
+
/* add connection table string */
|
1043
|
+
if ( !bOvfl && bAddDelim ) {
|
1044
|
+
if ( nLen_szLinearCT > 2 ) {
|
1045
|
+
strcpy( szLinearCT, ", " );
|
1046
|
+
nLen += 2;
|
1047
|
+
} else {
|
1048
|
+
bOvfl = 1;
|
1049
|
+
}
|
1050
|
+
}
|
1051
|
+
for ( k = 0; !bOvfl && k < nLenCT && nLen < nLen_szLinearCT; k ++ ) {
|
1052
|
+
/* find the first equivalence number */
|
1053
|
+
if ( k != (int)LinearCT[k] - 1 )
|
1054
|
+
continue;
|
1055
|
+
for ( i = k; i < nLenCT && nLen < nLen_szLinearCT; i ++ ) {
|
1056
|
+
if ( k != (int)LinearCT[i]-1 )
|
1057
|
+
continue;
|
1058
|
+
/* equivalence number: a minimal canon_number out of a group of equivalent atoms */
|
1059
|
+
/* is at canon_number-1 position of each equivalent atom. */
|
1060
|
+
if ( bAbcNumbers ) {
|
1061
|
+
len = MakeAbcNumber( szValue, (int)sizeof(szValue), (i==k && bNext)? ITEM_DELIMETER : NULL, i+1 );
|
1062
|
+
} else {
|
1063
|
+
len = MakeDecNumber( szValue, (int)sizeof(szValue), (i==k)? "(":ITEM_DELIMETER, i+1 );
|
1064
|
+
}
|
1065
|
+
if ( 0 <= len && nLen+len < nLen_szLinearCT ) {
|
1066
|
+
strcpy( szLinearCT+nLen, szValue );
|
1067
|
+
nLen += len;
|
1068
|
+
bNext ++;
|
1069
|
+
} else
|
1070
|
+
if ( 0 > len ) {
|
1071
|
+
bOvfl = 1;
|
1072
|
+
break;
|
1073
|
+
}
|
1074
|
+
}
|
1075
|
+
if ( !bOvfl && !bAbcNumbers ) {
|
1076
|
+
if ( nLen + 2 < nLen_szLinearCT ) {
|
1077
|
+
strcpy( szLinearCT+nLen, ")" );
|
1078
|
+
nLen ++;
|
1079
|
+
} else {
|
1080
|
+
bOvfl = 1;
|
1081
|
+
}
|
1082
|
+
}
|
1083
|
+
}
|
1084
|
+
*bOverflow |= bOvfl;
|
1085
|
+
return nLen;
|
1086
|
+
}
|
1087
|
+
/**********************************************************************************************
|
1088
|
+
* nCtMode = 0: full
|
1089
|
+
* 2: compressed CT
|
1090
|
+
**********************************************************************************************/
|
1091
|
+
int MakeIsoAtomString( INChI_IsotopicAtom *IsotopicAtom, int nNumberOfIsotopicAtoms,
|
1092
|
+
char *szLinearCT, int nLen_szLinearCT, int nCtMode, int *bOverflow)
|
1093
|
+
{
|
1094
|
+
/* produce output string; */
|
1095
|
+
int nLen = 0, len, tot_len, ret, i, j, bOvfl = *bOverflow;
|
1096
|
+
char szValue[64];
|
1097
|
+
char *p;
|
1098
|
+
int nValue;
|
1099
|
+
int bAbcNumbers = (nCtMode & CT_MODE_ABC_NUMBERS );
|
1100
|
+
static const char letter[] = "itdh";
|
1101
|
+
static const char *h[] = {"T", "D", "H"};
|
1102
|
+
static const char *sign[] = {"-", "+"};
|
1103
|
+
|
1104
|
+
if ( !bOvfl ) {
|
1105
|
+
for ( i = 0; i < nNumberOfIsotopicAtoms && nLen < nLen_szLinearCT; i ++ ) {
|
1106
|
+
p = szValue;
|
1107
|
+
tot_len = 0;
|
1108
|
+
for ( j = 0; j < 5; j ++ ) {
|
1109
|
+
len = 0;
|
1110
|
+
switch( j ) {
|
1111
|
+
case 0:
|
1112
|
+
nValue = (int)IsotopicAtom[i].nAtomNumber;
|
1113
|
+
break;
|
1114
|
+
case 1:
|
1115
|
+
nValue = (int)IsotopicAtom[i].nIsoDifference;
|
1116
|
+
break;
|
1117
|
+
case 2:
|
1118
|
+
nValue = (int)IsotopicAtom[i].nNum_T;
|
1119
|
+
break;
|
1120
|
+
case 3:
|
1121
|
+
nValue = (int)IsotopicAtom[i].nNum_D;
|
1122
|
+
break;
|
1123
|
+
case 4:
|
1124
|
+
nValue = (int)IsotopicAtom[i].nNum_H;
|
1125
|
+
break;
|
1126
|
+
}
|
1127
|
+
if ( !j ) {
|
1128
|
+
/* atom canonical number */
|
1129
|
+
len = (bAbcNumbers? MakeAbcNumber:MakeDecNumber)
|
1130
|
+
( p, (int)sizeof(szValue)-tot_len,
|
1131
|
+
bAbcNumbers?NULL:(i?ITEM_DELIMETER:EXTRA_SPACE), nValue
|
1132
|
+
);
|
1133
|
+
} else
|
1134
|
+
if ( bAbcNumbers ) { /* Abc output */
|
1135
|
+
switch ( j ) {
|
1136
|
+
case 1: /* nIsoDifference */
|
1137
|
+
len = MakeDecNumber( p, (int)sizeof(szValue)-tot_len, NULL, nValue );
|
1138
|
+
break;
|
1139
|
+
case 2: /* nNum_T */
|
1140
|
+
case 3: /* nNum_D */
|
1141
|
+
case 4: /* nNum_H */
|
1142
|
+
if ( nValue ) {
|
1143
|
+
if ( (int)sizeof(szValue) - tot_len > 1 ) {
|
1144
|
+
p[len++]=letter[j-1];
|
1145
|
+
if ( 1 == nValue ) {
|
1146
|
+
p[len] = '\0';
|
1147
|
+
} else {
|
1148
|
+
ret = MakeDecNumber( p+len, (int)sizeof(szValue)-tot_len-len, NULL, nValue );
|
1149
|
+
len = (ret >= 0)? len+ret : ret;
|
1150
|
+
}
|
1151
|
+
} else {
|
1152
|
+
len = -1; /* overflow */
|
1153
|
+
}
|
1154
|
+
}
|
1155
|
+
}
|
1156
|
+
} else
|
1157
|
+
if ( nValue ) {
|
1158
|
+
if ( j == 1 ) { /* Decimal output */
|
1159
|
+
/* signed isotopic mass difference */
|
1160
|
+
int subtract = (nValue > 0);
|
1161
|
+
/* (n = mass difference) > 0 corresponds to nValue = n+1 */
|
1162
|
+
/* subtract 1 from it so that mass difference for 35Cl or 12C is zero */
|
1163
|
+
len = MakeDecNumber( p, (int)sizeof(szValue)-tot_len, sign[nValue>=0], abs(nValue-subtract) );
|
1164
|
+
} else {
|
1165
|
+
/* hydrogen isotope */
|
1166
|
+
if ( nValue != 1 ) {
|
1167
|
+
len = MakeDecNumber( p, (int)sizeof(szValue)-tot_len, h[j-2], nValue );
|
1168
|
+
} else
|
1169
|
+
if ( (int)sizeof(szValue)-tot_len > 1 ) {
|
1170
|
+
strcpy( p, h[j-2] );
|
1171
|
+
len = 1;
|
1172
|
+
} else {
|
1173
|
+
len = -1; /* overflow */
|
1174
|
+
}
|
1175
|
+
}
|
1176
|
+
} else {
|
1177
|
+
continue; /* do not write zeroes */
|
1178
|
+
}
|
1179
|
+
if ( len < 0 ) {
|
1180
|
+
bOvfl = 1;
|
1181
|
+
break;
|
1182
|
+
}
|
1183
|
+
tot_len += len;
|
1184
|
+
p += len;
|
1185
|
+
}
|
1186
|
+
if ( nLen+tot_len < nLen_szLinearCT ) {
|
1187
|
+
memcpy( szLinearCT+nLen, szValue, tot_len+1 );
|
1188
|
+
nLen += tot_len;
|
1189
|
+
} else {
|
1190
|
+
bOvfl = 1;
|
1191
|
+
break;
|
1192
|
+
}
|
1193
|
+
}
|
1194
|
+
}
|
1195
|
+
*bOverflow |= bOvfl;
|
1196
|
+
return nLen;
|
1197
|
+
}
|
1198
|
+
/**********************************************************************************************/
|
1199
|
+
int MakeIsoTautString( INChI_IsotopicTGroup *IsotopicTGroup, int nNumberOfIsotopicTGroups,
|
1200
|
+
char *szLinearCT, int nLen_szLinearCT, int nCtMode, int *bOverflow)
|
1201
|
+
{
|
1202
|
+
/* produce output string; */
|
1203
|
+
int nLen = 0, len, tot_len, i, j, bOvfl = *bOverflow;
|
1204
|
+
AT_NUMB nMax;
|
1205
|
+
char szValue[32];
|
1206
|
+
char *p;
|
1207
|
+
int nValue;
|
1208
|
+
int bAbcNumbers = ( nCtMode & CT_MODE_ABC_NUMBERS );
|
1209
|
+
static const char letter[] = "tdh";
|
1210
|
+
static const char *h[] = {"T", "D", "H"};
|
1211
|
+
/* add connection table string */
|
1212
|
+
nMax = 0;
|
1213
|
+
if ( !bOvfl ) {
|
1214
|
+
for ( i = 0; i < nNumberOfIsotopicTGroups && nLen < nLen_szLinearCT; i ++ ) {
|
1215
|
+
p = szValue;
|
1216
|
+
tot_len = 0;
|
1217
|
+
for ( j = 0; j < 4; j ++ ) {
|
1218
|
+
switch( j ) {
|
1219
|
+
case 0:
|
1220
|
+
nValue = (int)IsotopicTGroup[i].nTGroupNumber;
|
1221
|
+
break;
|
1222
|
+
case 1:
|
1223
|
+
nValue = (int)IsotopicTGroup[i].nNum_T;
|
1224
|
+
break;
|
1225
|
+
case 2:
|
1226
|
+
nValue = (int)IsotopicTGroup[i].nNum_D;
|
1227
|
+
break;
|
1228
|
+
case 3:
|
1229
|
+
nValue = (int)IsotopicTGroup[i].nNum_H;
|
1230
|
+
break;
|
1231
|
+
}
|
1232
|
+
if ( !j ) {
|
1233
|
+
/* atom canonical number */
|
1234
|
+
len = (bAbcNumbers?MakeAbcNumber:MakeDecNumber)
|
1235
|
+
( p, (int)sizeof(szValue)-tot_len,
|
1236
|
+
bAbcNumbers?NULL:(i?ITEM_DELIMETER:EXTRA_SPACE),
|
1237
|
+
nValue
|
1238
|
+
);
|
1239
|
+
} else
|
1240
|
+
if ( nValue ) {
|
1241
|
+
if ( bAbcNumbers ) {
|
1242
|
+
len = MakeDecNumber( p, (int)sizeof(szValue)-tot_len, NULL, nValue );
|
1243
|
+
if ( len > 0 ) { /* make sure overflow has not happened */
|
1244
|
+
if ( (int)sizeof(szValue)-tot_len-len > 1 ) {
|
1245
|
+
p[len++]=letter[j-1];
|
1246
|
+
p[len] = '\0';
|
1247
|
+
} else {
|
1248
|
+
len = -1; /* overflow */
|
1249
|
+
}
|
1250
|
+
}
|
1251
|
+
} else {
|
1252
|
+
/* hydrogen isotope */
|
1253
|
+
if ( nValue != 1 ) {
|
1254
|
+
len = MakeDecNumber( p, (int)sizeof(szValue)-tot_len, h[j-1], nValue );
|
1255
|
+
} else
|
1256
|
+
if ( (int)sizeof(szValue)-tot_len > 1 ) {
|
1257
|
+
strcpy( p, h[j-1] );
|
1258
|
+
len = 1;
|
1259
|
+
} else {
|
1260
|
+
len = -1; /* overflow */
|
1261
|
+
}
|
1262
|
+
}
|
1263
|
+
} else {
|
1264
|
+
continue; /* do not write zeroes */
|
1265
|
+
}
|
1266
|
+
if ( len < 0 ) {
|
1267
|
+
bOvfl = 1;
|
1268
|
+
break;
|
1269
|
+
}
|
1270
|
+
p += len;
|
1271
|
+
tot_len += len;
|
1272
|
+
}
|
1273
|
+
if ( nLen+tot_len < nLen_szLinearCT ) {
|
1274
|
+
memcpy( szLinearCT+nLen, szValue, tot_len+1 );
|
1275
|
+
nLen += tot_len;
|
1276
|
+
} else {
|
1277
|
+
bOvfl = 1;
|
1278
|
+
break;
|
1279
|
+
}
|
1280
|
+
}
|
1281
|
+
}
|
1282
|
+
*bOverflow |= bOvfl;
|
1283
|
+
return nLen;
|
1284
|
+
}
|
1285
|
+
/**********************************************************************************************/
|
1286
|
+
int MakeIsoHString( int num_iso_H[], char *szLinearCT, int nLen_szLinearCT, int nCtMode, int *bOverflow)
|
1287
|
+
{
|
1288
|
+
/* produce output string; */
|
1289
|
+
int nLen = 0, len, tot_len, j, bOvfl = *bOverflow;
|
1290
|
+
AT_NUMB nMax;
|
1291
|
+
char szValue[32];
|
1292
|
+
char *p;
|
1293
|
+
int nValue;
|
1294
|
+
int bAbcNumbers = ( nCtMode & CT_MODE_ABC_NUMBERS );
|
1295
|
+
static const char letter[] = "tdh";
|
1296
|
+
static const char *h[] = {"T", "D", "H"};
|
1297
|
+
/* add connection table string */
|
1298
|
+
nMax = 0;
|
1299
|
+
if ( !bOvfl ) {
|
1300
|
+
p = szValue;
|
1301
|
+
tot_len = 0;
|
1302
|
+
for ( j = 1; j < 4; j ++ ) {
|
1303
|
+
nValue = num_iso_H[NUM_H_ISOTOPES-j];/* j: 1=>T, 2=>D, 3=>1H */
|
1304
|
+
if ( nValue ) {
|
1305
|
+
if ( bAbcNumbers ) {
|
1306
|
+
len = MakeDecNumber( p, (int)sizeof(szValue)-tot_len, NULL, nValue );
|
1307
|
+
if ( len > 0 ) { /* make sure overflow has not happened */
|
1308
|
+
if ( (int)sizeof(szValue)-tot_len-len > 1 ) {
|
1309
|
+
p[len++]=letter[j-1];
|
1310
|
+
p[len] = '\0';
|
1311
|
+
} else {
|
1312
|
+
len = -1; /* overflow */
|
1313
|
+
}
|
1314
|
+
}
|
1315
|
+
} else {
|
1316
|
+
/* hydrogen isotope */
|
1317
|
+
if ( nValue != 1 ) {
|
1318
|
+
len = MakeDecNumber( p, (int)sizeof(szValue)-tot_len, h[j-1], nValue );
|
1319
|
+
} else
|
1320
|
+
if ( (int)sizeof(szValue)-tot_len > 1 ) {
|
1321
|
+
strcpy( p, h[j-1] );
|
1322
|
+
len = 1;
|
1323
|
+
} else {
|
1324
|
+
len = -1; /* overflow */
|
1325
|
+
}
|
1326
|
+
}
|
1327
|
+
} else {
|
1328
|
+
continue; /* do not write zeroes */
|
1329
|
+
}
|
1330
|
+
if ( len < 0 ) {
|
1331
|
+
bOvfl = 1;
|
1332
|
+
break;
|
1333
|
+
}
|
1334
|
+
p += len;
|
1335
|
+
tot_len += len;
|
1336
|
+
}
|
1337
|
+
if ( nLen+tot_len < nLen_szLinearCT ) {
|
1338
|
+
memcpy( szLinearCT+nLen, szValue, tot_len+1 );
|
1339
|
+
nLen += tot_len;
|
1340
|
+
} else {
|
1341
|
+
bOvfl = 1;
|
1342
|
+
}
|
1343
|
+
}
|
1344
|
+
*bOverflow |= bOvfl;
|
1345
|
+
return nLen;
|
1346
|
+
}
|
1347
|
+
/**********************************************************************************************/
|
1348
|
+
int MakeStereoString( AT_NUMB *at1, AT_NUMB *at2, S_CHAR *parity, int bAddDelim, int nLenCT,
|
1349
|
+
char *szLinearCT, int nLen_szLinearCT, int nCtMode, int *bOverflow)
|
1350
|
+
{
|
1351
|
+
/* produce output string; */
|
1352
|
+
int nLen = 0, len, tot_len, i, j, bOvfl = *bOverflow;
|
1353
|
+
char szValue[32];
|
1354
|
+
char *p;
|
1355
|
+
int nValue;
|
1356
|
+
static const char parity_char[] = "!-+u?";
|
1357
|
+
bAddDelim = 0;
|
1358
|
+
if ( !bOvfl ) {
|
1359
|
+
for ( i = 0; i < nLenCT && nLen < nLen_szLinearCT; i ++ ) {
|
1360
|
+
p = szValue;
|
1361
|
+
tot_len = 0;
|
1362
|
+
for ( j = 0; j < 3; j ++ ) {
|
1363
|
+
if ( j == 0 && at1 )
|
1364
|
+
nValue = (int)at1[i];
|
1365
|
+
else
|
1366
|
+
if ( j == 1 && at2 )
|
1367
|
+
nValue = (int)at2[i];
|
1368
|
+
else
|
1369
|
+
if ( j == 2 && parity )
|
1370
|
+
nValue = (int)parity[i];
|
1371
|
+
else
|
1372
|
+
continue;
|
1373
|
+
if ( nCtMode & CT_MODE_ABC_NUMBERS ) {
|
1374
|
+
len = (j==2? MakeDecNumber : MakeAbcNumber)( p, (int)sizeof(szValue)-tot_len, NULL, nValue );
|
1375
|
+
} else {
|
1376
|
+
if ( j < 2 ) {
|
1377
|
+
len = MakeDecNumber( p, (int)sizeof(szValue)-tot_len, tot_len?"-":(i||bAddDelim)?ITEM_DELIMETER:NULL, nValue );
|
1378
|
+
} else
|
1379
|
+
if ( tot_len + 1 < (int)sizeof(szValue) ) {
|
1380
|
+
*p ++ = (0<=nValue && nValue<=4)? parity_char[nValue]:parity_char[0];
|
1381
|
+
*p = '\0';
|
1382
|
+
len = 1;
|
1383
|
+
} else {
|
1384
|
+
len = -1; /* Overflow */
|
1385
|
+
}
|
1386
|
+
}
|
1387
|
+
if ( len < 0 ) {
|
1388
|
+
bOvfl = 1;
|
1389
|
+
break;
|
1390
|
+
}
|
1391
|
+
p += len;
|
1392
|
+
tot_len += len;
|
1393
|
+
}
|
1394
|
+
if ( nLen+tot_len < nLen_szLinearCT ) {
|
1395
|
+
memcpy( szLinearCT+nLen, szValue, tot_len+1 );
|
1396
|
+
nLen += tot_len;
|
1397
|
+
} else {
|
1398
|
+
bOvfl = 1;
|
1399
|
+
break;
|
1400
|
+
}
|
1401
|
+
}
|
1402
|
+
}
|
1403
|
+
*bOverflow |= bOvfl;
|
1404
|
+
return nLen;
|
1405
|
+
}
|
1406
|
+
|
1407
|
+
/**********************************************************************************************/
|
1408
|
+
/* Produce an "Alphabetic" number, base 27 (27 digits: 0, a, b, ..., z) */
|
1409
|
+
/* The leading "digit" uppercase, the rest -- lowercase */
|
1410
|
+
/* szString length nStringLen includes 1 byte for zero termination */
|
1411
|
+
/* Return Value: length without zero termination; -1 means not enough room */
|
1412
|
+
/* Note: ASCII-encoding specific implementation */
|
1413
|
+
int MakeAbcNumber( char *szString, int nStringLen, const char *szLeadingDelim, int nValue )
|
1414
|
+
{
|
1415
|
+
#define ALPHA_BASE 27
|
1416
|
+
#define ALPHA_MINUS '-'
|
1417
|
+
#define ALPHA_ZERO_VAL '.'
|
1418
|
+
#define ALPHA_ONE 'a'
|
1419
|
+
#define ALPHA_ZERO '@'
|
1420
|
+
char *p = szString;
|
1421
|
+
char *q;
|
1422
|
+
int nChar;
|
1423
|
+
|
1424
|
+
if ( nStringLen < 2 )
|
1425
|
+
return -1;
|
1426
|
+
while ( szLeadingDelim && *szLeadingDelim && --nStringLen ) {
|
1427
|
+
*p ++ = *szLeadingDelim ++;
|
1428
|
+
}
|
1429
|
+
if ( nStringLen < 2 )
|
1430
|
+
return -1;
|
1431
|
+
if ( !nValue ) {
|
1432
|
+
*p++ = ALPHA_ZERO_VAL; /* zero value (cannot use 0) */
|
1433
|
+
*p = '\0';
|
1434
|
+
return 1;
|
1435
|
+
}
|
1436
|
+
if ( nValue < 0 ) {
|
1437
|
+
*p++ = ALPHA_MINUS;
|
1438
|
+
nStringLen --;
|
1439
|
+
nValue = -nValue;
|
1440
|
+
}
|
1441
|
+
for ( q = p; nValue && --nStringLen; nValue /= ALPHA_BASE ) {
|
1442
|
+
if ( nChar = nValue % ALPHA_BASE ) {
|
1443
|
+
nChar = ALPHA_ONE + nChar - 1;
|
1444
|
+
} else {
|
1445
|
+
nChar = ALPHA_ZERO;
|
1446
|
+
}
|
1447
|
+
*q++ = nChar;
|
1448
|
+
}
|
1449
|
+
if ( nStringLen <= 0 )
|
1450
|
+
return -1;
|
1451
|
+
*q = '\0';
|
1452
|
+
mystrrev( p );
|
1453
|
+
p[0] = toupper(p[0]);
|
1454
|
+
return (q - szString);
|
1455
|
+
#undef ALPHA_BASE
|
1456
|
+
#undef ALPHA_MINUS
|
1457
|
+
#undef ALPHA_ZERO_VAL
|
1458
|
+
#undef ALPHA_ONE
|
1459
|
+
#undef ALPHA_ZERO
|
1460
|
+
}
|
1461
|
+
/**********************************************************************************************/
|
1462
|
+
/* Produce a decimal number */
|
1463
|
+
/* szString length nStringLen includes 1 byte for zero termination */
|
1464
|
+
/* Return Value: length without zero termination; -1 means not enough room */
|
1465
|
+
int MakeDecNumber( char *szString, int nStringLen, const char *szLeadingDelim, int nValue )
|
1466
|
+
{
|
1467
|
+
#define DECIMAL_BASE 10
|
1468
|
+
#define DECIMAL_MINUS '-'
|
1469
|
+
#define DECIMAL_ZERO_VAL '0'
|
1470
|
+
#define DECIMAL_ONE '1'
|
1471
|
+
#define DECIMAL_ZERO '0'
|
1472
|
+
char *p = szString;
|
1473
|
+
char *q;
|
1474
|
+
int nChar;
|
1475
|
+
|
1476
|
+
if ( nStringLen < 2 )
|
1477
|
+
return -1;
|
1478
|
+
while ( szLeadingDelim && *szLeadingDelim && --nStringLen ) {
|
1479
|
+
*p ++ = *szLeadingDelim ++;
|
1480
|
+
}
|
1481
|
+
if ( nStringLen < 2 )
|
1482
|
+
return -1;
|
1483
|
+
if ( !nValue ) {
|
1484
|
+
*p++ = DECIMAL_ZERO_VAL; /* zero value (cannot use 0) */
|
1485
|
+
*p = '\0';
|
1486
|
+
return p-szString;
|
1487
|
+
}
|
1488
|
+
if ( nValue < 0 ) {
|
1489
|
+
*p++ = DECIMAL_MINUS;
|
1490
|
+
nStringLen --;
|
1491
|
+
nValue = -nValue;
|
1492
|
+
}
|
1493
|
+
for ( q = p; nValue && --nStringLen; nValue /= DECIMAL_BASE ) {
|
1494
|
+
if ( nChar = nValue % DECIMAL_BASE ) {
|
1495
|
+
nChar = DECIMAL_ONE + nChar - 1;
|
1496
|
+
} else {
|
1497
|
+
nChar = DECIMAL_ZERO;
|
1498
|
+
}
|
1499
|
+
*q++ = nChar;
|
1500
|
+
}
|
1501
|
+
if ( nStringLen <= 0 )
|
1502
|
+
return -1;
|
1503
|
+
*q = '\0';
|
1504
|
+
mystrrev( p );
|
1505
|
+
return (q - szString);
|
1506
|
+
#undef DECIMAL_BASE
|
1507
|
+
#undef DECIMAL_MINUS
|
1508
|
+
#undef DECIMAL_ZERO_VAL
|
1509
|
+
#undef DECIMAL_ONE
|
1510
|
+
#undef DECIMAL_ZERO
|
1511
|
+
}
|