rino 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }