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,3612 @@
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
+ #include <math.h>
15
+
16
+ #include "mode.h"
17
+
18
+ #include "inpdef.h"
19
+ #include "ichi.h"
20
+ #include "strutil.h"
21
+ #include "util.h"
22
+ #include "extr_ct.h"
23
+ #include "ichitaut.h"
24
+ #include "ichinorm.h"
25
+ #include "ichicant.h"
26
+ #include "ichicano.h"
27
+ #include "ichicomn.h"
28
+ #include "ichister.h"
29
+
30
+ #include "ichicomp.h"
31
+ #include "ichimain.h"
32
+ #include "ichimake.h"
33
+
34
+ int PrintXmlStartTag( char *pStr, int indent, int bEnd, const char *tag,
35
+ const char *l1, int v1, const char *l2, int v2, const char *l3, int v3,
36
+ const char *l4, int v4, const char *l5, int v5, const char *l6, int v6);
37
+ int Needs2addXmlEntityRefs( const char *s );
38
+ int AddXmlEntityRefs( const char *p, char *d );
39
+ #if( TEST_RENUMB_ATOMS == 1 ) /* { */
40
+ int CompareStereoINChI( INChI_Stereo *s1, INChI_Stereo *s2 );
41
+ #endif
42
+
43
+ int str_LineStart( const char *tag, char *tag2, int val2, char *pStr, int ind );
44
+ int str_LineEnd( const char *tag, int tot_len, int nStrLen, int *bOverflow, char *pStr, int ind, int bPlainTextTags );
45
+ int CleanOrigCoord( MOL_COORD szCoord, int delim );
46
+ int WriteOrigCoord( int num_inp_atoms, MOL_COORD *szMolCoord, int *i, char *szBuf, int buf_len);
47
+ int WriteOrigAtoms( int num_inp_atoms, inp_ATOM *at, int *i, char *szBuf, int buf_len, STRUCT_DATA *sd);
48
+ int WriteOrigBonds( int num_inp_atoms, inp_ATOM *at, int *i, char *szBuf, int buf_len, STRUCT_DATA *sd);
49
+
50
+
51
+ char VER_STRING[64];
52
+
53
+ const char sCompDelim[] = ";"; /* component delimiter */
54
+ const char sIdenticalValues[] = "*"; /* identical component */
55
+
56
+ const char x_space[] = " ";
57
+
58
+ /* xml output: words & additional tags */
59
+ const char x_inchi[] = INCHI_NAME;
60
+ const char x_inchi_ver[] = "version"; /* "InChI.version"; */
61
+ const char x_curr_ver[] = INCHI_VERSION;
62
+
63
+ const char x_structure[] = "structure";
64
+ const char x_number[] = "number";
65
+ const char x_header[] = "id.name";
66
+ const char x_value[] = "id.value";
67
+
68
+ const char x_empty[] = "";
69
+
70
+ const char x_type[] = "type";
71
+
72
+ const char x_message[] = "message";
73
+ const char x_text[] = "value";
74
+
75
+ const char x_ferr[] = "fatal (aborted)";
76
+ const char x_err[] = "error (no InChI)";
77
+ const char x_warn[] = "warning";
78
+
79
+ const char x_basic[] = "identifier";
80
+ const char x_tautomeric[] = "mobile-H";
81
+ const char x_reconnected[] = "reconnected";
82
+
83
+ const char x_ver[] = "version";
84
+
85
+ const char x_type_alpha[] = "alpha";
86
+ const char x_type_numer[] = "numeric";
87
+ const char x_type_predec[] = "sct";
88
+ const char x_type_normal[] = "normal";
89
+ const char x_type_short[] = "compressed";
90
+ const char x_basic_layer[] = "basic";
91
+
92
+ const char x_aux_basic[] = "identifier.auxiliary-info";
93
+ const char x_aux_comm[] = "!-- This section is NOT a part of the identifier, it is not unique --";
94
+
95
+ const char x_ign_uu_sp2[] = "omit_undef_dbond";
96
+ const char x_ign_uu_sp3[] = "omit_undef_sp3";
97
+
98
+ const char x_line_opening[] = "<";
99
+ const char x_line_closing[] = "</";
100
+ const char x_close_line[] = ">";
101
+
102
+
103
+
104
+ const char x_abs[] = "1";
105
+ const char x_rel[] = "2";
106
+ const char x_rac[] = "3";
107
+
108
+
109
+ #define MAX_TAG_LEN 64
110
+
111
+ typedef struct tagInchiTag {
112
+ const char *szPlainLabel;
113
+ const char *szPlainComment;
114
+ const char *szXmlLabel;
115
+ int bAlwaysOutput;
116
+ } INCHI_TAG;
117
+
118
+ /* identifier */
119
+ const INCHI_TAG IdentLbl[] = {
120
+ /* prefixes: may be combined in this order */
121
+ /* IL_FIXH_ORD, */ { "/", "fixed_H", "fixed-H", 0 }, /* fixed H */
122
+ /* IL_ISOT_ORD, */ { "/", "isotopic", "isotopic", 0 }, /* isotopic */
123
+ /* IL_STER_ORD, */ { "/", "stereo", "stereo", 0 }, /* stereo */
124
+ /* items */
125
+ /* IL_VERS_ORD, */ { "" , "version", "version", 1 },
126
+ /* IL_FML__ORD, */ { "/", "formula", "formula", 1 }, /* basic part formula */
127
+ /* IL_CONN_ORD, */ { "/c", "connections", "connections", 1 },
128
+ /* IL_ALLH_ORD, */ { "/h", "H_atoms", "H", 1 },
129
+ /* IL_CHRG_ORD, */ { "/q", "charge", "charge", 1 },
130
+ /* IL_PROT_ORD, */ { "/p", "protons", "protons", 0 },
131
+ /* stereo */
132
+ /* IL_DBND_ORD, */ { "/b", "dbond", "dbond", 0 },
133
+ /* IL_SP3S_ORD, */ { "/t", "sp3", "sp3", 0 },
134
+ /* IL_INVS_ORD, */ { "/m", "sp3:inverted", "abs.inverted", 0 }, /* mirrored */
135
+ /* IL_TYPS_ORD, */ { "/s", "type (1=abs, 2=rel, 3=rac)", "type", 0 }, /* stereo type */
136
+ /* isotopic */
137
+ /* IL_ATMS_ORD, */ { "/i", "atoms", "atoms", 1 },
138
+ /* isotopic mobile H only */
139
+ /* IL_XCGA_ORD, */ { "/h", "exchangeable_H", "H-isotopic", 1 },
140
+ /* fixed H only */
141
+ /* IL_FMLF_ORD, */ { "/f", "formula", "formula", 1 }, /* fixed H formula */
142
+ /* IL_HFIX_ORD, */ { "/h", "H_fixed" , "H-fixed" , 1 }, /* fixed-H */
143
+ /* IL_TRNS_ORD, */ { "/o", "transposition", "transposition", 0 }, /* order */
144
+ /* IL_REC__ORD, */ { "/r", "reconnected bond(s) to metal(s) formula", "formula", 0 }
145
+
146
+ };
147
+ /*
148
+
149
+ Parsing plain text InChI (FML is a chemical formula)
150
+ ========================
151
+
152
+ 1.12Beta/FML /i /f[FML] /i [/o] /rFML /i /f[FML] /i [/o] end
153
+ | | | | | | | | |
154
+ Labels | chqpbtms | hbtms | hqbtms | btms | chqpbtms | hbtms | hqbtms | btms |
155
+ inside: | | | | | | | | |
156
+ | non-iso- | iso- | fix- | iso- | non-iso- | iso- | fix- | iso- |
157
+ meaning: | topic | topic | ed H | topic | topic | topic | ed H | topic |
158
+ |----------+-------+--------+---------|----------+-------+--------+---------|
159
+ | mobile-H | fixed-H | mobile-H | fixed-H |
160
+ |----------+-------+--------+---------|----------+-------+--------+---------|
161
+ | | |
162
+ | normal or disconected metal | reconnected bonds to metal |
163
+ |_____________________________________|_____________________________________|
164
+
165
+ meanings of h:
166
+
167
+ /h - immobile H & mobile H group(s)
168
+ /i/h - exchangeable isotopic H (common)
169
+ /f/h - fixed-H
170
+ /f/i/h - never happens
171
+
172
+ */
173
+
174
+ typedef enum tagIdentLblOrd {
175
+
176
+ IL_FIXH_ORD,
177
+ IL_ISOT_ORD,
178
+ IL_STER_ORD,
179
+
180
+ IL_VERS_ORD,
181
+ IL_FML__ORD,
182
+ IL_CONN_ORD,
183
+ IL_ALLH_ORD,
184
+ IL_CHRG_ORD,
185
+ IL_PROT_ORD,
186
+
187
+ IL_DBND_ORD,
188
+ IL_SP3S_ORD,
189
+ IL_INVS_ORD,
190
+ IL_TYPS_ORD,
191
+
192
+ IL_ATMS_ORD,
193
+
194
+ IL_XCGA_ORD,
195
+
196
+ IL_FMLF_ORD,
197
+ IL_HFIX_ORD,
198
+ IL_TRNS_ORD,
199
+ IL_REC__ORD,
200
+
201
+ IL_MAX_ORD /* max number of tags */
202
+
203
+ } IDENT_LBL_ORD;
204
+
205
+ typedef enum tagIdentLblBit {
206
+
207
+ IL_FIXH = 1 << IL_FIXH_ORD,
208
+ IL_ISOT = 1 << IL_ISOT_ORD,
209
+ IL_STER = 1 << IL_STER_ORD,
210
+
211
+ IL_VERS = 1 << IL_VERS_ORD,
212
+ IL_FML_ = 1 << IL_FML__ORD,
213
+ IL_CONN = 1 << IL_CONN_ORD,
214
+ IL_ALLH = 1 << IL_ALLH_ORD,
215
+ IL_CHRG = 1 << IL_CHRG_ORD,
216
+ IL_PROT = 1 << IL_PROT_ORD,
217
+
218
+ IL_DBND = 1 << IL_DBND_ORD,
219
+ IL_SP3S = 1 << IL_SP3S_ORD,
220
+ IL_INVS = 1 << IL_INVS_ORD,
221
+ IL_TYPS = 1 << IL_TYPS_ORD,
222
+
223
+ IL_ATMS = 1 << IL_ATMS_ORD,
224
+
225
+ IL_XCGA = 1 << IL_XCGA_ORD,
226
+
227
+ IL_FMLF = 1 << IL_FMLF_ORD,
228
+ IL_HFIX = 1 << IL_HFIX_ORD,
229
+ IL_TRNS = 1 << IL_TRNS_ORD,
230
+ IL_REC_ = 1 << IL_REC__ORD
231
+
232
+ } IDENT_LBL_BIT;
233
+
234
+
235
+ /* aux info */
236
+ const INCHI_TAG AuxLbl[] = {
237
+
238
+ /* prefixes may be combined in this order */
239
+ /* AL_FIXH_ORD, */ { "/", "fixed_H", "fixed-H", 0 }, /* fixed-H */
240
+ /* AL_ISOT_ORD, */ { "/", "isotopic", "isotopic", 0 }, /* isotopic */
241
+ /* AL_STER_ORD, */ { "/", "abs_stereo_inverted", "stereo.abs.inverted", 0 }, /* inv abs sp3 stereo */
242
+ /* AL_REVR_ORD, */ { "/", "reversibility", "reversibility", 0 }, /* reversibility */
243
+ /* items */
244
+ /* AL_VERS_ORD, */ { "", "version", "version", 1 },
245
+ /* AL_NORM_ORD, */ { "/", "normalization_type", "norm-type", 1 },
246
+ /* AL_ANBR_ORD, */ { "/N:", "original_atom_numbers", "atom.orig-nbr", 1 },
247
+ /* AL_AEQU_ORD, */ { "/E:", "atom_equivalence", "atom.equivalence", 0 },
248
+ /* AL_GEQU_ORD, */ { "/gE:", "group_equivalence", "group.equivalence", 0 },
249
+ /* inv abs sp3 stereo */
250
+ /* AL_SP3I_ORD, */ { "/it:", "sp3", "sp3", 0 },
251
+ /* AL_SP3N_ORD, */ { "/iN:", "original_atom_numbers", "atom.orig-nbr", 0 },
252
+
253
+ /* AL_CRV__ORD, */ { "/CRV:", "charge_radical_valence", "charges-rad-val", 0 },
254
+ /* reversibility */
255
+ /* AL_ATMR_ORD, */ { "/rA:", "atoms", "atoms", 0 },
256
+ /* AL_BNDR_ORD, */ { "/rB:", "bonds", "bonds", 0 },
257
+ /* AL_XYZR_ORD, */ { "/rC:", "xyz", "xyz", 0 },
258
+ /* fixed-H only */
259
+ /* AL_FIXN_ORD, */ { "/F:", "original_atom_numbers", "atom.orig-nbr", 1 },
260
+ /* isotopic only */
261
+ /* AL_ISON_ORD, */ { "/I:", "original_atom_numbers", "atom.orig-nbr", 1 },
262
+
263
+ /* AL_REC__ORD, */ { "/R:", "reconnected bond(s) to metal(s) part", "", 1 }
264
+
265
+ };
266
+
267
+ typedef enum tagAuxLblOrd {
268
+
269
+ AL_FIXH_ORD,
270
+ AL_ISOT_ORD,
271
+ AL_STER_ORD,
272
+ AL_REVR_ORD,
273
+
274
+ AL_VERS_ORD,
275
+ AL_NORM_ORD,
276
+ AL_ANBR_ORD,
277
+ AL_AEQU_ORD,
278
+ AL_GEQU_ORD,
279
+
280
+ AL_SP3I_ORD,
281
+ AL_SP3N_ORD,
282
+
283
+ AL_CRV__ORD,
284
+
285
+ AL_ATMR_ORD,
286
+ AL_BNDR_ORD,
287
+ AL_XYZR_ORD,
288
+
289
+ AL_FIXN_ORD,
290
+
291
+ AL_ISON_ORD,
292
+
293
+ AL_REC__ORD,
294
+
295
+ AL_MAX_ORD /* max number of tags */
296
+
297
+ } AUX_LBL_ORD;
298
+
299
+
300
+ typedef enum tagAuxLblBit {
301
+
302
+ AL_FIXH = 1 << AL_FIXH_ORD,
303
+ AL_ISOT = 1 << AL_ISOT_ORD,
304
+ AL_STER = 1 << AL_STER_ORD,
305
+ AL_REVR = 1 << AL_REVR_ORD,
306
+
307
+ AL_VERS = 1 << AL_VERS_ORD,
308
+ AL_NORM = 1 << AL_NORM_ORD,
309
+ AL_ANBR = 1 << AL_ANBR_ORD,
310
+ AL_AEQU = 1 << AL_AEQU_ORD,
311
+ AL_GEQU = 1 << AL_GEQU_ORD,
312
+
313
+ AL_SP3I = 1 << AL_SP3I_ORD,
314
+ AL_SP3N = 1 << AL_SP3N_ORD,
315
+
316
+ AL_CRV_ = 1 << AL_CRV__ORD,
317
+
318
+ AL_ATMR = 1 << AL_ATMR_ORD,
319
+ AL_BNDR = 1 << AL_BNDR_ORD,
320
+ AL_XYZR = 1 << AL_XYZR_ORD,
321
+
322
+ AL_FIXN = 1 << AL_FIXN_ORD,
323
+
324
+ AL_ISON = 1 << AL_ISON_ORD,
325
+
326
+ AL_REC_ = 1 << AL_REC__ORD
327
+
328
+ } AUX_LBL_BIT;
329
+
330
+ const int MAX_TAG_NUM = inchi_max((int)IL_MAX_ORD, (int)AL_MAX_ORD);
331
+
332
+ char *szGetTag( const INCHI_TAG *Tag, int nTag, int bTag, char *szTag, int *bAlways );
333
+
334
+
335
+ #define SP(N) (x_space+sizeof(x_space)-1-(N))
336
+ /**********************************************************************************************/
337
+ typedef struct tagXmlEntityRef {
338
+ char nChar;
339
+ const char *pRef;
340
+ } X_REF;
341
+ X_REF xmlRef[] = { {'<', "&lt;"}, {'&', "&amp;"}, {'>', "&gt;"}, {'"', "&quot;"}, {'\'', "&apos;"}, {0, NULL}, };
342
+ const char szRefChars[sizeof(xmlRef)/sizeof(xmlRef[0])] = {'<', '&', '>', '"', '\'', '\0' };
343
+ /**********************************************************************************************/
344
+ int PrintXmlStartTag( char *pStr, int indent, int bEnd, const char *tag,
345
+ const char *l1, int v1, const char *l2, int v2, const char *l3, int v3,
346
+ const char *l4, int v4, const char *l5, int v5, const char *l6, int v6)
347
+ {
348
+ int len=0;
349
+ if ( tag ) {
350
+ len += sprintf( pStr+len, "%s<%s", SP(indent), tag);
351
+ }
352
+ if ( l1 ) {
353
+ len += sprintf( pStr+len, " %s=\"%d\"", l1, v1);
354
+ }
355
+ if ( l2 ) {
356
+ len += sprintf( pStr+len, " %s=\"%d\"", l2, v2);
357
+ }
358
+ if ( l3 ) {
359
+ len += sprintf( pStr+len, " %s=\"%d\"", l3, v3);
360
+ }
361
+ if ( l4 ) {
362
+ len += sprintf( pStr+len, " %s=\"%d\"", l4, v4);
363
+ }
364
+ if ( l5 ) {
365
+ len += sprintf( pStr+len, " %s=\"%d\"", l5, v5);
366
+ }
367
+ if ( l6 ) {
368
+ len += sprintf( pStr+len, " %s=\"%d\"", l6, v6);
369
+ }
370
+ if ( (bEnd & 3) ) {
371
+ len += sprintf( pStr+len, "%s%s", (bEnd & 1)?"/":"", (bEnd & 2)?">":"");
372
+ }
373
+ return len;
374
+ }
375
+ /**********************************************************************************************/
376
+ int Needs2addXmlEntityRefs( const char *s )
377
+ {
378
+ int len = 0;
379
+ const X_REF *q = xmlRef, *r;
380
+ const char *p;
381
+ if ( s && *s ) {
382
+ for ( q = xmlRef, len = 0; q->nChar; q ++ ) {
383
+ for ( p = s; p = strchr( p, q->nChar ); p ++ ) {
384
+ if ( q->nChar == '&' ) {
385
+ for ( r = xmlRef; r->nChar; r ++ ) {
386
+ if ( !memcmp( p, r->pRef, strlen(r->pRef) ) )
387
+ goto DoNotSubstitute;
388
+ }
389
+ }
390
+ len += strlen(q->pRef)-1;
391
+ DoNotSubstitute:;
392
+ }
393
+ }
394
+ if ( len ) {
395
+ len += strlen( s );
396
+ }
397
+ }
398
+ return len;
399
+ }
400
+ /**********************************************************************************************/
401
+ int AddXmlEntityRefs( const char *p, char *d )
402
+ {
403
+ int len_d, n;
404
+ const X_REF *q = xmlRef, *r;
405
+
406
+ len_d = 0;
407
+ while ( *p ) {
408
+ n = strcspn( p, szRefChars );
409
+ if ( n > 0 ) {
410
+ /* first n characters of p do not contain referenced chars; copy them */
411
+ strncpy( d+len_d, p, n ); /* does not have zero termination */
412
+ len_d += n; /* new destination length */
413
+ p += n; /* position of the referenced char in the source */
414
+ }
415
+ if ( *p ) {
416
+ if ( *p == '&' ) {
417
+ for ( r = xmlRef; r->nChar; r ++ ) {
418
+ if ( !memcmp( p, r->pRef, strlen(r->pRef) ) ) {
419
+ d[len_d++] = *p;
420
+ goto DoNotSubstitute;
421
+ }
422
+ }
423
+ }
424
+ q = xmlRef + (strchr( szRefChars, UCINT *p) - szRefChars);
425
+ strcpy( d+len_d, q->pRef ); /* add entity reference and zero termination */
426
+ len_d += strlen( d + len_d ); /* new destination length */
427
+ DoNotSubstitute:
428
+ p ++;
429
+ } else {
430
+ d[len_d] = '\0'; /* add zero termination */
431
+ }
432
+
433
+ }
434
+ return len_d;
435
+ }
436
+
437
+ /**********************************************************************************************/
438
+ int OutputINChIXmlRootStartTag( INCHI_FILE *output_file )
439
+ {
440
+ char pStr[128];
441
+ sprintf( pStr, "<%s %s=\"%s\">", x_inchi, x_inchi_ver, x_curr_ver );
442
+ inchi_print_nodisplay( output_file, "%s\n", pStr );
443
+ return 0;
444
+ }
445
+ /**********************************************************************************************/
446
+ int OutputINChIXmlRootEndTag( INCHI_FILE *output_file )
447
+ {
448
+ char pStr[128];
449
+ sprintf( pStr, "</%s>", x_inchi );
450
+ inchi_print_nodisplay( output_file, "%s\n", pStr );
451
+ return 0;
452
+ }
453
+
454
+ /**********************************************************************************************/
455
+ int OutputINChIXmlStructStartTag( INCHI_FILE *output_file, char *pStr, int ind /* indent*/, int nStrLen, int bNoStructLabels,
456
+ int num_input_struct, const char *szSdfLabel, const char *szSdfValue )
457
+ {
458
+ char szBuf[64];
459
+ int nEstLen1;
460
+ int nEstLen2;
461
+ int ret = 0;
462
+ int tot_len;
463
+ char *pSdfLabel = NULL, *pSdfValue = NULL, *p;
464
+ /* substitute special characters (see szRefChars[]) with xml Entity References */
465
+ int len;
466
+ if ( bNoStructLabels ) {
467
+ /* no labela at all */
468
+ inchi_print( output_file, "%s\n", "" ); /* empty line */
469
+ tot_len = 0;
470
+ tot_len += sprintf(pStr+tot_len, "%s<%s", SP(ind), x_structure);
471
+ tot_len += sprintf(pStr+tot_len, ">" );
472
+ inchi_print( output_file, "%s\n", pStr );
473
+ ret = 1; /* success */
474
+ } else
475
+ if ( !(szSdfLabel && szSdfLabel[0]) && !(szSdfValue && szSdfValue[0]) ) {
476
+ /* only structure number if present */
477
+ inchi_print( output_file, "%s\n", "" ); /* empty line */
478
+ tot_len = 0;
479
+ tot_len += sprintf(pStr+tot_len, "%s<%s", SP(ind), x_structure);
480
+ if ( num_input_struct > 0 ) {
481
+ tot_len += sprintf(pStr+tot_len, " %s=\"%d\"", x_number, num_input_struct);
482
+ }
483
+ tot_len += sprintf(pStr+tot_len, ">" );
484
+ inchi_print( output_file, "%s\n", pStr );
485
+ ret = 1; /* success */
486
+ } else {
487
+ if ( len = Needs2addXmlEntityRefs( szSdfLabel ) ) {
488
+ if ( p = (char*)inchi_malloc( len+1 ) ) {
489
+ AddXmlEntityRefs( szSdfLabel, p );
490
+ szSdfLabel = pSdfLabel = p;
491
+ }
492
+ }
493
+ if ( len = Needs2addXmlEntityRefs( szSdfValue ) ) {
494
+ if ( p = (char*)inchi_malloc( len+1 ) ) {
495
+ AddXmlEntityRefs( szSdfValue, p );
496
+ szSdfValue = pSdfValue = p;
497
+ }
498
+ }
499
+ nEstLen1 = ind + 1 + sizeof(x_structure)-1
500
+ + 1 + sizeof(x_number)-1 + 1 + sprintf(szBuf,"\"%d\"", num_input_struct) + 2;
501
+ nEstLen2 = 1 + sizeof(x_header)-1 + 1 + 2 + (szSdfLabel? strlen(szSdfLabel):0)
502
+ + 1 + sizeof(x_value) -1 + 1 + 2 + (szSdfValue? strlen(szSdfValue):0) + 2;
503
+ if ( nEstLen1 <= nStrLen ) {
504
+ inchi_print( output_file, "%s\n", "" ); /* empty line */
505
+ tot_len = 0;
506
+ tot_len += sprintf(pStr+tot_len, "%s<%s", SP(ind), x_structure);
507
+ tot_len += sprintf(pStr+tot_len, " %s=\"%d\"", x_number, num_input_struct);
508
+ if ( nEstLen1 + nEstLen2 <= nStrLen ) {
509
+ tot_len += sprintf(pStr+tot_len, " %s=\"%s\"", x_header, szSdfLabel? szSdfLabel:x_empty);
510
+ tot_len += sprintf(pStr+tot_len, " %s=\"%s\"", x_value, szSdfValue? szSdfValue:x_empty);
511
+ }
512
+ tot_len += sprintf(pStr+tot_len, ">" );
513
+ inchi_print( output_file, "%s\n", pStr );
514
+ ret = 1; /* success */
515
+ }
516
+ if ( pSdfValue ) {
517
+ inchi_free ( pSdfValue );
518
+ }
519
+ if ( pSdfLabel ) {
520
+ inchi_free( pSdfLabel );
521
+ }
522
+ }
523
+ return ret; /* 0 => Buffer overflow */
524
+ }
525
+ /**********************************************************************************************/
526
+ int OutputINChIXmlStructEndTag( INCHI_FILE *output_file, char *pStr, int nStrLen, int ind )
527
+ {
528
+ if ( output_file && pStr ) {
529
+ int nEstLen1 = ind + 1 + 1 + sizeof(x_structure)-1 + 2;
530
+ if ( nEstLen1 <= nStrLen ) {
531
+ sprintf(pStr, "%s</%s>", SP(ind), x_structure);
532
+ inchi_print( output_file, "%s\n", pStr );
533
+ return 1;
534
+ }
535
+ }
536
+ return 0;
537
+ }
538
+
539
+ /**********************************************************************************************/
540
+ int OutputINChIXmlError( INCHI_FILE *output_file, char *pStr, int nStrLen, int ind,
541
+ /*int nErrorNumber,*/ char *pErrorText, int bError )
542
+ {
543
+ /* char szBuf[64]; */
544
+ const char *pErr;
545
+ char *pNewErrorText=NULL, *szErrorText = pErrorText;
546
+ int nEstLen, len=0, ret = 0;
547
+
548
+ switch( bError ) {
549
+ case _IS_WARNING:
550
+ pErr = x_warn;
551
+ break;
552
+ case _IS_ERROR:
553
+ pErr = x_err;
554
+ break;
555
+ default: /* _IS_FATAL */
556
+ pErr = x_ferr;
557
+ break;
558
+ }
559
+
560
+ #if( ENTITY_REFS_IN_XML_MESSAGES == 1 )
561
+ /* insert xml entity references if necessary */
562
+ if ( len = Needs2addXmlEntityRefs( szErrorText ) ) {
563
+ if ( pNewErrorText = (char*)inchi_malloc( len+1 ) ) {
564
+ AddXmlEntityRefs( szErrorText, pNewErrorText );
565
+ szErrorText = pNewErrorText;
566
+ }
567
+ }
568
+ #else
569
+ szErrorText = pErrorText;
570
+ #endif
571
+
572
+
573
+ nEstLen = ind + 1 + sizeof(x_message)-1
574
+ + 1 + sizeof(x_type)-1 + 1 + 1 + strlen(pErr)-1
575
+ /* + 1 + sizeof(x_code)-1 + 1 + sprintf(szBuf, "%d", nErrorNumber) */
576
+ + 1 + sizeof(x_text)-1 + 1 + 1 + strlen(szErrorText) + 2;
577
+ if ( nEstLen <= nStrLen ) {
578
+ /*
579
+ sprintf( pStr, "%s<%s %s=\"%s\" %s=\"%d\" %s=\"%s\"/>",
580
+ SP(ind), x_message, x_type, pErr, x_code, nErrorNumber, x_text, szErrorText );
581
+ */
582
+ sprintf( pStr, "%s<%s %s=\"%s\" %s=\"%s\"/>",
583
+ SP(ind), x_message, x_type, pErr, x_text, szErrorText );
584
+ inchi_print( output_file, "%s\n", pStr );
585
+ /*
586
+ pErrorText[0] = '\0'; // do not repeat same output
587
+ */
588
+ ret = 1;
589
+ }
590
+ if ( pNewErrorText )
591
+ inchi_free( pNewErrorText );
592
+ return ret;
593
+
594
+ }
595
+ /**********************************************************************************************/
596
+ int OutputINChIPlainError( INCHI_FILE *output_file, char *pStr, int nStrLen,
597
+ char *pErrorText, int bError )
598
+ {
599
+ /* char szBuf[64]; */
600
+ const char *pErr;
601
+ char *pNewErrorText=NULL, *szErrorText = pErrorText;
602
+ int nEstLen, ret = 0;
603
+
604
+ switch( bError ) {
605
+ case _IS_WARNING:
606
+ pErr = x_warn;
607
+ break;
608
+ case _IS_ERROR:
609
+ pErr = x_err;
610
+ break;
611
+ default: /* _IS_FATAL */
612
+ pErr = x_ferr;
613
+ break;
614
+ }
615
+ /* <%s: >, x_message */
616
+ nEstLen = sizeof(x_message)-1 + 1 + 1
617
+ /* <%s=\"%s\">, x_type, pErr */
618
+ + sizeof(x_type)-1 + 1 + 1 + strlen(pErr) + 1
619
+ /* < %s=\"%s\"\n>, x_text, szErrorText */
620
+ + 1 + sizeof(x_text)-1 + 1 + 1 + strlen(szErrorText) + 1 + 1;
621
+ if ( nEstLen < nStrLen ) {
622
+ sprintf( pStr, "%s: %s=\"%s\" %s=\"%s\"",
623
+ x_message, x_type, pErr, x_text, szErrorText );
624
+ inchi_print( output_file, "%s\n", pStr );
625
+ ret = 1;
626
+ }
627
+ if ( pNewErrorText )
628
+ inchi_free( pNewErrorText );
629
+ return ret;
630
+
631
+ }
632
+
633
+ /**************************************************************************/
634
+
635
+ #ifndef OUT_TN /* defined in mode.h; quoted here for reference purposes only */
636
+
637
+ #define OUT_N1 0 /* non-tautomeric only */
638
+ #define OUT_T1 1 /* tautomeric if present otherwise non-tautomeric */
639
+ #define OUT_NT 2 /* only non-taut representations of tautomeric */
640
+ #define OUT_TN 3 /* tautomeric if present otherwise non-tautomeric;
641
+ sepatately output non-taut representations of tautomeric if present */
642
+ /* OUT_TN = OUT_T1 + OUT_NT */
643
+ #endif
644
+
645
+
646
+ /******************************************************************/
647
+ const char *EquString( int EquVal )
648
+ {
649
+ int bFrom = EquVal & (iiSTEREO | iiSTEREO_INV | iiNUMB | iiEQU );
650
+ int bType = EquVal & (iitISO | iitNONTAUT );
651
+ int bEq2 = EquVal & (iiEq2NONTAUT | iiEq2ISO | iiEq2INV );
652
+ const char *r = "";
653
+
654
+ switch ( bFrom ) {
655
+
656
+ case iiSTEREO: /* ------------ Stereo --------------------*/
657
+ switch ( bType ) {
658
+ case iitISO: /* iso main stereo =... */
659
+ switch( bEq2 ) {
660
+ case 0:
661
+ r = "m"; /* iso main stereo = main stereo */
662
+ break;
663
+ default:
664
+ r = "??"; /* should not happen */
665
+ break;
666
+ }
667
+ break;
668
+ case iitNONTAUT: /* non-taut stereo =... */
669
+ switch( bEq2 ) {
670
+ case 0:
671
+ r = "m"; /* non-taut stereo = main stereo */
672
+ break;
673
+ default:
674
+ r = "??"; /* should not happen */
675
+ break;
676
+ }
677
+ break;
678
+ case (iitNONTAUT | iitISO): /* iso non-taut stereo = ... */
679
+ switch( bEq2 ) {
680
+ case 0:
681
+ r = "m"; /* iso non-taut stereo = main stereo */
682
+ break;
683
+ case iiEq2ISO:
684
+ r = "M"; /* iso non-taut stereo = main iso stereo */
685
+ break;
686
+ case iiEq2NONTAUT:
687
+ r = "n"; /* iso non-taut stereo = non-taut stereo */
688
+ break;
689
+ default:
690
+ r = "??"; /* should not happen */
691
+ break;
692
+ }
693
+ break;
694
+ default:
695
+ r = "??"; /* should not happen */
696
+ break;
697
+ }
698
+ break;
699
+
700
+ case iiSTEREO_INV: /*---------- Inverted Aux Stereo ------*/
701
+ if ( bEq2 & iiEq2INV ) { /* stereo = Inverted(another stereo) */
702
+ bEq2 &= ~iiEq2INV;
703
+ switch( bType ) {
704
+ case 0: /* main = ...*/
705
+ switch( bEq2 ) {
706
+ case 0:
707
+ r = "im"; /* main = Inv(main) */
708
+ break;
709
+ case iiEq2ISO:
710
+ r = "iM"; /* main = Inv(main iso) */
711
+ break;
712
+ case iiEq2NONTAUT:
713
+ r = "in"; /* maim = Inv(non-taut) */
714
+ break;
715
+ case (iiEq2NONTAUT | iiEq2ISO):
716
+ r = "iN"; /* maim = Inv(non-taut iso ) */
717
+ break;
718
+ default:
719
+ r = "??"; /* should not happen */
720
+ break;
721
+ }
722
+ break;
723
+ case iitISO: /* main iso = ...*/
724
+ switch( bEq2 ) {
725
+ case 0:
726
+ r = "im"; /* main iso = Inv(main) */
727
+ break;
728
+ case iiEq2ISO:
729
+ r = "iM"; /* main iso = Inv(main iso) */
730
+ break;
731
+ case iiEq2NONTAUT:
732
+ r = "in"; /* maim iso = Inv(non-taut) */
733
+ break;
734
+ case (iiEq2NONTAUT | iiEq2ISO):
735
+ r = "iN"; /* maim = Inv(non-taut iso ) */
736
+ break;
737
+ default:
738
+ r = "??"; /* should not happen */
739
+ break;
740
+ }
741
+ break;
742
+ case iitNONTAUT: /* non-taut = ... */
743
+ switch( bEq2 ) {
744
+ case 0:
745
+ r = "im"; /* non-taut = Inv(main) */
746
+ break;
747
+ case iiEq2ISO:
748
+ r = "iM"; /* non-taut = Inv(main iso) */
749
+ break;
750
+ case iiEq2NONTAUT:
751
+ r = "in"; /* non-taut = Inv(non-taut) */
752
+ break;
753
+ case (iiEq2NONTAUT | iiEq2ISO):
754
+ r = "iN"; /* non-taut = Inv(non-taut iso ) */
755
+ break;
756
+ default:
757
+ r = "??"; /* should not happen */
758
+ break;
759
+ }
760
+ break;
761
+ case (iitNONTAUT | iitISO):
762
+ switch( bEq2 ) {
763
+ case 0:
764
+ r = "im"; /* non-taut iso = Inv(main) */
765
+ break;
766
+ case iiEq2ISO:
767
+ r = "iM"; /* non-taut iso = Inv(main iso) */
768
+ break;
769
+ case iiEq2NONTAUT:
770
+ r = "in"; /* non-taut iso = Inv(non-taut) */
771
+ break;
772
+ case (iiEq2NONTAUT | iiEq2ISO):
773
+ r = "iN"; /* non-taut iso = Inv(non-taut iso ) */
774
+ break;
775
+ default:
776
+ r = "??"; /* should not happen */
777
+ }
778
+ break;
779
+ default:
780
+ r = "??"; /* should not happen */
781
+ break;
782
+ }
783
+
784
+ } else { /* Inv stereo = another (non-inverted) stereo */
785
+
786
+ switch( bType ) {
787
+ case iitISO: /* main iso = ...*/
788
+ switch( bEq2 ) {
789
+ case 0:
790
+ r = "m"; /* main = (inverted aux) main */
791
+ break;
792
+ default:
793
+ r = "??"; /* should not happen */
794
+ break;
795
+ }
796
+ break;
797
+ case iitNONTAUT: /* non-taut = ... */
798
+ switch( bEq2 ) {
799
+ case 0:
800
+ r = "m"; /* non-taut = (inverted aux) main */
801
+ break;
802
+ default:
803
+ r = "??"; /* should not happen */
804
+ break;
805
+ }
806
+ break;
807
+ case (iitNONTAUT | iitISO): /* non-taut iso = ...*/
808
+ switch( bEq2 ) {
809
+ case 0:
810
+ r = "m"; /* non-taut iso = (inverted aux) main */
811
+ break;
812
+ case iiEq2ISO:
813
+ r = "M"; /* non-taut iso = (inverted aux) main iso */
814
+ break;
815
+ case iiEq2NONTAUT:
816
+ r = "n"; /* non-taut iso = (inverted aux) non-taut */
817
+ break;
818
+ default:
819
+ r = "??"; /* should not happen */
820
+ break;
821
+ }
822
+ break;
823
+ default:
824
+ r = "??"; /* should not happen */
825
+ break;
826
+ }
827
+ }
828
+ break;
829
+
830
+ case ( iiNUMB | iiSTEREO_INV): /*------------- Inv Stereo Numbering ------------*/
831
+ switch( bType ) {
832
+ case 0: /* inv stereo numb main = ...*/
833
+ switch( bEq2 ) {
834
+ case 0:
835
+ r = "m"; /* inv stereo numb main = main numb */
836
+ break;
837
+ default:
838
+ r = "??"; /* should not happen */
839
+ break;
840
+ }
841
+ break;
842
+ case iitISO: /* inv stereo iso numb main = ...*/
843
+ switch( bEq2 ) {
844
+ case 0:
845
+ r = "m"; /* inv stereo iso numb main = main numb */
846
+ break;
847
+ case iiEq2INV:
848
+ r = "im"; /* inv stereo iso numb main = InvStereo(main) numb */
849
+ break;
850
+ case iiEq2ISO:
851
+ r = "M"; /* inv stereo iso numb main = isotopic main numb */
852
+ break;
853
+ default:
854
+ r = "??"; /* should not happen */
855
+ break;
856
+ }
857
+ break;
858
+ case iitNONTAUT: /* inv stereo numb non-taut = ... */
859
+ switch( bEq2 ) {
860
+ case 0:
861
+ r = "m"; /* inv stereo numb non-taut = main numb */
862
+ break;
863
+ case iiEq2NONTAUT:
864
+ r = "n"; /* inv stereo numb non-taut = non-taut numb */
865
+ break;
866
+ case iiEq2INV:
867
+ r = "im"; /* inv stereo numb non-taut = InvStereo(main) numb */
868
+ break;
869
+ default:
870
+ r = "??"; /* should not happen */
871
+ break;
872
+ }
873
+ break;
874
+ case (iitNONTAUT | iitISO): /* inv stereo numb non-taut iso = ... */
875
+ switch( bEq2 ) {
876
+ case 0:
877
+ r = "m"; /* inv stereo numb non-taut iso = main numb */
878
+ break;
879
+ case iiEq2ISO:
880
+ r = "M"; /* inv stereo numb non-taut iso = main numb iso */
881
+ break;
882
+ case (iiEq2ISO | iiEq2INV):
883
+ r = "iM"; /* inv stereo numb non-taut iso = InvStereo(main iso) numb */
884
+ break;
885
+ case iiEq2NONTAUT:
886
+ r = "n"; /* inv stereo numb non-taut iso = non-taut numb */
887
+ break;
888
+ case (iiEq2NONTAUT | iiEq2ISO):
889
+ r = "N"; /* inv stereo numb non-taut iso = non-taut iso numb */
890
+ break;
891
+ case iiEq2INV:
892
+ r = "im"; /* inv stereo numb non-taut iso = InvStereo(main) numb */
893
+ break;
894
+ case (iiEq2NONTAUT | iiEq2INV):
895
+ r = "in"; /* inv stereo numb non-taut iso = InvStereo(non-taut) numb ) */
896
+ break;
897
+ default:
898
+ r = "??"; /* should not happen */
899
+ break;
900
+ }
901
+ break;
902
+ default:
903
+ r = "??"; /* should not happen */
904
+ break;
905
+ }
906
+ break;
907
+
908
+ case iiNUMB: /*------------- Canonical Numbering ------------*/
909
+ switch( bType ) {
910
+ case 0: /* numb main = ...*/
911
+ r = "??"; /* should not happen */
912
+ break;
913
+ case iitISO: /* iso numb main = ...*/
914
+ switch( bEq2 ) {
915
+ case 0:
916
+ r = "m"; /* iso numb main = main numb */
917
+ break;
918
+ default:
919
+ r = "??"; /* should not happen */
920
+ }
921
+ break;
922
+ case iitNONTAUT: /* numb non-taut = ... */
923
+ switch( bEq2 ) {
924
+ case 0:
925
+ r = "m"; /* numb non-taut = main numb */
926
+ break;
927
+ default:
928
+ r = "??"; /* should not happen */
929
+ }
930
+ break;
931
+ case (iitNONTAUT | iitISO): /* numb non-taut iso = ... */
932
+ switch( bEq2 ) {
933
+ case 0:
934
+ r = "m"; /* numb non-taut iso = main numb */
935
+ break;
936
+ case iiEq2ISO:
937
+ r = "M"; /* numb non-taut iso = main numb iso */
938
+ break;
939
+ case iiEq2NONTAUT:
940
+ r = "n"; /* numb non-taut iso = non-taut numb */
941
+ break;
942
+ default:
943
+ r = "??"; /* should not happen */
944
+ break;
945
+ }
946
+ break;
947
+ default:
948
+ r = "??"; /* should not happen */
949
+ break;
950
+ }
951
+ break;
952
+
953
+ case iiEQU: /*------------- Atom Equivalence ------------*/
954
+ switch( bType ) {
955
+ case 0: /* equivalence main = ...*/
956
+ r = "??"; /* should not happen */
957
+ break;
958
+ case iitISO: /* equivalence main iso = ...*/
959
+ switch( bEq2 ) {
960
+ case 0:
961
+ r = "m"; /* equivalence main = main equ */
962
+ break;
963
+ default:
964
+ r = "??"; /* should not happen */
965
+ break;
966
+ }
967
+ break;
968
+ case iitNONTAUT: /* equivalence non-taut = ... */
969
+ switch( bEq2 ) {
970
+ case 0:
971
+ r = "m"; /* equivalence non-taut = main equ */
972
+ break;
973
+ default:
974
+ r = "??"; /* should not happen */
975
+ break;
976
+ }
977
+ break;
978
+ case (iitNONTAUT | iitISO): /* equivalence non-taut iso = ... */
979
+ switch( bEq2 ) {
980
+ case 0:
981
+ r = "m"; /* equivalence non-taut iso = main equ */
982
+ break;
983
+ case iiEq2ISO:
984
+ r = "M"; /* equivalence non-taut iso = main iso equ */
985
+ break;
986
+ case iiEq2NONTAUT:
987
+ r = "n"; /* equivalence non-taut iso = non-taut equ */
988
+ break;
989
+ default:
990
+ r = "??"; /* should not happen */
991
+ break;
992
+ }
993
+ break;
994
+ default:
995
+ r = "??"; /* should not happen */
996
+ break;
997
+ }
998
+ break;
999
+ default:
1000
+ r = "??"; /* should not happen */
1001
+ break;
1002
+ }
1003
+ return r;
1004
+ }
1005
+
1006
+ /**********************************************************************************************/
1007
+
1008
+ #define OUT_NONTAUT OUT_NN /* was OUT_NT until 2004-04-07 */
1009
+
1010
+ /**********************************************************************************************/
1011
+ int OutputINChI2( char *pStr, int nStrLen, INCHI_SORT *pINChISortTautAndNonTaut2[][TAUT_NUM], int iINChI,
1012
+ ORIG_STRUCT *pOrigStruct,
1013
+ int bDisconnectedCoord, int bOutputType, int bINChIOutputOptions, int bXml, int bAbcNumbers,
1014
+ int bCtPredecessors, int bNoStructLabels,
1015
+ int num_components2[], int num_non_taut2[], int num_taut2[],
1016
+ INCHI_FILE *output_file, INCHI_FILE *log_file, int num_input_struct,
1017
+ const char *szSdfLabel, const char *szSdfValue, long lSdfId, int *pSortPrintINChIFlags )
1018
+ {
1019
+ int bINChIOutputOptions0 = bINChIOutputOptions & ~(INCHI_OUT_XML | INCHI_OUT_PLAIN_TEXT | INCHI_OUT_PLAIN_TEXT_COMMENTS);
1020
+ int bINChIOutputOptionsCur;
1021
+ int bCurOption, ret, i;
1022
+
1023
+ ret = 0;
1024
+
1025
+ for ( i = 0; i < 3; i ++ ) {
1026
+ switch( i ) {
1027
+ case 0:
1028
+ bCurOption = INCHI_OUT_XML;
1029
+ break;
1030
+ case 1:
1031
+ bCurOption = INCHI_OUT_PLAIN_TEXT;
1032
+ break;
1033
+ case 2:
1034
+ bCurOption = INCHI_OUT_PLAIN_TEXT_COMMENTS;
1035
+ break;
1036
+ default:
1037
+ continue;
1038
+ }
1039
+ if ( bINChIOutputOptions & bCurOption ) {
1040
+ bINChIOutputOptionsCur = bINChIOutputOptions0 | bCurOption;
1041
+ if ( i != 1 ) {
1042
+ bINChIOutputOptionsCur &= ~INCHI_OUT_TABBED_OUTPUT;
1043
+ }
1044
+ ret |= OutputINChI1( pStr, nStrLen, pINChISortTautAndNonTaut2, iINChI,
1045
+ pOrigStruct, bDisconnectedCoord, bOutputType, bINChIOutputOptionsCur, bXml, bAbcNumbers,
1046
+ bCtPredecessors, bNoStructLabels,
1047
+ num_components2, num_non_taut2, num_taut2,
1048
+ output_file, log_file, num_input_struct,
1049
+ szSdfLabel, szSdfValue, lSdfId, pSortPrintINChIFlags );
1050
+ }
1051
+ }
1052
+ return ret;
1053
+ }
1054
+
1055
+ /**********************************************************************************/
1056
+ char *szGetTag( const INCHI_TAG *Tag, int nTag, int bTag, char *szTag, int *bAlways )
1057
+ {
1058
+ int i, j, bit, num, len;
1059
+ if ( 0 < nTag && nTag < 3 ) {
1060
+ /* no plain text comments: pick up the last tag */
1061
+ for ( i = 0, j = -1, bit = 1; i < MAX_TAG_NUM; i ++, bit <<= 1 ) {
1062
+ if ( bTag & bit ) {
1063
+ j = i;
1064
+ }
1065
+ }
1066
+ if ( j >= 0 ) {
1067
+ strcpy( szTag, nTag == 1? Tag[j].szXmlLabel : nTag == 2? Tag[j].szPlainLabel : "???" );
1068
+ if ( nTag != 2 ) {
1069
+ *bAlways = Tag[j].bAlwaysOutput;
1070
+ }
1071
+ return szTag;
1072
+ }
1073
+ } else
1074
+ if ( nTag == 3 ) {
1075
+ /* plain text with comments */
1076
+ szTag[0] = '{';
1077
+ szTag[1] = '\0';
1078
+ for ( i = 0, j = -1, bit = 1, num=0; i < MAX_TAG_NUM; i ++, bit <<= 1 ) {
1079
+ if ( bTag & bit ) {
1080
+ j = i;
1081
+ if ( num ++ ) {
1082
+ strcat( szTag, ":" );
1083
+ }
1084
+ strcat( szTag, Tag[i].szPlainComment );
1085
+ }
1086
+ }
1087
+ if ( num ) {
1088
+ strcat( szTag, "}" );
1089
+ num = strlen( Tag[j].szPlainLabel );
1090
+ len = strlen( szTag );
1091
+ if ( len ) {
1092
+ memmove( szTag + num, szTag, len+1 );
1093
+ memcpy( szTag, Tag[j].szPlainLabel, num );
1094
+ } else {
1095
+ strcpy ( szTag, Tag[j].szPlainLabel );
1096
+ }
1097
+ *bAlways = Tag[j].bAlwaysOutput;
1098
+ } else {
1099
+ strcpy( szTag, "???" );
1100
+ }
1101
+ return szTag;
1102
+ }
1103
+ strcpy( szTag, "???" );
1104
+ return szTag;
1105
+ }
1106
+
1107
+
1108
+ /**********************************************************************************************/
1109
+ /* sorting in descending order: return -1 if *p1 > *p2, return +1 if *p1 < *p2 */
1110
+ /**********************************************************************************************/
1111
+ int OutputINChI1( char *pStr, int nStrLen, INCHI_SORT *pINChISortTautAndNonTaut2[][TAUT_NUM], int iINChI,
1112
+ ORIG_STRUCT *pOrigStruct,
1113
+ int bDisconnectedCoord, int bOutputType, int bINChIOutputOptions, int bXml, int bAbcNumbers,
1114
+ int bCtPredecessors, int bNoStructLabels,
1115
+ int num_components2[], int num_non_taut2[], int num_taut2[],
1116
+ INCHI_FILE *output_file, INCHI_FILE *log_file, int num_input_struct,
1117
+ const char *szSdfLabel, const char *szSdfValue, long lSdfId, int *pSortPrintINChIFlags )
1118
+ {
1119
+ /*
1120
+ bINChIOutputOptions bits:
1121
+
1122
+ INCHI_OUT_NO_AUX_INFO 0x0001 do not output Aux Info
1123
+ INCHI_OUT_SHORT_AUX_INFO 0x0002 output short version of Aux Info
1124
+ INCHI_OUT_ONLY_AUX_INFO 0x0004 output only Aux Info
1125
+ INCHI_OUT_EMBED_REC 0x0008 embed reconnected INChI into disconnected INChI
1126
+
1127
+ */
1128
+ /*int ATOM_MODE = ((bAbcNumbers?2:0)|5|(bCtPredecessors?8:0));*/
1129
+ int ATOM_MODE = ((bAbcNumbers?CT_MODE_ABC_NUMBERS:0)
1130
+ | CT_MODE_ATOM_COUNTS
1131
+ | CT_MODE_NO_ORPHANS
1132
+ #if( EQL_H_NUM_TOGETHER == 1 )
1133
+ | CT_MODE_EQL_H_TOGETHER
1134
+ #endif
1135
+ #if( ABC_CT_NUM_CLOSURES == 1 )
1136
+ | (bAbcNumbers && bCtPredecessors? CT_MODE_ABC_NUM_CLOSURES:0)
1137
+ #endif
1138
+ | (bCtPredecessors?CT_MODE_PREDECESSORS:0));
1139
+
1140
+ int TAUT_MODE = (bAbcNumbers?CT_MODE_ABC_NUMBERS:0);
1141
+ char sDifSegs[DIFL_LENGTH][DIFS_LENGTH];
1142
+ /* bOutputType =
1143
+ TAUT_YES => tautomeric only (if no tautomeric components then no output;
1144
+ TAUT_NON => only non-tautomeric output (if no non-taut present then no output;
1145
+ TAUT_BOTH => tautomeric and non-tautomeric */
1146
+
1147
+ int i, j, ii, jj, /*ii2, jj2,*/ tot_len, tot_len2, bOverflow, bEmbeddedOutputCalled=0;
1148
+ int bIsotopic, bTautIsoHNum, bTautIsoAt, bHasIsotopicAtoms[TAUT_NUM];
1149
+ int bStereoSp2[TAUT_NUM], bStereoSp3[TAUT_NUM];
1150
+ int bIsotopicStereoSp2[TAUT_NUM], bIsotopicStereoSp3[TAUT_NUM];
1151
+ int bStereoAbsInverted[TAUT_NUM], bIsotopicStereoAbsInverted[TAUT_NUM];
1152
+ int bStereoAbs[TAUT_NUM], bIsotopicStereoAbs[TAUT_NUM];
1153
+ int bAtomEqu[TAUT_NUM], bTautEqu[TAUT_NUM], bIsotopicAtomEqu[TAUT_NUM], bIsotopicTautEqu[TAUT_NUM];
1154
+ int bInvStereo[TAUT_NUM], bInvIsotopicStereo[TAUT_NUM];
1155
+ int bInvStereoOrigNumb[TAUT_NUM], bInvIsotopicStereoOrigNumb[TAUT_NUM], bIsotopicOrigNumb[TAUT_NUM];
1156
+ int bTautomeric, bNonTautomeric, bTautomericAcid, bHardAddRemProton, iCurTautMode;
1157
+ int bRequestedRacemicStereo=0, bRequestedRelativeStereo = 0, bRelRac;
1158
+ int bRacemicStereo[TAUT_NUM], bRelativeStereo[TAUT_NUM];
1159
+ int bIsotopicRacemicStereo[TAUT_NUM], bIsotopicRelativeStereo[TAUT_NUM];
1160
+ int bChargesRadVal[TAUT_NUM], bOrigCoord[TAUT_NUM];
1161
+ int bIgn_UU_Sp3[TAUT_NUM], bIgn_UU_Sp2[TAUT_NUM];
1162
+ int bIgn_UU_Sp3_Iso[TAUT_NUM], bIgn_UU_Sp2_Iso[TAUT_NUM];
1163
+ int ind, inc, bNonTautIsIdenticalToTaut = 1;
1164
+ int bNonTautNonIsoIdentifierNotEmpty = 0, bNonTautIsoIdentifierNotEmpty = 0;
1165
+ INCHI_SORT **pINChISortTautAndNonTaut = pINChISortTautAndNonTaut2[iINChI];
1166
+ INCHI_SORT *pINChISort =pINChISortTautAndNonTaut[TAUT_YES];
1167
+ INCHI_SORT *pINChISort2=pINChISortTautAndNonTaut[TAUT_YES];
1168
+ INCHI_SORT *is, *is2;
1169
+ INChI *pINChI /*, *pINChI2*/;
1170
+ INChI_Aux *pINChI_Aux = NULL;
1171
+
1172
+ int ret = 0; /* 0=>failed, 1=>success */
1173
+ int bOutType = bOutputType; /* ??? */
1174
+ int nTag;
1175
+ int bTautomericOutputAllowed, bSecondNonTautPass;
1176
+ int num_components = num_components2[iINChI];
1177
+ int num_comp[TAUT_NUM], max_num_comp;
1178
+ int num_iso_H[NUM_H_ISOTOPES], bHasIsoH;
1179
+ int nNumRemovedProtons, nNumMovedProtons;
1180
+ int bTautAndNonTaut, bTautIsNonTaut;
1181
+
1182
+ int bAlways = 0;
1183
+ int bUseMulipliers = 1;
1184
+ int bOmitRepetitions = 1;
1185
+ int bPlainTextTags = 2; /* 0 => no plain tags, 1=> plain text tags, 2=>plaintext tags without consecutive // */
1186
+ int bPlainText = 0 != (bINChIOutputOptions & (INCHI_OUT_PLAIN_TEXT | INCHI_OUT_PLAIN_TEXT_COMMENTS));
1187
+ int bPlainTextCommnts = 0 != (bINChIOutputOptions & INCHI_OUT_PLAIN_TEXT_COMMENTS);
1188
+ int bPlainTabbedOutput;
1189
+ int bTag1, bTag2, bTag3, bFhTag; /* tag bits */
1190
+ int nCurINChISegment, nSegmAction;
1191
+ char szTag1[MAX_TAG_LEN], szTag2[MAX_TAG_LEN], szTag3[MAX_TAG_LEN];
1192
+ const char *pLF, *pTAB;
1193
+ bXml = 0 != (bINChIOutputOptions & INCHI_OUT_XML);
1194
+ nTag = bPlainTextCommnts? 3 : bPlainText? 2 : bXml? 1 : 0; /* tag type */
1195
+ ind = bXml? 1 : -1;
1196
+ inc = bXml? 1 : -1;
1197
+ pLF = bPlainTextCommnts? "\n" : "\0";
1198
+ bFhTag = 0;
1199
+ bPlainTabbedOutput = 0 != (bINChIOutputOptions & INCHI_OUT_TABBED_OUTPUT) &&
1200
+ bPlainText && !bXml && !bPlainTextCommnts;
1201
+ #if ( !defined(INCHI_LIBRARY) && !defined(INCHI_LIB) )
1202
+ pTAB = bPlainTabbedOutput? "\t" : "\n";
1203
+ #else
1204
+ pTAB = "\n";
1205
+ #endif
1206
+
1207
+ memset( sDifSegs, DIFV_BOTH_EMPTY, sizeof(sDifSegs) );
1208
+
1209
+ if ( !pStr ) {
1210
+ my_fprintf( log_file, "Cannot allocate output buffer. No output for structure #%d.%s%s%s%s\n", num_input_struct, SDF_LBL_VAL(szSdfLabel, szSdfValue) );
1211
+ return ret;
1212
+ }
1213
+
1214
+ bSecondNonTautPass = 0;
1215
+ /* -- commented out to allow empty InChI --
1216
+ if (!num_components ) {
1217
+ return 0;
1218
+ }
1219
+ */
1220
+ /* init version string */
1221
+ if ( !VER_STRING[0] ) {
1222
+ strcpy(VER_STRING, "(V");
1223
+ strcat(VER_STRING, INCHI_VERSION);
1224
+ strcat(VER_STRING, ")");
1225
+ }
1226
+ for ( i = 0; i < TAUT_NUM; i ++ ) {
1227
+ bHasIsotopicAtoms[i] = num_comp[i] =
1228
+ bStereoSp2[i] = bStereoSp3[i] =
1229
+ bIsotopicStereoSp2[i] = bIsotopicStereoSp3[i] =
1230
+ bIsotopicOrigNumb[i] =
1231
+ bStereoAbs[i] = bIsotopicStereoAbs[i] =
1232
+ bStereoAbsInverted[i] = bIsotopicStereoAbsInverted[i] =
1233
+ bRacemicStereo[i] = bRelativeStereo[i] =
1234
+ bIsotopicRacemicStereo[i] = bIsotopicRelativeStereo[i] =
1235
+ bAtomEqu[i] = bTautEqu[i] =
1236
+ bIsotopicAtomEqu[i] = bIsotopicTautEqu[i] =
1237
+ bInvStereo[i] = bInvIsotopicStereo[i] =
1238
+ bInvStereoOrigNumb[i] = bInvIsotopicStereoOrigNumb[i] =
1239
+ bIgn_UU_Sp3[i] = bIgn_UU_Sp2[i] =
1240
+ bIgn_UU_Sp3_Iso[i] = bIgn_UU_Sp2_Iso[i] =
1241
+ bChargesRadVal[i] = bOrigCoord[i] = 0;
1242
+ }
1243
+ /* find if it is isotopic */
1244
+ bIsotopic = bTautomeric = bNonTautomeric =
1245
+ bTautomericAcid = bHardAddRemProton = bTautIsoHNum = bTautIsoAt = 0;
1246
+ bTautAndNonTaut = bTautIsNonTaut = 0;
1247
+ /*
1248
+ x = bStereo, bStereoSp2, bStereoSp3, bStereoAbsInverted,
1249
+ bIsotopicStereo, bIsotopicStereoSp2, bIsotopicStereoSp3, bIsotopicStereoAbsInverted
1250
+
1251
+ OUT_N1: x[TAUT_NON] refers to non-tautomeric only
1252
+ OUT_T1: x[TAUT_YES] refers to tautomeric if exists otherwise non-tautomeric
1253
+ OUT_NT: x[TAUT_NON] refers to non-taut representations of tautomeric
1254
+ OUT_TN: x[TAUT_YES] refers to tautomeric if exists otherwise non-tautomeric
1255
+ x[TAUT_NON] refers to non-taut representations of tautomeric
1256
+ */
1257
+
1258
+ memset( num_iso_H, 0, sizeof(num_iso_H) );
1259
+ nNumRemovedProtons = 0;
1260
+ nNumMovedProtons = 0;
1261
+ bHasIsoH = 0;
1262
+ bTautomericOutputAllowed = (bOutType==OUT_T1 || bOutType== OUT_TN);
1263
+ pINChISort=pINChISortTautAndNonTaut[bTautomericOutputAllowed? TAUT_YES : TAUT_NON];
1264
+ is = pINChISort;
1265
+ is2 = (bOutType== OUT_TN)? pINChISortTautAndNonTaut[TAUT_NON] : NULL;
1266
+ for ( i = 0, is2 = pINChISortTautAndNonTaut[TAUT_NON]; i < num_components; i ++, is ++, is2? is2++:NULL ) {
1267
+ CompINChILayers( is, is2, sDifSegs );
1268
+ bNonTautIsIdenticalToTaut = bNonTautIsIdenticalToTaut && !CompINChITautVsNonTaut(is, is2, 1);
1269
+ if ( is && (pINChI_Aux = is->pINChI_Aux[TAUT_YES]) ) {
1270
+ for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
1271
+ bHasIsoH += abs(pINChI_Aux->nNumRemovedIsotopicH[j]);
1272
+ num_iso_H[j] += pINChI_Aux->nNumRemovedIsotopicH[j];
1273
+ }
1274
+ nNumRemovedProtons += pINChI_Aux->nNumRemovedProtons;
1275
+ nNumMovedProtons += abs(pINChI_Aux->nNumRemovedProtons);
1276
+ }
1277
+ if ( bTautomericOutputAllowed ) {
1278
+ /* check for removed isotopic H */
1279
+ for ( j = TAUT_YES; j < TAUT_NUM; j ++ ) {
1280
+ switch ( bOutType ) {
1281
+ case OUT_N1: /* x[TAUT_NON]: non-tautomeric only -- never happens */
1282
+ jj = GET_II(bOutType,is);
1283
+ if ( jj != j )
1284
+ continue;
1285
+ ii = TAUT_NON;
1286
+ break;
1287
+ case OUT_T1: /* x[TAUT_YES]: tautomeric if present otherwise non-tautomeric */
1288
+ jj = GET_II(bOutType,is);
1289
+ if ( jj != j )
1290
+ continue;
1291
+ ii = TAUT_YES;
1292
+ break;
1293
+ case OUT_NT: /* x[TAUT_NON]: only non-taut representations of tautomeric -- never happens */
1294
+ jj = GET_II(bOutType,is);
1295
+ if ( jj != j )
1296
+ continue;
1297
+ ii = TAUT_NON;
1298
+ break;
1299
+ /* main path of control flow */
1300
+ case OUT_TN: /* x[TAUT_YES]: tautomeric if present otherwise non-tautomeric;
1301
+ * x[TAUT_NON]: non-taut only if tautomeric is present */
1302
+ jj = ( j == TAUT_YES )? GET_II(OUT_T1,is) : ( j == TAUT_NON )? GET_II(OUT_NT,is) : -1;
1303
+ if ( jj == TAUT_YES ) { /* Fix12 */
1304
+ if ( is->pINChI[jj]->lenTautomer > 0 ) {
1305
+ bTautAndNonTaut += (!is->pINChI[jj]->bDeleted && HAS_N(is));
1306
+ } else {
1307
+ bTautIsNonTaut ++;
1308
+ }
1309
+ }
1310
+ if ( jj < 0 )
1311
+ continue;
1312
+ ii = j;
1313
+ break;
1314
+ default:
1315
+ continue;
1316
+ }
1317
+ if ( jj != j )
1318
+ continue;
1319
+ if ( (pINChI = is->pINChI[jj]) && pINChI->nNumberOfAtoms > 0 && (pINChI_Aux = is->pINChI_Aux[jj]) ) {
1320
+ bTautIsoHNum += (pINChI_Aux->nNumRemovedIsotopicH[0] +
1321
+ pINChI_Aux->nNumRemovedIsotopicH[1] +
1322
+ pINChI_Aux->nNumRemovedIsotopicH[2]);
1323
+ bTautIsoAt += (pINChI->nNumberOfIsotopicAtoms>0 || pINChI->nNumberOfIsotopicTGroups > 0 );
1324
+ }
1325
+ }
1326
+ }
1327
+ }
1328
+ sDifSegs[DIFL_M ][DIFS_p_PROTONS] = nNumRemovedProtons? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
1329
+ sDifSegs[DIFL_MI][DIFS_h_H_ATOMS] = bHasIsoH? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
1330
+
1331
+ MarkUnusedAndEmptyLayers( sDifSegs );
1332
+
1333
+
1334
+
1335
+
1336
+ bNonTautIsIdenticalToTaut = bNonTautIsIdenticalToTaut && !bTautIsoHNum;
1337
+ /*********************************************************************************************/
1338
+ for ( i = 0, is = pINChISort; i < num_components; i ++, is ++ )
1339
+ {
1340
+ int bCurIso, bCurStereo, bCurIsoStereo, bCurHasIsoStereo /* Fix14 */, bCurTaut /*, bCurTaut2*/;
1341
+ int bCompExists, bCurIsoHPos, bCurIsoHStereo;
1342
+ int bCurStereoSp2, bCurIsoStereoSp2, bCurStereoSp3, bCurIsoStereoSp3, bCurIsoStereoSp3Inv;
1343
+ int bCurRacemic, bCurRelative, bCurIsoRacemic, bCurIsoRelative;
1344
+ bCompExists = 0;
1345
+ for ( j = TAUT_NON; j < TAUT_NUM; j ++ ) {
1346
+ switch ( bOutType ) {
1347
+ case OUT_N1: /* x[TAUT_NON]: non-tautomeric only */
1348
+ jj = GET_II(bOutType,is);
1349
+ if ( jj != j )
1350
+ continue;
1351
+ ii = TAUT_NON;
1352
+ break;
1353
+ case OUT_T1: /* x[TAUT_YES]: tautomeric if present otherwise non-tautomeric */
1354
+ jj = GET_II(bOutType,is);
1355
+ if ( jj != j )
1356
+ continue;
1357
+ ii = TAUT_YES;
1358
+ break;
1359
+ case OUT_NT: /* x[TAUT_NON]: only non-taut representations of tautomeric */
1360
+ jj = GET_II(bOutType,is);
1361
+ if ( jj != j )
1362
+ continue;
1363
+ ii = TAUT_NON;
1364
+ break;
1365
+ /* main control flow comes here: requested both mobile and fixed H results */
1366
+ case OUT_TN: /* x[TAUT_YES]: tautomeric if present otherwise non-tautomeric;
1367
+ * x[TAUT_NON]: non-taut only if tautomeric is present */
1368
+ jj = ( j == TAUT_YES )? GET_II(OUT_T1,is) : ( j == TAUT_NON )? GET_II(OUT_NT,is) : -1;
1369
+ if ( jj < 0 ) {
1370
+ /* Fix12 */
1371
+ if ( bTautAndNonTaut && bTautIsNonTaut &&
1372
+ j == TAUT_NON && 0 <= (jj = GET_II(OUT_T1,is)) &&
1373
+ !is->pINChI[jj]->bDeleted && !is->pINChI[jj]->lenTautomer ) {
1374
+ ; /* the requested non-tautomeric component is in tautomeric position
1375
+ (is->pINChI[TAUT_YES]);
1376
+ process it also as non-tautomeric if Fixed-H layer was requested */
1377
+ } else {
1378
+ continue;
1379
+ }
1380
+ }
1381
+ ii = j; /* ii is what we wanted; jj is what we found (0 = TAUT_NON: fixed_H, 1 = TAUT_YES: mobile_H) */
1382
+ /* -- not used 2004-09-16 ---
1383
+ if ( is2 ) {
1384
+ jj2 = ( j == TAUT_YES )? GET_II(OUT_T1,is2) : ( j == TAUT_NON )? GET_II(OUT_NT,is2) : -1;
1385
+ if ( jj2 >= 0 ) {
1386
+ ii2 = j;
1387
+ } else {
1388
+ ii2 = -1;
1389
+ }
1390
+ } else {
1391
+ jj2 = ii2 = -1;
1392
+ }
1393
+ -----------------------------*/
1394
+ break;
1395
+ default:
1396
+ continue;
1397
+ }
1398
+ if ( (pINChI = is->pINChI[jj]) && pINChI->nNumberOfAtoms > 0 ) {
1399
+ /*pINChI_Aux = is->pINChI_Aux[jj];*/
1400
+ bCompExists ++;
1401
+ bCurTaut = (pINChI->lenTautomer > 0);
1402
+ bCurIso = (pINChI->nNumberOfIsotopicAtoms>0 || pINChI->nNumberOfIsotopicTGroups > 0 );
1403
+ bCurIsoHPos = (pINChI->nPossibleLocationsOfIsotopicH && pINChI->nPossibleLocationsOfIsotopicH[0] > 1 || pINChI->lenTautomer > 1);
1404
+ /* present isotopic H + their possible positions AND/OR isotopic atoms */
1405
+ bCurIsoHStereo = bCurIsoHPos && (bTautIsoHNum || bTautIsoAt) || bCurIso;
1406
+ if ( jj == j && pINChI->bDeleted ) {
1407
+ num_comp[j] --;
1408
+ if ( bCurTaut ) {
1409
+ bTautomeric |= 1; /* tautomeric representation is present */
1410
+ bNonTautomeric |= HAS_N(is);
1411
+ }
1412
+ bIsotopic |= bCurIso;
1413
+ continue; /* deleted H(+) in tautomeric representation */
1414
+ }
1415
+ bCurStereoSp2 = pINChI->Stereo && (pINChI->Stereo->nNumberOfStereoBonds > 0);
1416
+ bCurHasIsoStereo =
1417
+ bCurStereoSp3 = pINChI->Stereo && (pINChI->Stereo->nNumberOfStereoCenters > 0 );
1418
+ bCurIsoStereoSp2 = bCurIsoHStereo && pINChI->StereoIsotopic && (pINChI->StereoIsotopic->nNumberOfStereoBonds > 0);
1419
+ bCurIsoStereoSp3 = bCurIsoHStereo && pINChI->StereoIsotopic && (pINChI->StereoIsotopic->nNumberOfStereoCenters > 0);
1420
+ bCurIsoStereoSp3Inv = bCurIsoStereoSp3 && pINChI->StereoIsotopic->nCompInv2Abs; /* inversion changes sp3 stereo */
1421
+ bRequestedRacemicStereo |= (0!=(pINChI->nFlags & INCHI_FLAG_RAC_STEREO));
1422
+ bRequestedRelativeStereo |= (0!=(pINChI->nFlags & INCHI_FLAG_REL_STEREO));
1423
+ /* check whether isotopic stereo is same as non-isotopic; if same than do not output isotopic stereo */
1424
+ if ( bCurStereoSp2 && bCurIsoStereoSp2 ) {
1425
+ bCurIsoStereoSp2 = !Eql_INChI_Stereo( pINChI->Stereo, EQL_SP2, pINChI->StereoIsotopic, EQL_SP2, 0 );
1426
+ }
1427
+ if ( bCurStereoSp3 && bCurIsoStereoSp3 ) {
1428
+ /* bCurIsoStereoSp3=0 means (iso stereo sp3) = (non-iso stereo sp3) or (iso stereo sp3) = Inv(non-iso stereo sp3) */
1429
+ bCurIsoStereoSp3 = !Eql_INChI_Stereo( pINChI->Stereo, EQL_SP3, pINChI->StereoIsotopic, EQL_SP3,
1430
+ (pINChI->nFlags & INCHI_FLAG_RAC_STEREO) || (pINChI->nFlags & INCHI_FLAG_REL_STEREO) );
1431
+ if ( !bCurIsoStereoSp3 ) {
1432
+ /* inversion changes iso sp3 differently from non-iso sp3 Fix11 */
1433
+ bCurIsoStereoSp3Inv &= (pINChI->StereoIsotopic->nCompInv2Abs != pINChI->Stereo->nCompInv2Abs);
1434
+ }
1435
+ }
1436
+
1437
+ bCurRelative = bRequestedRelativeStereo && bCurStereoSp3;
1438
+ #if( REL_RAC_STEREO_IGN_1_SC == 1 )
1439
+ bCurRelative = bCurRelative &&
1440
+ (pINChI->Stereo->nNumberOfStereoCenters > 1 ) &&
1441
+ (pINChI->Stereo->nCompInv2Abs != 0) &&
1442
+ #endif
1443
+
1444
+
1445
+
1446
+ bCurIsoRelative = bRequestedRelativeStereo && (bCurIsoStereoSp3 || bCurIsoStereoSp3Inv);
1447
+ #if( REL_RAC_STEREO_IGN_1_SC == 1 )
1448
+ bCurIsoRelative = bCurIsoRelative &&
1449
+ (pINChI->StereoIsotopic->nNumberOfStereoCenters > 1 ) &&
1450
+ (pINChI->StereoIsotopic->nCompInv2Abs != 0) &&
1451
+ #endif
1452
+
1453
+
1454
+ bCurRacemic = bRequestedRacemicStereo && bCurStereoSp3;
1455
+ #if( REL_RAC_STEREO_IGN_1_SC == 1 )
1456
+ bCurRacemic = bCurRacemic &&
1457
+ (pINChI->Stereo->nCompInv2Abs != 0) &&
1458
+ (pINChI->Stereo->nNumberOfStereoCenters > 0 ) ?
1459
+ pINChI->Stereo->nNumberOfStereoCenters : 0;
1460
+ #endif
1461
+
1462
+ bCurIsoRacemic = bRequestedRacemicStereo && (bCurIsoStereoSp3 || bCurIsoStereoSp3Inv);
1463
+ #if( REL_RAC_STEREO_IGN_1_SC == 1 )
1464
+ bCurIsoRacemic = bCurIsoRacemic &
1465
+ (pINChI->StereoIsotopic->nCompInv2Abs != 0) &&
1466
+ (pINChI->StereoIsotopic->nNumberOfStereoCenters > 0 ) ?
1467
+ pINChI->StereoIsotopic->nNumberOfStereoCenters : 0;
1468
+ #endif
1469
+ if ( bRequestedRelativeStereo ) {
1470
+ bCurStereoSp3 = bCurRelative || bCurStereoSp3 && (pINChI->Stereo->nNumberOfStereoCenters > 1 ); /* Fix11 */
1471
+ bCurIsoStereoSp3 = bCurIsoRelative ? bCurIsoStereoSp3 : 0;
1472
+ } else
1473
+ if ( bRequestedRacemicStereo ) {
1474
+ bCurStereoSp3 = bCurRacemic > 1 || bCurStereoSp3 && (pINChI->Stereo->nNumberOfStereoCenters > 1 ); /* Fix11 */
1475
+ bCurIsoStereoSp3 = bCurIsoRacemic > 1? bCurIsoStereoSp3 : 0;
1476
+ }
1477
+ bCurStereo = bCurStereoSp2 || bCurStereoSp3;
1478
+ bCurIsoStereo = bCurIsoStereoSp2 || bCurIsoStereoSp3;
1479
+
1480
+ bIsotopic |= bCurIso;
1481
+ bHasIsotopicAtoms[ii] |= bCurIso;
1482
+ bStereoSp2[ii] |= bCurStereoSp2;
1483
+ bStereoSp3[ii] |= bCurStereoSp3;
1484
+ bIgn_UU_Sp3[ii] |= !bCurStereoSp3 && (pINChI->nFlags & INCHI_FLAG_SC_IGN_ALL_UU);
1485
+ bIgn_UU_Sp2[ii] |= !bCurStereoSp2 && (pINChI->nFlags & INCHI_FLAG_SB_IGN_ALL_UU);
1486
+ bIsotopicStereoSp2[ii] |= bCurIsoStereoSp2;
1487
+ bIsotopicStereoSp3[ii] |= bCurIsoStereoSp3;
1488
+ bIgn_UU_Sp3_Iso[ii] |= !bCurIsoStereoSp3 && (pINChI->nFlags & INCHI_FLAG_SC_IGN_ALL_ISO_UU);
1489
+ bIgn_UU_Sp2_Iso[ii] |= !bCurIsoStereoSp2 && (pINChI->nFlags & INCHI_FLAG_SB_IGN_ALL_ISO_UU);
1490
+ bStereoAbs[ii] |= bCurStereoSp3 && (pINChI->Stereo->nCompInv2Abs != 0);
1491
+ bStereoAbsInverted[ii] |= bCurStereoSp3 && (pINChI->Stereo->nCompInv2Abs < 0);
1492
+ /* Fix08: missing isotopic inverted flag if isotopic = inverted non-isotopic */
1493
+ bIsotopicStereoAbsInverted[ii] |= bCurIsoStereoSp3 && (pINChI->StereoIsotopic->nCompInv2Abs < 0) ||
1494
+ !bCurIsoStereoSp3 && pINChI->StereoIsotopic && pINChI->Stereo &&
1495
+ pINChI->StereoIsotopic->nCompInv2Abs &&
1496
+ pINChI->StereoIsotopic->nCompInv2Abs != pINChI->Stereo->nCompInv2Abs;
1497
+ /* Fix 11: missing /s1 if only isotopic stereo is inverted */
1498
+ bIsotopicStereoAbs[ii] |= bCurIsoStereoSp3 && (pINChI->StereoIsotopic->nCompInv2Abs != 0) ||
1499
+ !bCurIsoStereoSp3 && pINChI->StereoIsotopic && pINChI->Stereo &&
1500
+ pINChI->StereoIsotopic->nCompInv2Abs &&
1501
+ pINChI->StereoIsotopic->nCompInv2Abs != pINChI->Stereo->nCompInv2Abs;
1502
+
1503
+ bRelativeStereo[ii] |= bCurRelative;
1504
+ bIsotopicRelativeStereo[ii] |= bCurIsoRelative;
1505
+ bRacemicStereo[ii] |= bCurRacemic;
1506
+ bIsotopicRacemicStereo[ii] |= bCurIsoRacemic;
1507
+
1508
+ bTautomericAcid |= (0!=(pINChI->nFlags & INCHI_FLAG_ACID_TAUT));
1509
+ bHardAddRemProton |= (0!=(pINChI->nFlags & INCHI_FLAG_HARD_ADD_REM_PROTON));
1510
+ if ( bCurTaut ) {
1511
+ bTautomeric |= 1; /* tautomeric representation is present */
1512
+ /* does tautomeric structure have also a non-tautomeric repesentation? */
1513
+ bNonTautomeric |= HAS_N(is);
1514
+ }
1515
+
1516
+ /* auxiliary info */
1517
+ if ( !(bINChIOutputOptions & INCHI_OUT_NO_AUX_INFO) && (pINChI_Aux = is->pINChI_Aux[jj]) ) {
1518
+ /* detect presence of constitutional equivalence onfo */
1519
+ int bCurEqu, bCurTautEqu=0, bCurIsoEqu=0, bCurIsoTautEqu=0; /* Fix15-disabled */
1520
+ bAtomEqu[ii] |= (bCurEqu = bHasEquString( pINChI_Aux->nConstitEquNumbers,
1521
+ pINChI_Aux->nNumberOfAtoms));
1522
+ if ( bCurTaut ) {
1523
+ bTautEqu[ii] |= (bCurTautEqu = bHasEquString( pINChI_Aux->nConstitEquTGroupNumbers,
1524
+ pINChI_Aux->nNumberOfTGroups));
1525
+ }
1526
+ if ( bCurIso ) {
1527
+ bIsotopicAtomEqu[ii] |= (bCurIsoEqu = bHasEquString( pINChI_Aux->nConstitEquIsotopicNumbers,
1528
+ pINChI_Aux->nNumberOfAtoms)) /*|| bCurEqu*/;
1529
+ if ( bCurTaut ) {
1530
+ bIsotopicTautEqu[ii] |= (bCurIsoTautEqu = bHasEquString( pINChI_Aux->nConstitEquIsotopicTGroupNumbers,
1531
+ pINChI_Aux->nNumberOfTGroups)) /*|| bCurTautEqu*/;
1532
+ }
1533
+ /* non-zero if isotopic numbering for inverted isotopic stereo is different */
1534
+ bIsotopicOrigNumb[ii] |= bCurHasIsoStereo && /* Fix14 */
1535
+ pINChI_Aux->nOrigAtNosInCanonOrdInv &&
1536
+ pINChI_Aux->nIsotopicOrigAtNosInCanonOrd &&
1537
+ (0 != memcmp( pINChI_Aux->nOrigAtNosInCanonOrdInv,
1538
+ pINChI_Aux->nIsotopicOrigAtNosInCanonOrd,
1539
+ sizeof(pINChI_Aux->nOrigAtNosInCanonOrdInv[0])
1540
+ * pINChI_Aux->nNumberOfAtoms));
1541
+
1542
+ }
1543
+ /* inverted stereo */
1544
+ if ( bCurStereoSp3 && pINChI->Stereo->nCompInv2Abs ) {
1545
+ bInvStereo[ii] |= 1;
1546
+ bInvStereoOrigNumb[ii] |= pINChI_Aux->nOrigAtNosInCanonOrd &&
1547
+ pINChI_Aux->nOrigAtNosInCanonOrdInv &&
1548
+ (0 != memcmp( pINChI_Aux->nOrigAtNosInCanonOrd,
1549
+ pINChI_Aux->nOrigAtNosInCanonOrdInv,
1550
+ sizeof(pINChI_Aux->nOrigAtNosInCanonOrd[0])
1551
+ * pINChI_Aux->nNumberOfAtoms));
1552
+ }
1553
+ /* inverted isotopic stereo */
1554
+ if ( bCurIsoStereoSp3 && pINChI->StereoIsotopic->nCompInv2Abs ) {
1555
+ bInvIsotopicStereo[ii] |= 1;
1556
+ bInvIsotopicStereoOrigNumb[ii] |= pINChI_Aux->nIsotopicOrigAtNosInCanonOrd &&
1557
+ pINChI_Aux->nIsotopicOrigAtNosInCanonOrdInv &&
1558
+ (0 != memcmp( pINChI_Aux->nIsotopicOrigAtNosInCanonOrd,
1559
+ pINChI_Aux->nIsotopicOrigAtNosInCanonOrdInv,
1560
+ sizeof(pINChI_Aux->nIsotopicOrigAtNosInCanonOrd[0])
1561
+ * pINChI_Aux->nNumberOfAtoms));
1562
+ }
1563
+ if ( pINChI_Aux->OrigInfo && bHasOrigInfo(pINChI_Aux->OrigInfo, pINChI_Aux->nNumberOfAtoms) ) {
1564
+ bChargesRadVal[ii] |= 1;
1565
+ }
1566
+ }
1567
+ }
1568
+ }
1569
+ if ( bCompExists ) {
1570
+ for ( j = TAUT_NON; j < TAUT_NUM; j ++ ) {
1571
+ num_comp[j] ++;
1572
+ }
1573
+ }
1574
+ }
1575
+ if ( bTautomeric /*&& bTautomericAcid*/ ) { /* "&& bTautomericAcid" commented out 2004-06-02 */
1576
+ bTautomeric += bTautomericAcid; /* long-range tautomerism */
1577
+ bTautomeric += (bHardAddRemProton? 4 : 0);
1578
+ }
1579
+ if ( bRequestedRacemicStereo || bRequestedRelativeStereo ) {
1580
+ /* do not output inverted stereo info */
1581
+ for ( i = 0; i < TAUT_NUM; i ++ ) {
1582
+ /* Fix11 */
1583
+ bStereoAbsInverted[i] =
1584
+ bStereoAbs[i] =
1585
+ bInvStereo[i] =
1586
+ bInvStereoOrigNumb[i] = 0;
1587
+ /* bIsotopicRelativeStereo[i]=0 may happen because iso stereo is same or inverted non-iso stereo */
1588
+ bIsotopicStereoAbsInverted[i] =
1589
+ bIsotopicStereoAbs[i] =
1590
+ bInvIsotopicStereo[i] =
1591
+ bInvIsotopicStereoOrigNumb[i] = 0;
1592
+ /* -- commented out: Fix11--
1593
+ if ( bRacemicStereo[i] || bRelativeStereo[i] ) {
1594
+ bStereoAbsInverted[i] =
1595
+ bStereoAbs[i] =
1596
+ bInvStereo[i] =
1597
+ bInvStereoOrigNumb[i] = 0;
1598
+ }
1599
+ if ( bIsotopicRacemicStereo[i] || bIsotopicRelativeStereo[i] ) {
1600
+ bIsotopicStereoAbsInverted[i] =
1601
+ bIsotopicStereoAbs[i] =
1602
+ bInvIsotopicStereo[i] =
1603
+ bInvIsotopicStereoOrigNumb[i] = 0;
1604
+ }
1605
+ */
1606
+ }
1607
+ }
1608
+
1609
+
1610
+ iCurTautMode = bOutType == OUT_N1? TAUT_NON: /* only non-taut */
1611
+ bOutType == OUT_T1? TAUT_YES: /* tautomeric if present, otherwise non-tautomeric */
1612
+ bOutType == OUT_NT? TAUT_NON: /* only non-taut representations of tautomeric */
1613
+ bOutType == OUT_TN? TAUT_YES: /* tautomeric if present otherwise non-tautomeric; */
1614
+ -1; /* separately output non-taut representations of tautomeric if present */
1615
+
1616
+ if ( iCurTautMode < 0 ) {
1617
+ return 0; /* error */
1618
+ }
1619
+
1620
+ if ( bXml ) {
1621
+ ind += inc* (1+iINChI);
1622
+ }
1623
+
1624
+ bOverflow = 0;
1625
+
1626
+ num_components = num_comp[iCurTautMode];
1627
+
1628
+ max_num_comp = inchi_max(num_comp[TAUT_NON], num_comp[TAUT_YES]);
1629
+
1630
+ if ( bINChIOutputOptions & INCHI_OUT_ONLY_AUX_INFO ) {
1631
+ goto output_aux_info;
1632
+ }
1633
+
1634
+ nCurINChISegment = DIFL_M;
1635
+
1636
+ /******************************************
1637
+ *
1638
+ * Structure (Compound) Header
1639
+ *
1640
+ ******************************************/
1641
+ if ( bXml ) {
1642
+ /* -- moved to the line above goto output_aux_info;
1643
+ ind += inc* (1+iINChI);
1644
+ */
1645
+ /* basic title, version */
1646
+ if ( INCHI_BAS == iINChI ) {
1647
+ inchi_print( output_file, "\n" ); /* empty line */
1648
+ }
1649
+ tot_len = sprintf(pStr, "%s<%s %s=\"%s\"",
1650
+ SP(ind), x_basic, x_ver, x_curr_ver);
1651
+ if ( INCHI_REC == iINChI || INCHI_BAS == iINChI && bDisconnectedCoord ) {
1652
+ tot_len += sprintf(pStr+tot_len, " %s=\"%d\"", x_reconnected, iINChI );
1653
+ }
1654
+ if ( bAbcNumbers || bCtPredecessors ) {
1655
+ const char *pNumber = "";
1656
+ const char *pDelim = "";
1657
+ const char *pCtType = "";
1658
+ if ( bAbcNumbers && bCtPredecessors ) {
1659
+ pNumber = x_type_short;
1660
+ } else {
1661
+ pNumber = bAbcNumbers? x_type_alpha : x_type_numer;
1662
+ pDelim = (bAbcNumbers && bCtPredecessors)? "-":"";
1663
+ pCtType = bCtPredecessors? x_type_predec:"";
1664
+ }
1665
+ /* type */
1666
+ tot_len += sprintf(pStr+tot_len, " %s=\"%s%s%s\"", x_type, pNumber, pDelim, pCtType);
1667
+ }
1668
+ sprintf(pStr+tot_len,">");
1669
+ inchi_print( output_file, "%s\n", pStr );
1670
+ ind += inc;
1671
+ } else
1672
+ if ( INCHI_BAS == iINChI ) { /* eliminate empty line in plain text output */
1673
+ if ( bNoStructLabels ) {
1674
+ ;
1675
+ /* -- removed empty line before InChI ---
1676
+ #ifndef INCHI_LIBRARY
1677
+ inchi_print( output_file, "\n" );
1678
+ #else
1679
+ ;
1680
+ #endif
1681
+ */
1682
+ } else
1683
+ if ( !(szSdfLabel && szSdfLabel[0]) && !(szSdfValue && szSdfValue[0]) ) {
1684
+ tot_len = sprintf( pStr, "%sStructure: %d", pLF, num_input_struct );
1685
+ inchi_print( output_file, "%s%s", pStr, pTAB );
1686
+ } else {
1687
+ tot_len = sprintf( pStr, "%sStructure: %d.%s%s%s%s",
1688
+ pLF,
1689
+ num_input_struct,
1690
+ SDF_LBL_VAL(szSdfLabel, szSdfValue) );
1691
+ if ( lSdfId ) {
1692
+ tot_len --;
1693
+ tot_len += sprintf( pStr + tot_len, ":%ld", lSdfId );
1694
+ }
1695
+ inchi_print( output_file, "%s%s", pStr, pTAB );
1696
+ }
1697
+ inchi_print( output_file, "%s%s=%s", pLF, INCHI_NAME, pLF );
1698
+ }
1699
+ /*****************************************************
1700
+ *
1701
+ * version (10-29-2003)
1702
+ *
1703
+ ****************************************************/
1704
+ if ( INCHI_BAS == iINChI || !(bINChIOutputOptions & INCHI_OUT_EMBED_REC) /* || !bXml */) {
1705
+ /* xml: only if the first or not embedded; plain: always */
1706
+ szGetTag( IdentLbl, nTag, bTag1 = IL_VERS, szTag1, &bAlways );
1707
+ tot_len = str_LineStart( szTag1, NULL, 0, pStr, ind );
1708
+ tot_len += sprintf(pStr + tot_len, "%s", x_curr_ver);
1709
+ /*if ( bXml ) {*/ /* avoid leading slash in plain output */
1710
+ if ( str_LineEnd( szTag1, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -1, bPlainTextTags ) )
1711
+ goto exit_function;
1712
+ /*}*/
1713
+ inchi_print( output_file, "%s%s", pStr, pLF );
1714
+ }
1715
+ /*****************************************************
1716
+ *
1717
+ * atoms, connection tables and tautomeric info
1718
+ *
1719
+ ****************************************************/
1720
+ /******************* constitution: dot-disconnected Hill formulas: <formula> */
1721
+ if ( num_components2[0] || num_components2[1] ) {
1722
+ szGetTag( IdentLbl, nTag, bTag1 = INCHI_REC == iINChI? IL_REC_ : IL_FML_, szTag1, &bAlways );
1723
+ tot_len = str_LineStart( szTag1, NULL, 0, pStr, ind );
1724
+ tot_len = str_HillFormula(pINChISort, pStr, nStrLen, tot_len,
1725
+ &bOverflow, bOutType, num_components, bUseMulipliers);
1726
+
1727
+ if ( str_LineEnd( szTag1, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -1, 1 ) )
1728
+ goto exit_function;
1729
+ inchi_print( output_file, "%s%s", pStr, pLF );
1730
+ }
1731
+ /**************** semicolon/dot-disconnected connection tables */
1732
+ szGetTag( IdentLbl, nTag, bTag1 = IL_CONN, szTag1, &bAlways );
1733
+ tot_len = str_LineStart( szTag1, NULL, 0, pStr, ind );
1734
+ tot_len2 = str_Connections(pINChISort, pStr, nStrLen, tot_len,
1735
+ &bOverflow, bOutType, ATOM_MODE, num_components, bUseMulipliers);
1736
+ /* current version does not output empty (";;;;") connectivity */
1737
+ if ( tot_len != tot_len2 /*|| !bXml*/ ) { /* 2004-06-30: never output empty connection table */
1738
+ tot_len = tot_len2;
1739
+ if ( str_LineEnd( szTag1, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -2, bPlainTextTags ) )
1740
+ goto exit_function; /* pStr overfow */
1741
+ inchi_print( output_file, "%s%s", pStr, pLF );
1742
+ }
1743
+ /************** hydrogen atoms; do not output empty */
1744
+ if ( INCHI_SEGM_FILL == INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_h_H_ATOMS] ) ) {
1745
+ szGetTag( IdentLbl, nTag, bTag1 = IL_ALLH, szTag1, &bAlways );
1746
+ tot_len = str_LineStart( szTag1, NULL, 0, pStr, ind );
1747
+ tot_len2 = str_H_atoms(pINChISort, pStr, nStrLen, tot_len,
1748
+ &bOverflow, bOutType, ATOM_MODE, TAUT_MODE,
1749
+ num_components, bUseMulipliers);
1750
+ if ( tot_len != tot_len2 /*|| !bXml*/ ) { /* 2004-06-21: never output empty */
1751
+ tot_len = tot_len2;
1752
+ if ( str_LineEnd( szTag1, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -2, 1 ) )
1753
+ goto exit_function;
1754
+ inchi_print( output_file, "%s%s", pStr, pLF );
1755
+ }
1756
+ }
1757
+
1758
+ bFhTag = 0;
1759
+
1760
+ repeat_INChI_output:
1761
+ /*****************************************************
1762
+ * charge
1763
+ */
1764
+ nSegmAction = INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_q_CHARGE] );
1765
+ if ( nSegmAction ) {
1766
+ szGetTag( IdentLbl, nTag, bTag1 = IL_CHRG | bFhTag, szTag1, &bAlways );
1767
+ tot_len = str_LineStart( szTag1, NULL, 0, pStr, ind );
1768
+ if ( INCHI_SEGM_FILL == nSegmAction ) {
1769
+ tot_len = str_Charge2(pINChISort, pINChISort2, pStr, nStrLen, tot_len,
1770
+ &bOverflow, bOutType, num_components,
1771
+ bSecondNonTautPass, bOmitRepetitions, bUseMulipliers);
1772
+ bNonTautNonIsoIdentifierNotEmpty += bSecondNonTautPass;
1773
+ }
1774
+ if ( str_LineEnd( szTag1, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -nSegmAction, bPlainTextTags ) )
1775
+ goto exit_function;
1776
+ inchi_print( output_file, "%s%s", pStr, pLF );
1777
+ } else
1778
+ if ( !bXml ) {
1779
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "/" );
1780
+ }
1781
+
1782
+ /*****************************************************
1783
+ * removed protons
1784
+ */
1785
+
1786
+ if ( iCurTautMode == TAUT_YES && !bSecondNonTautPass ) {
1787
+ nSegmAction = INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_p_PROTONS] );
1788
+ if ( nSegmAction ) {
1789
+ szGetTag( IdentLbl, nTag, bTag1 = IL_PROT | bFhTag, szTag1, &bAlways );
1790
+ tot_len = str_LineStart( szTag1, NULL, 0, pStr, ind );
1791
+ tot_len += sprintf( pStr + tot_len, "%+d", nNumRemovedProtons );
1792
+ if ( str_LineEnd( szTag1, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -nSegmAction, bPlainTextTags ) )
1793
+ goto exit_function;
1794
+ inchi_print( output_file, "%s%s", pStr, pLF );
1795
+ } else
1796
+ if ( !bXml ) {
1797
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "/" );
1798
+ }
1799
+ }
1800
+
1801
+ /**************************************************
1802
+ *
1803
+ * non-isotopic stereo
1804
+ */
1805
+
1806
+ if ( INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_b_SBONDS] ) ||
1807
+ INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_t_SATOMS] ) ||
1808
+ INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_m_SP3INV] ) ||
1809
+ INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_s_STYPE] ) )
1810
+ {
1811
+ /* stereo */
1812
+ szGetTag( IdentLbl, nTag, bTag1 = IL_STER | bFhTag, szTag1, &bAlways );
1813
+ if ( bXml ) {
1814
+ str_LineStart( szTag1, NULL, 0, pStr, ind );
1815
+ inchi_print( output_file, "%s\n", pStr );
1816
+ ind += inc;
1817
+ }
1818
+ /* sp2 */
1819
+ /*if ( bStereoSp2[iCurTautMode] )*/
1820
+ if ( nSegmAction = INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_b_SBONDS] ) )
1821
+ {
1822
+ szGetTag( IdentLbl, nTag, bTag2 = bTag1 | IL_DBND, szTag2, &bAlways );
1823
+ tot_len = str_LineStart( szTag2, NULL, 0, pStr, ind );
1824
+ if ( INCHI_SEGM_FILL == nSegmAction ) {
1825
+ tot_len = str_Sp2(pINChISort, pINChISort2, pStr, nStrLen, tot_len,
1826
+ &bOverflow, bOutType, TAUT_MODE, num_components,
1827
+ bSecondNonTautPass, bOmitRepetitions, bUseMulipliers);
1828
+ bNonTautNonIsoIdentifierNotEmpty += bSecondNonTautPass;
1829
+ }
1830
+ if ( str_LineEnd( szTag2, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -nSegmAction, bPlainTextTags ) )
1831
+ goto exit_function;
1832
+ inchi_print( output_file, "%s%s", pStr, pLF );
1833
+ } else
1834
+ if ( !bXml ) {
1835
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "/" ); /* sp2 */
1836
+ }
1837
+
1838
+ /* sp3 */
1839
+ /*if ( bStereoSp3[iCurTautMode] )*/
1840
+ if ( nSegmAction = INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_t_SATOMS] ) )
1841
+ {
1842
+ bRelRac = bRelativeStereo[iCurTautMode] || bRacemicStereo[iCurTautMode];
1843
+ szGetTag( IdentLbl, nTag, bTag2 = bTag1 | IL_SP3S, szTag2, &bAlways );
1844
+ tot_len = str_LineStart( szTag2, NULL, 0, pStr, ind );
1845
+ if ( INCHI_SEGM_FILL == nSegmAction ) {
1846
+ tot_len = str_Sp3(pINChISort, pINChISort2, pStr, nStrLen, tot_len,
1847
+ &bOverflow, bOutType, TAUT_MODE, num_components, bRelRac,
1848
+ bSecondNonTautPass, bOmitRepetitions, bUseMulipliers);
1849
+ bNonTautNonIsoIdentifierNotEmpty += bSecondNonTautPass;
1850
+ }
1851
+ if ( str_LineEnd( szTag2, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -nSegmAction, bPlainTextTags ) )
1852
+ goto exit_function;
1853
+ inchi_print( output_file, "%s%s", pStr, pLF );
1854
+ } else
1855
+ if ( !bXml ) {
1856
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "/" ); /* sp3 */
1857
+ }
1858
+
1859
+ /* bStereoAbsInverted[iCurTautMode] */
1860
+ /*if ( bStereoAbs[iCurTautMode] )*/
1861
+ if ( nSegmAction = INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_m_SP3INV] ) )
1862
+ {
1863
+ szGetTag( IdentLbl, nTag, bTag2 = bTag1 | IL_INVS, szTag2, &bAlways );
1864
+ tot_len = str_LineStart( szTag2, NULL, 0, pStr, ind );
1865
+ if ( INCHI_SEGM_FILL == nSegmAction ) {
1866
+ tot_len = str_StereoAbsInv(pINChISort, pStr, nStrLen, tot_len,
1867
+ &bOverflow, bOutType, num_components);
1868
+ bNonTautNonIsoIdentifierNotEmpty += bSecondNonTautPass;
1869
+ }
1870
+ if ( str_LineEnd( szTag2, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -nSegmAction, bPlainTextTags ) )
1871
+ goto exit_function;
1872
+ inchi_print( output_file, "%s%s", pStr, pLF );
1873
+ } else
1874
+ if ( !bXml ) {
1875
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "/" ); /* stereo-abs-inv */
1876
+ }
1877
+
1878
+ /* stereo type */
1879
+ /*if ( bRacemicStereo[iCurTautMode] || bRelativeStereo[iCurTautMode] || bStereoAbs[iCurTautMode] )*/
1880
+ if ( nSegmAction = INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_s_STYPE] ) )
1881
+ {
1882
+ const char *p_stereo = bRelativeStereo[iCurTautMode]? x_rel :
1883
+ bRacemicStereo[iCurTautMode] ? x_rac : x_abs;
1884
+ szGetTag( IdentLbl, nTag, bTag2 = bTag1 | IL_TYPS, szTag2, &bAlways );
1885
+ tot_len = str_LineStart( szTag2, NULL, 0, pStr, ind );
1886
+ if ( INCHI_SEGM_FILL == nSegmAction ) {
1887
+ tot_len += MakeDelim( p_stereo, pStr + tot_len, nStrLen-tot_len, &bOverflow);
1888
+ bNonTautNonIsoIdentifierNotEmpty += bSecondNonTautPass;
1889
+ }
1890
+ if ( str_LineEnd( szTag2, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -nSegmAction, bPlainTextTags ) )
1891
+ goto exit_function;
1892
+ inchi_print( output_file, "%s%s", pStr, pLF );
1893
+ }
1894
+ if ( !bXml ) {
1895
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "/" ); /* no abs, inv or racemic stereo */
1896
+ }
1897
+ if ( bXml ) {
1898
+ /* close stereo */
1899
+ ind -= inc;
1900
+ if ( str_LineEnd( szTag1, 0, nStrLen, &bOverflow, pStr, ind, bPlainTextTags ) )
1901
+ goto exit_function;
1902
+ inchi_print( output_file, "%s", pStr );
1903
+ }
1904
+ } else
1905
+ if ( !bXml ) {
1906
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "////" ); /* sp3, sp2, abs-inv, stereo.type */
1907
+ }
1908
+ /****************************************************
1909
+ *
1910
+ * Isotopic canonical results
1911
+ *
1912
+ ****************************************************/
1913
+ nCurINChISegment ++; /* switch from M to MI or from F to FI */
1914
+
1915
+ /*if ( bIsotopic || !bSecondNonTautPass && bHasIsoH )*/
1916
+ if ( INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_i_IATOMS] ) )
1917
+ {
1918
+ /* isotopic #1: composition -- atoms -- do not output in xml if empty */
1919
+ szGetTag( IdentLbl, nTag, bTag1 = IL_ISOT | bFhTag, szTag1, &bAlways );
1920
+ if ( bXml ) {
1921
+ str_LineStart( szTag1, NULL, 0, pStr, ind );
1922
+ inchi_print( output_file, "%s\n", pStr );
1923
+ ind += inc;
1924
+ }
1925
+ /* isotopic atoms without mobile H.
1926
+ * Fixed 2004-06-15: always output if not bXml. Note:
1927
+ * Previous condition if( bHasIsotopicAtoms[iCurTautMode] || bIsotopic && !bXml)
1928
+ * did not optput /i in case of only mobile isotopic H
1929
+ */
1930
+ if ( nSegmAction = INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_i_IATOMS] ) )
1931
+ {
1932
+ szGetTag( IdentLbl, nTag, bTag2 = bTag1 | IL_ATMS, szTag2, &bAlways );
1933
+ tot_len = str_LineStart( szTag2, NULL, 0, pStr, ind );
1934
+ /*if ( bHasIsotopicAtoms[iCurTautMode] )*/
1935
+ if ( INCHI_SEGM_FILL == nSegmAction )
1936
+ {
1937
+ tot_len2 = str_IsoAtoms(pINChISort, pINChISort2, pStr, nStrLen, tot_len,
1938
+ &bOverflow, bOutType, TAUT_MODE, num_components, bAbcNumbers,
1939
+ bSecondNonTautPass, bOmitRepetitions, bUseMulipliers);
1940
+ bNonTautIsoIdentifierNotEmpty += bSecondNonTautPass;
1941
+ } else {
1942
+ tot_len2 = tot_len;
1943
+ }
1944
+
1945
+ tot_len = tot_len2;
1946
+ if ( str_LineEnd( szTag2, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -nSegmAction, bPlainTextTags ) )
1947
+ goto exit_function;
1948
+ inchi_print( output_file, "%s%s", pStr, pLF );
1949
+
1950
+ }
1951
+ /* isotopic #1a: composition -- exchangeable isotopic H (mobile H only) */
1952
+ /*if ( !bSecondNonTautPass && bHasIsoH )*/
1953
+ if ( nSegmAction = INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_h_H_ATOMS] ) )
1954
+ {
1955
+ szGetTag( IdentLbl, nTag, bTag2 = bTag1 | IL_XCGA, szTag2, &bAlways );
1956
+ tot_len = str_LineStart( szTag2, NULL, 0, pStr, ind );
1957
+ tot_len += MakeIsoHString( num_iso_H, pStr + tot_len, nStrLen-tot_len, TAUT_MODE, &bOverflow);
1958
+ bNonTautIsoIdentifierNotEmpty += bSecondNonTautPass;
1959
+ if ( str_LineEnd( szTag2, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -nSegmAction, bPlainTextTags ) )
1960
+ goto exit_function;
1961
+ inchi_print( output_file, "%s%s", pStr, pLF );
1962
+ }
1963
+
1964
+ /***************************************************
1965
+ *
1966
+ * Isotopic stereo
1967
+ *
1968
+ ***************************************************/
1969
+
1970
+ /*if ( bIsotopicStereo[iCurTautMode] )*/
1971
+ if ( INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_b_SBONDS] ) ||
1972
+ INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_t_SATOMS] ) ||
1973
+ INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_m_SP3INV] ) ||
1974
+ INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_s_STYPE] ) )
1975
+ {
1976
+ /* stereo */
1977
+ szGetTag( IdentLbl, nTag, bTag2 = bTag1 | IL_STER, szTag2, &bAlways );
1978
+ if ( bXml ) {
1979
+ str_LineStart( szTag2, NULL, 0, pStr, ind );
1980
+ inchi_print( output_file, "%s\n", pStr );
1981
+ ind += inc;
1982
+ }
1983
+ /************************
1984
+ isotopic #2: sp2
1985
+ ************************/
1986
+ /*if ( bIsotopicStereoSp2[iCurTautMode] )*/
1987
+ if ( nSegmAction = INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_b_SBONDS] ) )
1988
+ {
1989
+ szGetTag( IdentLbl, nTag, bTag3 = bTag2 | IL_DBND, szTag3, &bAlways );
1990
+ tot_len = str_LineStart( szTag3, NULL, 0, pStr, ind );
1991
+ if ( INCHI_SEGM_FILL == nSegmAction ) {
1992
+ tot_len = str_IsoSp2(pINChISort, pINChISort2, pStr, nStrLen, tot_len,
1993
+ &bOverflow, bOutType, TAUT_MODE, num_components,
1994
+ bSecondNonTautPass, bOmitRepetitions, bUseMulipliers);
1995
+ bNonTautIsoIdentifierNotEmpty += bSecondNonTautPass;
1996
+ }
1997
+ if ( str_LineEnd( szTag3, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -nSegmAction, bPlainTextTags ) )
1998
+ goto exit_function;
1999
+ inchi_print( output_file, "%s%s", pStr, pLF );
2000
+ } else
2001
+ if ( !bXml ) {
2002
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "/" ); /* iso sp2 */
2003
+ }
2004
+ /************************
2005
+ isotopic #3: sp3
2006
+ ************************/
2007
+ /*if ( bIsotopicStereoSp3[iCurTautMode] )*/
2008
+ if ( nSegmAction = INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_t_SATOMS] ) )
2009
+ {
2010
+ bRelRac = bIsotopicRelativeStereo[iCurTautMode] || bIsotopicRacemicStereo[iCurTautMode];
2011
+ szGetTag( IdentLbl, nTag, bTag3 = bTag2 | IL_SP3S, szTag3, &bAlways );
2012
+ tot_len = str_LineStart( szTag3, NULL, 0, pStr, ind );
2013
+ if ( INCHI_SEGM_FILL == nSegmAction ) {
2014
+ tot_len = str_IsoSp3(pINChISort, pINChISort2, pStr, nStrLen, tot_len,
2015
+ &bOverflow, bOutType, TAUT_MODE, num_components, bRelRac,
2016
+ bSecondNonTautPass, bOmitRepetitions, bUseMulipliers);
2017
+ bNonTautIsoIdentifierNotEmpty += bSecondNonTautPass;
2018
+ }
2019
+ if ( str_LineEnd( szTag3, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -nSegmAction, bPlainTextTags ) )
2020
+ goto exit_function;
2021
+ inchi_print( output_file, "%s%s", pStr, pLF );
2022
+ } else
2023
+ if ( !bXml ) {
2024
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "/" ); /* iso-sp3 */
2025
+ }
2026
+ /* isotopic #4: abs inverted */
2027
+ if ( nSegmAction = INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_m_SP3INV] ) )
2028
+ {
2029
+ szGetTag( IdentLbl, nTag, bTag3 = bTag2 | IL_INVS, szTag3, &bAlways );
2030
+ tot_len = str_LineStart( szTag3, NULL, 0, pStr, ind );
2031
+ if ( INCHI_SEGM_FILL == nSegmAction ) {
2032
+ tot_len = str_IsoStereoAbsInv(pINChISort, pStr, nStrLen, tot_len,
2033
+ &bOverflow, bOutType, num_components);
2034
+ bNonTautIsoIdentifierNotEmpty += bSecondNonTautPass;
2035
+ }
2036
+ if ( str_LineEnd( szTag3, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -nSegmAction, bPlainTextTags ) )
2037
+ goto exit_function;
2038
+ inchi_print( output_file, "%s%s", pStr, pLF );
2039
+ } else
2040
+ if ( !bXml ) {
2041
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "/" );
2042
+ }
2043
+ /* isotopic #5: stereo type. Do not output if it has already been output in non-iso */
2044
+ if ( nSegmAction = INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_s_STYPE] ) )
2045
+ {
2046
+ const char *p_stereo = bIsotopicRelativeStereo[iCurTautMode]? x_rel :
2047
+ bIsotopicRacemicStereo[iCurTautMode] ? x_rac : x_abs;
2048
+ szGetTag( IdentLbl, nTag, bTag3 = bTag2 | IL_TYPS, szTag3, &bAlways );
2049
+ tot_len = str_LineStart( szTag3, NULL, 0, pStr, ind );
2050
+ if ( INCHI_SEGM_FILL == nSegmAction ) {
2051
+ tot_len += MakeDelim( p_stereo, pStr + tot_len, nStrLen-tot_len, &bOverflow);
2052
+ bNonTautIsoIdentifierNotEmpty += bSecondNonTautPass;
2053
+ }
2054
+ if ( str_LineEnd( szTag3, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -nSegmAction, bPlainTextTags ) )
2055
+ goto exit_function;
2056
+ inchi_print( output_file, "%s%s", pStr, pLF );
2057
+ }
2058
+ if ( !bXml ) {
2059
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "/" ); /* no abs, inv or racemic stereo */
2060
+ }
2061
+ if ( bXml ) {
2062
+ /************************
2063
+ close isotopic stereo
2064
+ ************************/
2065
+ ind -= inc;
2066
+ if ( str_LineEnd( szTag2, 0, nStrLen, &bOverflow, pStr, ind, bPlainTextTags ) )
2067
+ goto exit_function;
2068
+ inchi_print( output_file, "%s", pStr );
2069
+ }
2070
+ }
2071
+ else
2072
+ if ( !bXml ) { /* no isotopic stereo */
2073
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "////" ); /* sp3, sp2, abs-inv, stereo.type */
2074
+ }
2075
+
2076
+ /* close isotopic */
2077
+ if ( bXml ) {
2078
+ ind -= inc;
2079
+ if ( str_LineEnd( szTag1, 0, nStrLen, &bOverflow, pStr, ind, bPlainTextTags ) )
2080
+ goto exit_function;
2081
+ inchi_print( output_file, "%s", pStr );
2082
+ }
2083
+ } else
2084
+ if ( !bXml ) {
2085
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "///" ); /* isotopic composition, sp2, sp3 */
2086
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "//" ); /* inv or racemic stereo */
2087
+ }
2088
+ #if( CANON_FIXH_TRANS == 1 )
2089
+ if ( bOutType == OUT_NONTAUT && bOutputType == OUT_TN && bSecondNonTautPass &&
2090
+ INCHI_SEGM_FILL == INChI_SegmentAction( sDifSegs[DIFL_F][DIFS_o_TRANSP] )) {
2091
+ /* find and print non-tautomeric components transposition, if non-trivial */
2092
+ AT_NUMB *nTrans_n, *nTrans_s;
2093
+
2094
+ if ( 0 < bin_AuxTautTrans(pINChISort, pINChISort2, &nTrans_n, &nTrans_s, bOutType, num_components) ) {
2095
+ /* a non-trivial transposition does exist; output start tag */
2096
+ szGetTag( IdentLbl, nTag, bTag1 = IL_TRNS | bFhTag, szTag1, &bAlways );
2097
+ tot_len = str_LineStart( szTag1, NULL, 0, pStr, ind );
2098
+ /* print the transposition, cycle after cycle */
2099
+ tot_len = str_AuxTautTrans(nTrans_n, nTrans_s, pStr, nStrLen, tot_len,
2100
+ &bOverflow, TAUT_MODE, num_components);
2101
+ bNonTautIsoIdentifierNotEmpty += bSecondNonTautPass;
2102
+ if ( str_LineEnd( szTag1, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -1, bPlainTextTags ) )
2103
+ goto exit_function;
2104
+ inchi_print( output_file, "%s%s", pStr, pLF );
2105
+ /* detected transposition */
2106
+ *pSortPrintINChIFlags |= (INCHI_BAS == iINChI)? FLAG_SORT_PRINT_TRANSPOS_BAS :
2107
+ FLAG_SORT_PRINT_TRANSPOS_REC;
2108
+ } else
2109
+ if ( !bXml ) {
2110
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "/" );
2111
+ }
2112
+ }
2113
+ #endif
2114
+
2115
+
2116
+ /**************************************************************
2117
+ At this point the INChI part of the output has been done.
2118
+ If this INChI is tautomeric and non-tautomeric results exist
2119
+ then we need to output non-tautomeric data:
2120
+ fixed H,
2121
+ stereo,
2122
+ isotopic
2123
+ isotopic stereo
2124
+ ***************************************************************/
2125
+ if ( bOutType == OUT_TN && !bSecondNonTautPass &&
2126
+ bNonTautIsIdenticalToTaut && bTautomeric && bNonTautomeric ) {
2127
+ /* Fixed-H layer is empty in the Identifier */
2128
+ *pSortPrintINChIFlags |= (INCHI_BAS == iINChI)? FLAG_SORT_PRINT_NO_NFIX_H_BAS :
2129
+ FLAG_SORT_PRINT_NO_NFIX_H_REC;
2130
+ *pSortPrintINChIFlags |= (INCHI_BAS == iINChI)? FLAG_SORT_PRINT_NO_IFIX_H_BAS :
2131
+ FLAG_SORT_PRINT_NO_IFIX_H_REC;
2132
+ }
2133
+ if ( bOutType == OUT_TN && !bNonTautIsIdenticalToTaut /* added 2004-10-04 Fix16 */
2134
+ #ifdef OLD_ITEM_DISCOVERY
2135
+ && bTautomeric && bNonTautomeric
2136
+ #endif
2137
+ && INChI_SegmentAction( sDifSegs[DIFL_F][DIFS_f_FORMULA] )
2138
+ /* special case: removed isolated H(+): */
2139
+ /* || iCurTautMode == TAUT_YES && num_comp[TAUT_YES] < num_comp[TAUT_NON] &&
2140
+ 0 < num_comp[TAUT_NON]*/
2141
+ ) {
2142
+ /* add the second (non-tautomeric) output */
2143
+ bOutType = OUT_NONTAUT; /* pick up only non-tautomeric representation of tautomeric */
2144
+ iCurTautMode = TAUT_NON;
2145
+ pINChISort = pINChISortTautAndNonTaut[TAUT_NON];
2146
+ bSecondNonTautPass = 1;
2147
+ nCurINChISegment = DIFL_F;
2148
+ num_components = num_comp[iCurTautMode]; /* number of components could change due to removal of isolated H(+) from tautomeric */
2149
+ bFhTag = IL_FIXH;
2150
+ szGetTag( IdentLbl, nTag, bTag1 = bFhTag, szTag1, &bAlways );
2151
+ if ( bXml ) { /* open non-tautomeric */
2152
+ str_LineStart( szTag1, NULL, 0, pStr, ind );
2153
+ inchi_print( output_file, "%s\n", pStr );
2154
+ ind += inc;
2155
+ }
2156
+ /***** constitution non-taut: dot-disconnected Hill formulas: <formula> -- only if different */
2157
+ szGetTag( IdentLbl, nTag, bTag1 = IL_FMLF | bFhTag, szTag1, &bAlways );
2158
+ tot_len = str_LineStart( szTag1, NULL, 0, pStr, ind );
2159
+ nSegmAction = INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_f_FORMULA] );
2160
+ if ( INCHI_SEGM_FILL == nSegmAction ) {
2161
+ tot_len2 = str_HillFormula2(pINChISort, pINChISort2, pStr, nStrLen, tot_len,
2162
+ &bOverflow, bOutType, num_components, bUseMulipliers);
2163
+ bNonTautNonIsoIdentifierNotEmpty += bSecondNonTautPass;
2164
+ } else {
2165
+ tot_len2 = tot_len;
2166
+ }
2167
+ tot_len = tot_len2;
2168
+ if ( str_LineEnd( szTag1, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -nSegmAction, bPlainTextTags ) )
2169
+ goto exit_function;
2170
+ inchi_print( output_file, "%s%s", pStr, pLF );
2171
+
2172
+ nSegmAction = INChI_SegmentAction( sDifSegs[nCurINChISegment][DIFS_h_H_ATOMS] );
2173
+ if ( INCHI_SEGM_FILL == nSegmAction ) {
2174
+ szGetTag( IdentLbl, nTag, bTag1 = IL_HFIX | bFhTag, szTag1, &bAlways );
2175
+ tot_len = str_LineStart( szTag1, NULL, 0, pStr, ind ); /* open H-fixed */
2176
+ /* output the second non-tautomeric item: fixed H -- do not output in xml if empty */
2177
+ tot_len2 = str_FixedH_atoms(pINChISort, pStr, nStrLen, tot_len,
2178
+ &bOverflow, bOutType, ATOM_MODE, num_components, bUseMulipliers);
2179
+ tot_len = tot_len2;
2180
+ if ( str_LineEnd( szTag1, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -nSegmAction, bPlainTextTags ) )
2181
+ goto exit_function;
2182
+ inchi_print( output_file, "%s%s", pStr, pLF );
2183
+ bNonTautNonIsoIdentifierNotEmpty += bSecondNonTautPass;
2184
+ }
2185
+ goto repeat_INChI_output;
2186
+ } else
2187
+ if ( bOutType == OUT_NONTAUT && bOutputType == OUT_TN && bSecondNonTautPass /* && bTautomeric && bNonTautomeric*/ ) {
2188
+ /* the second (non-taut) output has been done; restore variables */
2189
+ bOutType = OUT_TN;
2190
+ iCurTautMode = TAUT_YES;
2191
+ pINChISort = pINChISortTautAndNonTaut[TAUT_YES];
2192
+ bSecondNonTautPass = 0;
2193
+ num_components = num_comp[iCurTautMode];
2194
+ if ( !bNonTautNonIsoIdentifierNotEmpty ) {
2195
+ /* Fixed-H layer is empty in the Identifier */
2196
+ *pSortPrintINChIFlags |= (INCHI_BAS == iINChI)? FLAG_SORT_PRINT_NO_NFIX_H_BAS :
2197
+ FLAG_SORT_PRINT_NO_NFIX_H_REC;
2198
+ }
2199
+ if ( !bNonTautIsoIdentifierNotEmpty ) {
2200
+ /* Fixed-H layer is empty in the Identifier */
2201
+ *pSortPrintINChIFlags |= (INCHI_BAS == iINChI)? FLAG_SORT_PRINT_NO_IFIX_H_BAS :
2202
+ FLAG_SORT_PRINT_NO_IFIX_H_REC;
2203
+ }
2204
+ if ( bXml ) {
2205
+ /* close non-tautomeric */
2206
+ ind -= inc;
2207
+ szGetTag( IdentLbl, nTag, bTag1 = bFhTag, szTag1, &bAlways );
2208
+ if ( str_LineEnd( szTag1, 0, nStrLen, &bOverflow, pStr, ind, bPlainTextTags ) )
2209
+ goto exit_function;
2210
+ inchi_print( output_file, "%s", pStr );
2211
+ }
2212
+ bFhTag = 0;
2213
+ }
2214
+
2215
+ /************************************************
2216
+ * output INChI of the reconnected structure *
2217
+ ************************************************/
2218
+ bEmbeddedOutputCalled = 0;
2219
+ if ( bDisconnectedCoord && INCHI_BAS == iINChI &&
2220
+ (bINChIOutputOptions & INCHI_OUT_EMBED_REC) && num_components2[INCHI_REC] ) {
2221
+ int nRet;
2222
+ bEmbeddedOutputCalled = 1;
2223
+
2224
+ if ( !bXml ) {
2225
+ /* output blank line before /R: in case of bPlainTextCommnts=1 */
2226
+ inchi_print( output_file, "%s", pLF );
2227
+ }
2228
+ /* end of disconnected INChI output */
2229
+ nRet = OutputINChI1( pStr, nStrLen, pINChISortTautAndNonTaut2, INCHI_REC, NULL,
2230
+ 0 /*bDisconnectedCoord*/, bOutputType, bINChIOutputOptions | INCHI_OUT_NO_AUX_INFO,
2231
+ bXml, bAbcNumbers, bCtPredecessors, bNoStructLabels,
2232
+ num_components2, num_non_taut2, num_taut2,
2233
+ output_file, log_file, num_input_struct,
2234
+ szSdfLabel, szSdfValue, lSdfId, pSortPrintINChIFlags );
2235
+
2236
+ if ( !nRet ) {
2237
+ goto exit_function; /* error */
2238
+ }
2239
+ }
2240
+
2241
+ if ( bXml ) {
2242
+ /* close INChI identifier (basic) */
2243
+ ind -= inc;
2244
+ if ( str_LineEnd( x_basic, 0, nStrLen, &bOverflow, pStr, ind, bPlainTextTags ) )
2245
+ goto exit_function;
2246
+ inchi_print( output_file, "%s", pStr );
2247
+ } else
2248
+ if ( !bEmbeddedOutputCalled && !bPlainTextCommnts ) { /* plain text comment earlier ended with LF */
2249
+ inchi_print( output_file, "%s%s", (!num_components2[0] && !num_components2[1])? "//":"", /* empty InChI=// */
2250
+ (bINChIOutputOptions & INCHI_OUT_NO_AUX_INFO)? "\n" : pTAB );
2251
+ /* end of INChI= output */
2252
+ }
2253
+
2254
+ output_aux_info:
2255
+ bFhTag = 0;
2256
+ if( !(bINChIOutputOptions & INCHI_OUT_NO_AUX_INFO) ) { /* output aux info */
2257
+ /*************************************************************
2258
+ *
2259
+ * Aux info non-isotopic
2260
+ *
2261
+ *************************************************************/
2262
+ num_components = num_comp[iCurTautMode];
2263
+ if ( bXml ) {
2264
+ /* aux. info header */
2265
+ /* empty line if INChI output has been printed */
2266
+ if ( !(bINChIOutputOptions & INCHI_OUT_ONLY_AUX_INFO) ) {
2267
+ inchi_print( output_file, "\n" );
2268
+ }
2269
+ /* basic.aux-info title, version */
2270
+ tot_len = sprintf(pStr, "%s<%s %s=\"%s\"",
2271
+ SP(ind), x_aux_basic, x_ver, x_curr_ver );
2272
+ if ( INCHI_REC == iINChI || INCHI_BAS == iINChI && bDisconnectedCoord ) {
2273
+ tot_len += sprintf(pStr+tot_len, " %s=\"%d\"", x_reconnected, iINChI );
2274
+ }
2275
+ if ( bAbcNumbers ) {
2276
+ /* type */
2277
+ const char *pNumber = x_type_short;
2278
+ tot_len += sprintf(pStr+tot_len, " %s=\"%s\"", x_type, pNumber);
2279
+ }
2280
+
2281
+ sprintf(pStr+tot_len,">");
2282
+ inchi_print( output_file, "%s\n", pStr );
2283
+ ind += inc;
2284
+ if ( !(bINChIOutputOptions & INCHI_OUT_ONLY_AUX_INFO) ) {
2285
+ /* comment */
2286
+ tot_len = sprintf( pStr, "%s<%s>", SP(ind), x_aux_comm );
2287
+ inchi_print( output_file, "%s\n", pStr );
2288
+ }
2289
+ } else {
2290
+ if ( INCHI_BAS == iINChI ) {
2291
+ tot_len = sprintf( pStr, "AuxInfo=" ); /* in wINChI window, separate INChI: from AuxInfo: with blank line */
2292
+ inchi_print( output_file, "%s%s%s",
2293
+ /* blank line before AuxInfo in winchi window unless it is an annotation */
2294
+ (bINChIOutputOptions & INCHI_OUT_WINCHI_WINDOW) ? "\n":"",
2295
+ pStr,
2296
+ pLF);
2297
+ szGetTag( AuxLbl, nTag, bTag1 = AL_VERS, szTag1, &bAlways );
2298
+ tot_len = str_LineStart( szTag1, NULL, 0, pStr, ind );
2299
+ tot_len += sprintf(pStr + tot_len, "%s", x_curr_ver);
2300
+ /* avoid leading slash in plain output */
2301
+ if ( str_LineEnd( szTag1, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -1, bPlainTextTags ) )
2302
+ goto exit_function;
2303
+ inchi_print( output_file, "%s%s", pStr, pLF );
2304
+ } else
2305
+ if ( INCHI_REC == iINChI ) {
2306
+ szGetTag( AuxLbl, nTag, bTag1 = AL_REC_, szTag1, &bAlways );
2307
+ inchi_print( output_file, "%s%s", szTag1, pLF );
2308
+ }
2309
+
2310
+ }
2311
+ /* normalization type */
2312
+ if ( num_components2[0] || num_components2[1] ) {
2313
+ szGetTag( AuxLbl, nTag, bTag1 = AL_NORM, szTag1, &bAlways );
2314
+ tot_len = str_LineStart( szTag1, NULL, 0, pStr, ind );
2315
+ tot_len += sprintf( pStr + tot_len, "%d", (bTautomeric && bTautomericOutputAllowed)? bTautomeric : 0);
2316
+ if ( str_LineEnd( szTag1, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -1, bPlainTextTags ) )
2317
+ goto exit_function;
2318
+ inchi_print( output_file, "%s%s", pStr, pLF );
2319
+ }
2320
+
2321
+ repeat_INChI_Aux_output:
2322
+
2323
+ /**************************************************************
2324
+ * Original atom numbers in order of canonical numbers
2325
+ **************************************************************/
2326
+ if ( num_components2[0] || num_components2[1] ) {
2327
+ szGetTag( AuxLbl, nTag, bTag1 = (bSecondNonTautPass? AL_FIXN : AL_ANBR) | bFhTag, szTag1, &bAlways );
2328
+ tot_len = str_LineStart( szTag1, NULL, 0, pStr, ind );
2329
+ /* original numbering output */
2330
+ tot_len = str_AuxNumb(pINChISort, pINChISort2, pStr, nStrLen, tot_len,
2331
+ &bOverflow, bOutType, TAUT_MODE, num_components,
2332
+ bSecondNonTautPass, bOmitRepetitions);
2333
+
2334
+ if ( str_LineEnd( szTag1, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -1, bPlainTextTags ) )
2335
+ goto exit_function;
2336
+ inchi_print( output_file, "%s%s", pStr, pLF );
2337
+ }
2338
+ /**********************************************
2339
+ * Symmetry numbers (constit. equivalence)
2340
+ **********************************************/
2341
+ if ( bAtomEqu[iCurTautMode] ) {
2342
+ /* aux equ atoms */
2343
+ /* 1. Compare to tautomeric equivalence (in case of second, non-taut, pass only) */
2344
+ /* 2. Compare to the previous component if (1) failed to find equivalence */
2345
+ szGetTag( AuxLbl, nTag, bTag1 = AL_AEQU | bFhTag, szTag1, &bAlways );
2346
+ tot_len = str_LineStart( szTag1, NULL, 0, pStr, ind );
2347
+ tot_len = str_AuxEqu(pINChISort, pINChISort2, pStr, nStrLen, tot_len,
2348
+ &bOverflow, bOutType, TAUT_MODE, num_components,
2349
+ bSecondNonTautPass, bOmitRepetitions, bUseMulipliers);
2350
+
2351
+ if ( str_LineEnd( szTag1, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -1, bPlainTextTags ) )
2352
+ goto exit_function;
2353
+ inchi_print( output_file, "%s%s", pStr, pLF );
2354
+ } else
2355
+ if ( !bXml ) {
2356
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "/" );
2357
+ }
2358
+ /*****************************************************
2359
+ * Tautomeric groups equivalence
2360
+ *****************************************************/
2361
+ if ( bTautomericOutputAllowed && bTautomeric && bTautEqu[iCurTautMode] && !bSecondNonTautPass ) {
2362
+ /*****************************************************
2363
+ * Tautomeric groups constitutional equivalence
2364
+ */
2365
+ /* aux tgroup equ */
2366
+ szGetTag( AuxLbl, nTag, bTag1 = AL_GEQU | bFhTag, szTag1, &bAlways );
2367
+ tot_len = str_LineStart( szTag1, NULL, 0, pStr, ind );
2368
+ tot_len = str_AuxTgroupEqu(pINChISort, pStr, nStrLen, tot_len,
2369
+ &bOverflow, bOutType, TAUT_MODE,
2370
+ num_components, bUseMulipliers);
2371
+ if ( str_LineEnd( szTag1, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -1, bPlainTextTags ) )
2372
+ goto exit_function;
2373
+ inchi_print( output_file, "%s", pStr );
2374
+ } else
2375
+ if ( !bXml && bTautomericOutputAllowed && bTautomeric ) {
2376
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "/" );
2377
+ }
2378
+ /****************************************************
2379
+ * Inverted stereo -- sp3 only + canonical numbering
2380
+ ****************************************************/
2381
+ if ( bInvStereo[iCurTautMode] ) {
2382
+
2383
+ szGetTag( AuxLbl, nTag, bTag1 = AL_STER | bFhTag, szTag1, &bAlways );
2384
+ if ( bXml ) {
2385
+ /***************************
2386
+ inv stereo start tag
2387
+ ****************************/
2388
+ str_LineStart( szTag1, NULL, 0, pStr, ind );
2389
+ inchi_print( output_file, "%s\n", pStr );
2390
+ ind += inc;
2391
+ }
2392
+ /****************************
2393
+ inverted sp3 start tag
2394
+ *****************************/
2395
+ szGetTag( AuxLbl, nTag, bTag2 = bTag1 | AL_SP3I, szTag2, &bAlways );
2396
+ tot_len = str_LineStart( szTag2, NULL, 0, pStr, ind );
2397
+ tot_len = str_AuxInvSp3(pINChISort, pINChISort2, pStr, nStrLen, tot_len,
2398
+ &bOverflow, bOutType, TAUT_MODE, num_components,
2399
+ bSecondNonTautPass, bOmitRepetitions, bUseMulipliers);
2400
+ if ( str_LineEnd( szTag2, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -1, bPlainTextTags ) )
2401
+ goto exit_function;
2402
+ inchi_print( output_file, "%s%s", pStr, pLF );
2403
+ /*************************************
2404
+ inverted sp3 canonical numbering
2405
+ **************************************/
2406
+ if ( bInvStereoOrigNumb[iCurTautMode] ) {
2407
+ szGetTag( AuxLbl, nTag, bTag2 = bTag1 | AL_SP3N, szTag2, &bAlways );
2408
+ tot_len = str_LineStart( szTag2, NULL, 0, pStr, ind );
2409
+ tot_len = str_AuxInvSp3Numb(pINChISort, pINChISort2, pStr, nStrLen, tot_len,
2410
+ &bOverflow, bOutType, TAUT_MODE, num_components,
2411
+ bSecondNonTautPass, bOmitRepetitions);
2412
+ if ( str_LineEnd( szTag2, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -1, bPlainTextTags ) )
2413
+ goto exit_function;
2414
+ inchi_print( output_file, "%s%s", pStr, pLF );
2415
+ } else
2416
+ if ( !bXml ) {
2417
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "/" );
2418
+ }
2419
+ if ( bXml ) {
2420
+ /* close sp3 inv */
2421
+ ind -= inc;
2422
+ if ( str_LineEnd( szTag1, 0, nStrLen, &bOverflow, pStr, ind, bPlainTextTags ) )
2423
+ goto exit_function;
2424
+ inchi_print( output_file, "%s%s", pStr, pLF );
2425
+ }
2426
+ } else
2427
+ if ( !bXml ) {
2428
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "//" );
2429
+ } /* Inverted stereo -- sp3 only + canonical numbering */
2430
+
2431
+
2432
+ /* omitted undefined/unknown non-isotopic stereo */
2433
+ if ( bXml ) {
2434
+ if ( bIgn_UU_Sp2[iCurTautMode] || bIgn_UU_Sp3[iCurTautMode] ) {
2435
+ /* <stereo omit_undef_dbond="1" omit_undef_sp3="1"/> */
2436
+ szGetTag( IdentLbl, nTag, bTag1 = IL_STER, szTag1, &bAlways );
2437
+ tot_len = PrintXmlStartTag( pStr, ind, 3, szTag1,
2438
+ (bIgn_UU_Sp2[iCurTautMode])? x_ign_uu_sp2 : NULL, 1,
2439
+ (bIgn_UU_Sp3[iCurTautMode])? x_ign_uu_sp3 : NULL, 1,
2440
+ NULL, 0, NULL, 0, NULL, 0, NULL, 0 );
2441
+ inchi_print( output_file, "%s\n", pStr );
2442
+ }
2443
+ }
2444
+
2445
+ /***************************************************************
2446
+ *
2447
+ * Additional information: charges, radicals,
2448
+ * special valences, coordinates
2449
+ *
2450
+ ***************************************************************/
2451
+ /**************************************************************
2452
+ *
2453
+ * Aux info isotopic
2454
+ *
2455
+ **************************************************************/
2456
+ repeat_INChI_Aux_Iso_output:
2457
+ /* if InChI Fixed-H isotopic is empty then do not output corresponding AuxInfo */
2458
+ i = bSecondNonTautPass &&
2459
+ (*pSortPrintINChIFlags & ((INCHI_BAS == iINChI)? FLAG_SORT_PRINT_NO_IFIX_H_BAS :
2460
+ FLAG_SORT_PRINT_NO_IFIX_H_REC ));
2461
+
2462
+ if ( bIsotopic && !i &&
2463
+ (bIsotopicOrigNumb[iCurTautMode] ||
2464
+ bIsotopicAtomEqu[iCurTautMode] ||
2465
+ bTautomericOutputAllowed && bTautomeric && bIsotopicTautEqu[iCurTautMode] ||
2466
+ bInvIsotopicStereo[iCurTautMode] ||
2467
+ bXml && ( bIgn_UU_Sp3_Iso[iCurTautMode] || bIgn_UU_Sp2_Iso[iCurTautMode] ) ) ) {
2468
+ /*************************************/
2469
+ /* isotopic aux info header */
2470
+ /*************************************/
2471
+ szGetTag( AuxLbl, nTag, bTag1 = AL_ISOT | bFhTag, szTag1, &bAlways );
2472
+ if ( bXml ) {
2473
+ str_LineStart( szTag1, NULL, 0, pStr, ind );
2474
+ inchi_print( output_file, "%s\n", pStr );
2475
+ ind += inc;
2476
+ } else {
2477
+ pStr[tot_len = 0] = '\0';
2478
+ }
2479
+ /*****************************************************************
2480
+ * Original atom numbers in order of isotopic canonical numbers
2481
+ *****************************************************************/
2482
+ szGetTag( AuxLbl, nTag, bTag2 = bTag1 | AL_ISON, szTag2, &bAlways );
2483
+ if ( bIsotopicOrigNumb[iCurTautMode] ) {
2484
+ tot_len = str_LineStart( szTag2, NULL, 0, pStr, ind );
2485
+ tot_len = str_AuxIsoNumb(pINChISort, pINChISort2, pStr, nStrLen, tot_len,
2486
+ &bOverflow, bOutType, TAUT_MODE, num_components,
2487
+ bSecondNonTautPass, bOmitRepetitions);
2488
+ if ( str_LineEnd( szTag2, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -1, bPlainTextTags ) )
2489
+ goto exit_function;
2490
+ inchi_print( output_file, "%s%s", pStr, pLF );
2491
+ } else
2492
+ if ( !bXml ) {
2493
+ /*if ( bPlainTextTags == 1 ) inchi_print( output_file, "/" );*/
2494
+ inchi_print( output_file, "%s%s", szTag2, pLF ); /* mark isotopic output */
2495
+ }
2496
+ /*************************/
2497
+ /* Isotopic symmetry */
2498
+ /*************************/
2499
+ if ( bIsotopicAtomEqu[iCurTautMode] ) {
2500
+ /* atoms */
2501
+ szGetTag( AuxLbl, nTag, bTag2 = bTag1 | AL_AEQU, szTag2, &bAlways );
2502
+ tot_len = str_LineStart( szTag2, NULL, 0, pStr, ind );
2503
+ tot_len = str_AuxIsoEqu(pINChISort, pINChISort2, pStr, nStrLen, tot_len,
2504
+ &bOverflow, bOutType, TAUT_MODE, num_components,
2505
+ bSecondNonTautPass, bOmitRepetitions, bUseMulipliers);
2506
+ if ( str_LineEnd( szTag2, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -2/*was -1: Fix15*/, bPlainTextTags ) )
2507
+ goto exit_function;
2508
+ inchi_print( output_file, "%s%s", pStr, pLF );
2509
+ } else
2510
+ if ( !bXml ) {
2511
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "/" );
2512
+ }
2513
+
2514
+ /********************************/
2515
+ /* Tautomeric groups, isotopic */
2516
+ /********************************/
2517
+ if ( bTautomericOutputAllowed && bTautomeric && bIsotopicTautEqu[iCurTautMode] ) {
2518
+ /********************************************/
2519
+ /* Isotopic tautomeric groups equivalence */
2520
+ /********************************************/
2521
+ szGetTag( AuxLbl, nTag, bTag2 = bTag1 | AL_GEQU, szTag2, &bAlways );
2522
+ tot_len = str_LineStart( szTag2, NULL, 0, pStr, ind );
2523
+ tot_len = str_AuxIsoTgroupEqu(pINChISort, pStr, nStrLen, tot_len,
2524
+ &bOverflow, bOutType, TAUT_MODE, num_components,
2525
+ bOmitRepetitions, bUseMulipliers);
2526
+ if ( str_LineEnd( szTag2, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -2/*was -1: Fix15*/, bPlainTextTags ) )
2527
+ goto exit_function;
2528
+ inchi_print( output_file, "%s%s", pStr, pLF );
2529
+ } else
2530
+ if ( !bXml && bTautomericOutputAllowed && bTautomeric ) {
2531
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "/" );
2532
+ }
2533
+
2534
+ /*************************************
2535
+ * Isotopic inverted stereo
2536
+ *************************************/
2537
+ if ( bInvIsotopicStereo[iCurTautMode] ) {
2538
+ szGetTag( AuxLbl, nTag, bTag2 = bTag1 | AL_STER, szTag2, &bAlways );
2539
+ if ( bXml ) {
2540
+ /************************************
2541
+ inv isotopic stereo start tag
2542
+ *************************************/
2543
+ str_LineStart( szTag2, NULL, 0, pStr, ind );
2544
+ inchi_print( output_file, "%s\n", pStr );
2545
+ ind += inc;
2546
+ }
2547
+ /*************************************
2548
+ inverted isotopic sp3 start tag
2549
+ **************************************/
2550
+ szGetTag( AuxLbl, nTag, bTag3 = bTag2 | AL_SP3I, szTag3, &bAlways );
2551
+ tot_len = str_LineStart( szTag3, NULL, 0, pStr, ind );
2552
+ tot_len = str_AuxInvIsoSp3(pINChISort, pINChISort2, pStr, nStrLen, tot_len,
2553
+ &bOverflow, bOutType, TAUT_MODE, num_components,
2554
+ bSecondNonTautPass, bOmitRepetitions, bUseMulipliers);
2555
+ if ( str_LineEnd( szTag3, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -1, bPlainTextTags ) )
2556
+ goto exit_function;
2557
+ inchi_print( output_file, "%s", pStr );
2558
+ /*********************************************
2559
+ inverted isotopic sp3 canonical numbering
2560
+ **********************************************/
2561
+ if ( bInvIsotopicStereoOrigNumb[iCurTautMode] ) {
2562
+ szGetTag( AuxLbl, nTag, bTag3 = bTag2 | AL_SP3N, szTag3, &bAlways );
2563
+ tot_len = str_LineStart( szTag3, NULL, 0, pStr, ind );
2564
+ tot_len = str_AuxInvIsoSp3Numb(pINChISort, pINChISort2, pStr, nStrLen, tot_len,
2565
+ &bOverflow, bOutType, TAUT_MODE, num_components,
2566
+ bSecondNonTautPass, bOmitRepetitions);
2567
+ if ( str_LineEnd( szTag3, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -1, bPlainTextTags ) )
2568
+ goto exit_function;
2569
+ inchi_print( output_file, "%s%s", pStr, pLF );
2570
+ } else
2571
+ if ( !bXml ) {
2572
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "/" );
2573
+ }
2574
+ if ( bXml ) {
2575
+ /* close sp3 inv */
2576
+ ind -= inc;
2577
+ if ( str_LineEnd( szTag2, 0, nStrLen, &bOverflow, pStr, ind, bPlainTextTags ) )
2578
+ goto exit_function;
2579
+ inchi_print( output_file, "%s", pStr );
2580
+ }
2581
+ } else
2582
+ if ( !bXml ) {
2583
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "//" );
2584
+ }
2585
+
2586
+ /* totally omitted undefined/unknown isotopic stereo */
2587
+ if ( bXml ) {
2588
+ if ( bIgn_UU_Sp3_Iso[iCurTautMode] || bIgn_UU_Sp2_Iso[iCurTautMode] ) {
2589
+ /* <stereo omit_undef_dbond="1" omit_undef_sp3="1"/> */
2590
+ szGetTag( IdentLbl, nTag, bTag1 = IL_STER, szTag1, &bAlways );
2591
+ tot_len = PrintXmlStartTag( pStr, ind, 3, szTag1,
2592
+ (bIgn_UU_Sp2_Iso[iCurTautMode])? x_ign_uu_sp2 : NULL, 1,
2593
+ (bIgn_UU_Sp3_Iso[iCurTautMode])? x_ign_uu_sp3 : NULL, 1,
2594
+ NULL, 0, NULL, 0, NULL, 0, NULL, 0 );
2595
+ inchi_print( output_file, "%s\n", pStr );
2596
+ }
2597
+ }
2598
+
2599
+
2600
+ if ( bXml ) {
2601
+ /***************** close isotopic ***********************/
2602
+ ind -= inc;
2603
+ if ( str_LineEnd( szTag1, 0, nStrLen, &bOverflow, pStr, ind, bPlainTextTags ) )
2604
+ goto exit_function;
2605
+ inchi_print( output_file, "%s", pStr );
2606
+ }
2607
+ } /* Aux info isotopic */
2608
+
2609
+ #if( CANON_FIXH_TRANS != 1 )
2610
+ if ( bSecondNonTautPass ) {
2611
+ /* find and print non-tautomeric components transposition, if non-trivial */
2612
+ AT_NUMB *nTrans_n, *nTrans_s;
2613
+ if ( 0 < bin_AuxTautTrans(pINChISort, pINChISort2, &nTrans_n, &nTrans_s, bOutType, num_components) ) {
2614
+ /* a non-trivial transposition does exist; output start tag */
2615
+ tot_len = str_LineStart( tag=x_aux_trans, NULL, 0, pStr, ind );
2616
+ /* print the transposition, cycle after cycle */
2617
+ tot_len = str_AuxTautTrans(nTrans_n, nTrans_s, pStr, nStrLen, tot_len,
2618
+ &bOverflow, TAUT_MODE, num_components);
2619
+ if ( str_LineEnd( bXml? tag:p_aux_at_inv_nbr, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -1, bPlainTextTags ) )
2620
+ goto exit_function;
2621
+ inchi_print( output_file, "%s", pStr );
2622
+ /* detected transposition */
2623
+ *pSortPrintINChIFlags |= (INCHI_BAS == iINChI)? FLAG_SORT_PRINT_TRANSPOS_BAS :
2624
+ FLAG_SORT_PRINT_TRANSPOS_REC;
2625
+ } else
2626
+ if ( !bXml ) {
2627
+ if ( bPlainTextTags == 1 ) inchi_print( output_file, "/" );
2628
+ }
2629
+ }
2630
+ #endif
2631
+
2632
+ /**************************************************************
2633
+ At this point the INChI_Aux part of the output has been copleted.
2634
+ If this INChI is tautomeric and non-tautomeric results exist
2635
+ then we need to output non-tautomeric auxilialy data
2636
+ (same as above excluding tautomeric information)
2637
+ Currently this is enabled for xml output only
2638
+ ***************************************************************/
2639
+
2640
+ if ( bOutType == OUT_TN && bTautomeric && bNonTautomeric &&
2641
+ /* Check whether the Fixed-H layer is empty */
2642
+ (*pSortPrintINChIFlags & ((INCHI_BAS == iINChI)? FLAG_SORT_PRINT_NO_NFIX_H_BAS :
2643
+ FLAG_SORT_PRINT_NO_NFIX_H_REC )) &&
2644
+ (*pSortPrintINChIFlags & ((INCHI_BAS == iINChI)? FLAG_SORT_PRINT_NO_IFIX_H_BAS :
2645
+ FLAG_SORT_PRINT_NO_IFIX_H_REC ))
2646
+ ) {
2647
+ bNonTautomeric = 0; /* bNonTautIdentifierNotEmpty == 0 => no fixed H info 02-10-2995 */
2648
+ }
2649
+ if ( bOutType == OUT_TN && bTautomeric && bNonTautomeric ) {
2650
+ /* add the second (non-tautomeric) output */
2651
+ bOutType = OUT_NONTAUT;
2652
+ iCurTautMode = TAUT_NON;
2653
+ pINChISort = pINChISortTautAndNonTaut[TAUT_NON];
2654
+ bSecondNonTautPass = 1;
2655
+ num_components = num_comp[iCurTautMode];
2656
+ bFhTag = AL_FIXH;
2657
+ if ( bXml ) {
2658
+ szGetTag( AuxLbl, nTag, bTag1 = bFhTag, szTag1, &bAlways );
2659
+ str_LineStart( szTag1, NULL, 0, pStr, ind );
2660
+ inchi_print( output_file, "%s\n", pStr );
2661
+ ind += inc;
2662
+ } else {
2663
+ pStr[tot_len=0] = '\0';
2664
+ }
2665
+ /* if InChI Fixed-H isotopic is empty then do not output corresponding AuxInfo */
2666
+ if ( !(*pSortPrintINChIFlags &
2667
+ ((INCHI_BAS == iINChI)? FLAG_SORT_PRINT_NO_NFIX_H_BAS :
2668
+ FLAG_SORT_PRINT_NO_NFIX_H_REC ))
2669
+ ) {
2670
+ goto repeat_INChI_Aux_output;
2671
+ } else {
2672
+ goto repeat_INChI_Aux_Iso_output;
2673
+ }
2674
+ } else
2675
+ if ( bOutType == OUT_NONTAUT && bOutputType == OUT_TN && bTautomeric && bNonTautomeric ) {
2676
+ /* the second (non-taut) output has been done; restore variables */
2677
+ bOutType = OUT_TN;
2678
+ iCurTautMode = TAUT_YES;
2679
+ pINChISort = pINChISortTautAndNonTaut[TAUT_YES];
2680
+ bSecondNonTautPass = 0;
2681
+ /* set correct num components for the reversibility info 02-10-2005 */
2682
+ num_components = num_comp[iCurTautMode];
2683
+ if ( bXml ) {
2684
+ /* close non-tautomeric */
2685
+ szGetTag( AuxLbl, nTag, bTag1 = bFhTag, szTag1, &bAlways );
2686
+ ind -= inc;
2687
+ if ( str_LineEnd( szTag1, 0, nStrLen, &bOverflow, pStr, ind, bPlainTextTags ) )
2688
+ goto exit_function;
2689
+ inchi_print( output_file, "%s", pStr );
2690
+ }
2691
+ bFhTag = 0;
2692
+ }
2693
+
2694
+ /***************************************/
2695
+ /* charges, radicals, unusual valences */
2696
+ /***************************************/
2697
+ if ( !bSecondNonTautPass && bChargesRadVal[iCurTautMode] ) {
2698
+ /* aux equ atoms */
2699
+ /* 1. Compare to tautomeric equivalence (in case of second, non-taut, pass only) */
2700
+ /* 2. Compare to the previous component if (1) failed to find equivalence */
2701
+ szGetTag( AuxLbl, nTag, bTag1 = AL_CRV_ | bFhTag, szTag1, &bAlways );
2702
+ tot_len = str_LineStart( szTag1, NULL, 0, pStr, ind );
2703
+ tot_len = str_AuxChargeRadVal(pINChISort, pStr, nStrLen, tot_len,
2704
+ &bOverflow, bOutType, TAUT_MODE,
2705
+ num_components, bUseMulipliers);
2706
+ if ( str_LineEnd( szTag1, tot_len, nStrLen, &bOverflow, pStr, bXml? 0 : -1, bPlainTextTags ) )
2707
+ goto exit_function;
2708
+ inchi_print( output_file, "%s%s", pStr, pLF );
2709
+ }
2710
+
2711
+ /* output the original input structure -- quick fix */
2712
+ if ( !bSecondNonTautPass && pOrigStruct && pOrigStruct->num_atoms &&
2713
+ pOrigStruct->szAtoms && pOrigStruct->szBonds && pOrigStruct->szCoord ) {
2714
+ int length, cur_pos, line_len, last_pos, nMaxLineLen;
2715
+ char *p;
2716
+ nMaxLineLen = inchi_min( 80, nStrLen ); /* restrict line length to 80 characters */
2717
+ /**********************
2718
+ reversibility info
2719
+ **********************/
2720
+ szGetTag( AuxLbl, nTag, bTag1 = AL_REVR | bFhTag, szTag1, &bAlways );
2721
+ if ( bXml ) {
2722
+ str_LineStart( szTag1, NULL, 0, pStr, ind );
2723
+ inchi_print( output_file, "%s\n", pStr );
2724
+ ind += inc;
2725
+ }
2726
+ /* === atoms === */
2727
+ szGetTag( AuxLbl, nTag, bTag2 = bTag1 | AL_ATMR, szTag2, &bAlways );
2728
+ if ( bXml ) {
2729
+ str_LineStart( szTag2, NULL, 0, pStr, ind );
2730
+ inchi_print( output_file, "%s\n", pStr );
2731
+ ind += inc;
2732
+ /* first line indent */
2733
+ strcpy( pStr, SP(ind));
2734
+ tot_len = ind;
2735
+ } else {
2736
+ pStr[tot_len = 0] = '\0';
2737
+ inchi_print( output_file, "%s%s", szTag2, pStr );
2738
+ }
2739
+ p = pOrigStruct->szAtoms;
2740
+ length = strlen( p );
2741
+ line_len = nMaxLineLen - tot_len;
2742
+ for ( cur_pos = 0; cur_pos < length; cur_pos = last_pos ) {
2743
+ if ( length - cur_pos >= line_len ) {
2744
+ last_pos = cur_pos + line_len;
2745
+ /* search backward for the nearest first atom letter (always uppercase) */
2746
+ while ( cur_pos < last_pos && !isupper( UCINT p[last_pos] ) ) {
2747
+ last_pos --;
2748
+ }
2749
+ } else {
2750
+ last_pos = length;
2751
+ }
2752
+ if ( last_pos > cur_pos ) {
2753
+ memcpy( pStr + tot_len, p+cur_pos, last_pos - cur_pos );
2754
+ pStr[tot_len + last_pos - cur_pos] = '\0';
2755
+ inchi_print( output_file, "%s%s", pStr, !bXml && bPlainTextTags? "" : "\n" );
2756
+ } else {
2757
+ break;
2758
+ }
2759
+ }
2760
+ if ( bXml ) {
2761
+ ind -= inc;
2762
+ pStr[0] = '\0';
2763
+ if ( str_LineEnd( szTag2, 0, nMaxLineLen, &bOverflow, pStr, ind, bPlainTextTags ) )
2764
+ goto exit_function;
2765
+ inchi_print( output_file, "%s", pStr );
2766
+ } else
2767
+ if ( pLF[0] ) {
2768
+ inchi_print( output_file, "%s", pLF );
2769
+ }
2770
+
2771
+ /* === bonds === */
2772
+ szGetTag( AuxLbl, nTag, bTag2 = bTag1 | AL_BNDR, szTag2, &bAlways );
2773
+ if ( bXml ) {
2774
+ str_LineStart( szTag2, NULL, 0, pStr, ind );
2775
+ inchi_print( output_file, "%s\n", pStr );
2776
+ ind += inc;
2777
+ /* first line indent */
2778
+ strcpy( pStr, SP(ind));
2779
+ tot_len = ind;
2780
+ } else {
2781
+ pStr[tot_len = 0] = '\0';
2782
+ inchi_print( output_file, "%s%s", szTag2, pStr );
2783
+ }
2784
+ p = pOrigStruct->szBonds;
2785
+ length = strlen( p );
2786
+ line_len = nMaxLineLen - tot_len;
2787
+ for ( cur_pos = 0; cur_pos < length; cur_pos = last_pos ) {
2788
+ if ( length - cur_pos >= line_len ) {
2789
+ last_pos = cur_pos + line_len - 1;
2790
+ /* search backward for the nearest first bond delimiter ";" */
2791
+ while ( cur_pos < last_pos && p[last_pos] != ';' ) {
2792
+ last_pos --;
2793
+ }
2794
+ if ( cur_pos < last_pos ) {
2795
+ last_pos ++; /* include ';' at the end of the line */
2796
+ }
2797
+ } else {
2798
+ last_pos = length;
2799
+ }
2800
+ if ( last_pos > cur_pos ) {
2801
+ memcpy( pStr + tot_len, p+cur_pos, last_pos - cur_pos );
2802
+ pStr[tot_len + last_pos - cur_pos] = '\0';
2803
+ inchi_print( output_file, "%s%s", pStr, !bXml && bPlainTextTags? "" : "\n" );
2804
+ } else {
2805
+ break;
2806
+ }
2807
+ }
2808
+ if ( bXml ) {
2809
+ ind -= inc;
2810
+ pStr[0] = '\0';
2811
+ if ( str_LineEnd( szTag2, 0, nMaxLineLen, &bOverflow, pStr, ind, bPlainTextTags ) )
2812
+ goto exit_function;
2813
+ inchi_print( output_file, "%s", pStr );
2814
+ } else
2815
+ if ( pLF[0] ) {
2816
+ inchi_print( output_file, "%s", pLF );
2817
+ }
2818
+
2819
+ /* === coordinates === */
2820
+ szGetTag( AuxLbl, nTag, bTag2 = bTag1 | AL_XYZR, szTag2, &bAlways );
2821
+ if ( bXml ) {
2822
+ str_LineStart( szTag2, NULL, 0, pStr, ind );
2823
+ inchi_print( output_file, "%s\n", pStr );
2824
+ ind += inc;
2825
+ /* first line indent */
2826
+ strcpy( pStr, SP(ind));
2827
+ tot_len = ind;
2828
+ } else {
2829
+ pStr[tot_len = 0] = '\0';
2830
+ inchi_print( output_file, "%s%s", szTag2, pStr );
2831
+ }
2832
+ p = pOrigStruct->szCoord;
2833
+ length = strlen( p );
2834
+ line_len = nMaxLineLen - tot_len;
2835
+ for ( cur_pos = 0; cur_pos < length; cur_pos = last_pos ) {
2836
+ if ( length - cur_pos >= line_len ) {
2837
+ last_pos = cur_pos + line_len - 1;
2838
+ /* search backward for the nearest first coord. delimiter ";" */
2839
+ while ( cur_pos < last_pos && p[last_pos] != ';' ) {
2840
+ last_pos --;
2841
+ }
2842
+ if ( cur_pos < last_pos ) {
2843
+ last_pos ++; /* include ';' at the end of the line */
2844
+ }
2845
+ } else {
2846
+ last_pos = length;
2847
+ }
2848
+ if ( last_pos > cur_pos ) {
2849
+ memcpy( pStr + tot_len, p+cur_pos, last_pos - cur_pos );
2850
+ pStr[tot_len + last_pos - cur_pos] = '\0';
2851
+ inchi_print( output_file, "%s%s", pStr, !bXml && bPlainTextTags? "" : "\n" );
2852
+ } else {
2853
+ break;
2854
+ }
2855
+ }
2856
+ if ( bXml ) {
2857
+ ind -= inc;
2858
+ pStr[0] = '\0';
2859
+ if ( str_LineEnd( szTag2, 0, nMaxLineLen, &bOverflow, pStr, ind, bPlainTextTags ) )
2860
+ goto exit_function;
2861
+ inchi_print( output_file, "%s", pStr );
2862
+ } else
2863
+ if ( pLF[0] ) {
2864
+ inchi_print( output_file, "%s", pLF );
2865
+ }
2866
+ if ( bXml ) {
2867
+ /***************************
2868
+ close reversibility info
2869
+ ***************************/
2870
+ ind -= inc;
2871
+ if ( str_LineEnd( szTag1, 0, nStrLen, &bOverflow, pStr, ind, bPlainTextTags ) )
2872
+ goto exit_function;
2873
+ inchi_print( output_file, "%s", pStr );
2874
+ }
2875
+ }
2876
+
2877
+
2878
+
2879
+ /************************************************
2880
+ * output INChI_Aux of the reconnected structure *
2881
+ ************************************************/
2882
+ bEmbeddedOutputCalled = 0;
2883
+ if ( bDisconnectedCoord && INCHI_BAS == iINChI && (bINChIOutputOptions & INCHI_OUT_EMBED_REC) &&
2884
+ num_components2[INCHI_REC] && !(bINChIOutputOptions & INCHI_OUT_NO_AUX_INFO) ) {
2885
+ int nRet;
2886
+ bEmbeddedOutputCalled = 1;
2887
+ if ( !bXml ) {
2888
+ inchi_print( output_file, "%s", pLF );
2889
+ }
2890
+ nRet = OutputINChI1( pStr, nStrLen, pINChISortTautAndNonTaut2, INCHI_REC, NULL,
2891
+ 0 /*bDisconnectedCoord*/, bOutputType, INCHI_OUT_ONLY_AUX_INFO | bINChIOutputOptions,
2892
+ bXml, bAbcNumbers, bCtPredecessors, bNoStructLabels,
2893
+ num_components2, num_non_taut2, num_taut2,
2894
+ output_file, log_file, num_input_struct,
2895
+ szSdfLabel, szSdfValue, lSdfId, pSortPrintINChIFlags );
2896
+ if ( !nRet ) {
2897
+ goto exit_function; /* error */
2898
+ }
2899
+ }
2900
+ /* close INChI_Aux */
2901
+ if ( bXml ) {
2902
+ ind -= inc;
2903
+ if ( str_LineEnd( x_aux_basic, 0, nStrLen, &bOverflow, pStr, ind, bPlainTextTags ) )
2904
+ goto exit_function;
2905
+ inchi_print( output_file, "%s", pStr );
2906
+ } else
2907
+ if ( !bEmbeddedOutputCalled && !bPlainTextCommnts ) {
2908
+ inchi_print( output_file, "%s\n", (!num_components2[0] && !num_components2[1])? "//":"" );
2909
+ /* plain text comment earlier ended with LF */
2910
+ }
2911
+ } /* end of output aux info */
2912
+ ret = 1;
2913
+ exit_function:
2914
+
2915
+ if ( bOverflow ) {
2916
+ strcpy( pStr, "Output buffer overflow");
2917
+ if ( bXml ) {
2918
+ OutputINChIXmlError( output_file, pStr, nStrLen, ind /*, 0*/ /* err number */, pStr, _IS_FATAL );
2919
+ } else {
2920
+ inchi_print( output_file, "\nFATAL ERROR: %s\n", pStr );
2921
+ }
2922
+ }
2923
+
2924
+ /* inchi_free( pStr ); */
2925
+ return ret;
2926
+ }
2927
+
2928
+ /***************************************************************/
2929
+ int str_LineStart( const char *tag, char *tag2, int val2, char *pStr, int ind )
2930
+ {
2931
+ int tot_len = 0;
2932
+ if ( ind >= 0 ) {
2933
+ if ( ind > 0 ) {
2934
+ /* xml: indent */
2935
+ memset( pStr + tot_len, ' ', ind );
2936
+ tot_len += ind;
2937
+ }
2938
+ /* xml: tag */
2939
+ strcpy( pStr + tot_len, x_line_opening );
2940
+ strcat( pStr + tot_len, tag );
2941
+ if ( tag2 ) {
2942
+ tot_len += strlen(pStr + tot_len);
2943
+ tot_len += sprintf( pStr + tot_len, " %s=\"%d\"%s", tag2, val2, x_close_line );
2944
+
2945
+ } else {
2946
+ strcat( pStr + tot_len, x_close_line );
2947
+ tot_len += strlen(pStr + tot_len);
2948
+ }
2949
+ } else {
2950
+ pStr[tot_len] = '\0';
2951
+ }
2952
+ return tot_len;
2953
+ }
2954
+ /***************************************************************/
2955
+ int str_LineEnd( const char *tag, int tot_len, int nStrLen, int *bOverflow, char *pStr, int ind, int bPlainTextTags )
2956
+ {
2957
+ static int add_tag_len = sizeof(x_line_closing)-1 + sizeof(x_close_line)-1;
2958
+ int tag_len;
2959
+ /* check buffer overflow */
2960
+ if ( *bOverflow )
2961
+ return 1;
2962
+ if ( ind >= 0 ) { /* xml */
2963
+ tag_len = ind + add_tag_len + strlen(tag);
2964
+ if ( tot_len + tag_len < nStrLen - 2 ) {
2965
+ /* output " </tag>\n" */
2966
+ tot_len += sprintf( pStr + tot_len, "%s%s%s%s\n", SP(ind), x_line_closing, tag, x_close_line );
2967
+ } else {
2968
+ *bOverflow += 1;
2969
+ return 1;
2970
+ }
2971
+ } else { /* plain */
2972
+ pStr[tot_len] = '\0'; /* add zero termination 2004-04-26 */
2973
+ /* insert plain text tag if:
2974
+ (a) pStr has non-zero length, or
2975
+ (b) ind < -1
2976
+ */
2977
+ if ( pStr[0] || ind < -1 ) {
2978
+ tag_len = bPlainTextTags? strlen( tag ):0;
2979
+ if ( tot_len + tag_len < nStrLen - 2 ) {
2980
+ if ( tag_len > 0 ) {
2981
+ /* insert plain text tag */
2982
+ memmove( pStr+tag_len, pStr, tot_len + 1 );
2983
+ memcpy( pStr, tag, tag_len );
2984
+ }
2985
+ } else {
2986
+ *bOverflow += 1;
2987
+ return 1;
2988
+ }
2989
+ }/* else
2990
+ if ( bPlainTextTags == 1 ) {
2991
+ strcpy( pStr, "/" );
2992
+ }*/
2993
+ }
2994
+ return 0;
2995
+ }
2996
+ /**********************************************************************************************/
2997
+ int CleanOrigCoord( MOL_COORD szCoord, int delim )
2998
+ {
2999
+ #define MIN_BOND_LENGTH (1.0e-6)
3000
+ char szVal[LEN_COORD+1];
3001
+ MOL_COORD szBuf;
3002
+ char *q;
3003
+ int len, last, fst, dec_pnt, num_zer=0, len_buf = 0, e;
3004
+ int k, i;
3005
+ double coord;
3006
+
3007
+ for ( k = 0; k < NUM_COORD*LEN_COORD; k += LEN_COORD ) {
3008
+ memcpy( szVal, szCoord+k, LEN_COORD );
3009
+ szVal[LEN_COORD] = '\0';
3010
+ LtrimRtrim(szVal, &len);
3011
+ coord = strtod(szVal, &q);
3012
+ if ( MIN_BOND_LENGTH > fabs(coord) ) {
3013
+ strcpy( szVal, "0" );
3014
+ len = 1;
3015
+ num_zer ++;
3016
+ } else {
3017
+ len = q - szVal;
3018
+ /* last = (last mantissa digit position + 1) */
3019
+ if ( (q = strchr(szVal, 'e')) || (q = strchr(szVal, 'E')) ||
3020
+ (q = strchr(szVal, 'd')) || (q = strchr(szVal, 'D')) ) {
3021
+ /* floating point */
3022
+ last = q - szVal;
3023
+ /* remove (+) and leading zeroes from the exponent */
3024
+ e = (int)strtol( szVal+last+1, &q, 10 ); /* exponent */
3025
+ if ( e ) {
3026
+ /* new exp; update the length */
3027
+ len = last+1+sprintf( szVal+last+1, "%d", e ); /* print exp without leading zeroes and '+' */
3028
+ } else {
3029
+ /* exponent is zero */
3030
+ len = last;
3031
+ }
3032
+ } else {
3033
+ last = len;
3034
+ }
3035
+ /* fst = (first mantissa digit); fst=1 if the sign is present, otherwise 0 */
3036
+ fst = (szVal[0]!='.' && !isdigit( UCINT szVal[0] ));
3037
+ /* dec_pnt = (decimal point position) or last */
3038
+ if ( q = strchr(szVal, '.') ) {
3039
+ dec_pnt = q - szVal;
3040
+ } else {
3041
+ dec_pnt = last;
3042
+ }
3043
+ last -= 1; /* last mantissa digit position */
3044
+ /* remove trailing zeroes in the range dec_pnt+1..last-1 */
3045
+ for ( i = last; dec_pnt < i && '0' == szVal[i]; i -- )
3046
+ ;
3047
+ if ( i == dec_pnt ) {
3048
+ i --; /* remove decimal point, too */
3049
+ }
3050
+ if ( i < last ) {
3051
+ memmove( szVal+i+1, szVal+last+1, len-last );
3052
+ len -= last-i;
3053
+ }
3054
+ /* remove leading zeroes */
3055
+ for ( i = fst; i < len && '0' == szVal[i]; i ++ )
3056
+ ;
3057
+ if ( i > fst ) {
3058
+ memmove( szVal + fst, szVal+i, len-fst );
3059
+ len -= i-fst;
3060
+ }
3061
+ }
3062
+ if ( len_buf )
3063
+ szBuf[len_buf++] = delim;
3064
+ memcpy( szBuf + len_buf, szVal, len ); /* does not copy zero termination*/
3065
+ len_buf += len;
3066
+ }
3067
+ /* zero termination */
3068
+ if ( len_buf < (int)sizeof(MOL_COORD) ) {
3069
+ memset( szBuf+len_buf, 0, sizeof(MOL_COORD) - len_buf);
3070
+ }
3071
+ memcpy( szCoord, szBuf, sizeof(MOL_COORD) );
3072
+ return num_zer;
3073
+ #undef MIN_BOND_LENGTH
3074
+ }
3075
+
3076
+ /******************************************************************************************/
3077
+ int WriteOrigCoord( int num_inp_atoms, MOL_COORD *szMolCoord, int *i, char *szBuf, int buf_len )
3078
+ {
3079
+
3080
+ int j, num_zer, len, cur_len;
3081
+ char *p;
3082
+ MOL_COORD szCurCoord;
3083
+ cur_len = 0;
3084
+ for ( j = *i; j < num_inp_atoms; ) {
3085
+ memcpy( szCurCoord, szMolCoord[j], sizeof(szCurCoord));
3086
+ num_zer = CleanOrigCoord( szCurCoord, ',' );
3087
+ if ( NUM_COORD == num_zer ) {
3088
+ len = 0;
3089
+ } else {
3090
+ if ( p = (char *)memchr( szCurCoord, '\0', sizeof(szCurCoord)) ) {
3091
+ len = p - szCurCoord;
3092
+ } else {
3093
+ len = sizeof(szCurCoord);
3094
+ }
3095
+ }
3096
+ if ( len + cur_len + 1 < buf_len ) {
3097
+ if ( len ) {
3098
+ memcpy( szBuf + cur_len, szCurCoord, len * sizeof(szBuf[0]) );
3099
+ }
3100
+ szBuf[cur_len += len] = ';';
3101
+ cur_len ++;
3102
+ j ++;
3103
+ } else {
3104
+ break;
3105
+ }
3106
+ }
3107
+ szBuf[cur_len] = '\0';
3108
+ *i = j; /* next item */
3109
+ return cur_len;
3110
+ }
3111
+ /******************************************************************************************/
3112
+ /*
3113
+ number of atoms
3114
+ [c|n] chiral/nonchiral
3115
+
3116
+ Element
3117
+ #valence
3118
+ +/-[charge>1]
3119
+ .#rad (#rad=1, 2, 3: singlet, doulet, triplet)
3120
+ [.]i#iso_mass
3121
+ [.]{o|e|u|?} atom parity = {1:2:3:4}
3122
+ [.]h[#of 1H>1]
3123
+ [.]d[#of 2H>1]
3124
+ [.]t[#of 3H>1]
3125
+
3126
+ Note: . occurs only once and only if radical or 1-character element
3127
+ */
3128
+ int WriteOrigAtoms( int num_inp_atoms, inp_ATOM *at, int *i, char *szBuf, int buf_len, STRUCT_DATA *sd)
3129
+ {
3130
+ int j, k, n, len, len0, cur_len, val, mw, parity, num_trans, is_ok, b_self;
3131
+ static char szIsoH[] = "hdt";
3132
+ char szCurAtom[32];
3133
+ AT_NUMB nNeighOrder[MAXVAL], neigh;
3134
+
3135
+ cur_len = 0;
3136
+ if ( 0 == *i ) {
3137
+ cur_len = sprintf( szBuf, "%d%s", num_inp_atoms,
3138
+ (sd->bChiralFlag & FLAG_INP_AT_CHIRAL)? "c" :
3139
+ (sd->bChiralFlag & FLAG_INP_AT_NONCHIRAL)? "n" : "" );
3140
+ }
3141
+ for ( j = *i; j < num_inp_atoms; ) {
3142
+ /* tetrahedral parity treatment */
3143
+ parity = 0;
3144
+ num_trans = 0;
3145
+ if ( at[j].p_parity ) {
3146
+ /* verify neighbors */
3147
+ is_ok = 1;
3148
+ b_self = 0;
3149
+ for ( n = 0, k = 0; n < MAX_NUM_STEREO_ATOM_NEIGH; n ++ ) {
3150
+ neigh = at[j].p_orig_at_num[n]-1;
3151
+ if ( is_in_the_list( at[j].neighbor, neigh, at[j].valence ) &&
3152
+ at[neigh].orig_at_number == at[j].p_orig_at_num[n] ) {
3153
+ /* real neighbor */
3154
+ nNeighOrder[k ++] = at[j].p_orig_at_num[n];
3155
+ } else
3156
+ if ( (int)neigh == j && at[neigh].orig_at_number == at[j].p_orig_at_num[n] ) {
3157
+ /* central atom is a neighbor */
3158
+ num_trans = n; /* move this neighbor to 0 position permutation parity */
3159
+ b_self ++;
3160
+ } else {
3161
+ is_ok = 0;
3162
+ break;
3163
+ }
3164
+ }
3165
+ if ( is_ok && b_self <= 1 && b_self + k == MAX_NUM_STEREO_ATOM_NEIGH ) {
3166
+ num_trans += insertions_sort( nNeighOrder, k, sizeof(nNeighOrder[0]), comp_AT_RANK );
3167
+ if ( ATOM_PARITY_WELL_DEF( at[j].p_parity ) ) {
3168
+ parity = 2 - (num_trans + at[j].p_parity) % 2;
3169
+ } else
3170
+ if ( ATOM_PARITY_ILL_DEF( at[j].p_parity ) ) {
3171
+ parity = at[j].p_parity;
3172
+ } else {
3173
+ ; /* invalid atom parity */
3174
+ }
3175
+ } else {
3176
+ ;/* add error message here */
3177
+ }
3178
+ }
3179
+
3180
+ len = len0 = strlen( at[j].elname );
3181
+ memcpy( szCurAtom, at[j].elname, len );
3182
+ if ( (val=needed_unusual_el_valence( at[j].el_number, at[j].charge, at[j].radical,
3183
+ at[j].chem_bonds_valence, at[j].num_H, at[j].valence )) ||
3184
+ at[j].charge || at[j].radical || at[j].iso_atw_diff || NUM_ISO_H(at,j) || parity ) {
3185
+ /* valence */
3186
+ if ( val ) {
3187
+ len += sprintf( szCurAtom + len, "%d", val > 0? val : 0 );
3188
+ }
3189
+ /* charge */
3190
+ if ( val = at[j].charge ) {
3191
+ szCurAtom[len++] = val>0? '+' : '-';
3192
+ if ( (val = abs(val)) > 1 ) {
3193
+ len += sprintf( szCurAtom + len, "%d", val );
3194
+ }
3195
+ }
3196
+ /* radical */
3197
+ if ( val = at[j].radical ) {
3198
+ len += sprintf(szCurAtom + len, ".%d", val);
3199
+ }
3200
+ /* isotopic shift */
3201
+ if ( val = at[j].iso_atw_diff ) {
3202
+ mw = get_atw_from_elnum( at[j].el_number );
3203
+ if ( val == 1 )
3204
+ val = mw;
3205
+ else
3206
+ if ( val > 0 )
3207
+ val = mw + val -1;
3208
+ else
3209
+ val = mw + val;
3210
+ len += sprintf( szCurAtom + len, "%si%d", len == len0? ".":"", val );
3211
+ }
3212
+ /* parity */
3213
+ if ( parity ) {
3214
+ len += sprintf( szCurAtom + len, "%s%s", len == len0? ".":"",
3215
+ parity == AB_PARITY_ODD? "o" :
3216
+ parity == AB_PARITY_EVEN? "e" :
3217
+ parity == AB_PARITY_UNKN? "u" :
3218
+ parity == AB_PARITY_UNDF? "?" : "" );
3219
+ }
3220
+ /* implicit isotopic H */
3221
+ if ( NUM_ISO_H(at,j) ) {
3222
+ for ( k = 0; k < NUM_H_ISOTOPES; k ++ ) {
3223
+ if ( val = at[j].num_iso_H[k] ) {
3224
+ len += sprintf( szCurAtom + len, "%s%c", len == len0? ".":"", szIsoH[k] );
3225
+ if ( val > 1 ) {
3226
+ len += sprintf(szCurAtom + len, "%d", val);
3227
+ }
3228
+ }
3229
+ }
3230
+ }
3231
+ }
3232
+ if ( len + cur_len < buf_len ) {
3233
+ memcpy( szBuf + cur_len, szCurAtom, len );
3234
+ cur_len += len;
3235
+ j ++;
3236
+ } else {
3237
+ break;
3238
+ }
3239
+ szBuf[cur_len] = '\0';
3240
+ *i = j;
3241
+
3242
+ }
3243
+ return cur_len;
3244
+ }
3245
+ /******************************************************************************************/
3246
+ /*
3247
+ <bonds> bpA;bpAbpA... </bonds>
3248
+
3249
+ b = bond type:
3250
+ =============
3251
+ v = undefined stereo, single
3252
+ w = undefined stereo, double
3253
+ s = single
3254
+ d = double
3255
+ t = triple
3256
+ a = aromatic
3257
+ p = up from the current atom to the neighbor
3258
+ P = uP from the neighbor to the current atom
3259
+ n = down from the current atom to the neighbor
3260
+ N = dowN from the neighbor to the current atom
3261
+
3262
+ p = bond parity:
3263
+ ================
3264
+ - = odd
3265
+ + = even
3266
+ u = unknown
3267
+ ? = undefined
3268
+ = no parity (empty)
3269
+
3270
+
3271
+ A=orig. number
3272
+ ===============
3273
+ of the neighbor < number of the current atom
3274
+ Number of the current atom: 2 until first ";", 3 until 2nd ";", etc.
3275
+
3276
+ */
3277
+
3278
+ /************************************************************************************/
3279
+ /* output bonds in ascending order of the neighboring atom original numbers */
3280
+ int WriteOrigBonds( int num_inp_atoms, inp_ATOM *at, int *i, char *szBuf, int buf_len, STRUCT_DATA *sd)
3281
+ {
3282
+ int j, k, k2, kk, len, cur_len, j2=0, bond_stereo, bond_char, bond_parity, bond_parityNM, num_trans;
3283
+ char szCurBonds[5*MAXVAL+1+2*MAXVAL]; /* 1 byte bond type + up to 4 digits per neighbor number + 1 + 2*sign for bond parity; */
3284
+ AT_RANK nNeighOrder[MAXVAL];
3285
+ int chain_len, pnxt_atom, pinxt2cur, pinxt_sb_parity_ord;
3286
+ int chain_len2, pnxt_atom2, pinxt2cur2, pinxt_sb_parity_ord2, m1, m2;
3287
+ int pcur_atom, picur2nxt, picur_sb_parity_ord;
3288
+
3289
+ cur_len = 0;
3290
+ for ( j = *i; j < num_inp_atoms; ) {
3291
+ len = 0;
3292
+ if ( at[j].valence > 1 ) {
3293
+ for ( k = 0; k < at[j].valence; k ++ ) {
3294
+ nNeighOrder[k] = k;
3295
+ }
3296
+ pn_RankForSort = at[j].neighbor;
3297
+ num_trans = insertions_sort( nNeighOrder, at[j].valence, sizeof(nNeighOrder[0]), CompRank );
3298
+ } else {
3299
+ num_trans = 0;
3300
+ nNeighOrder[0] = 0;
3301
+ }
3302
+ for ( kk = 0; kk < at[j].valence; kk ++ ) {
3303
+ k = nNeighOrder[kk];
3304
+ j2 = at[j].neighbor[k];
3305
+ bond_parity = 0;
3306
+ bond_parityNM = 0;
3307
+ if ( j2 < j ) {
3308
+ bond_stereo = at[j].bond_stereo[k];
3309
+ switch( at[j].bond_type[k] ) {
3310
+ case BOND_TYPE_SINGLE:
3311
+ switch( bond_stereo ) {
3312
+ case STEREO_SNGL_UP:
3313
+ bond_char = 'p';
3314
+ break;
3315
+ case -STEREO_SNGL_UP:
3316
+ bond_char = 'P';
3317
+ break;
3318
+ case STEREO_SNGL_DOWN:
3319
+ bond_char = 'n';
3320
+ break;
3321
+ case -STEREO_SNGL_DOWN:
3322
+ bond_char = 'N';
3323
+ break;
3324
+ case STEREO_SNGL_EITHER:
3325
+ case -STEREO_SNGL_EITHER:
3326
+ bond_char = 'v';
3327
+ break;
3328
+ default:
3329
+ bond_char = 's';
3330
+ break;
3331
+ }
3332
+ break;
3333
+ case BOND_TYPE_DOUBLE:
3334
+ switch( bond_stereo ) {
3335
+ case STEREO_DBLE_EITHER:
3336
+ case -STEREO_DBLE_EITHER:
3337
+ bond_char = 'w';
3338
+ break;
3339
+ default:
3340
+ bond_char = 'd';
3341
+ break;
3342
+ }
3343
+ break;
3344
+ case BOND_TYPE_TRIPLE:
3345
+ bond_char = 't';
3346
+ break;
3347
+ case BOND_TYPE_ALTERN:
3348
+ bond_char = 'a';
3349
+ break;
3350
+ default:
3351
+ bond_char = 's';
3352
+ break;
3353
+ }
3354
+ /* check for allene/cumulene */
3355
+ k2 = is_in_the_list( at[j2].neighbor, (AT_NUMB)j, at[j2].valence ) - at[j2].neighbor;
3356
+ chain_len = chain_len2 = 0;
3357
+ if ( at[j].sb_parity[0] ) {
3358
+ for ( m1 = 0; m1 < MAX_NUM_STEREO_BONDS && at[j].sb_parity[m1]; m1 ++ ) {
3359
+ if ( k == at[j].sb_ord[m1] ) {
3360
+ chain_len = get_opposite_sb_atom( at, j, k,
3361
+ &pnxt_atom, &pinxt2cur, &pinxt_sb_parity_ord );
3362
+ break;
3363
+ }
3364
+ }
3365
+ }
3366
+ if ( at[j2].sb_parity[0] ) {
3367
+ for ( m2 = 0; m2 < MAX_NUM_STEREO_BONDS && at[j2].sb_parity[m2]; m2 ++ ) {
3368
+ if ( k2 == at[j2].sb_ord[m2] ) {
3369
+ chain_len2 = get_opposite_sb_atom( at, j2, k2,
3370
+ &pnxt_atom2, &pinxt2cur2, &pinxt_sb_parity_ord2 );
3371
+ break;
3372
+ }
3373
+ }
3374
+ }
3375
+ if ( chain_len == 1 && chain_len2 == 1 || /* regular stereobond */
3376
+ chain_len > 1 && j > pnxt_atom ) { /* j is a cumulene endpoint */
3377
+ int m;
3378
+ pcur_atom = j; /* pcur_atom > pnxt_atom */
3379
+ picur2nxt = k;
3380
+ picur_sb_parity_ord = -1;
3381
+ for ( m = 0; m < MAX_NUM_STEREO_BONDS && at[pcur_atom].sb_parity[m]; m ++ ) {
3382
+ if ( at[pcur_atom].sb_ord[m] == k ) {
3383
+ picur_sb_parity_ord = m;
3384
+ break;
3385
+ }
3386
+ }
3387
+ chain_len2 = 0;
3388
+ } else
3389
+ if ( chain_len2 > 1 && j2 > pnxt_atom2 ) { /* j2 is a cumulene endpoint */
3390
+ int m;
3391
+ pcur_atom = j2;
3392
+ picur2nxt = k2;
3393
+ pnxt_atom = pnxt_atom2;
3394
+ pinxt2cur = pinxt2cur2;
3395
+ pinxt_sb_parity_ord = pinxt_sb_parity_ord2;
3396
+ picur_sb_parity_ord = -1;
3397
+ for ( m = 0; m < MAX_NUM_STEREO_BONDS && at[pcur_atom].sb_parity[m]; m ++ ) {
3398
+ if ( at[pcur_atom].sb_ord[m] == k2 )
3399
+ picur_sb_parity_ord = m;
3400
+ }
3401
+ chain_len = chain_len2;
3402
+ chain_len2 = 0;
3403
+ } else {
3404
+ chain_len = chain_len2 = 0;
3405
+ }
3406
+
3407
+ /*len += sprintf( szCurBonds + len, "%c%d", bond_char, val+1);*/
3408
+ if ( chain_len ) {
3409
+ /* both atoms belong to a stereo bond */
3410
+ int kc;
3411
+ int p1, p2, p1NM, p2NM, neigh, neigh1, neigh2, bHasMetal, bWellDef;
3412
+ int bNeighSwitched1, bNeighSwitched2;
3413
+
3414
+ p1 = SB_PARITY_1(at[pcur_atom].sb_parity[picur_sb_parity_ord]);
3415
+ p1NM = SB_PARITY_2(at[pcur_atom].sb_parity[picur_sb_parity_ord]);
3416
+ p2 = SB_PARITY_1(at[pnxt_atom].sb_parity[pinxt_sb_parity_ord]);
3417
+ p2NM = SB_PARITY_2(at[pnxt_atom].sb_parity[pinxt_sb_parity_ord]);
3418
+
3419
+ bWellDef = ATOM_PARITY_WELL_DEF(p1) && ATOM_PARITY_WELL_DEF(p2);
3420
+ bHasMetal = ATOM_PARITY_WELL_DEF(p1NM) && ATOM_PARITY_WELL_DEF(p2NM);
3421
+
3422
+ bNeighSwitched1 = bNeighSwitched2 = 0;
3423
+
3424
+ if ( bWellDef || bHasMetal ) {
3425
+
3426
+ neigh1 = num_inp_atoms;
3427
+ for ( kc = 0; kc < at[pcur_atom].valence; kc ++ ) {
3428
+ if ( kc == picur2nxt )
3429
+ continue;
3430
+ neigh = at[pcur_atom].neighbor[kc];
3431
+ if ( bHasMetal && is_el_a_metal( at[neigh].el_number ) )
3432
+ continue;
3433
+ if ( neigh < neigh1 )
3434
+ neigh1 = neigh;
3435
+ }
3436
+ if ( neigh1 < num_inp_atoms ) {
3437
+ bNeighSwitched1 = (neigh1 != at[pcur_atom].neighbor[(int)at[pcur_atom].sn_ord[picur_sb_parity_ord]]);
3438
+ } else {
3439
+ AddMOLfileError(sd->pStrErrStruct, "Cannot find 0D stereobond neighbor");
3440
+ /*
3441
+ sd->nStructReadError = 99;
3442
+ sd->nErrorType = _IS_ERROR;
3443
+ */
3444
+
3445
+ }
3446
+
3447
+ neigh2 = num_inp_atoms;
3448
+ for ( kc = 0; kc < at[pnxt_atom].valence; kc ++ ) {
3449
+ if ( kc == pinxt2cur )
3450
+ continue;
3451
+ neigh = at[pnxt_atom].neighbor[kc];
3452
+ if ( bHasMetal && is_el_a_metal( at[neigh].el_number ) )
3453
+ continue;
3454
+ if ( neigh < neigh2 )
3455
+ neigh2 = neigh;
3456
+ }
3457
+ if ( neigh2 < num_inp_atoms ) {
3458
+ bNeighSwitched2 = (neigh2 != at[pnxt_atom].neighbor[(int)at[pnxt_atom].sn_ord[pinxt_sb_parity_ord]]);
3459
+ } else {
3460
+ AddMOLfileError(sd->pStrErrStruct, "Cannot find 0D stereobond neighbor");
3461
+ /*
3462
+ sd->nStructReadError = 99;
3463
+ sd->nErrorType = _IS_ERROR;
3464
+ */
3465
+
3466
+ }
3467
+
3468
+ if ( neigh1 < num_inp_atoms && neigh2 < num_inp_atoms ) {
3469
+ if ( ATOM_PARITY_WELL_DEF(p1) && ATOM_PARITY_WELL_DEF(p2) ) {
3470
+ bond_parity = 2 - (p1 + p2 + bNeighSwitched1 + bNeighSwitched2) % 2;
3471
+ } else {
3472
+ bond_parity = inchi_min( p1, p2 );
3473
+ }
3474
+
3475
+ if ( bHasMetal ) {
3476
+ bond_parityNM = 2 - (p1NM + p2NM + bNeighSwitched1 + bNeighSwitched2) % 2;
3477
+ } else
3478
+ if ( p1NM && p2NM ) {
3479
+ bond_parityNM = inchi_min( p1NM, p2NM );
3480
+ }
3481
+ }
3482
+ } else {
3483
+ if ( p1 && p2 ) {
3484
+ bond_parity = inchi_min( p1, p2 );
3485
+ }
3486
+ if ( p1NM && p2NM ) {
3487
+ bond_parityNM = inchi_min( p1NM, p2NM );
3488
+ }
3489
+ if ( bond_parityNM && !bond_parity ) {
3490
+ bond_parity = AB_PARITY_UNDF;
3491
+ }
3492
+ }
3493
+ }
3494
+ len += sprintf( szCurBonds + len, "%c%s%s%d",
3495
+
3496
+ bond_char,
3497
+
3498
+ (bond_parity == AB_PARITY_ODD)? "-" :
3499
+ (bond_parity == AB_PARITY_EVEN)? "+" :
3500
+ (bond_parity == AB_PARITY_UNKN)? "u" :
3501
+ (bond_parity == AB_PARITY_UNDF)? "?" : "",
3502
+
3503
+ (bond_parityNM == AB_PARITY_ODD)? "-" :
3504
+ (bond_parityNM == AB_PARITY_EVEN)? "+" :
3505
+ (bond_parityNM == AB_PARITY_UNKN)? "u" :
3506
+ (bond_parityNM == AB_PARITY_UNDF)? "?" : "",
3507
+
3508
+ j2+1);
3509
+ }
3510
+ }
3511
+ if ( len + cur_len + 2 < buf_len ) {
3512
+ memcpy( szBuf + cur_len, szCurBonds, len );
3513
+ cur_len += len;
3514
+ szBuf[ cur_len ++ ] = ';';
3515
+ j ++;
3516
+ } else {
3517
+ break;
3518
+ }
3519
+ }
3520
+ szBuf[cur_len] = '\0';
3521
+ *i = num_inp_atoms>0? j : 0;
3522
+ return cur_len;
3523
+ }
3524
+
3525
+
3526
+ #define ORIG_STR_BUFLEN 64 /* > 5*MAXVAL+2 = 52 */
3527
+ /******************************************************************************************/
3528
+ int FillOutOrigStruct( ORIG_ATOM_DATA *orig_inp_data, ORIG_STRUCT *pOrigStruct, STRUCT_DATA *sd )
3529
+ {
3530
+ char szBuf[ORIG_STR_BUFLEN];
3531
+ int i, len, len_coord, len_atoms, len_bonds;
3532
+ /* coordinates */
3533
+ len_coord = i = 0;
3534
+
3535
+ if (orig_inp_data->szCoord) {
3536
+
3537
+ while ( len = WriteOrigCoord( orig_inp_data->num_inp_atoms,
3538
+ orig_inp_data->szCoord, &i, szBuf, sizeof(szBuf) )) {
3539
+ len_coord += len;
3540
+ }
3541
+ pOrigStruct->szCoord = (char*) inchi_malloc( (len_coord + 1)*sizeof(pOrigStruct->szCoord[0]) );
3542
+ i = 0;
3543
+ if ( pOrigStruct->szCoord &&
3544
+ len_coord == WriteOrigCoord( orig_inp_data->num_inp_atoms,
3545
+ orig_inp_data->szCoord, &i, pOrigStruct->szCoord, len_coord+1 ) &&
3546
+ i == orig_inp_data->num_inp_atoms ) {
3547
+ /* success */
3548
+ if ( orig_inp_data->szCoord ) {
3549
+ inchi_free( orig_inp_data->szCoord );
3550
+ orig_inp_data->szCoord = NULL;
3551
+ }
3552
+ } else {
3553
+ return -1;
3554
+ }
3555
+
3556
+ }
3557
+
3558
+ /* atoms */
3559
+ len_atoms = i = 0;
3560
+ while ( len = WriteOrigAtoms( orig_inp_data->num_inp_atoms,
3561
+ orig_inp_data->at, &i, szBuf, sizeof(szBuf), sd)) {
3562
+ len_atoms += len;
3563
+ if ( !orig_inp_data->num_inp_atoms )
3564
+ break;
3565
+ }
3566
+ pOrigStruct->szAtoms = (char*) inchi_malloc( (len_atoms + 1)*sizeof(pOrigStruct->szAtoms[0]) );
3567
+ i = 0;
3568
+ if ( pOrigStruct->szAtoms &&
3569
+ len_atoms == WriteOrigAtoms( orig_inp_data->num_inp_atoms,
3570
+ orig_inp_data->at, &i, pOrigStruct->szAtoms, len_atoms+1, sd ) &&
3571
+ i == orig_inp_data->num_inp_atoms ) {
3572
+ ; /* success */
3573
+ } else {
3574
+ return -1;
3575
+ }
3576
+ /* bonds */
3577
+ len_bonds = 0;
3578
+ i = 1;
3579
+ while ( len = WriteOrigBonds( orig_inp_data->num_inp_atoms,
3580
+ orig_inp_data->at, &i, szBuf, sizeof(szBuf), NULL)) {
3581
+ len_bonds += len;
3582
+ if ( !orig_inp_data->num_inp_atoms )
3583
+ break;
3584
+ }
3585
+ pOrigStruct->szBonds = (char*) inchi_malloc( (len_bonds + 2)*sizeof(pOrigStruct->szBonds[0]) );
3586
+ i = 1;
3587
+ if ( pOrigStruct->szBonds &&
3588
+ len_bonds == WriteOrigBonds( orig_inp_data->num_inp_atoms,
3589
+ orig_inp_data->at, &i, pOrigStruct->szBonds, len_bonds+2, sd ) &&
3590
+ i == orig_inp_data->num_inp_atoms ) {
3591
+ ; /* success */
3592
+ } else {
3593
+ return -1;
3594
+ }
3595
+ pOrigStruct->num_atoms = orig_inp_data->num_inp_atoms;
3596
+ return 0;
3597
+ }
3598
+ /*****************************************************************/
3599
+ void FreeOrigStruct( ORIG_STRUCT *pOrigStruct)
3600
+ {
3601
+ if ( pOrigStruct ) {
3602
+ if ( pOrigStruct->szAtoms )
3603
+ inchi_free( pOrigStruct->szAtoms );
3604
+ if ( pOrigStruct->szBonds )
3605
+ inchi_free( pOrigStruct->szBonds );
3606
+ if ( pOrigStruct->szCoord )
3607
+ inchi_free( pOrigStruct->szCoord );
3608
+ memset( pOrigStruct, 0, sizeof(*pOrigStruct) );
3609
+
3610
+ }
3611
+ }
3612
+