rino 0.1.0

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