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.
Files changed (87) hide show
  1. data/README +44 -0
  2. data/Rakefile +123 -0
  3. data/ext/extconf.rb +26 -0
  4. data/ext/ruby_inchi_main.so +0 -0
  5. data/ext/src/aux2atom.h +2786 -0
  6. data/ext/src/comdef.h +148 -0
  7. data/ext/src/e_0dstereo.c +3014 -0
  8. data/ext/src/e_0dstereo.h +31 -0
  9. data/ext/src/e_comdef.h +57 -0
  10. data/ext/src/e_ctl_data.h +147 -0
  11. data/ext/src/e_ichi_io.c +498 -0
  12. data/ext/src/e_ichi_io.h +40 -0
  13. data/ext/src/e_ichi_parms.c +37 -0
  14. data/ext/src/e_ichi_parms.h +41 -0
  15. data/ext/src/e_ichicomp.h +50 -0
  16. data/ext/src/e_ichierr.h +40 -0
  17. data/ext/src/e_ichimain.c +593 -0
  18. data/ext/src/e_ichisize.h +43 -0
  19. data/ext/src/e_inchi_atom.c +75 -0
  20. data/ext/src/e_inchi_atom.h +33 -0
  21. data/ext/src/e_inpdef.h +41 -0
  22. data/ext/src/e_mode.h +706 -0
  23. data/ext/src/e_mol2atom.c +649 -0
  24. data/ext/src/e_readinch.c +58 -0
  25. data/ext/src/e_readmol.c +54 -0
  26. data/ext/src/e_readmol.h +180 -0
  27. data/ext/src/e_readstru.c +251 -0
  28. data/ext/src/e_readstru.h +33 -0
  29. data/ext/src/e_util.c +284 -0
  30. data/ext/src/e_util.h +61 -0
  31. data/ext/src/extr_ct.h +251 -0
  32. data/ext/src/ichi.h +206 -0
  33. data/ext/src/ichi_bns.c +7999 -0
  34. data/ext/src/ichi_bns.h +231 -0
  35. data/ext/src/ichican2.c +5000 -0
  36. data/ext/src/ichicano.c +2195 -0
  37. data/ext/src/ichicano.h +49 -0
  38. data/ext/src/ichicans.c +1625 -0
  39. data/ext/src/ichicant.h +379 -0
  40. data/ext/src/ichicomn.h +260 -0
  41. data/ext/src/ichicomp.h +50 -0
  42. data/ext/src/ichidrp.h +119 -0
  43. data/ext/src/ichierr.h +124 -0
  44. data/ext/src/ichiisot.c +101 -0
  45. data/ext/src/ichilnct.c +286 -0
  46. data/ext/src/ichimain.h +132 -0
  47. data/ext/src/ichimak2.c +1189 -0
  48. data/ext/src/ichimake.c +3812 -0
  49. data/ext/src/ichimake.h +205 -0
  50. data/ext/src/ichimap1.c +851 -0
  51. data/ext/src/ichimap2.c +2856 -0
  52. data/ext/src/ichimap4.c +1609 -0
  53. data/ext/src/ichinorm.c +741 -0
  54. data/ext/src/ichinorm.h +67 -0
  55. data/ext/src/ichiparm.c +45 -0
  56. data/ext/src/ichiparm.h +1441 -0
  57. data/ext/src/ichiprt1.c +3612 -0
  58. data/ext/src/ichiprt2.c +1511 -0
  59. data/ext/src/ichiprt3.c +3011 -0
  60. data/ext/src/ichiqueu.c +1003 -0
  61. data/ext/src/ichiring.c +326 -0
  62. data/ext/src/ichiring.h +49 -0
  63. data/ext/src/ichisize.h +35 -0
  64. data/ext/src/ichisort.c +539 -0
  65. data/ext/src/ichister.c +3538 -0
  66. data/ext/src/ichister.h +35 -0
  67. data/ext/src/ichitaut.c +3843 -0
  68. data/ext/src/ichitaut.h +387 -0
  69. data/ext/src/ichitime.h +74 -0
  70. data/ext/src/inchi_api.h +670 -0
  71. data/ext/src/inchi_dll.c +1480 -0
  72. data/ext/src/inchi_dll.h +34 -0
  73. data/ext/src/inchi_dll_main.c +23 -0
  74. data/ext/src/inchi_dll_main.h +31 -0
  75. data/ext/src/inpdef.h +328 -0
  76. data/ext/src/lreadmol.h +1246 -0
  77. data/ext/src/mode.h +706 -0
  78. data/ext/src/ruby_inchi_main.c +558 -0
  79. data/ext/src/runichi.c +4179 -0
  80. data/ext/src/strutil.c +3861 -0
  81. data/ext/src/strutil.h +182 -0
  82. data/ext/src/util.c +1130 -0
  83. data/ext/src/util.h +85 -0
  84. data/lib/clean_tempfile.rb +220 -0
  85. data/lib/rino.rb +111 -0
  86. data/test/test.rb +386 -0
  87. metadata +130 -0
@@ -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
+ }