Branch data Line data Source code
1 : : /*
2 : : * SPDX-License-Identifier: MIT
3 : : * Copyright (c) 2024 IUPAC and InChI Trust
4 : : */
5 : :
6 : : #include <stdlib.h>
7 : : #include <string.h>
8 : : #include <ctype.h>
9 : : #include <math.h>
10 : :
11 : : #include "mode.h"
12 : :
13 : : #include "ichister.h"
14 : : #include "ichimain.h"
15 : : #include "ichimake.h"
16 : : #include "ichi_io.h"
17 : :
18 : : #include "bcf_s.h"
19 : :
20 : : #include "logging.h" /*(@nnuk : Nauman Ullah Khan) :: Needed for logging functionality*/
21 : :
22 : : /*
23 : : Local functions
24 : : */
25 : :
26 : : /* djb-rwth: removing redundant code */
27 : : static int str_LineEnd( const char *tag,
28 : : int *bOverflow,
29 : : INCHI_IOS_STRING *buf,
30 : : int ind,
31 : : int bPlainTextTags );
32 : : static int CleanOrigCoord( MOL_COORD szCoord, int delim );
33 : : static int WriteOrigCoord( int num_inp_atoms,
34 : : MOL_COORD *szMolCoord,
35 : : int *i,
36 : : char *szBuf,
37 : : int buf_len );
38 : : static int WriteOrigAtoms( CANON_GLOBALS *pCG,
39 : : int num_inp_atoms,
40 : : inp_ATOM *at,
41 : : int *i,
42 : : char *szBuf,
43 : : int buf_len,
44 : : STRUCT_DATA *sd );
45 : : static int WriteOrigBonds( CANON_GLOBALS *pCG,
46 : : int num_inp_atoms,
47 : : inp_ATOM *at,
48 : : int *i,
49 : : char *szBuf,
50 : : int buf_len,
51 : : STRUCT_DATA *sd );
52 : : static void GetSaveOptLetters( unsigned char save_opt_bits,
53 : : char* let1,
54 : : char* let2 );
55 : : static int OutputINCHI_VersionAndKind( INCHI_IOSTREAM *out_file,
56 : : INCHI_IOS_STRING *strbuf,
57 : : int bINChIOutputOptions,
58 : : int is_beta,
59 : : char *pLF,
60 : : char *pTAB );
61 : : static int OutputINCHI_MainLayerFormula( CANON_GLOBALS *pCG,
62 : : INCHI_IOSTREAM *out_file,
63 : : INCHI_IOS_STRING *strbuf,
64 : : int num_components2[],
65 : : int *INCHI_basic_or_INCHI_reconnected,
66 : : INCHI_OUT_CTL *io,
67 : : char *pLF,
68 : : char *pTAB );
69 : : static int OutputINCHI_MainLayerConnections( CANON_GLOBALS *pCG,
70 : : INCHI_IOSTREAM *out_file,
71 : : INCHI_IOS_STRING *strbuf,
72 : : int num_components2[],
73 : : int *INCHI_basic_or_INCHI_reconnected,
74 : : INCHI_OUT_CTL *io,
75 : : char *pLF,
76 : : char *pTAB );
77 : : static int OutputINCHI_MainLayerHydrogens( CANON_GLOBALS *pCG,
78 : : INCHI_IOSTREAM *out_file,
79 : : INCHI_IOS_STRING *strbuf,
80 : : int num_components2[],
81 : : int *INCHI_basic_or_INCHI_reconnected,
82 : : INCHI_OUT_CTL *io,
83 : : char *pLF,
84 : : char *pTAB );
85 : : static int OutputINCHI_ChargeAndRemovedAddedProtonsLayers( CANON_GLOBALS *pCG,
86 : : INCHI_IOSTREAM *out_file,
87 : : INCHI_IOS_STRING *strbuf,
88 : : INCHI_OUT_CTL *io,
89 : : char *pLF,
90 : : char *pTAB );
91 : : static int OutputINCHI_StereoLayer( CANON_GLOBALS *pCG,
92 : : INCHI_IOSTREAM *out_file,
93 : : INCHI_IOS_STRING *strbuf,
94 : : INCHI_OUT_CTL *io,
95 : : char *pLF,
96 : : char *pTAB );
97 : : static int OutputINCHI_StereoLayer_EnhancedStereo( CANON_GLOBALS *pCG,
98 : : INCHI_IOSTREAM *out_file,
99 : : INCHI_IOS_STRING *strbuf,
100 : : INCHI_OUT_CTL *io,
101 : : ORIG_ATOM_DATA *orig_inp_data,
102 : : char *pLF,
103 : : char *pTAB );
104 : : static int OutputINCHI_IsotopicLayer( CANON_GLOBALS *pCG,
105 : : INCHI_IOSTREAM *out_file,
106 : : INCHI_IOS_STRING *strbuf,
107 : : int *INCHI_basic_or_INCHI_reconnected,
108 : : INCHI_OUT_CTL *io,
109 : : char *pLF,
110 : : char *pTAB );
111 : : static int OutputINCHI_FixedHLayerWithSublayers( CANON_GLOBALS *pCG,
112 : : INCHI_IOSTREAM *out_file,
113 : : INCHI_IOS_STRING *strbuf,
114 : : int *INCHI_basic_or_INCHI_reconnected,
115 : : INCHI_OUT_CTL *io,
116 : : char *pLF,
117 : : char *pTAB,
118 : : int *then_goto_repeat );
119 : : static int OutputINCHI_PolymerLayer( CANON_GLOBALS *pCG, INCHI_IOSTREAM *out_file, INCHI_IOS_STRING *strbuf,
120 : : int *INCHI_basic_or_INCHI_reconnected,
121 : : ORIG_ATOM_DATA *orig_inp_data, ORIG_STRUCT *pOrigStruct,
122 : : INCHI_OUT_CTL *io, char *pLF, char *pTAB );
123 : : static int OutputINCHI_PolymerLayer_SingleUnit( OAD_PolymerUnit *u,
124 : : int bPolymers,
125 : : int total_star_atoms,
126 : : int *n_used_stars,
127 : : OAD_AtProps *aprops,
128 : : int *cano_nums,
129 : : ORIG_ATOM_DATA *orig_inp_data,
130 : : ORIG_STRUCT *pOrigStruct,
131 : : INCHI_IOS_STRING *strbuf );
132 : : static int OutputAUXINFO_HeaderAndNormalization_type( CANON_GLOBALS *pCG,
133 : : INCHI_IOSTREAM *out_file,
134 : : INCHI_IOS_STRING *strbuf,
135 : : int bINChIOutputOptions,
136 : : int *INCHI_basic_or_INCHI_reconnected,
137 : : int num_components2[],
138 : : INCHI_OUT_CTL *io,
139 : : char *pLF,
140 : : char *pTAB );
141 : : static int OutputAUXINFO_OriginalNumbersAndEquivalenceClasses( CANON_GLOBALS *pCG,
142 : : INCHI_IOSTREAM *out_file,
143 : : INCHI_IOS_STRING *strbuf,
144 : : int num_components2[],
145 : : INCHI_OUT_CTL *io,
146 : : char *pLF,
147 : : char *pTAB );
148 : : static int OutputAUXINFO_TautomericGroupsEquivalence( CANON_GLOBALS *pCG,
149 : : INCHI_IOSTREAM *out_file,
150 : : INCHI_IOS_STRING *strbuf,
151 : : INCHI_OUT_CTL *io );
152 : : static int OutputAUXINFO_Stereo( CANON_GLOBALS *pCG,
153 : : INCHI_IOSTREAM *out_file,
154 : : INCHI_IOS_STRING *strbuf,
155 : : INCHI_OUT_CTL *io,
156 : : char *pLF,
157 : : char *pTAB );
158 : : static int OutputAUXINFO_IsotopicInfo( CANON_GLOBALS *pCG,
159 : : INCHI_IOSTREAM *out_file,
160 : : INCHI_IOS_STRING *strbuf,
161 : : int *INCHI_basic_or_INCHI_reconnected,
162 : : INCHI_OUT_CTL *io,
163 : : char *pLF, char *pTAB );
164 : : /* djb-rwth: removing redundant code */
165 : : static int OutputAUXINFO_ChargesRadicalsAndUnusualValences( CANON_GLOBALS *pCG,
166 : : INCHI_IOSTREAM *out_file,
167 : : INCHI_IOS_STRING *strbuf,
168 : : INCHI_OUT_CTL *io,
169 : : char *pLF,
170 : : char *pTAB );
171 : : static int OutputAUXINFO_ReversibilityInfo( CANON_GLOBALS *pCG,
172 : : INCHI_IOSTREAM *out_file,
173 : : INCHI_IOS_STRING *strbuf,
174 : : ORIG_STRUCT *pOrigStruct,
175 : : INCHI_OUT_CTL *io,
176 : : char *pLF,
177 : : char *pTAB );
178 : :
179 : : static int OutputAUXINFO_PolymerInfo(CANON_GLOBALS *pCG,
180 : : INCHI_IOSTREAM *out_file,
181 : : INCHI_IOS_STRING *strbuf,
182 : : ORIG_STRUCT *pOrigStruct,
183 : : INCHI_OUT_CTL *io,
184 : : char *pLF,
185 : : char *pTAB);
186 : :
187 : : static int InternallyGetCanoNumsAndComponentNums(CANON_GLOBALS *pCG,
188 : : INCHI_IOS_STRING *strbuf,
189 : : INCHI_OUT_CTL *io,
190 : : int nat,
191 : : int *cano_nums,
192 : : int *compnt_nums);
193 : :
194 : : static int CountPseudoElementInFormula(const char *pseudo, char *s);
195 : : static int IsBondAtomNumsLesser(int *bond1, int *bond2);
196 : :
197 : : static void inchi_sort_int_pair_ascending(int *a, int *b);
198 : :
199 : : /* djb-rwth: removing redundant code */
200 : :
201 : : static void MergeZzInStrHillFormulaComponent(char *s);
202 : :
203 : : /*
204 : : Local constants
205 : : */
206 : : const char sCompDelim[] = ";"; /* component delimiter */
207 : : const char sIdenticalValues[] = "*"; /* identical component */
208 : : const char x_space[] = " ";
209 : :
210 : : /*
211 : : Output: words & additional tags
212 : : */
213 : : const char x_inchi[] = INCHI_NAME;
214 : : const char x_inchi_ver[] = "version"; /* "InChI.version"; */
215 : : const char x_curr_ver[] = INCHI_VERSION;
216 : : const char x_structure[] = "structure";
217 : : const char x_number[] = "number";
218 : : const char x_header[] = "id.name";
219 : : const char x_value[] = "id.value";
220 : : const char x_empty[] = "";
221 : : const char x_type[] = "type";
222 : : const char x_message[] = "message";
223 : : const char x_text[] = "value";
224 : : const char x_ferr[] = "fatal (aborted)";
225 : : const char x_err[] = "error (no InChI)";
226 : : const char x_warn[] = "warning";
227 : : const char x_basic[] = "identifier";
228 : : const char x_tautomeric[] = "mobile-H";
229 : : const char x_reconnected[] = "reconnected";
230 : : const char x_ver[] = "version";
231 : : const char x_type_alpha[] = "alpha";
232 : : const char x_type_numer[] = "numeric";
233 : : const char x_type_predec[] = "sct";
234 : : const char x_type_normal[] = "normal";
235 : : const char x_type_short[] = "compressed";
236 : : const char x_basic_layer[] = "basic";
237 : : const char x_aux_basic[] = "identifier.auxiliary-info";
238 : : const char x_aux_comm[] = "!-- This section is NOT a part of the identifier, it is not unique --";
239 : : const char x_ign_uu_sp2[] = "omit_undef_dbond";
240 : : const char x_ign_uu_sp3[] = "omit_undef_sp3";
241 : : const char x_line_opening[] = "<";
242 : : const char x_line_closing[] = "</";
243 : : const char x_close_line[] = ">";
244 : : const char x_abs[] = "1";
245 : : const char x_rel[] = "2";
246 : : const char x_rac[] = "3";
247 : :
248 : : typedef struct tagInchiTag
249 : : {
250 : : const char *szPlainLabel;
251 : : const char *szPlainComment;
252 : : const char *szXmlLabel;
253 : : int bAlwaysOutput;
254 : : } INCHI_TAG;
255 : :
256 : : /*
257 : : Identifier
258 : : */
259 : : const INCHI_TAG IdentLbl[] =
260 : : {
261 : : /* prefixes: may be combined in this order */
262 : : /* IL_FIXH_ORD, */ {"/", "fixed_H", "fixed-H", 0}, /* fixed H */
263 : : /* IL_ISOT_ORD, */ {"/", "isotopic", "isotopic", 0}, /* isotopic */
264 : : /* IL_STER_ORD, */ {"/", "stereo", "stereo", 0}, /* stereo */
265 : : /* items */
266 : : /* IL_VERS_ORD, */ {"", "version", "version", 1},
267 : : /* IL_FML__ORD, */ {"/", "formula", "formula", 1}, /* basic part formula */
268 : : /* IL_CONN_ORD, */ {"/c", "connections", "connections", 1},
269 : : /* IL_ALLH_ORD, */ {"/h", "H_atoms", "H", 1},
270 : : /* IL_CHRG_ORD, */ {"/q", "charge", "charge", 1},
271 : : /* IL_PROT_ORD, */ {"/p", "protons", "protons", 0},
272 : : /* stereo */
273 : : /* IL_DBND_ORD, */ {"/b", "dbond", "dbond", 0},
274 : : /* IL_SP3S_ORD, */ {"/t", "sp3", "sp3", 0},
275 : : /* IL_INVS_ORD, */ {"/m", "sp3:inverted", "abs.inverted", 0}, /* mirrored */
276 : : /* IL_TYPS_ORD, */ {"/s", "type (1=abs, 2=rel, 3=rac)", "type", 0}, /* stereo type */
277 : : /* isotopic */
278 : : /* IL_ATMS_ORD, */ {"/i", "atoms", "atoms", 1},
279 : : /* isotopic mobile H only */
280 : : /* IL_XCGA_ORD, */ {"/h", "exchangeable_H", "H-isotopic", 1},
281 : : /* fixed H only */
282 : : /* IL_FMLF_ORD, */ {"/f", "formula", "formula", 1}, /* fixed H formula */
283 : : /* IL_HFIX_ORD, */ {"/h", "H_fixed", "H-fixed", 1}, /* fixed-H */
284 : : /* IL_TRNS_ORD, */ {"/o", "transposition", "transposition", 0}, /* order */
285 : : /* IL_REC__ORD, */ {"/r", "reconnected bond(s) to metal(s) formula", "formula", 0}};
286 : :
287 : : /*
288 : :
289 : : Parsing plain text InChI (FML is a chemical formula)
290 : : ========================
291 : :
292 : : 1.12Beta/FML /i /f[FML] /i [/o] /rFML /i /f[FML] /i [/o] end
293 : : | | | | | | | | |
294 : : Labels | chqpbtms | hbtms | hqbtms | btms | chqpbtms | hbtms | hqbtms | btms |
295 : : inside: | | | | | | | | |
296 : : | non-iso- | iso- | fix- | iso- | non-iso- | iso- | fix- | iso- |
297 : : meaning: | topic | topic | ed H | topic | topic | topic | ed H | topic |
298 : : |----------+-------+--------+---------|----------+-------+--------+---------|
299 : : | mobile-H | fixed-H | mobile-H | fixed-H |
300 : : |----------+-------+--------+---------|----------+-------+--------+---------|
301 : : | | |
302 : : | normal or disconected metal | reconnected bonds to metal |
303 : : |_____________________________________|_____________________________________|
304 : :
305 : : meanings of h:
306 : :
307 : : /h - immobile H & mobile H group(s)
308 : : /i/h - exchangeable isotopic H (common)
309 : : /f/h - fixed-H
310 : : /f/i/h - never happens
311 : :
312 : : */
313 : : typedef enum tagIdentLblOrd
314 : : {
315 : : IL_FIXH_ORD,
316 : : IL_ISOT_ORD,
317 : : IL_STER_ORD,
318 : :
319 : : IL_VERS_ORD,
320 : : IL_FML__ORD,
321 : : IL_CONN_ORD,
322 : : IL_ALLH_ORD,
323 : : IL_CHRG_ORD,
324 : : IL_PROT_ORD,
325 : :
326 : : IL_DBND_ORD,
327 : : IL_SP3S_ORD,
328 : : IL_INVS_ORD,
329 : : IL_TYPS_ORD,
330 : :
331 : : IL_ATMS_ORD,
332 : :
333 : : IL_XCGA_ORD,
334 : :
335 : : IL_FMLF_ORD,
336 : : IL_HFIX_ORD,
337 : : IL_TRNS_ORD,
338 : : IL_REC__ORD,
339 : :
340 : : IL_MAX_ORD /* max number of tags */
341 : : } IDENT_LBL_ORD;
342 : :
343 : : typedef enum tagIdentLblBit
344 : : {
345 : : IL_FIXH = 1 << IL_FIXH_ORD,
346 : : IL_ISOT = 1 << IL_ISOT_ORD,
347 : : IL_STER = 1 << IL_STER_ORD,
348 : :
349 : : IL_VERS = 1 << IL_VERS_ORD,
350 : : IL_FML_ = 1 << IL_FML__ORD,
351 : : IL_CONN = 1 << IL_CONN_ORD,
352 : : IL_ALLH = 1 << IL_ALLH_ORD,
353 : : IL_CHRG = 1 << IL_CHRG_ORD,
354 : : IL_PROT = 1 << IL_PROT_ORD,
355 : :
356 : : IL_DBND = 1 << IL_DBND_ORD,
357 : : IL_SP3S = 1 << IL_SP3S_ORD,
358 : : IL_INVS = 1 << IL_INVS_ORD,
359 : : IL_TYPS = 1 << IL_TYPS_ORD,
360 : :
361 : : IL_ATMS = 1 << IL_ATMS_ORD,
362 : :
363 : : IL_XCGA = 1 << IL_XCGA_ORD,
364 : :
365 : : IL_FMLF = 1 << IL_FMLF_ORD,
366 : : IL_HFIX = 1 << IL_HFIX_ORD,
367 : : IL_TRNS = 1 << IL_TRNS_ORD,
368 : : IL_REC_ = 1 << IL_REC__ORD
369 : : } IDENT_LBL_BIT;
370 : :
371 : : /*
372 : : Aux Info constants
373 : : */
374 : : const INCHI_TAG AuxLbl[] =
375 : : {
376 : : /* prefixes may be combined in this order */
377 : : /* AL_FIXH_ORD, */ {"/", "fixed_H", "fixed-H", 0}, /* fixed-H */
378 : : /* AL_ISOT_ORD, */ {"/", "isotopic", "isotopic", 0}, /* isotopic */
379 : : /* AL_STER_ORD, */ {"/", "abs_stereo_inverted", "stereo.abs.inverted", 0}, /* inv abs sp3 stereo */
380 : : /* AL_REVR_ORD, */ {"/", "reversibility", "reversibility", 0}, /* reversibility */
381 : : /* items */
382 : : /* AL_VERS_ORD, */ {"", "version", "version", 1},
383 : : /* AL_NORM_ORD, */ {"/", "normalization_type", "norm-type", 1},
384 : : /* AL_ANBR_ORD, */ {"/N:", "original_atom_numbers", "atom.orig-nbr", 1},
385 : : /* AL_AEQU_ORD, */ {"/E:", "atom_equivalence", "atom.equivalence", 0},
386 : : /* AL_GEQU_ORD, */ {"/gE:", "group_equivalence", "group.equivalence", 0},
387 : : /* inv abs sp3 stereo */
388 : : /* AL_SP3I_ORD, */ {"/it:", "sp3", "sp3", 0},
389 : : /* AL_SP3N_ORD, */ {"/iN:", "original_atom_numbers", "atom.orig-nbr", 0},
390 : :
391 : : /* AL_CRV__ORD, */ {"/CRV:", "charge_radical_valence", "charges-rad-val", 0},
392 : : /* reversibility */
393 : : /* AL_ATMR_ORD, */ {"/rA:", "atoms", "atoms", 0},
394 : : /* AL_BNDR_ORD, */ {"/rB:", "bonds", "bonds", 0},
395 : : /* AL_XYZR_ORD, */ {"/rC:", "xyz", "xyz", 0},
396 : : /* fixed-H only */
397 : : /* AL_FIXN_ORD, */ {"/F:", "original_atom_numbers", "atom.orig-nbr", 1},
398 : : /* isotopic only */
399 : : /* AL_ISON_ORD, */ {"/I:", "original_atom_numbers", "atom.orig-nbr", 1},
400 : :
401 : : /* AL_REC__ORD, */ {"/R:", "reconnected bond(s) to metal(s) part", "", 1}};
402 : :
403 : : typedef enum tagAuxLblOrd
404 : : {
405 : : AL_FIXH_ORD,
406 : : AL_ISOT_ORD,
407 : : AL_STER_ORD,
408 : : AL_REVR_ORD,
409 : :
410 : : AL_VERS_ORD,
411 : : AL_NORM_ORD,
412 : : AL_ANBR_ORD,
413 : : AL_AEQU_ORD,
414 : : AL_GEQU_ORD,
415 : :
416 : : AL_SP3I_ORD,
417 : : AL_SP3N_ORD,
418 : :
419 : : AL_CRV__ORD,
420 : :
421 : : AL_ATMR_ORD,
422 : : AL_BNDR_ORD,
423 : : AL_XYZR_ORD,
424 : :
425 : : AL_FIXN_ORD,
426 : :
427 : : AL_ISON_ORD,
428 : :
429 : : AL_REC__ORD,
430 : :
431 : : AL_MAX_ORD /* max number of tags */
432 : : } AUX_LBL_ORD;
433 : :
434 : : typedef enum tagAuxLblBit
435 : : {
436 : : AL_FIXH = 1 << AL_FIXH_ORD,
437 : : AL_ISOT = 1 << AL_ISOT_ORD,
438 : : AL_STER = 1 << AL_STER_ORD,
439 : : AL_REVR = 1 << AL_REVR_ORD,
440 : :
441 : : AL_VERS = 1 << AL_VERS_ORD,
442 : : AL_NORM = 1 << AL_NORM_ORD,
443 : : AL_ANBR = 1 << AL_ANBR_ORD,
444 : : AL_AEQU = 1 << AL_AEQU_ORD,
445 : : AL_GEQU = 1 << AL_GEQU_ORD,
446 : :
447 : : AL_SP3I = 1 << AL_SP3I_ORD,
448 : : AL_SP3N = 1 << AL_SP3N_ORD,
449 : :
450 : : AL_CRV_ = 1 << AL_CRV__ORD,
451 : :
452 : : AL_ATMR = 1 << AL_ATMR_ORD,
453 : : AL_BNDR = 1 << AL_BNDR_ORD,
454 : : AL_XYZR = 1 << AL_XYZR_ORD,
455 : :
456 : : AL_FIXN = 1 << AL_FIXN_ORD,
457 : :
458 : : AL_ISON = 1 << AL_ISON_ORD,
459 : :
460 : : AL_REC_ = 1 << AL_REC__ORD
461 : : } AUX_LBL_BIT;
462 : :
463 : : /* const int MAX_TAG_NUM = inchi_max((short)IL_MAX_ORD, (short)AL_MAX_ORD); */ /* djb-rwth: fixing MSVC warning C5287 */
464 : :
465 : : char *szGetTag(const INCHI_TAG *Tag, int nTag, int bTag, char *szTag, int *bAlways, short tag_flag); /* djb-rwth: fixing GHI #160 */
466 : :
467 : : #define SP(N) (x_space + sizeof(x_space) - 1 - (N))
468 : :
469 : : #define NOT_YET_I2I_FOR_POLYMERS 40
470 : :
471 : : /****************************************************************************
472 : : Print error message (plain text)
473 : : ****************************************************************************/
474 : 0 : int OutputINChIPlainError(INCHI_IOSTREAM *out_file,
475 : : char *pErrorText,
476 : : int bError)
477 : : {
478 : : /* char szBuf[64]; */
479 : : const char *pErr;
480 : 0 : char *szErrorText = pErrorText;
481 : 0 : int ret = 0; /* djb-rwth: removing redundant variables */
482 : :
483 [ # # # ]: 0 : switch (bError)
484 : : {
485 : 0 : case _IS_WARNING:
486 : 0 : pErr = x_warn;
487 : 0 : break;
488 : 0 : case _IS_ERROR:
489 : 0 : pErr = x_err;
490 : 0 : break;
491 : 0 : default: /* _IS_FATAL */
492 : 0 : pErr = x_ferr;
493 : 0 : break;
494 : : }
495 : :
496 : : /* djb-rwth: removing redundant code */
497 : :
498 : 0 : inchi_ios_print(out_file,
499 : : "%s: %s=\"%s\" %s=\"%s\"",
500 : : x_message, x_type, pErr, x_text, szErrorText);
501 : : #ifdef TARGET_LIB_FOR_WINCHI
502 : : inchi_ios_print(out_file, "\n");
503 : : #endif
504 : 0 : ret = 1;
505 : :
506 : 0 : return ret;
507 : : }
508 : :
509 : : #ifndef OUT_TN /* defined in mode.h; quoted here for reference purposes only */
510 : :
511 : : #define OUT_N1 0 /* non-tautomeric only */
512 : : #define OUT_T1 1 /* tautomeric if present otherwise non-tautomeric */
513 : : #define OUT_NT 2 /* only non-taut representations of tautomeric */
514 : : #define OUT_TN 3 /* tautomeric if present otherwise non-tautomeric; \
515 : : sepatately output non-taut representations of tautomeric if present */
516 : : /* OUT_TN = OUT_T1 + OUT_NT */
517 : : #endif
518 : :
519 : : /****************************************************************************
520 : : Calculate equivalence mark (used to check for repeating (sub)layer(s) )
521 : : ****************************************************************************/
522 : 38 : const char *EquString(int EquVal)
523 : : {
524 : 38 : int bFrom = EquVal & (iiSTEREO | iiSTEREO_INV | iiNUMB | iiEQU);
525 : 38 : int bType = EquVal & (iitISO | iitNONTAUT);
526 : 38 : int bEq2 = EquVal & (iiEq2NONTAUT | iiEq2ISO | iiEq2INV);
527 : 38 : const char *r = "";
528 : :
529 : : #if (FIX_EMPTY_LAYER_BUG == 1)
530 : : int bEmpty = EquVal & iiEmpty;
531 : : if (bEmpty)
532 : : {
533 : : r = "e";
534 : : return r;
535 : : }
536 : : #endif
537 : :
538 [ - + - - : 38 : switch (bFrom)
- - ]
539 : : {
540 : :
541 : 0 : case iiSTEREO: /* ------------ Stereo --------------------*/
542 [ # # # # ]: 0 : switch (bType)
543 : : {
544 : 0 : case iitISO: /* iso main stereo =... */
545 [ # # ]: 0 : switch (bEq2)
546 : : {
547 : 0 : case 0:
548 : 0 : r = "m"; /* iso main stereo = main stereo */
549 : 0 : break;
550 : 0 : default:
551 : 0 : r = "??"; /* should not happen */
552 : 0 : break;
553 : : }
554 : 0 : break;
555 : 0 : case iitNONTAUT: /* non-taut stereo =... */
556 [ # # ]: 0 : switch (bEq2)
557 : : {
558 : 0 : case 0:
559 : 0 : r = "m"; /* non-taut stereo = main stereo */
560 : 0 : break;
561 : 0 : default:
562 : 0 : r = "??"; /* should not happen */
563 : 0 : break;
564 : : }
565 : 0 : break;
566 : 0 : case (iitNONTAUT | iitISO): /* iso non-taut stereo = ... */
567 [ # # # # ]: 0 : switch (bEq2)
568 : : {
569 : 0 : case 0:
570 : 0 : r = "m"; /* iso non-taut stereo = main stereo */
571 : 0 : break;
572 : 0 : case iiEq2ISO:
573 : 0 : r = "M"; /* iso non-taut stereo = main iso stereo */
574 : 0 : break;
575 : 0 : case iiEq2NONTAUT:
576 : 0 : r = "n"; /* iso non-taut stereo = non-taut stereo */
577 : 0 : break;
578 : 0 : default:
579 : 0 : r = "??"; /* should not happen */
580 : 0 : break;
581 : : }
582 : 0 : break;
583 : 0 : default:
584 : 0 : r = "??"; /* should not happen */
585 : 0 : break;
586 : : }
587 : 0 : break;
588 : :
589 : 38 : case iiSTEREO_INV: /*---------- Inverted Aux Stereo ------*/
590 [ + - ]: 38 : if (bEq2 & iiEq2INV)
591 : : { /* stereo = Inverted(another stereo) */
592 : 38 : bEq2 &= ~iiEq2INV;
593 [ + - - - : 38 : switch (bType)
- ]
594 : : {
595 : 38 : case 0: /* main = ...*/
596 [ + - - - : 38 : switch (bEq2)
- ]
597 : : {
598 : 38 : case 0:
599 : 38 : r = "im"; /* main = Inv(main) */
600 : 38 : break;
601 : 0 : case iiEq2ISO:
602 : 0 : r = "iM"; /* main = Inv(main iso) */
603 : 0 : break;
604 : 0 : case iiEq2NONTAUT:
605 : 0 : r = "in"; /* maim = Inv(non-taut) */
606 : 0 : break;
607 : 0 : case (iiEq2NONTAUT | iiEq2ISO):
608 : 0 : r = "iN"; /* maim = Inv(non-taut iso ) */
609 : 0 : break;
610 : 0 : default:
611 : 0 : r = "??"; /* should not happen */
612 : 0 : break;
613 : : }
614 : 38 : break;
615 : 0 : case iitISO: /* main iso = ...*/
616 [ # # # # : 0 : switch (bEq2)
# ]
617 : : {
618 : 0 : case 0:
619 : 0 : r = "im"; /* main iso = Inv(main) */
620 : 0 : break;
621 : 0 : case iiEq2ISO:
622 : 0 : r = "iM"; /* main iso = Inv(main iso) */
623 : 0 : break;
624 : 0 : case iiEq2NONTAUT:
625 : 0 : r = "in"; /* maim iso = Inv(non-taut) */
626 : 0 : break;
627 : 0 : case (iiEq2NONTAUT | iiEq2ISO):
628 : 0 : r = "iN"; /* maim = Inv(non-taut iso ) */
629 : 0 : break;
630 : 0 : default:
631 : 0 : r = "??"; /* should not happen */
632 : 0 : break;
633 : : }
634 : 0 : break;
635 : 0 : case iitNONTAUT: /* non-taut = ... */
636 [ # # # # : 0 : switch (bEq2)
# ]
637 : : {
638 : 0 : case 0:
639 : 0 : r = "im"; /* non-taut = Inv(main) */
640 : 0 : break;
641 : 0 : case iiEq2ISO:
642 : 0 : r = "iM"; /* non-taut = Inv(main iso) */
643 : 0 : break;
644 : 0 : case iiEq2NONTAUT:
645 : 0 : r = "in"; /* non-taut = Inv(non-taut) */
646 : 0 : break;
647 : 0 : case (iiEq2NONTAUT | iiEq2ISO):
648 : 0 : r = "iN"; /* non-taut = Inv(non-taut iso ) */
649 : 0 : break;
650 : 0 : default:
651 : 0 : r = "??"; /* should not happen */
652 : 0 : break;
653 : : }
654 : 0 : break;
655 : 0 : case (iitNONTAUT | iitISO):
656 [ # # # # : 0 : switch (bEq2)
# ]
657 : : {
658 : 0 : case 0:
659 : 0 : r = "im"; /* non-taut iso = Inv(main) */
660 : 0 : break;
661 : 0 : case iiEq2ISO:
662 : 0 : r = "iM"; /* non-taut iso = Inv(main iso) */
663 : 0 : break;
664 : 0 : case iiEq2NONTAUT:
665 : 0 : r = "in"; /* non-taut iso = Inv(non-taut) */
666 : 0 : break;
667 : 0 : case (iiEq2NONTAUT | iiEq2ISO):
668 : 0 : r = "iN"; /* non-taut iso = Inv(non-taut iso ) */
669 : 0 : break;
670 : 0 : default:
671 : 0 : r = "??"; /* should not happen */
672 : : }
673 : 0 : break;
674 : 0 : default:
675 : 0 : r = "??"; /* should not happen */
676 : 0 : break;
677 : : }
678 : : }
679 : : else
680 : : { /* Inv stereo = another (non-inverted) stereo */
681 : :
682 [ # # # # ]: 0 : switch (bType)
683 : : {
684 : 0 : case iitISO: /* main iso = ...*/
685 [ # # ]: 0 : switch (bEq2)
686 : : {
687 : 0 : case 0:
688 : 0 : r = "m"; /* main = (inverted aux) main */
689 : 0 : break;
690 : 0 : default:
691 : 0 : r = "??"; /* should not happen */
692 : 0 : break;
693 : : }
694 : 0 : break;
695 : 0 : case iitNONTAUT: /* non-taut = ... */
696 [ # # ]: 0 : switch (bEq2)
697 : : {
698 : 0 : case 0:
699 : 0 : r = "m"; /* non-taut = (inverted aux) main */
700 : 0 : break;
701 : 0 : default:
702 : 0 : r = "??"; /* should not happen */
703 : 0 : break;
704 : : }
705 : 0 : break;
706 : 0 : case (iitNONTAUT | iitISO): /* non-taut iso = ...*/
707 [ # # # # ]: 0 : switch (bEq2)
708 : : {
709 : 0 : case 0:
710 : 0 : r = "m"; /* non-taut iso = (inverted aux) main */
711 : 0 : break;
712 : 0 : case iiEq2ISO:
713 : 0 : r = "M"; /* non-taut iso = (inverted aux) main iso */
714 : 0 : break;
715 : 0 : case iiEq2NONTAUT:
716 : 0 : r = "n"; /* non-taut iso = (inverted aux) non-taut */
717 : 0 : break;
718 : 0 : default:
719 : 0 : r = "??"; /* should not happen */
720 : 0 : break;
721 : : }
722 : 0 : break;
723 : 0 : default:
724 : 0 : r = "??"; /* should not happen */
725 : 0 : break;
726 : : }
727 : : }
728 : 38 : break;
729 : :
730 : 0 : case (iiNUMB | iiSTEREO_INV): /*------------- Inv Stereo Numbering ------------*/
731 [ # # # # : 0 : switch (bType)
# ]
732 : : {
733 : 0 : case 0: /* inv stereo numb main = ...*/
734 [ # # ]: 0 : switch (bEq2)
735 : : {
736 : 0 : case 0:
737 : 0 : r = "m"; /* inv stereo numb main = main numb */
738 : 0 : break;
739 : 0 : default:
740 : 0 : r = "??"; /* should not happen */
741 : 0 : break;
742 : : }
743 : 0 : break;
744 : 0 : case iitISO: /* inv stereo iso numb main = ...*/
745 [ # # # # ]: 0 : switch (bEq2)
746 : : {
747 : 0 : case 0:
748 : 0 : r = "m"; /* inv stereo iso numb main = main numb */
749 : 0 : break;
750 : 0 : case iiEq2INV:
751 : 0 : r = "im"; /* inv stereo iso numb main = InvStereo(main) numb */
752 : 0 : break;
753 : 0 : case iiEq2ISO:
754 : 0 : r = "M"; /* inv stereo iso numb main = isotopic main numb */
755 : 0 : break;
756 : 0 : default:
757 : 0 : r = "??"; /* should not happen */
758 : 0 : break;
759 : : }
760 : 0 : break;
761 : 0 : case iitNONTAUT: /* inv stereo numb non-taut = ... */
762 [ # # # # ]: 0 : switch (bEq2)
763 : : {
764 : 0 : case 0:
765 : 0 : r = "m"; /* inv stereo numb non-taut = main numb */
766 : 0 : break;
767 : 0 : case iiEq2NONTAUT:
768 : 0 : r = "n"; /* inv stereo numb non-taut = non-taut numb */
769 : 0 : break;
770 : 0 : case iiEq2INV:
771 : 0 : r = "im"; /* inv stereo numb non-taut = InvStereo(main) numb */
772 : 0 : break;
773 : 0 : default:
774 : 0 : r = "??"; /* should not happen */
775 : 0 : break;
776 : : }
777 : 0 : break;
778 : 0 : case (iitNONTAUT | iitISO): /* inv stereo numb non-taut iso = ... */
779 [ # # # # : 0 : switch (bEq2)
# # # # ]
780 : : {
781 : 0 : case 0:
782 : 0 : r = "m"; /* inv stereo numb non-taut iso = main numb */
783 : 0 : break;
784 : 0 : case iiEq2ISO:
785 : 0 : r = "M"; /* inv stereo numb non-taut iso = main numb iso */
786 : 0 : break;
787 : 0 : case (iiEq2ISO | iiEq2INV):
788 : 0 : r = "iM"; /* inv stereo numb non-taut iso = InvStereo(main iso) numb */
789 : 0 : break;
790 : 0 : case iiEq2NONTAUT:
791 : 0 : r = "n"; /* inv stereo numb non-taut iso = non-taut numb */
792 : 0 : break;
793 : 0 : case (iiEq2NONTAUT | iiEq2ISO):
794 : 0 : r = "N"; /* inv stereo numb non-taut iso = non-taut iso numb */
795 : 0 : break;
796 : 0 : case iiEq2INV:
797 : 0 : r = "im"; /* inv stereo numb non-taut iso = InvStereo(main) numb */
798 : 0 : break;
799 : 0 : case (iiEq2NONTAUT | iiEq2INV):
800 : 0 : r = "in"; /* inv stereo numb non-taut iso = InvStereo(non-taut) numb ) */
801 : 0 : break;
802 : 0 : default:
803 : 0 : r = "??"; /* should not happen */
804 : 0 : break;
805 : : }
806 : 0 : break;
807 : 0 : default:
808 : 0 : r = "??"; /* should not happen */
809 : 0 : break;
810 : : }
811 : 0 : break;
812 : :
813 : 0 : case iiNUMB: /*------------- Canonical Numbering ------------*/
814 [ # # # # : 0 : switch (bType)
# ]
815 : : {
816 : 0 : case 0: /* numb main = ...*/
817 : 0 : r = "??"; /* should not happen */
818 : 0 : break;
819 : 0 : case iitISO: /* iso numb main = ...*/
820 [ # # ]: 0 : switch (bEq2)
821 : : {
822 : 0 : case 0:
823 : 0 : r = "m"; /* iso numb main = main numb */
824 : 0 : break;
825 : 0 : default:
826 : 0 : r = "??"; /* should not happen */
827 : : }
828 : 0 : break;
829 : 0 : case iitNONTAUT: /* numb non-taut = ... */
830 [ # # ]: 0 : switch (bEq2)
831 : : {
832 : 0 : case 0:
833 : 0 : r = "m"; /* numb non-taut = main numb */
834 : 0 : break;
835 : 0 : default:
836 : 0 : r = "??"; /* should not happen */
837 : : }
838 : 0 : break;
839 : 0 : case (iitNONTAUT | iitISO): /* numb non-taut iso = ... */
840 [ # # # # ]: 0 : switch (bEq2)
841 : : {
842 : 0 : case 0:
843 : 0 : r = "m"; /* numb non-taut iso = main numb */
844 : 0 : break;
845 : 0 : case iiEq2ISO:
846 : 0 : r = "M"; /* numb non-taut iso = main numb iso */
847 : 0 : break;
848 : 0 : case iiEq2NONTAUT:
849 : 0 : r = "n"; /* numb non-taut iso = non-taut numb */
850 : 0 : break;
851 : 0 : default:
852 : 0 : r = "??"; /* should not happen */
853 : 0 : break;
854 : : }
855 : 0 : break;
856 : 0 : default:
857 : 0 : r = "??"; /* should not happen */
858 : 0 : break;
859 : : }
860 : 0 : break;
861 : :
862 : 0 : case iiEQU: /*------------- Atom Equivalence ------------*/
863 [ # # # # : 0 : switch (bType)
# ]
864 : : {
865 : 0 : case 0: /* equivalence main = ...*/
866 : 0 : r = "??"; /* should not happen */
867 : 0 : break;
868 : 0 : case iitISO: /* equivalence main iso = ...*/
869 [ # # ]: 0 : switch (bEq2)
870 : : {
871 : 0 : case 0:
872 : 0 : r = "m"; /* equivalence main = main equ */
873 : 0 : break;
874 : 0 : default:
875 : 0 : r = "??"; /* should not happen */
876 : 0 : break;
877 : : }
878 : 0 : break;
879 : 0 : case iitNONTAUT: /* equivalence non-taut = ... */
880 [ # # ]: 0 : switch (bEq2)
881 : : {
882 : 0 : case 0:
883 : 0 : r = "m"; /* equivalence non-taut = main equ */
884 : 0 : break;
885 : 0 : default:
886 : 0 : r = "??"; /* should not happen */
887 : 0 : break;
888 : : }
889 : 0 : break;
890 : 0 : case (iitNONTAUT | iitISO): /* equivalence non-taut iso = ... */
891 [ # # # # ]: 0 : switch (bEq2)
892 : : {
893 : 0 : case 0:
894 : 0 : r = "m"; /* equivalence non-taut iso = main equ */
895 : 0 : break;
896 : 0 : case iiEq2ISO:
897 : 0 : r = "M"; /* equivalence non-taut iso = main iso equ */
898 : 0 : break;
899 : 0 : case iiEq2NONTAUT:
900 : 0 : r = "n"; /* equivalence non-taut iso = non-taut equ */
901 : 0 : break;
902 : 0 : default:
903 : 0 : r = "??"; /* should not happen */
904 : 0 : break;
905 : : }
906 : 0 : break;
907 : 0 : default:
908 : 0 : r = "??"; /* should not happen */
909 : 0 : break;
910 : : }
911 : 0 : break;
912 : 0 : default:
913 : 0 : r = "??"; /* should not happen */
914 : 0 : break;
915 : : }
916 : 38 : return r;
917 : : }
918 : :
919 : : #define OUT_NONTAUT OUT_NN /* was OUT_NT until 2004-04-07 */
920 : :
921 : : /****************************************************************************
922 : : OutputINChI2( ... ) is called from SortAndPrintINChI( ... )
923 : : ****************************************************************************/
924 : 122 : int OutputINChI2(CANON_GLOBALS *pCG,
925 : : INCHI_IOS_STRING *strbuf,
926 : : INCHI_SORT *pINChISortTautAndNonTaut2[][TAUT_NUM],
927 : : int INCHI_basic_or_INCHI_reconnected,
928 : : ORIG_ATOM_DATA *orig_inp_data,
929 : : ORIG_STRUCT *pOrigStruct,
930 : : INPUT_PARMS *ip,
931 : : int bDisconnectedCoord,
932 : : int bOutputType,
933 : : int bINChIOutputOptions,
934 : : int num_components2[],
935 : : int num_non_taut2[],
936 : : int num_taut2[],
937 : : INCHI_IOSTREAM *output_file,
938 : : INCHI_IOSTREAM *log_file,
939 : : int num_input_struct,
940 : : int *pSortPrintINChIFlags,
941 : : unsigned char save_opt_bits)
942 : : {
943 : 122 : int bINChIOutputOptions0 = bINChIOutputOptions & ~(INCHI_OUT_PLAIN_TEXT | INCHI_OUT_PLAIN_TEXT_COMMENTS);
944 : : int bINChIOutputOptionsCur;
945 : : int bCurOption, ret, i;
946 : :
947 : 122 : ret = 0;
948 : :
949 [ + + ]: 488 : for (i = 0; i < 3; i++)
950 : : {
951 [ + + + ]: 366 : switch (i)
952 : : {
953 : 122 : case 1:
954 : 122 : bCurOption = INCHI_OUT_PLAIN_TEXT;
955 : 122 : break;
956 : 122 : case 2:
957 : 122 : bCurOption = INCHI_OUT_PLAIN_TEXT_COMMENTS;
958 : 122 : break;
959 : 122 : default:
960 : 122 : continue;
961 : : }
962 [ + + ]: 244 : if (bINChIOutputOptions & bCurOption)
963 : : {
964 : 122 : bINChIOutputOptionsCur = bINChIOutputOptions0 | bCurOption;
965 [ - + ]: 122 : if (i != 1)
966 : : {
967 : 0 : bINChIOutputOptionsCur &= ~INCHI_OUT_TABBED_OUTPUT;
968 : : }
969 : 122 : ret |= OutputINChI1(pCG,
970 : : strbuf,
971 : : pINChISortTautAndNonTaut2,
972 : : INCHI_basic_or_INCHI_reconnected,
973 : : orig_inp_data,
974 : : pOrigStruct,
975 : : ip,
976 : : bDisconnectedCoord,
977 : : bOutputType,
978 : : bINChIOutputOptionsCur,
979 : : num_components2,
980 : : num_non_taut2,
981 : : num_taut2,
982 : : output_file,
983 : : log_file,
984 : : num_input_struct,
985 : : pSortPrintINChIFlags,
986 : : save_opt_bits);
987 : : }
988 : : }
989 : :
990 : 122 : return ret;
991 : : }
992 : :
993 : : /**
994 : : * @brief Main actual worker which serializes InChI to string. Called from OutputINChI2( ... ) and from itself.
995 : : *
996 : : * @param pCG Pointer to global canonicalization data.
997 : : * @param strbuf Pointer to the output string buffer.
998 : : * @param pINChISortTautAndNonTaut2 Array of pointers to INCHI_SORT structures for tautomeric and non-tautomeric forms.
999 : : * @param INCHI_basic_or_INCHI_reconnected Flag indicating basic or reconnected InChI output.
1000 : : * @param orig_inp_data Pointer to original atom data.
1001 : : * @param pOrigStruct Pointer to the original structure data.
1002 : : * @param ip Pointer to input parameters.
1003 : : * @param bDisconnectedCoord Flag for disconnected metal coordination.
1004 : : * @param bOutputType Output type (tautomeric/non-tautomeric/both).
1005 : : * @param bINChIOutputOptions Bitmask of output options.
1006 : : * @param num_components2 Array of component counts for each structure type.
1007 : : * @param num_non_taut2 Array of non-tautomeric component counts.
1008 : : * @param num_taut2 Array of tautomeric component counts.
1009 : : * @param out_file Output stream for InChI string.
1010 : : * @param log_file Output stream for logging.
1011 : : * @param num_input_struct Number of input structures.
1012 : : * @param pSortPrintINChIFlags Pointer to flags controlling sorting and printing.
1013 : : * @param save_opt_bits Encoded bits for saved InChI creation options.
1014 : : * @return int
1015 : : */
1016 : 122 : int OutputINChI1( CANON_GLOBALS *pCG,
1017 : : INCHI_IOS_STRING *strbuf,
1018 : : INCHI_SORT *pINChISortTautAndNonTaut2[][TAUT_NUM],
1019 : : int INCHI_basic_or_INCHI_reconnected,
1020 : : ORIG_ATOM_DATA *orig_inp_data,
1021 : : ORIG_STRUCT *pOrigStruct,
1022 : : INPUT_PARMS *ip,
1023 : : int bDisconnectedCoord,
1024 : : int bOutputType,
1025 : : int bINChIOutputOptions,
1026 : : int num_components2[],
1027 : : int num_non_taut2[],
1028 : : int num_taut2[],
1029 : : INCHI_IOSTREAM *out_file,
1030 : : INCHI_IOSTREAM *log_file,
1031 : : int num_input_struct,
1032 : : int *pSortPrintINChIFlags,
1033 : : unsigned char save_opt_bits )
1034 : : {
1035 : : INCHI_OUT_CTL io;
1036 : : /*
1037 : : bINChIOutputOptions bits:
1038 : : INCHI_OUT_NO_AUX_INFO 0x0001 do not output Aux Info
1039 : : INCHI_OUT_SHORT_AUX_INFO 0x0002 output short version of Aux Info
1040 : : INCHI_OUT_ONLY_AUX_INFO 0x0004 output only Aux Info
1041 : : INCHI_OUT_EMBED_REC 0x0008 embed reconnected INChI into disconnected INChI
1042 : :
1043 : : bOutputType =
1044 : : TAUT_YES => tautomeric only (if no tautomeric components then no output;
1045 : : TAUT_NON => only non-tautomeric output (if no non-taut present then no output;
1046 : : TAUT_BOTH => tautomeric and non-tautomeric
1047 : : */
1048 : 122 : int i, j, ii, jj, /*ii2, jj2,*/ bEmbeddedOutputCalled = 0;
1049 : : int bTautIsoHNum, bTautIsoAt, bHasIsotopicAtoms[TAUT_NUM];
1050 : : int bStereoSp2[TAUT_NUM], bStereoSp3[TAUT_NUM];
1051 : : int bIsotopicStereoSp2[TAUT_NUM], bIsotopicStereoSp3[TAUT_NUM];
1052 : : int bStereoAbsInverted[TAUT_NUM], bIsotopicStereoAbsInverted[TAUT_NUM];
1053 : : int bStereoAbs[TAUT_NUM], bIsotopicStereoAbs[TAUT_NUM];
1054 : : int bTautomericAcid, bHardAddRemProton;
1055 : 122 : int bRequestedRacemicStereo = 0, bRequestedRelativeStereo = 0;
1056 : 122 : int npass = 0; /* djb-rwth: removing redundant variables */
1057 : :
1058 : : INCHI_SORT *is, *is2;
1059 : : INChI *pINChI /*, *pINChI2*/;
1060 : 122 : INChI_Aux *pINChI_Aux = NULL;
1061 : :
1062 : 122 : int ret = 0; /* 0 failed, 1 success */
1063 : 122 : int intermediate_result = 0;
1064 : 122 : int then_goto_repeat = 0;
1065 : : /* djb-rwth: removing redundant variables */
1066 : : int bHasIsoH;
1067 : : /* djb-rwth: removing redundant variables */
1068 : : int bTautAndNonTaut, bTautIsNonTaut;
1069 : : int nAtomsAllComp1, nAtomsAllComp2; /* v. 1.05 Total atoms in all components */
1070 : :
1071 : 122 : int bPlainText = 0 != (bINChIOutputOptions & (INCHI_OUT_PLAIN_TEXT | INCHI_OUT_PLAIN_TEXT_COMMENTS));
1072 : 122 : int bPlainTextCommnts = 0 != (bINChIOutputOptions & INCHI_OUT_PLAIN_TEXT_COMMENTS);
1073 : :
1074 : : char *pLF, *pTAB;
1075 : : #ifdef TARGET_LIB_FOR_WINCHI
1076 : : int silent = 1;
1077 : : #endif
1078 : :
1079 : 122 : int bFixTranspChargeBug = 0;
1080 : : #if (FIX_TRANSPOSITION_CHARGE_BUG == 1) /* 2008-01-02 */
1081 [ + - ]: 122 : if (INCHI_OUT_FIX_TRANSPOSITION_CHARGE_BUG & bINChIOutputOptions)
1082 : 122 : bFixTranspChargeBug = 1;
1083 : : #endif
1084 : :
1085 : 122 : io.bAbcNumbers = ip->bAbcNumbers;
1086 : :
1087 : 244 : io.ATOM_MODE = ((io.bAbcNumbers ? CT_MODE_ABC_NUMBERS : 0) | CT_MODE_ATOM_COUNTS | CT_MODE_NO_ORPHANS
1088 : : #if (EQL_H_NUM_TOGETHER == 1)
1089 [ - + ]: 122 : | CT_MODE_EQL_H_TOGETHER
1090 : : #endif
1091 : : #if (ABC_CT_NUM_CLOSURES == 1)
1092 [ - + - - ]: 122 : | (io.bAbcNumbers && ip->bCtPredecessors ? CT_MODE_ABC_NUM_CLOSURES : 0)
1093 : : #endif
1094 [ - + ]: 122 : | (ip->bCtPredecessors ? CT_MODE_PREDECESSORS : 0));
1095 : :
1096 [ - + ]: 122 : io.TAUT_MODE = (io.bAbcNumbers ? CT_MODE_ABC_NUMBERS : 0);
1097 : 122 : io.pSortPrintINChIFlags = pSortPrintINChIFlags;
1098 : 122 : io.num_components = num_components2[INCHI_basic_or_INCHI_reconnected];
1099 : 122 : io.pINChISortTautAndNonTaut = pINChISortTautAndNonTaut2[INCHI_basic_or_INCHI_reconnected];
1100 : 122 : io.pINChISort = io.pINChISortTautAndNonTaut[TAUT_YES];
1101 : 122 : io.pINChISort2 = io.pINChISortTautAndNonTaut[TAUT_YES];
1102 : 122 : io.bAlways = 0;
1103 : 122 : io.bUseMulipliers = 1;
1104 : 122 : io.bOmitRepetitions = 1;
1105 : 122 : io.bPlainTextTags = 2; /* 0 => no plain tags, 1=> plain text tags, 2=>plaintext tags without consecutive // */
1106 : 122 : io.bOutputType = bOutputType; /* remains constant */
1107 : 122 : io.bOutType = bOutputType; /* will change! */
1108 : 122 : io.bOverflow = 0;
1109 : 122 : io.bSecondNonTautPass = 0;
1110 : 122 : io.bNonTautIsoIdentifierNotEmpty = 0;
1111 : 122 : io.bNonTautNonIsoIdentifierNotEmpty = 0;
1112 : 122 : io.bNonTautIsIdenticalToTaut = 1;
1113 : 122 : io.bFhTag = 0;
1114 [ + - ]: 244 : io.nTag = bPlainTextCommnts ? 3 : bPlainText ? 2
1115 [ + - ]: 122 : : 0; /* tag type */
1116 : :
1117 [ - + ]: 122 : if (NULL == orig_inp_data)
1118 : : {
1119 : : /*intermediate_result = 1;
1120 : : goto exit_function;*/
1121 : 0 : io.n_zy = 0;
1122 : 0 : io.n_pzz = 0;
1123 : 0 : io.n_pzz = 0;
1124 : : }
1125 : : else
1126 : : {
1127 : 122 : io.n_zy = orig_inp_data->n_zy;
1128 : 122 : io.n_pzz = 0;
1129 [ + + ]: 122 : if (orig_inp_data->polymer)
1130 : : {
1131 : 2 : io.n_pzz = orig_inp_data->polymer->n_pzz;
1132 : : }
1133 : : }
1134 : :
1135 : :
1136 : 122 : io.bPolymers = ip->bPolymers;
1137 : :
1138 : : /* djb-rwth: removing redundant code */
1139 : :
1140 : : #ifdef TARGET_LIB_FOR_WINCHI
1141 : : /* @@@ From now on we will go with silent output; it ends on @@@ below */
1142 : : silent = 1;
1143 : : #endif
1144 : :
1145 : : /* Analyze layers, make adjustments and fixes, etc. */
1146 : :
1147 : 122 : set_line_separators(bINChIOutputOptions, &pLF, &pTAB);
1148 : 122 : memset(io.sDifSegs, DIFV_BOTH_EMPTY, sizeof(io.sDifSegs)); /* djb-rwth: memset_s C11/Annex K variant? */
1149 [ + - + - : 122 : if (!strbuf || !(strbuf->pStr) || strbuf->nAllocatedLength <= 0)
- + ]
1150 : : {
1151 : 0 : inchi_ios_eprint(log_file, "Cannot allocate output buffer. No output for structure #%d.%s%s%s%s\n",
1152 [ # # # # : 0 : num_input_struct, SDF_LBL_VAL(ip->pSdfLabel, ip->pSdfValue));
# # # # #
# # # # #
# # # # #
# # # #
# ]
1153 : 0 : return ret;
1154 : : }
1155 : :
1156 : : /* -- commented out to allow empty InChI --
1157 : : if (!io.num_components ) return 0;
1158 : : */
1159 : :
1160 [ + + ]: 366 : for (i = 0; i < TAUT_NUM; i++)
1161 : : {
1162 : 244 : bHasIsotopicAtoms[i] =
1163 : 244 : io.num_comp[i] =
1164 : 244 : bStereoSp2[i] =
1165 : 244 : bStereoSp3[i] =
1166 : 244 : bIsotopicStereoSp2[i] =
1167 : 244 : bIsotopicStereoSp3[i] =
1168 : 244 : io.bIsotopicOrigNumb[i] =
1169 : 244 : bStereoAbs[i] =
1170 : 244 : bIsotopicStereoAbs[i] =
1171 : 244 : bStereoAbsInverted[i] =
1172 : 244 : bIsotopicStereoAbsInverted[i] =
1173 : 244 : io.bRacemicStereo[i] =
1174 : 244 : io.bRelativeStereo[i] =
1175 : 244 : io.bIsotopicRacemicStereo[i] =
1176 : 244 : io.bIsotopicRelativeStereo[i] =
1177 : 244 : io.bAtomEqu[i] =
1178 : 244 : io.bTautEqu[i] =
1179 : 244 : io.bIsotopicAtomEqu[i] =
1180 : 244 : io.bIsotopicTautEqu[i] =
1181 : 244 : io.bInvStereo[i] =
1182 : 244 : io.bInvIsotopicStereo[i] =
1183 : 244 : io.bInvStereoOrigNumb[i] =
1184 : 244 : io.bInvIsotopicStereoOrigNumb[i] =
1185 : 244 : io.bIgn_UU_Sp3[i] =
1186 : 244 : io.bIgn_UU_Sp2[i] =
1187 : 244 : io.bIgn_UU_Sp3_Iso[i] =
1188 : 244 : io.bIgn_UU_Sp2_Iso[i] =
1189 : 244 : io.bChargesRadVal[i] =
1190 : 244 : io.bOrigCoord[i] = 0;
1191 : : }
1192 : :
1193 : : /* Find if it is isotopic */
1194 : 122 : io.bIsotopic =
1195 : 122 : io.bTautomeric =
1196 : 122 : io.bNonTautomeric =
1197 : 122 : bTautomericAcid =
1198 : 122 : bHardAddRemProton =
1199 : 122 : bTautIsoHNum =
1200 : 122 : bTautIsoAt =
1201 : 122 : bTautAndNonTaut =
1202 : 122 : bTautIsNonTaut = 0;
1203 : :
1204 : : /*
1205 : : x = bStereo, bStereoSp2, bStereoSp3, bStereoAbsInverted,
1206 : : bIsotopicStereo, bIsotopicStereoSp2, bIsotopicStereoSp3, bIsotopicStereoAbsInverted
1207 : :
1208 : : OUT_N1: x[TAUT_NON] refers to non-tautomeric only
1209 : : OUT_T1: x[TAUT_YES] refers to tautomeric if exists otherwise non-tautomeric
1210 : : OUT_NT: x[TAUT_NON] refers to non-taut representations of tautomeric
1211 : : OUT_TN: x[TAUT_YES] refers to tautomeric if exists otherwise non-tautomeric
1212 : : x[TAUT_NON] refers to non-taut representations of tautomeric
1213 : : */
1214 : :
1215 : 122 : memset(io.num_iso_H, 0, sizeof(io.num_iso_H)); /* djb-rwth: memset_s C11/Annex K variant? */
1216 : 122 : io.nNumRemovedProtons = 0;
1217 : : /* djb-rwth: removing redundant code */
1218 : 122 : bHasIsoH = 0;
1219 [ + - + - ]: 122 : io.bTautomericOutputAllowed = (io.bOutType == OUT_T1 || io.bOutType == OUT_TN);
1220 [ + - ]: 122 : io.pINChISort = io.pINChISortTautAndNonTaut[io.bTautomericOutputAllowed ? TAUT_YES : TAUT_NON];
1221 : 122 : is = io.pINChISort;
1222 : : /* djb-rwth: removing redundant variables/code */
1223 : :
1224 [ + - + + ]: 444 : for (i = 0, is2 = io.pINChISortTautAndNonTaut[TAUT_NON]; i < io.num_components; i++, is++, is2 ? is2++ : NULL)
1225 : : {
1226 : :
1227 : 161 : CompINChILayers(is, is2, io.sDifSegs, bFixTranspChargeBug);
1228 : :
1229 [ + - + - ]: 161 : io.bNonTautIsIdenticalToTaut = io.bNonTautIsIdenticalToTaut && !CompINChITautVsNonTaut(is, is2, 1);
1230 : :
1231 [ + - + - ]: 161 : if (is && (pINChI_Aux = is->pINChI_Aux[TAUT_YES]))
1232 : : {
1233 [ + + ]: 644 : for (j = 0; j < NUM_H_ISOTOPES; j++)
1234 : : {
1235 : 483 : bHasIsoH += abs(pINChI_Aux->nNumRemovedIsotopicH[j]);
1236 : 483 : io.num_iso_H[j] += pINChI_Aux->nNumRemovedIsotopicH[j];
1237 : : }
1238 : 161 : io.nNumRemovedProtons += pINChI_Aux->nNumRemovedProtons;
1239 : : /* djb-rwth: removing redundant code */
1240 : : }
1241 : :
1242 [ + - + - ]: 161 : if (io.bTautomericOutputAllowed && is) /* djb-rwth: fixing a NULL pointer dereference */
1243 : : {
1244 : : /* Check for removed isotopic H */
1245 [ + + ]: 322 : for (j = TAUT_YES; j < TAUT_NUM; j++)
1246 : : {
1247 [ - - - + : 161 : switch (io.bOutType)
- ]
1248 : : {
1249 : 0 : case OUT_N1: /* x[TAUT_NON]: non-tautomeric only -- never happens */
1250 [ # # # # : 0 : jj = GET_II(io.bOutType, is);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
1251 [ # # ]: 0 : if (jj != j)
1252 : 0 : continue;
1253 : : /* djb-rwth: removing redundant code */
1254 : 0 : break;
1255 : 0 : case OUT_T1: /* x[TAUT_YES]: tautomeric if present otherwise non-tautomeric */
1256 [ # # # # : 0 : jj = GET_II(io.bOutType, is);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
1257 [ # # ]: 0 : if (jj != j)
1258 : 0 : continue;
1259 : : /* djb-rwth: removing redundant code */
1260 : 0 : break;
1261 : 0 : case OUT_NT: /* x[TAUT_NON]: only non-taut representations of tautomeric -- never happens */
1262 [ # # # # : 0 : jj = GET_II(io.bOutType, is);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
1263 [ # # ]: 0 : if (jj != j)
1264 : 0 : continue;
1265 : : /* djb-rwth: removing redundant code */
1266 : 0 : break;
1267 : : /* main path of control flow */
1268 : 161 : case OUT_TN: /* x[TAUT_YES]: tautomeric if present otherwise non-tautomeric;
1269 : : * x[TAUT_NON]: non-taut only if tautomeric is present */
1270 [ + - + - : 161 : jj = (j == TAUT_YES) ? GET_II(OUT_T1, is) : (j == TAUT_NON) ? GET_II(OUT_NT, is)
- + - - -
- - - - -
- - - - -
- - - ]
1271 [ # # ]: 0 : : -1;
1272 [ + - ]: 161 : if (jj == TAUT_YES)
1273 : : {
1274 : : /* Fix12 */
1275 [ + + ]: 161 : if (is->pINChI[jj]->lenTautomer > 0)
1276 : : {
1277 [ + - - + : 14 : bTautAndNonTaut += (!is->pINChI[jj]->bDeleted && HAS_N(is));
- - ]
1278 : : }
1279 : : else
1280 : : {
1281 : 147 : bTautIsNonTaut++;
1282 : : }
1283 : : }
1284 [ - + ]: 161 : if (jj < 0)
1285 : 0 : continue;
1286 : : /* djb-rwth: removing redundant code */
1287 : 161 : break;
1288 : 0 : default:
1289 : 0 : continue;
1290 : : }
1291 [ - + ]: 161 : if (jj != j)
1292 : 0 : continue;
1293 [ + - + - : 161 : if ((pINChI = is->pINChI[jj]) && pINChI->nNumberOfAtoms > 0 && (pINChI_Aux = is->pINChI_Aux[jj]))
+ - ]
1294 : : {
1295 : 161 : bTautIsoHNum += (pINChI_Aux->nNumRemovedIsotopicH[0] +
1296 : 161 : pINChI_Aux->nNumRemovedIsotopicH[1] +
1297 : 161 : pINChI_Aux->nNumRemovedIsotopicH[2]);
1298 [ + - - + ]: 161 : bTautIsoAt += (pINChI->nNumberOfIsotopicAtoms > 0 || pINChI->nNumberOfIsotopicTGroups > 0);
1299 : : }
1300 : : }
1301 : : }
1302 : : }
1303 : :
1304 [ + + ]: 122 : io.sDifSegs[DIFL_M][DIFS_p_PROTONS] = io.nNumRemovedProtons ? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
1305 [ - + ]: 122 : io.sDifSegs[DIFL_MI][DIFS_h_H_ATOMS] = bHasIsoH ? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
1306 : :
1307 : 122 : MarkUnusedAndEmptyLayers(io.sDifSegs);
1308 : :
1309 [ + - + - ]: 122 : io.bNonTautIsIdenticalToTaut = io.bNonTautIsIdenticalToTaut && !bTautIsoHNum;
1310 : 122 : nAtomsAllComp1 = nAtomsAllComp2 = 0;
1311 : :
1312 [ + + ]: 283 : for (i = 0, is = io.pINChISort; i < io.num_components; i++, is++)
1313 : : {
1314 : : int bCurIso, bCurHasIsoStereo /* Fix14 */, bCurTaut /*, bCurTaut2*/; /* djb-rwth: removing redundant variables */
1315 : : int bCompExists, bCurIsoHPos, bCurIsoHStereo;
1316 : : int bCurStereoSp2, bCurIsoStereoSp2, bCurStereoSp3, bCurIsoStereoSp3, bCurIsoStereoSp3Inv;
1317 : : int bCurRacemic, bCurRelative, bCurIsoRacemic, bCurIsoRelative;
1318 : 161 : bCompExists = 0;
1319 : :
1320 [ + + ]: 483 : for (j = TAUT_NON; j < TAUT_NUM; j++)
1321 : : {
1322 [ - - - + : 322 : switch (io.bOutType)
- ]
1323 : : {
1324 : 0 : case OUT_N1:
1325 : : /* x[TAUT_NON]: non-tautomeric only */
1326 [ # # # # : 0 : jj = GET_II(io.bOutType, is);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
1327 [ # # ]: 0 : if (jj != j)
1328 : 0 : continue;
1329 : 0 : ii = TAUT_NON;
1330 : 0 : break;
1331 : 0 : case OUT_T1:
1332 : : /* x[TAUT_YES]: tautomeric if present otherwise non-tautomeric */
1333 [ # # # # : 0 : jj = GET_II(io.bOutType, is);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
1334 [ # # ]: 0 : if (jj != j)
1335 : 0 : continue;
1336 : 0 : ii = TAUT_YES;
1337 : 0 : break;
1338 : 0 : case OUT_NT:
1339 : : /* x[TAUT_NON]: only non-taut representations of tautomeric */
1340 [ # # # # : 0 : jj = GET_II(io.bOutType, is);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
1341 [ # # ]: 0 : if (jj != j)
1342 : 0 : continue;
1343 : 0 : ii = TAUT_NON;
1344 : 0 : break;
1345 : : /* main control flow comes here: requested both mobile and fixed H results */
1346 : 322 : case OUT_TN:
1347 : : /* x[TAUT_YES]: tautomeric if present otherwise non-tautomeric; */
1348 : : /* x[TAUT_NON]: non-taut only if tautomeric is present */
1349 [ + + + - : 644 : jj = (j == TAUT_YES) ? GET_II(OUT_T1, is) : (j == TAUT_NON) ? GET_II(OUT_NT, is)
- + - - -
- + - + -
+ + - + -
- - - ]
1350 [ + - ]: 322 : : -1;
1351 [ + + ]: 322 : if (jj < 0)
1352 : : {
1353 : : /* Fix12 */
1354 [ - + - - : 161 : if (bTautAndNonTaut && bTautIsNonTaut &&
- - ]
1355 [ # # # # : 0 : j == TAUT_NON && 0 <= (jj = GET_II(OUT_T1, is)) &&
# # # # #
# ]
1356 [ # # # # ]: 0 : !is->pINChI[jj]->bDeleted && !is->pINChI[jj]->lenTautomer)
1357 : : {
1358 : : ; /* the requested non-tautomeric component is in tautomeric position */
1359 : : /* (is->pINChI[TAUT_YES]); */
1360 : : /* process it also as non-tautomeric if Fixed-H layer was requested */
1361 : : }
1362 : : else
1363 : : {
1364 : 161 : continue;
1365 : : }
1366 : : }
1367 : :
1368 : 161 : ii = j; /* ii is what we wanted; jj is what we found (0 = TAUT_NON: fixed_H, 1 = TAUT_YES: mobile_H) */
1369 : :
1370 : : /* -- not used 2004-09-16 ---
1371 : : if ( is2 ) {
1372 : : jj2 = ( j == TAUT_YES )? GET_II(OUT_T1,is2) : ( j == TAUT_NON )? GET_II(OUT_NT,is2) : -1;
1373 : : if ( jj2 >= 0 ) {
1374 : : ii2 = j;
1375 : : } else {
1376 : : ii2 = -1;
1377 : : }
1378 : : } else {
1379 : : jj2 = ii2 = -1;
1380 : : }
1381 : : -----------------------------*/
1382 : 161 : break;
1383 : :
1384 : 0 : default:
1385 : 0 : continue;
1386 : : }
1387 : :
1388 [ + - + - ]: 161 : if ((pINChI = is->pINChI[jj]) && pINChI->nNumberOfAtoms > 0)
1389 : : {
1390 : : /*pINChI_Aux = is->pINChI_Aux[jj];*/
1391 : 161 : bCompExists++;
1392 : :
1393 [ - + ]: 161 : if (j == TAUT_NON)
1394 : 0 : nAtomsAllComp1 += pINChI->nNumberOfAtoms;
1395 [ + - ]: 161 : else if (j == TAUT_YES)
1396 : 161 : nAtomsAllComp2 += pINChI->nNumberOfAtoms;
1397 : :
1398 : 161 : bCurTaut = (pINChI->lenTautomer > 0);
1399 [ + - - + ]: 161 : bCurIso = (pINChI->nNumberOfIsotopicAtoms > 0 || pINChI->nNumberOfIsotopicTGroups > 0);
1400 [ - + - - : 161 : bCurIsoHPos = ((pINChI->nPossibleLocationsOfIsotopicH && pINChI->nPossibleLocationsOfIsotopicH[0] > 1) || pINChI->lenTautomer > 1); /* djb-rwth: addressing LLVM warning */
+ + ]
1401 : : /* present isotopic H + their possible positions AND/OR isotopic atoms */
1402 [ + + + - : 161 : bCurIsoHStereo = (bCurIsoHPos && (bTautIsoHNum || bTautIsoAt)) || bCurIso; /* djb-rwth: addressing LLVM warning */
+ - - + ]
1403 [ + - - + ]: 161 : if (jj == j && pINChI->bDeleted)
1404 : : {
1405 : 0 : io.num_comp[j]--;
1406 [ # # ]: 0 : if (bCurTaut)
1407 : : {
1408 : 0 : io.bTautomeric |= 1; /* tautomeric representation is present */
1409 [ # # # # ]: 0 : io.bNonTautomeric |= HAS_N(is);
1410 : : }
1411 : 0 : io.bIsotopic |= bCurIso;
1412 : 0 : continue; /* deleted H(+) in tautomeric representation */
1413 : : }
1414 : :
1415 [ + - - + ]: 161 : bCurStereoSp2 = pINChI->Stereo && (pINChI->Stereo->nNumberOfStereoBonds > 0);
1416 : :
1417 : 161 : bCurHasIsoStereo =
1418 [ + - + + ]: 161 : bCurStereoSp3 = pINChI->Stereo && (pINChI->Stereo->nNumberOfStereoCenters > 0);
1419 : :
1420 [ - + - - : 161 : bCurIsoStereoSp2 = bCurIsoHStereo && pINChI->StereoIsotopic && (pINChI->StereoIsotopic->nNumberOfStereoBonds > 0);
- - ]
1421 [ - + - - : 161 : bCurIsoStereoSp3 = bCurIsoHStereo && pINChI->StereoIsotopic && (pINChI->StereoIsotopic->nNumberOfStereoCenters > 0);
- - ]
1422 [ - + - - ]: 161 : bCurIsoStereoSp3Inv = bCurIsoStereoSp3 && pINChI->StereoIsotopic->nCompInv2Abs; /* inversion changes sp3 stereo */
1423 : 161 : bRequestedRacemicStereo |= (0 != (pINChI->nFlags & INCHI_FLAG_RAC_STEREO));
1424 : 161 : bRequestedRelativeStereo |= (0 != (pINChI->nFlags & INCHI_FLAG_REL_STEREO));
1425 : :
1426 : : /* Check whether isotopic stereo is same as non-isotopic; if same than do not output isotopic stereo */
1427 [ - + - - ]: 161 : if (bCurStereoSp2 && bCurIsoStereoSp2)
1428 : : {
1429 : 0 : bCurIsoStereoSp2 = !Eql_INChI_Stereo(pINChI->Stereo, EQL_SP2, pINChI->StereoIsotopic, EQL_SP2, 0);
1430 : : }
1431 [ + + - + ]: 161 : if (bCurStereoSp3 && bCurIsoStereoSp3)
1432 : : {
1433 : : /* bCurIsoStereoSp3=0 means (iso stereo sp3) = (non-iso stereo sp3) or (iso stereo sp3) = Inv(non-iso stereo sp3) */
1434 : 0 : bCurIsoStereoSp3 = !Eql_INChI_Stereo(pINChI->Stereo, EQL_SP3, pINChI->StereoIsotopic, EQL_SP3,
1435 [ # # # # ]: 0 : (pINChI->nFlags & INCHI_FLAG_RAC_STEREO) || (pINChI->nFlags & INCHI_FLAG_REL_STEREO));
1436 [ # # ]: 0 : if (!bCurIsoStereoSp3)
1437 : : {
1438 : : /* Inversion changes iso sp3 differently from non-iso sp3 Fix11 */
1439 : 0 : bCurIsoStereoSp3Inv &= (pINChI->StereoIsotopic->nCompInv2Abs != pINChI->Stereo->nCompInv2Abs);
1440 : : }
1441 : : }
1442 : :
1443 [ - + - - ]: 161 : bCurRelative = bRequestedRelativeStereo && bCurStereoSp3;
1444 : : #if (REL_RAC_STEREO_IGN_1_SC == 1)
1445 : : bCurRelative = bCurRelative &&
1446 : : (pINChI->Stereo->nNumberOfStereoCenters > 1) &&
1447 : : (pINChI->Stereo->nCompInv2Abs != 0) &&
1448 : : #endif
1449 : :
1450 [ - + - - : 161 : bCurIsoRelative = bRequestedRelativeStereo && (bCurIsoStereoSp3 || bCurIsoStereoSp3Inv);
- - ]
1451 : : #if (REL_RAC_STEREO_IGN_1_SC == 1)
1452 : : bCurIsoRelative = bCurIsoRelative &&
1453 : : (pINChI->StereoIsotopic->nNumberOfStereoCenters > 1) &&
1454 : : (pINChI->StereoIsotopic->nCompInv2Abs != 0) &&
1455 : : #endif
1456 : :
1457 [ - + - - ]: 161 : bCurRacemic = bRequestedRacemicStereo && bCurStereoSp3;
1458 : : #if (REL_RAC_STEREO_IGN_1_SC == 1)
1459 : : bCurRacemic = bCurRacemic &&
1460 : : (pINChI->Stereo->nCompInv2Abs != 0) &&
1461 : : (pINChI->Stereo->nNumberOfStereoCenters > 0)
1462 : : ? pINChI->Stereo->nNumberOfStereoCenters
1463 : : : 0;
1464 : : #endif
1465 : :
1466 [ - + - - : 161 : bCurIsoRacemic = bRequestedRacemicStereo && (bCurIsoStereoSp3 || bCurIsoStereoSp3Inv);
- - ]
1467 : : #if (REL_RAC_STEREO_IGN_1_SC == 1)
1468 : : bCurIsoRacemic = bCurIsoRacemic &
1469 : : (pINChI->StereoIsotopic->nCompInv2Abs != 0) &&
1470 : : (pINChI->StereoIsotopic->nNumberOfStereoCenters > 0)
1471 : : ? pINChI->StereoIsotopic->nNumberOfStereoCenters
1472 : : : 0;
1473 : : #endif
1474 [ - + ]: 161 : if (bRequestedRelativeStereo)
1475 : : {
1476 [ # # # # : 0 : bCurStereoSp3 = bCurRelative || (bCurStereoSp3 && (pINChI->Stereo->nNumberOfStereoCenters > 1)); /* Fix11 */ /* djb-rwth: addressing LLVM warning */
# # ]
1477 [ # # ]: 0 : bCurIsoStereoSp3 = bCurIsoRelative ? bCurIsoStereoSp3 : 0;
1478 : : }
1479 : : else
1480 : : {
1481 [ - + ]: 161 : if (bRequestedRacemicStereo)
1482 : : {
1483 [ # # # # : 0 : bCurStereoSp3 = bCurRacemic > 1 || (bCurStereoSp3 && (pINChI->Stereo->nNumberOfStereoCenters > 1)); /* Fix11 */ /* djb-rwth: addressing LLVM warning */
# # ]
1484 [ # # ]: 0 : bCurIsoStereoSp3 = bCurIsoRacemic > 1 ? bCurIsoStereoSp3 : 0;
1485 : : }
1486 : : }
1487 : : /* djb-rwth: removing redundant code */
1488 : :
1489 : 161 : io.bIsotopic |= bCurIso;
1490 : 161 : bHasIsotopicAtoms[ii] |= bCurIso;
1491 : 161 : bStereoSp2[ii] |= bCurStereoSp2;
1492 : 161 : bStereoSp3[ii] |= bCurStereoSp3;
1493 [ + + + + ]: 161 : io.bIgn_UU_Sp3[ii] |= !bCurStereoSp3 && (pINChI->nFlags & INCHI_FLAG_SC_IGN_ALL_UU);
1494 [ + - - + ]: 161 : io.bIgn_UU_Sp2[ii] |= !bCurStereoSp2 && (pINChI->nFlags & INCHI_FLAG_SB_IGN_ALL_UU);
1495 : 161 : bIsotopicStereoSp2[ii] |= bCurIsoStereoSp2;
1496 : 161 : bIsotopicStereoSp3[ii] |= bCurIsoStereoSp3;
1497 [ + - - + ]: 161 : io.bIgn_UU_Sp3_Iso[ii] |= !bCurIsoStereoSp3 && (pINChI->nFlags & INCHI_FLAG_SC_IGN_ALL_ISO_UU);
1498 [ + - - + ]: 161 : io.bIgn_UU_Sp2_Iso[ii] |= !bCurIsoStereoSp2 && (pINChI->nFlags & INCHI_FLAG_SB_IGN_ALL_ISO_UU);
1499 [ + + + - ]: 161 : bStereoAbs[ii] |= bCurStereoSp3 && (pINChI->Stereo->nCompInv2Abs != 0);
1500 : :
1501 [ + + + + ]: 161 : bStereoAbsInverted[ii] |= bCurStereoSp3 && (pINChI->Stereo->nCompInv2Abs < 0);
1502 : :
1503 : : /* Fix08: missing isotopic inverted flag if isotopic = inverted non-isotopic */
1504 [ - + - - : 322 : bIsotopicStereoAbsInverted[ii] |= (bCurIsoStereoSp3 && (pINChI->StereoIsotopic->nCompInv2Abs < 0)) ||
+ - ]
1505 [ - + - - ]: 161 : (!bCurIsoStereoSp3 && pINChI->StereoIsotopic && pINChI->Stereo &&
1506 [ # # ]: 0 : pINChI->StereoIsotopic->nCompInv2Abs &&
1507 [ # # ]: 0 : pINChI->StereoIsotopic->nCompInv2Abs != pINChI->Stereo->nCompInv2Abs); /* djb-rwth: addressing LLVM warnings */
1508 : :
1509 : : /* Fix 11: missing /s1 if only isotopic stereo is inverted */
1510 [ - + - - : 322 : bIsotopicStereoAbs[ii] |= (bCurIsoStereoSp3 && (pINChI->StereoIsotopic->nCompInv2Abs != 0)) ||
+ - ]
1511 [ - + - - ]: 161 : (!bCurIsoStereoSp3 && pINChI->StereoIsotopic && pINChI->Stereo &&
1512 [ # # ]: 0 : pINChI->StereoIsotopic->nCompInv2Abs &&
1513 [ # # ]: 0 : pINChI->StereoIsotopic->nCompInv2Abs != pINChI->Stereo->nCompInv2Abs); /* djb-rwth: addressing LLVM warnings */
1514 : :
1515 : 161 : io.bRelativeStereo[ii] |= bCurRelative;
1516 : 161 : io.bIsotopicRelativeStereo[ii] |= bCurIsoRelative;
1517 : 161 : io.bRacemicStereo[ii] |= bCurRacemic;
1518 : 161 : io.bIsotopicRacemicStereo[ii] |= bCurIsoRacemic;
1519 : :
1520 : 161 : bTautomericAcid |= (0 != (pINChI->nFlags & INCHI_FLAG_ACID_TAUT));
1521 : 161 : bHardAddRemProton |= (0 != (pINChI->nFlags & INCHI_FLAG_HARD_ADD_REM_PROTON));
1522 [ + + ]: 161 : if (bCurTaut)
1523 : : {
1524 : 14 : io.bTautomeric |= 1; /* tautomeric representation is present */
1525 : : /* does tautomeric structure have also a non-tautomeric repesentation? */
1526 [ - + - - ]: 14 : io.bNonTautomeric |= HAS_N(is);
1527 : : }
1528 : :
1529 : : /* Auxiliary info */
1530 [ + - + - ]: 161 : if (!(bINChIOutputOptions & INCHI_OUT_NO_AUX_INFO) && (pINChI_Aux = is->pINChI_Aux[jj]))
1531 : : {
1532 : : /* detect presence of constitutional equivalence onfo */
1533 : 161 : int bCurEqu, bCurTautEqu = 0, bCurIsoEqu = 0, bCurIsoTautEqu = 0; /* Fix15-disabled */
1534 : 161 : io.bAtomEqu[ii] |= (bCurEqu = bHasEquString(pINChI_Aux->nConstitEquNumbers,
1535 : : pINChI_Aux->nNumberOfAtoms)); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1536 [ + + ]: 161 : if (bCurTaut)
1537 : : {
1538 : 14 : io.bTautEqu[ii] |= (bCurTautEqu = bHasEquString(pINChI_Aux->nConstitEquTGroupNumbers,
1539 : : pINChI_Aux->nNumberOfTGroups)); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1540 : : }
1541 [ - + ]: 161 : if (bCurIso)
1542 : : {
1543 : 0 : io.bIsotopicAtomEqu[ii] |= (bCurIsoEqu = bHasEquString(pINChI_Aux->nConstitEquIsotopicNumbers,
1544 : : pINChI_Aux->nNumberOfAtoms)) /*|| bCurEqu*/; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1545 [ # # ]: 0 : if (bCurTaut)
1546 : : {
1547 : 0 : io.bIsotopicTautEqu[ii] |= (bCurIsoTautEqu = bHasEquString(pINChI_Aux->nConstitEquIsotopicTGroupNumbers,
1548 : : pINChI_Aux->nNumberOfTGroups)) /*|| bCurTautEqu*/; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1549 : : }
1550 : : /* non-zero if isotopic numbering for inverted isotopic stereo is different */
1551 : 0 : io.bIsotopicOrigNumb[ii] |= bCurHasIsoStereo && /* Fix14 */
1552 [ # # ]: 0 : pINChI_Aux->nOrigAtNosInCanonOrdInv &&
1553 [ # # # # ]: 0 : pINChI_Aux->nIsotopicOrigAtNosInCanonOrd &&
1554 : 0 : (0 != memcmp(pINChI_Aux->nOrigAtNosInCanonOrdInv,
1555 : 0 : pINChI_Aux->nIsotopicOrigAtNosInCanonOrd,
1556 [ # # ]: 0 : sizeof(pINChI_Aux->nOrigAtNosInCanonOrdInv[0]) * pINChI_Aux->nNumberOfAtoms));
1557 : : }
1558 : : /* Inverted stereo */
1559 [ + + + - ]: 161 : if (bCurStereoSp3 && pINChI->Stereo->nCompInv2Abs)
1560 : : {
1561 : 51 : io.bInvStereo[ii] |= 1;
1562 : 51 : io.bInvStereoOrigNumb[ii] |= pINChI_Aux->nOrigAtNosInCanonOrd &&
1563 [ + - + - ]: 102 : pINChI_Aux->nOrigAtNosInCanonOrdInv &&
1564 : 51 : (0 != memcmp(pINChI_Aux->nOrigAtNosInCanonOrd,
1565 : 51 : pINChI_Aux->nOrigAtNosInCanonOrdInv,
1566 [ - + ]: 51 : sizeof(pINChI_Aux->nOrigAtNosInCanonOrd[0]) * pINChI_Aux->nNumberOfAtoms));
1567 : : }
1568 : :
1569 : : /* Inverted isotopic stereo */
1570 [ - + - - ]: 161 : if (bCurIsoStereoSp3 && pINChI->StereoIsotopic->nCompInv2Abs)
1571 : : {
1572 : 0 : io.bInvIsotopicStereo[ii] |= 1;
1573 : :
1574 : 0 : io.bInvIsotopicStereoOrigNumb[ii] |= pINChI_Aux->nIsotopicOrigAtNosInCanonOrd &&
1575 [ # # # # ]: 0 : pINChI_Aux->nIsotopicOrigAtNosInCanonOrdInv &&
1576 : 0 : (0 != memcmp(pINChI_Aux->nIsotopicOrigAtNosInCanonOrd,
1577 : 0 : pINChI_Aux->nIsotopicOrigAtNosInCanonOrdInv,
1578 [ # # ]: 0 : sizeof(pINChI_Aux->nIsotopicOrigAtNosInCanonOrd[0]) * pINChI_Aux->nNumberOfAtoms));
1579 : : }
1580 : :
1581 [ + - + + ]: 161 : if (pINChI_Aux->OrigInfo && bHasOrigInfo(pINChI_Aux->OrigInfo, pINChI_Aux->nNumberOfAtoms))
1582 : : {
1583 : 12 : io.bChargesRadVal[ii] |= 1;
1584 : : }
1585 : : }
1586 : :
1587 [ + + ]: 161 : if (ip->bEnhancedStereo)
1588 : : {
1589 : 57 : set_EnhancedStereo_t_m_layers(orig_inp_data, pINChI, pINChI_Aux);
1590 : : }
1591 : : }
1592 : : }
1593 [ + - ]: 161 : if (bCompExists)
1594 : : {
1595 [ + + ]: 483 : for (j = TAUT_NON; j < TAUT_NUM; j++)
1596 : : {
1597 : 322 : io.num_comp[j]++;
1598 : : }
1599 : : }
1600 : : }
1601 [ + + ]: 122 : if (io.bTautomeric /*&& bTautomericAcid*/) /* "&& bTautomericAcid" commented out 2004-06-02 */
1602 : : {
1603 : 11 : io.bTautomeric += bTautomericAcid; /* long-range tautomerism */
1604 [ - + ]: 11 : io.bTautomeric += (bHardAddRemProton ? 4 : 0);
1605 : : }
1606 [ + - - + ]: 122 : if (bRequestedRacemicStereo || bRequestedRelativeStereo)
1607 : : {
1608 : : /* do not output inverted stereo info */
1609 [ # # ]: 0 : for (i = 0; i < TAUT_NUM; i++)
1610 : : {
1611 : : /* Fix11 */
1612 : 0 : bStereoAbsInverted[i] =
1613 : 0 : bStereoAbs[i] =
1614 : 0 : io.bInvStereo[i] =
1615 : 0 : io.bInvStereoOrigNumb[i] = 0;
1616 : : /* io.bIsotopicRelativeStereo[i]=0 may happen because iso stereo is same or inverted non-iso stereo */
1617 : 0 : bIsotopicStereoAbsInverted[i] =
1618 : 0 : bIsotopicStereoAbs[i] =
1619 : 0 : io.bInvIsotopicStereo[i] =
1620 : 0 : io.bInvIsotopicStereoOrigNumb[i] = 0;
1621 : : }
1622 : : }
1623 : :
1624 [ + - ]: 244 : io.iCurTautMode = io.bOutType == OUT_N1 ? TAUT_NON : /* only non-taut */
1625 : :
1626 : 122 : io.bOutType == OUT_T1 ? TAUT_YES
1627 [ + - ]: 244 : : /* tautomeric if present, otherwise non-tautomeric */
1628 : 122 : io.bOutType == OUT_NT ? TAUT_NON
1629 [ + - ]: 244 : : /* only non-taut representations of tautomeric */
1630 : 122 : io.bOutType == OUT_TN ? TAUT_YES
1631 [ + - ]: 122 : : /* tautomeric if present otherwise non-tautomeric; */
1632 : : -1; /* separately output non-taut representations of tautomeric if present */
1633 : :
1634 [ - + ]: 122 : if (io.iCurTautMode < 0)
1635 : : {
1636 : 0 : return 0; /* error */
1637 : : }
1638 : :
1639 : : /* Now print out */
1640 : :
1641 : 122 : io.bOverflow = 0;
1642 : 122 : io.num_components = io.num_comp[io.iCurTautMode];
1643 : : /* djb-rwth: removing redundant code */
1644 : :
1645 [ - + ]: 122 : if (bINChIOutputOptions & INCHI_OUT_ONLY_AUX_INFO)
1646 : : {
1647 : 0 : goto output_aux_info;
1648 : : }
1649 : :
1650 : 122 : io.nCurINChISegment = DIFL_M;
1651 : :
1652 : : /* InChI output: version and kind */
1653 [ - + - - ]: 122 : if (INCHI_basic_or_INCHI_reconnected == INCHI_BAS || !(bINChIOutputOptions & INCHI_OUT_EMBED_REC))
1654 : : {
1655 : 122 : int is_beta = 0;
1656 : 122 : int nAtomsAllComp = inchi_max(nAtomsAllComp1, nAtomsAllComp2);
1657 : :
1658 [ - + ]: 122 : if (nAtomsAllComp > NORMALLY_ALLOWED_INP_MAX_ATOMS)
1659 : : {
1660 : : /* v. 1.05 for LargeMolecules */
1661 : 0 : is_beta = 1;
1662 : : }
1663 [ + - + + ]: 122 : if (pOrigStruct && pOrigStruct->polymer)
1664 : : {
1665 : : /* v. 1.05 for Polymers */
1666 : 2 : is_beta = 1;
1667 : : }
1668 : : /* specifically put 'B' for empty structure InChI */
1669 : : /* if "Polymers" or "LargeMolecules" requested */
1670 [ - + - - : 120 : else if (!pOrigStruct && (ip->bLargeMolecules || ip->bPolymers))
- - ]
1671 : : {
1672 : 0 : is_beta = 1;
1673 : : }
1674 [ + - - + ]: 120 : else if (pOrigStruct && pOrigStruct->n_zy)
1675 : : {
1676 : 0 : is_beta = 1;
1677 : : }
1678 [ + + + + ]: 120 : else if (ip->bMolecularInorganics || ip->bEnhancedStereo)
1679 : : {
1680 : 69 : is_beta = 1;
1681 : : }
1682 : :
1683 : 122 : OutputINCHI_VersionAndKind(out_file, strbuf, bINChIOutputOptions, is_beta, pLF, pTAB);
1684 : : }
1685 : :
1686 : : /* InChI output: atoms */
1687 : 122 : intermediate_result = OutputINCHI_MainLayerFormula(pCG, out_file, strbuf,
1688 : : num_components2,
1689 : : &INCHI_basic_or_INCHI_reconnected,
1690 : : &io, pLF, pTAB);
1691 [ - + ]: 122 : if (intermediate_result != 0)
1692 : 0 : goto exit_function;
1693 : :
1694 : : /* InChI output: connection table */
1695 : 122 : intermediate_result = OutputINCHI_MainLayerConnections(pCG, out_file, strbuf, num_components2,
1696 : : &INCHI_basic_or_INCHI_reconnected,
1697 : : &io, pLF, pTAB);
1698 [ - + ]: 122 : if (intermediate_result != 0)
1699 : 0 : goto exit_function;
1700 : :
1701 : : /* InChI output: hydrogens (with tautomeric info) */
1702 : 122 : intermediate_result = OutputINCHI_MainLayerHydrogens(pCG, out_file, strbuf, num_components2,
1703 : : &INCHI_basic_or_INCHI_reconnected,
1704 : : &io, pLF, pTAB);
1705 [ - + ]: 122 : if (intermediate_result != 0)
1706 : 0 : goto exit_function;
1707 : :
1708 : 122 : io.bFhTag = 0;
1709 : 122 : npass = 0;
1710 : :
1711 : 122 : repeat_INChI_output:
1712 : :
1713 : : /* InChI output: charge and removed protons */
1714 : 122 : intermediate_result = OutputINCHI_ChargeAndRemovedAddedProtonsLayers(pCG, out_file, strbuf,
1715 : : &io, pLF, pTAB);
1716 [ - + ]: 122 : if (intermediate_result != 0)
1717 : 0 : goto exit_function;
1718 : :
1719 : : /* InChI output: polymer layer */
1720 [ + - ]: 122 : if (npass == 0)
1721 : : {
1722 : 122 : intermediate_result = OutputINCHI_PolymerLayer(pCG, out_file, strbuf,
1723 : : &INCHI_basic_or_INCHI_reconnected,
1724 : : orig_inp_data, pOrigStruct,
1725 : : &io, pLF, pTAB);
1726 [ - + ]: 122 : if (intermediate_result != 0)
1727 : 0 : goto exit_function;
1728 : : }
1729 : :
1730 : : /* InChI output: stereo (non-isotopic) */
1731 [ + + ]: 122 : if (ip->bEnhancedStereo) {
1732 : 47 : intermediate_result = OutputINCHI_StereoLayer_EnhancedStereo( pCG, out_file, strbuf, &io, orig_inp_data, pLF, pTAB );
1733 : : } else {
1734 : 75 : intermediate_result = OutputINCHI_StereoLayer( pCG, out_file, strbuf, &io, pLF, pTAB );
1735 : : }
1736 [ - + ]: 122 : if (intermediate_result != 0)
1737 : 0 : goto exit_function;
1738 : :
1739 : : /* Switch from M to MI or from F to FI */
1740 : 122 : io.nCurINChISegment++;
1741 : :
1742 : : /* InChI output: isotopic */
1743 : 122 : intermediate_result = OutputINCHI_IsotopicLayer(pCG, out_file, strbuf,
1744 : : &INCHI_basic_or_INCHI_reconnected,
1745 : : &io, pLF, pTAB);
1746 : :
1747 [ - + ]: 122 : if (intermediate_result != 0)
1748 : : {
1749 : 0 : goto exit_function;
1750 : : }
1751 : :
1752 : : /*
1753 : : At this point the INChI part of the output has been done.
1754 : : If this INChI is tautomeric and non-tautomeric results exist,
1755 : : then we need to output non-tautomeric data:
1756 : : fixed H
1757 : : stereo
1758 : : isotopic
1759 : : isotopic stereo
1760 : : */
1761 : :
1762 : : /* InChI output: FixedH and sublayers */
1763 : 122 : intermediate_result = OutputINCHI_FixedHLayerWithSublayers(pCG, out_file, strbuf,
1764 : : &INCHI_basic_or_INCHI_reconnected,
1765 : : &io, pLF, pTAB,
1766 : : &then_goto_repeat);
1767 [ - + ]: 122 : if (intermediate_result != 0)
1768 : : {
1769 : 0 : goto exit_function;
1770 : : }
1771 [ - + ]: 122 : if (then_goto_repeat)
1772 : : {
1773 : 0 : npass++;
1774 : 0 : goto repeat_INChI_output;
1775 : : }
1776 : :
1777 : : /*
1778 : : InChI output: reconnected structure
1779 : : */
1780 : :
1781 : 122 : bEmbeddedOutputCalled = 0;
1782 [ + + + - ]: 122 : if (bDisconnectedCoord && INCHI_basic_or_INCHI_reconnected == INCHI_BAS &&
1783 [ + - - + ]: 4 : (bINChIOutputOptions & INCHI_OUT_EMBED_REC) && num_components2[INCHI_REC])
1784 : : {
1785 : : int nRet;
1786 : 0 : bEmbeddedOutputCalled = 1;
1787 : :
1788 : : /* output blank line before /R: in case of bPlainTextCommnts=1 */
1789 : 0 : inchi_ios_print_nodisplay(out_file, "%s", pLF);
1790 : : /* end of disconnected INChI output */
1791 : :
1792 : 0 : nRet = OutputINChI1(pCG,
1793 : : strbuf,
1794 : : pINChISortTautAndNonTaut2,
1795 : : INCHI_REC,
1796 : : orig_inp_data,
1797 : : pOrigStruct,
1798 : : ip,
1799 : : 0 /*bDisconnectedCoord*/,
1800 : : bOutputType,
1801 : : bINChIOutputOptions | INCHI_OUT_NO_AUX_INFO,
1802 : : num_components2,
1803 : : num_non_taut2,
1804 : : num_taut2,
1805 : : out_file,
1806 : : log_file,
1807 : : num_input_struct,
1808 : : pSortPrintINChIFlags,
1809 : : save_opt_bits);
1810 : :
1811 [ # # ]: 0 : if (!nRet)
1812 : : {
1813 : 0 : goto exit_function; /* error */
1814 : : }
1815 : : }
1816 : :
1817 : : /* InChI output: save InChI creation options if requested */
1818 [ + - ]: 122 : if (!bEmbeddedOutputCalled &&
1819 [ - + ]: 122 : (bINChIOutputOptions & INCHI_OUT_SAVEOPT) &&
1820 [ # # ]: 0 : (0 == (bINChIOutputOptions & INCHI_OUT_STDINCHI)) /* not std-InChI output */
1821 : : )
1822 : : {
1823 : : char let1, let2;
1824 : 0 : GetSaveOptLetters(save_opt_bits, &let1, &let2);
1825 : 0 : inchi_ios_print_nodisplay(out_file, "\\%c%c", let1, let2);
1826 : : }
1827 [ + - + - ]: 122 : if (!bEmbeddedOutputCalled && !bPlainTextCommnts)
1828 : : { /* plain text comment earlier ended with LF */
1829 : 244 : inchi_ios_print_nodisplay(out_file, "%s%s",
1830 [ - + - - ]: 122 : (!num_components2[0] && !num_components2[1]) ? "//" : "", /* empty InChI=// */
1831 [ + - ]: 122 : (bINChIOutputOptions & INCHI_OUT_NO_AUX_INFO) ? "\n" : pTAB);
1832 : : /* end of INChI= output */
1833 : : }
1834 : :
1835 : 122 : inchi_strbuf_reset(strbuf);
1836 : :
1837 : : #ifdef TARGET_LIB_FOR_WINCHI
1838 : : /* @@@ Here we end up with silent output: display previously hidden output */
1839 : : if (inchi_ios_flush_not_displayed(out_file) != -1)
1840 : : silent = 0;
1841 : : #endif
1842 : :
1843 : 122 : output_aux_info:
1844 : :
1845 : : /* Output Aux Info */
1846 : :
1847 : 122 : io.bFhTag = 0;
1848 [ + - ]: 122 : if ((bINChIOutputOptions & INCHI_OUT_NO_AUX_INFO) == 0)
1849 : : {
1850 : :
1851 : 122 : io.num_components = io.num_comp[io.iCurTautMode];
1852 : :
1853 : : /* AuxInfo: header and normalization type */
1854 : 122 : intermediate_result = OutputAUXINFO_HeaderAndNormalization_type(pCG, out_file, strbuf,
1855 : : bINChIOutputOptions,
1856 : : &INCHI_basic_or_INCHI_reconnected,
1857 : : num_components2,
1858 : : &io, pLF, pTAB);
1859 [ + - ]: 122 : if (intermediate_result != 0)
1860 : 0 : goto exit_function;
1861 : :
1862 : 122 : repeat_INChI_Aux_output:
1863 : :
1864 : : /* AuxInfo: original atom numbers and symmetry numbers (constit. equivalence /E: ) */
1865 : 122 : intermediate_result = OutputAUXINFO_OriginalNumbersAndEquivalenceClasses(pCG, out_file, strbuf,
1866 : : num_components2,
1867 : : &io, pLF, pTAB);
1868 [ - + ]: 122 : if (intermediate_result != 0)
1869 : 0 : goto exit_function;
1870 : :
1871 : : /* AuxInfo: tautomeric groups equivalence */
1872 : 122 : intermediate_result = OutputAUXINFO_TautomericGroupsEquivalence(pCG, out_file, strbuf, &io);
1873 [ - + ]: 122 : if (intermediate_result != 0)
1874 : 0 : goto exit_function;
1875 : :
1876 : : /* AuxInfo: stereo data */
1877 : 122 : intermediate_result = OutputAUXINFO_Stereo(pCG, out_file, strbuf, &io, pLF, pTAB);
1878 [ + - ]: 122 : if (intermediate_result != 0)
1879 : 0 : goto exit_function;
1880 : :
1881 : 122 : repeat_INChI_Aux_Iso_output:
1882 : : /* AuxInfo: isotopic info */
1883 : 122 : intermediate_result = OutputAUXINFO_IsotopicInfo(pCG, out_file, strbuf,
1884 : : &INCHI_basic_or_INCHI_reconnected,
1885 : : &io, pLF, pTAB);
1886 [ - + ]: 122 : if (intermediate_result != 0)
1887 : : {
1888 : 0 : goto exit_function;
1889 : : }
1890 : :
1891 : : /*
1892 : : At this point the INChI_Aux part of the output has been completed.
1893 : : If this INChI is tautomeric and non-tautomeric results exist,
1894 : : then we need to output non-tautomeric auxilialy data
1895 : : (same as above excluding tautomeric information).
1896 : : Currently, this is enabled for xml output only
1897 : : */
1898 : :
1899 [ + - + + : 122 : if (io.bOutType == OUT_TN && io.bTautomeric && io.bNonTautomeric &&
- + ]
1900 : : /* Check whether the Fixed-H layer is empty */
1901 [ # # # # ]: 0 : (*pSortPrintINChIFlags & ((INCHI_basic_or_INCHI_reconnected == INCHI_BAS) ? FLAG_SORT_PRINT_NO_NFIX_H_BAS : FLAG_SORT_PRINT_NO_NFIX_H_REC)) &&
1902 [ # # # # ]: 0 : (*pSortPrintINChIFlags & ((INCHI_basic_or_INCHI_reconnected == INCHI_BAS) ? FLAG_SORT_PRINT_NO_IFIX_H_BAS : FLAG_SORT_PRINT_NO_IFIX_H_REC)))
1903 : : {
1904 : 0 : io.bNonTautomeric = 0; /* bNonTautIdentifierNotEmpty == 0 => no fixed H info 02-10-2995 */
1905 : : }
1906 : :
1907 [ + - + + : 122 : if (io.bOutType == OUT_TN && io.bTautomeric && io.bNonTautomeric)
- + ]
1908 : : {
1909 : : /* add the second (non-tautomeric) output */
1910 : 0 : io.bOutType = OUT_NONTAUT;
1911 : 0 : io.iCurTautMode = TAUT_NON;
1912 : 0 : io.pINChISort = io.pINChISortTautAndNonTaut[TAUT_NON];
1913 : 0 : io.bSecondNonTautPass = 1;
1914 : 0 : io.num_components = io.num_comp[io.iCurTautMode];
1915 : 0 : io.bFhTag = AL_FIXH;
1916 : 0 : inchi_strbuf_reset(strbuf); /*pStr[io.tot_len=0] = '\0';*/
1917 : :
1918 : : /* if InChI Fixed-H isotopic is empty then do not output corresponding AuxInfo */
1919 [ # # ]: 0 : if (!(*pSortPrintINChIFlags &
1920 [ # # ]: 0 : ((INCHI_basic_or_INCHI_reconnected == INCHI_BAS) ? FLAG_SORT_PRINT_NO_NFIX_H_BAS : FLAG_SORT_PRINT_NO_NFIX_H_REC)))
1921 : : {
1922 : 0 : npass++;
1923 : 0 : goto repeat_INChI_Aux_output;
1924 : : }
1925 : : else
1926 : : {
1927 : 0 : npass++;
1928 : 0 : goto repeat_INChI_Aux_Iso_output;
1929 : : }
1930 : : }
1931 : : else
1932 : : {
1933 [ - + - - : 122 : if (io.bOutType == OUT_NONTAUT && io.bOutputType == OUT_TN && io.bTautomeric && io.bNonTautomeric)
- - - - ]
1934 : : {
1935 : : /* the second (non-taut) output has been done; restore variables */
1936 : 0 : io.bOutType = OUT_TN;
1937 : 0 : io.iCurTautMode = TAUT_YES;
1938 : 0 : io.pINChISort = io.pINChISortTautAndNonTaut[TAUT_YES];
1939 : 0 : io.bSecondNonTautPass = 0;
1940 : : /* set correct num components for the reversibility info 02-10-2005 */
1941 : 0 : io.num_components = io.num_comp[io.iCurTautMode];
1942 : 0 : io.bFhTag = 0;
1943 : : }
1944 : : }
1945 : :
1946 : : /* Charges, radicals, unusual valences */
1947 : 122 : intermediate_result = OutputAUXINFO_ChargesRadicalsAndUnusualValences(pCG, out_file, strbuf, &io, pLF, pTAB);
1948 [ - + ]: 122 : if (intermediate_result != 0)
1949 : : {
1950 : 0 : goto exit_function;
1951 : : }
1952 : :
1953 : : /* Output the original input structure -- quick fix */
1954 : 122 : intermediate_result = OutputAUXINFO_ReversibilityInfo(pCG, out_file, strbuf, pOrigStruct, &io, pLF, pTAB);
1955 [ - + ]: 122 : if (intermediate_result != 0)
1956 : : {
1957 : 0 : goto exit_function;
1958 : : }
1959 : :
1960 : : /* Output polymeric Aux Info */
1961 : 122 : intermediate_result = OutputAUXINFO_PolymerInfo(pCG, out_file, strbuf, pOrigStruct, &io, pLF, pTAB);
1962 [ - + ]: 122 : if (intermediate_result != 0)
1963 : : {
1964 : 0 : goto exit_function;
1965 : : }
1966 : :
1967 : : /*
1968 : : Output INChI_Aux of the reconnected structure
1969 : : */
1970 : :
1971 : 122 : bEmbeddedOutputCalled = 0;
1972 [ + + + - : 122 : if (bDisconnectedCoord && INCHI_basic_or_INCHI_reconnected == INCHI_BAS && (bINChIOutputOptions & INCHI_OUT_EMBED_REC) &&
+ - ]
1973 [ - + - - ]: 4 : num_components2[INCHI_REC] && !(bINChIOutputOptions & INCHI_OUT_NO_AUX_INFO))
1974 : : {
1975 : : int nRet;
1976 : 0 : bEmbeddedOutputCalled = 1;
1977 : 0 : inchi_ios_print(out_file, "%s", pLF);
1978 : :
1979 : 0 : nRet = OutputINChI1(pCG,
1980 : : strbuf,
1981 : : pINChISortTautAndNonTaut2,
1982 : : INCHI_REC,
1983 : : NULL,
1984 : : NULL,
1985 : : ip,
1986 : : 0 /*bDisconnectedCoord*/,
1987 : : bOutputType,
1988 : : INCHI_OUT_ONLY_AUX_INFO | bINChIOutputOptions,
1989 : : num_components2,
1990 : : num_non_taut2,
1991 : : num_taut2,
1992 : : out_file,
1993 : : log_file,
1994 : : num_input_struct,
1995 : : pSortPrintINChIFlags,
1996 : : save_opt_bits);
1997 : :
1998 [ # # ]: 0 : if (!nRet)
1999 : : {
2000 : 0 : goto exit_function; /* error */
2001 : : }
2002 : : }
2003 : :
2004 : : /* Close INChI_Aux */
2005 [ + - + - ]: 122 : if (!bEmbeddedOutputCalled && !bPlainTextCommnts)
2006 : : {
2007 [ - + - - ]: 122 : inchi_ios_print(out_file, "%s\n", (!num_components2[0] && !num_components2[1]) ? "//" : "");
2008 : : /* plain text comment earlier ended with LF */
2009 : : }
2010 : :
2011 : : /* in wINChI window, separate AuxInfo: from InChIKey: with blank line */
2012 : 122 : inchi_ios_print(out_file, "%s",
2013 [ - + ]: 122 : (bINChIOutputOptions & INCHI_OUT_WINCHI_WINDOW) ? "\n" : "");
2014 : : } /* end of output AuxInfo */
2015 : :
2016 : 122 : ret = 1;
2017 : :
2018 : 122 : exit_function:
2019 : :
2020 : : #ifdef TARGET_LIB_FOR_WINCHI
2021 : : /* @@@ If for any error we get here silent, display previously hidden output */
2022 : : if (silent)
2023 : : {
2024 : : /*
2025 : : if ( !inchi_ios_flush_not_displayed( out_file ) != -1 )
2026 : : silent = 0;
2027 : : */
2028 : : silent = 0;
2029 : : }
2030 : : #endif
2031 : :
2032 [ - + ]: 122 : if (io.bOverflow)
2033 : : {
2034 : 0 : inchi_ios_print(out_file, "\nFATAL ERROR: Output buffer overflow\n");
2035 : : }
2036 : :
2037 [ - + ]: 122 : if (intermediate_result)
2038 : : {
2039 : 0 : ret = 0;
2040 : 0 : inchi_ios_eprint(log_file, "InChI serialization error for structure #%d.%s%s%s%s\n",
2041 [ # # # # : 0 : num_input_struct, SDF_LBL_VAL(ip->pSdfLabel, ip->pSdfValue));
# # # # #
# # # # #
# # # # #
# # # #
# ]
2042 : : }
2043 : :
2044 : 122 : return ret;
2045 : : } /* OutputINChI1 */
2046 : :
2047 : : /****************************************************************************/
2048 : 1498 : char *szGetTag(const INCHI_TAG *Tag,
2049 : : int nTag,
2050 : : int bTag,
2051 : : char *szTag,
2052 : : int *bAlways,
2053 : : short tag_flag)
2054 : : {
2055 : : int i, j, bit, num, len;
2056 [ + + ]: 1498 : const int MAX_TAG_NUM = tag_flag ? (int)IL_MAX_ORD : (int)AL_MAX_ORD; /* djb-rwth: fixing GHI #160 */
2057 [ + - + - ]: 1498 : if (0 < nTag && nTag < 3)
2058 : : {
2059 : : /* no plain text comments: pick up the last tag */
2060 [ + + ]: 28988 : for (i = 0, j = -1, bit = 1; i < MAX_TAG_NUM; i++, bit <<= 1)
2061 : : {
2062 [ + + ]: 27490 : if (bTag & bit)
2063 : : {
2064 : 2032 : j = i;
2065 : : }
2066 : : }
2067 [ + - ]: 1498 : if (j >= 0)
2068 : : {
2069 : : #if USE_BCF
2070 : : int stl1, stl2, dstsz;
2071 : : stl1 = strlen(Tag[j].szXmlLabel) + 1;
2072 : : stl2 = strlen(Tag[j].szPlainLabel) + 1;
2073 : : dstsz = max_3(stl1, stl2, 5);
2074 : : strcpy_s(szTag, dstsz, nTag == 1 ? Tag[j].szXmlLabel : nTag == 2 ? Tag[j].szPlainLabel
2075 : : : "???"); /* djb-rwth: function replaced with its safe C11 variant */
2076 : : #else
2077 [ - + + - ]: 1498 : strcpy(szTag, nTag == 1 ? Tag[j].szXmlLabel : nTag == 2 ? Tag[j].szPlainLabel : "???"); /* djb-rwth: addressing coverity ID #499488 -- when nTag == 2, the "???" is avoided, which is correct */
2078 : : #endif
2079 [ - + ]: 1498 : if (nTag != 2)
2080 : : {
2081 : 0 : *bAlways = Tag[j].bAlwaysOutput;
2082 : : }
2083 : 1498 : return szTag;
2084 : : }
2085 : : }
2086 [ # # ]: 0 : else if (nTag == 3)
2087 : : {
2088 : : /* plain text with comments */
2089 : 0 : szTag[0] = '{';
2090 : 0 : szTag[1] = '\0';
2091 [ # # ]: 0 : for (i = 0, j = -1, bit = 1, num = 0; i < MAX_TAG_NUM; i++, bit <<= 1)
2092 : : {
2093 [ # # ]: 0 : if (bTag & bit)
2094 : : {
2095 : 0 : j = i;
2096 [ # # ]: 0 : if (num++)
2097 : : {
2098 : 0 : strcat(szTag, ":");
2099 : : }
2100 : 0 : strcat(szTag, Tag[i].szPlainComment);
2101 : : }
2102 : : }
2103 [ # # ]: 0 : if (num)
2104 : : {
2105 : 0 : strcat(szTag, "}");
2106 : 0 : num = (int)strlen(Tag[j].szPlainLabel);
2107 : 0 : len = (int)strlen(szTag);
2108 [ # # ]: 0 : if (len)
2109 : : {
2110 : 0 : memmove(szTag + num, szTag, (long long)len + 1); /* djb-rwth: cast operator added */
2111 : 0 : memcpy(szTag, Tag[j].szPlainLabel, num);
2112 : : }
2113 : : else
2114 : : {
2115 : 0 : strcpy(szTag, Tag[j].szPlainLabel);
2116 : : }
2117 : 0 : *bAlways = Tag[j].bAlwaysOutput;
2118 : : }
2119 : : else
2120 : : {
2121 : 0 : strcpy(szTag, "???");
2122 : : }
2123 : 0 : return szTag;
2124 : : }
2125 : :
2126 : 0 : strcpy(szTag, "???");
2127 : 0 : return szTag;
2128 : : }
2129 : :
2130 : : /* djb-rwth: removing redundant code */
2131 : :
2132 : : /****************************************************************************
2133 : : str_LineEnd( ... )
2134 : :
2135 : : First, checks if buffer overflow; then:
2136 : : if ind < 0 (common usage, plain text output)
2137 : : sets terminating '\0' in pStr,
2138 : : optionally adds leading tag (e.g., '/' or "/c" )
2139 : : *obsolete* if ind >=0 XML output
2140 : :
2141 : : ****************************************************************************/
2142 : 869 : int str_LineEnd(const char *tag,
2143 : : int *bOverflow,
2144 : : INCHI_IOS_STRING *buf,
2145 : : int ind,
2146 : : int bPlainTextTags)
2147 : : {
2148 : : /* djb-rwth: removing redundant variables */
2149 : : int tag_len;
2150 : :
2151 : : /* check buffer overflow */
2152 [ - + ]: 869 : if (*bOverflow)
2153 : : {
2154 : 0 : return 1;
2155 : : }
2156 : :
2157 [ + - ]: 869 : if (ind < 0)
2158 : : {
2159 : : /* Plain text */
2160 : : /* insert plain text tag if:
2161 : : (a) pStr has non-zero length, or
2162 : : (b) ind < -1
2163 : : */
2164 [ + + - + ]: 869 : if (buf->pStr[0] || ind < -1)
2165 : : {
2166 [ + - ]: 867 : tag_len = bPlainTextTags ? (int)strlen(tag) : 0;
2167 [ + + ]: 867 : if (tag_len > 0)
2168 : : {
2169 : 745 : int n_added = tag_len + 2 + 2;
2170 : 745 : inchi_strbuf_update(buf, n_added);
2171 : :
2172 : 745 : memmove(buf->pStr + tag_len, buf->pStr, (long long)buf->nUsedLength + 1); /* djb-rwth: cast operator added */
2173 : : /* NB: trailing 0 is also memmoved */
2174 : 745 : memcpy(buf->pStr, tag, tag_len);
2175 : :
2176 : : /* to be sure... */
2177 : 745 : buf->nUsedLength = strlen(buf->pStr);
2178 : : }
2179 : : }
2180 : : }
2181 : :
2182 : 869 : return 0;
2183 : : }
2184 : :
2185 : : /****************************************************************************/
2186 : 1625 : int CleanOrigCoord(MOL_COORD szCoord, int delim)
2187 : : {
2188 : : #define MIN_BOND_LENGTH (1.0e-6)
2189 : : char szVal[LEN_COORD + 1];
2190 : : MOL_COORD szBuf;
2191 : : char *q;
2192 : 1625 : int len, last, fst, dec_pnt, num_zer = 0, len_buf = 0, e;
2193 : : int k, i;
2194 : : double coord;
2195 : :
2196 [ + + ]: 6500 : for (k = 0; k < NUM_COORD * LEN_COORD; k += LEN_COORD)
2197 : : {
2198 : 4875 : memcpy(szVal, szCoord + k, LEN_COORD);
2199 : 4875 : szVal[LEN_COORD] = '\0';
2200 : 4875 : lrtrim(szVal, &len);
2201 : 4875 : coord = strtod(szVal, &q);
2202 [ + + ]: 4875 : if (MIN_BOND_LENGTH > fabs(coord))
2203 : : {
2204 : 1815 : strcpy(szVal, "0");
2205 : 1815 : len = 1;
2206 : 1815 : num_zer++;
2207 : : }
2208 : : else
2209 : : {
2210 : 3060 : len = (int)(q - szVal);
2211 : : /* last = (last mantissa digit position + 1) */
2212 [ + - + - ]: 3060 : if ((q = strchr(szVal, 'e')) || (q = strchr(szVal, 'E')) ||
2213 [ + - - + ]: 3060 : (q = strchr(szVal, 'd')) || (q = strchr(szVal, 'D')))
2214 : : {
2215 : : /* floating point */
2216 : 0 : last = q - szVal;
2217 : : /* remove (+) and leading zeroes from the exponent */
2218 : 0 : e = (int)strtol(szVal + last + 1, &q, 10); /* exponent */
2219 [ # # ]: 0 : if (e)
2220 : : {
2221 : : /* new exp; update the length */
2222 : 0 : len = last + 1 + sprintf(szVal + last + 1, "%d", e); /* print exp without leading zeroes and '+' */
2223 : : }
2224 : : else
2225 : : {
2226 : : /* exponent is zero */
2227 : 0 : len = last;
2228 : : }
2229 : : }
2230 : : else
2231 : : {
2232 : 3060 : last = len;
2233 : : }
2234 : : /* fst = (first mantissa digit); fst=1 if the sign is present, otherwise 0 */
2235 [ + - + + ]: 3060 : fst = (szVal[0] != '.' && !isdigit(UCINT szVal[0]));
2236 : : /* dec_pnt = (decimal point position) or last */
2237 [ + - ]: 3060 : if ((q = strchr(szVal, '.'))) /* djb-rwth: addressing LLVM warning */
2238 : : {
2239 : 3060 : dec_pnt = (int)(q - szVal);
2240 : : }
2241 : : else
2242 : : {
2243 : 0 : dec_pnt = last;
2244 : : }
2245 : 3060 : last -= 1; /* last mantissa digit position */
2246 : : /* remove trailing zeroes in the range dec_pnt+1..last-1 */
2247 [ + - + + ]: 3251 : for (i = last; dec_pnt < i && '0' == szVal[i]; i--)
2248 : : ;
2249 [ - + ]: 3060 : if (i == dec_pnt)
2250 : : {
2251 : 0 : i--; /* remove decimal point, too */
2252 : : }
2253 [ + + ]: 3060 : if (i < last)
2254 : : {
2255 : 109 : memmove(szVal + i + 1, szVal + last + 1, (long long)len - (long long)last); /* djb-rwth: cast operator added */
2256 : 109 : len -= last - i;
2257 : : }
2258 : : /* remove leading zeroes */
2259 [ + - + + ]: 3802 : for (i = fst; i < len && '0' == szVal[i]; i++)
2260 : : {
2261 : : ;
2262 : : }
2263 [ + + + - : 3060 : if ((i > fst) && (len - fst <= LEN_COORD + 1 - i) && (len - fst <= LEN_COORD + 1 - fst)) /* djb-rwth: fixing GHI #138 */
+ - ]
2264 : : {
2265 : 742 : memmove(szVal + fst, szVal + i, (long long)len - (long long)fst); /* djb-rwth: cast operator added */
2266 : 742 : len -= i - fst;
2267 : : }
2268 : : }
2269 [ + + + - ]: 4875 : if (len_buf && (len_buf < (int)sizeof(MOL_COORD)))
2270 : : {
2271 : : #pragma warning(push)
2272 : : #pragma warning(disable : 6386)
2273 : 3250 : szBuf[len_buf++] = delim;
2274 : : #pragma warning(pop)
2275 : : }
2276 [ - + ]: 4875 : if (len_buf >= (int)sizeof(MOL_COORD)) /* djb-rwth: fixing coverity ID #499520 */
2277 : : {
2278 : 0 : len_buf = (int)sizeof(MOL_COORD) - 1;
2279 : 0 : len = 0;
2280 : : }
2281 : 4875 : memcpy(szBuf + len_buf, szVal, len); /* does not copy zero termination*/
2282 : 4875 : len_buf += len;
2283 : : }
2284 : : /* zero termination */
2285 [ + - ]: 1625 : if (len_buf < (int)sizeof(MOL_COORD))
2286 : : {
2287 : 1625 : memset(szBuf + len_buf, 0, sizeof(MOL_COORD) - len_buf); /* djb-rwth: memset_s C11/Annex K variant? */
2288 : : }
2289 : :
2290 : 1625 : memcpy(szCoord, szBuf, sizeof(MOL_COORD));
2291 : :
2292 : 1625 : return num_zer;
2293 : : #undef MIN_BOND_LENGTH
2294 : : }
2295 : :
2296 : : /****************************************************************************/
2297 : 377 : int WriteOrigCoord(int num_inp_atoms,
2298 : : MOL_COORD *szMolCoord,
2299 : : int *i,
2300 : : char *szBuf,
2301 : : int buf_len)
2302 : : {
2303 : :
2304 : : int j, num_zer, len, cur_len;
2305 : : char *p;
2306 : : MOL_COORD szCurCoord;
2307 : 377 : cur_len = 0;
2308 [ + + ]: 1991 : for (j = *i; j < num_inp_atoms;)
2309 : : {
2310 : 1625 : memcpy(szCurCoord, szMolCoord[j], sizeof(szCurCoord));
2311 : 1625 : num_zer = CleanOrigCoord(szCurCoord, ',');
2312 [ + + ]: 1625 : if (NUM_COORD == num_zer)
2313 : : {
2314 : 96 : len = 0;
2315 : : }
2316 : : else
2317 : : {
2318 [ + - ]: 1529 : if ((p = (char *)memchr(szCurCoord, '\0', sizeof(szCurCoord)))) /* djb-rwth: addressing LLVM warning */
2319 : : {
2320 : 1529 : len = (int)(p - szCurCoord);
2321 : : }
2322 : : else
2323 : : {
2324 : 0 : len = sizeof(szCurCoord);
2325 : : }
2326 : : }
2327 [ + + ]: 1625 : if (len + cur_len + 1 < buf_len)
2328 : : {
2329 [ + + ]: 1614 : if (len)
2330 : : {
2331 : 1518 : memcpy(szBuf + cur_len, szCurCoord, len * sizeof(szBuf[0]));
2332 : : }
2333 : 1614 : szBuf[cur_len += len] = ';';
2334 : 1614 : cur_len++;
2335 : 1614 : j++;
2336 : : }
2337 : : else
2338 : : {
2339 : 11 : break;
2340 : : }
2341 : : }
2342 : 377 : szBuf[cur_len] = '\0';
2343 : 377 : *i = j; /* next item */
2344 : :
2345 : 377 : return cur_len;
2346 : : }
2347 : :
2348 : : /****************************************************************************
2349 : : WriteOrigAtoms
2350 : :
2351 : : number of atoms
2352 : : [c|n] chiral/nonchiral
2353 : :
2354 : : Element
2355 : : #valence
2356 : : +/-[charge>1]
2357 : : .#rad (#rad=1, 2, 3: singlet, doulet, triplet)
2358 : : [.]i#iso_mass
2359 : : [.]{o|e|u|?} atom parity = {1:2:3:4}
2360 : : [.]h[#of 1H>1]
2361 : : [.]d[#of 2H>1]
2362 : : [.]t[#of 3H>1]
2363 : :
2364 : : Note: . occurs only once and only if radical or 1-character element
2365 : : ****************************************************************************/
2366 : 366 : int WriteOrigAtoms(CANON_GLOBALS *pCG,
2367 : : int num_inp_atoms,
2368 : : inp_ATOM *at,
2369 : : int *i,
2370 : : char *szBuf,
2371 : : int buf_len,
2372 : : STRUCT_DATA *sd)
2373 : : {
2374 : : int j, k, n, len, len0, cur_len, val, bonds_val, mw, parity, num_trans, is_ok, b_self;
2375 : : static const char szIsoH[] = "hdt";
2376 : : char szCurAtom[32];
2377 : : AT_NUMB nNeighOrder[MAXVAL], neigh;
2378 : :
2379 : 366 : cur_len = 0;
2380 [ + + ]: 366 : if (0 == *i)
2381 : : {
2382 : 244 : cur_len = sprintf(szBuf, "%d%s", num_inp_atoms,
2383 [ + + ]: 244 : (sd->bChiralFlag & FLAG_INP_AT_CHIRAL) ? "c" : (sd->bChiralFlag & FLAG_INP_AT_NONCHIRAL) ? "n"
2384 [ + - ]: 228 : : "");
2385 : : }
2386 [ + + ]: 1980 : for (j = *i; j < num_inp_atoms;)
2387 : : {
2388 : : /* tetrahedral parity treatment */
2389 : 1614 : parity = 0;
2390 : 1614 : num_trans = 0;
2391 [ - + ]: 1614 : if (at[j].p_parity)
2392 : : {
2393 : : /* verify neighbors */
2394 : 0 : is_ok = 1;
2395 : 0 : b_self = 0;
2396 [ # # ]: 0 : for (n = 0, k = 0; n < MAX_NUM_STEREO_ATOM_NEIGH; n++)
2397 : : {
2398 : 0 : neigh = at[j].p_orig_at_num[n] - 1;
2399 [ # # ]: 0 : if (is_in_the_list(at[j].neighbor, neigh, at[j].valence) &&
2400 [ # # ]: 0 : at[neigh].orig_at_number == at[j].p_orig_at_num[n])
2401 : : {
2402 : : /* real neighbor */
2403 : 0 : nNeighOrder[k++] = at[j].p_orig_at_num[n];
2404 : : }
2405 : : else
2406 : : {
2407 [ # # # # ]: 0 : if ((int)neigh == j && at[neigh].orig_at_number == at[j].p_orig_at_num[n])
2408 : : {
2409 : : /* central atom is a neighbor */
2410 : 0 : num_trans = n; /* move this neighbor to 0 position permutation parity */
2411 : 0 : b_self++;
2412 : : }
2413 : : else
2414 : : {
2415 : 0 : is_ok = 0;
2416 : 0 : break;
2417 : : }
2418 : : }
2419 : : }
2420 [ # # # # : 0 : if (is_ok && b_self <= 1 && b_self + k == MAX_NUM_STEREO_ATOM_NEIGH)
# # ]
2421 : : {
2422 : 0 : num_trans += insertions_sort(pCG, nNeighOrder, k, sizeof(nNeighOrder[0]), comp_AT_RANK);
2423 [ # # # # ]: 0 : if (ATOM_PARITY_WELL_DEF(at[j].p_parity))
2424 : : {
2425 : 0 : parity = 2 - (num_trans + at[j].p_parity) % 2;
2426 : : }
2427 : : else
2428 : : {
2429 [ # # # # ]: 0 : if (ATOM_PARITY_ILL_DEF(at[j].p_parity))
2430 : : {
2431 : 0 : parity = at[j].p_parity;
2432 : : }
2433 : : else
2434 : : {
2435 : : ; /* invalid atom parity */
2436 : : }
2437 : : }
2438 : : }
2439 : : else
2440 : : {
2441 : : ; /* add error message here */
2442 : : }
2443 : : }
2444 : :
2445 : 1614 : len = len0 = (int)strlen(at[j].elname);
2446 : :
2447 : 1614 : memcpy(szCurAtom, at[j].elname, len);
2448 : 1614 : bonds_val = nBondsValenceInpAt(at + j, NULL, NULL);
2449 : :
2450 [ + + ]: 1614 : if ((val = needed_unusual_el_valence(at[j].el_number, at[j].charge, at[j].radical,
2451 : 1614 : at[j].chem_bonds_valence, bonds_val, at[j].num_H, at[j].valence)) ||
2452 [ + + + - : 1540 : at[j].charge || at[j].radical || at[j].iso_atw_diff || NUM_ISO_H(at, j) || parity)
+ - + - -
+ ]
2453 : : {
2454 : : /* valence */
2455 [ + + ]: 80 : if (val)
2456 : : {
2457 : 74 : len += sprintf(szCurAtom + len, "%d", val > 0 ? val : 0);
2458 : : }
2459 : : /* charge */
2460 [ + + ]: 80 : if ((val = at[j].charge)) /* djb-rwth: addressing LLVM warning */
2461 : : {
2462 [ + + ]: 40 : szCurAtom[len++] = val > 0 ? '+' : '-';
2463 [ + + ]: 40 : if ((val = abs(val)) > 1)
2464 : : {
2465 : 14 : len += sprintf(szCurAtom + len, "%d", val);
2466 : : }
2467 : : }
2468 : : /* radical */
2469 [ - + ]: 80 : if ((val = at[j].radical)) /* djb-rwth: addressing LLVM warning */
2470 : : {
2471 : 0 : len += sprintf(szCurAtom + len, ".%d", val);
2472 : : }
2473 : : /* isotopic shift */
2474 [ - + ]: 80 : if ((val = at[j].iso_atw_diff)) /* djb-rwth: addressing LLVM warning */
2475 : : {
2476 : 0 : mw = get_atomic_mass_from_elnum(at[j].el_number);
2477 [ # # ]: 0 : if (val == 1)
2478 : 0 : val = mw;
2479 [ # # ]: 0 : else if (val > 0)
2480 : 0 : val = mw + val - 1;
2481 : : else
2482 : 0 : val = mw + val;
2483 : :
2484 [ # # ]: 0 : len += sprintf(szCurAtom + len, "%si%d", len == len0 ? "." : "", val);
2485 : : }
2486 : : /* parity */
2487 [ - + ]: 80 : if (parity)
2488 : : {
2489 [ # # # # ]: 0 : len += sprintf(szCurAtom + len, "%s%s", len == len0 ? "." : "",
2490 : : parity == AB_PARITY_ODD ? "o" : parity == AB_PARITY_EVEN ? "e"
2491 [ # # ]: 0 : : parity == AB_PARITY_UNKN ? "u"
2492 [ # # ]: 0 : : parity == AB_PARITY_UNDF ? "?"
2493 [ # # ]: 0 : : "");
2494 : : }
2495 : : /* implicit isotopic H */
2496 [ - + ]: 80 : if (NUM_ISO_H(at, j))
2497 : : {
2498 [ # # ]: 0 : for (k = 0; k < NUM_H_ISOTOPES; k++)
2499 : : {
2500 [ # # ]: 0 : if ((val = at[j].num_iso_H[k])) /* djb-rwth: addressing LLVM warning */
2501 : : {
2502 [ # # ]: 0 : len += sprintf(szCurAtom + len, "%s%c", len == len0 ? "." : "", szIsoH[k]);
2503 [ # # ]: 0 : if (val > 1)
2504 : : {
2505 : 0 : len += sprintf(szCurAtom + len, "%d", val);
2506 : : }
2507 : : }
2508 : : }
2509 : : }
2510 : : }
2511 : :
2512 [ + - ]: 1614 : if (len + cur_len < buf_len)
2513 : : {
2514 : 1614 : memcpy(szBuf + cur_len, szCurAtom, len);
2515 : 1614 : cur_len += len;
2516 : 1614 : j++;
2517 : : }
2518 : : else
2519 : : {
2520 : 0 : break;
2521 : : }
2522 : 1614 : szBuf[cur_len] = '\0';
2523 : 1614 : *i = j;
2524 : : }
2525 : :
2526 : 366 : return cur_len;
2527 : : }
2528 : :
2529 : : /****************************************************************************
2530 : : WriteOrigBonds( ... )
2531 : :
2532 : : Output bonds in ascending order of the neighboring atom original numbers
2533 : :
2534 : : <bonds> bpA;bpAbpA... </bonds>
2535 : :
2536 : : b = bond type:
2537 : : =============
2538 : : w = undefined stereo, double
2539 : : s = single
2540 : : d = double
2541 : : t = triple
2542 : : a = aromatic
2543 : : p = up from the current atom to the neighbor
2544 : : P = uP from the neighbor to the current atom
2545 : : v = undefined stereo Either, single from the current atom to the neighbor
2546 : : V = undefined stereo Either, single from the neighbor to the current atom
2547 : : n = down from the current atom to the neighbor
2548 : : N = dowN from the neighbor to the current atom
2549 : :
2550 : : p = bond parity:
2551 : : ================
2552 : : - = odd
2553 : : + = even
2554 : : u = unknown
2555 : : ? = undefined
2556 : : = no parity (empty)
2557 : :
2558 : :
2559 : : A = neighbor orig. atom number
2560 : : ===============
2561 : : neighbor orig. atom number < number of the current atom
2562 : : Number of the current atom: 2 until first ";", 3 until 2nd ";", etc.
2563 : : ****************************************************************************/
2564 : 318 : int WriteOrigBonds(CANON_GLOBALS *pCG,
2565 : : int num_inp_atoms,
2566 : : inp_ATOM *at,
2567 : : int *i,
2568 : : char *szBuf,
2569 : : int buf_len,
2570 : : STRUCT_DATA *sd)
2571 : : {
2572 : 318 : int j, k, k2, kk, len, cur_len, j2 = 0, bond_stereo, bond_char, bond_parity, bond_parityNM, num_trans; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
2573 : : char szCurBonds[7 * MAXVAL + 2]; /* num_neigh*(1 byte bond type + 2 bytes for bond parity up to 4 digits per neighbor number) + at the end one ';' */
2574 : : AT_RANK nNeighOrder[MAXVAL];
2575 : : int chain_len, pnxt_atom, pinxt2cur, pinxt_sb_parity_ord;
2576 : : int chain_len2, pnxt_atom2, pinxt2cur2, pinxt_sb_parity_ord2, m1, m2;
2577 : : int pcur_atom, picur2nxt, picur_sb_parity_ord;
2578 : :
2579 : 318 : cur_len = 0;
2580 [ + + ]: 1688 : for (j = *i; j < num_inp_atoms;)
2581 : : {
2582 : 1370 : len = 0;
2583 [ + + ]: 1370 : if (at[j].valence >= 1) /* djb-rwth: changing condition to avoid garbage values */
2584 : : {
2585 [ + + ]: 4010 : for (k = 0; k < at[j].valence; k++)
2586 : : {
2587 : 2642 : nNeighOrder[k] = k;
2588 : : }
2589 : 1368 : pCG->m_pn_RankForSort = at[j].neighbor;
2590 : 1368 : num_trans = insertions_sort(pCG, nNeighOrder, at[j].valence, sizeof(nNeighOrder[0]), CompRank); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
2591 : : }
2592 : : else
2593 : : {
2594 : 2 : num_trans = 0; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
2595 : 2 : nNeighOrder[0] = 0;
2596 : : }
2597 [ + + ]: 4012 : for (kk = 0; kk < at[j].valence; kk++)
2598 : : {
2599 : 2642 : k = nNeighOrder[kk];
2600 : 2642 : j2 = at[j].neighbor[k];
2601 : 2642 : bond_parity = 0;
2602 : 2642 : bond_parityNM = 0;
2603 [ + + ]: 2642 : if (j2 < j)
2604 : : {
2605 : 1424 : bond_stereo = at[j].bond_stereo[k];
2606 [ + + - - : 1424 : switch (at[j].bond_type[k])
+ ]
2607 : : {
2608 : 1294 : case BOND_TYPE_SINGLE:
2609 [ + + - + : 1294 : switch (bond_stereo)
- - + ]
2610 : : {
2611 : 20 : case STEREO_SNGL_UP:
2612 : 20 : bond_char = 'p';
2613 : 20 : break;
2614 : 276 : case -STEREO_SNGL_UP:
2615 : 276 : bond_char = 'P';
2616 : 276 : break;
2617 : 0 : case STEREO_SNGL_DOWN:
2618 : 0 : bond_char = 'n';
2619 : 0 : break;
2620 : 64 : case -STEREO_SNGL_DOWN:
2621 : 64 : bond_char = 'N';
2622 : 64 : break;
2623 : : #if (FIX_EITHER_STEREO_IN_AUX_INFO == 1)
2624 : 0 : case STEREO_SNGL_EITHER:
2625 : 0 : bond_char = 'v';
2626 : 0 : break;
2627 : 0 : case -STEREO_SNGL_EITHER:
2628 : 0 : bond_char = 'V';
2629 : 0 : break;
2630 : : #else
2631 : : case STEREO_SNGL_EITHER:
2632 : : case -STEREO_SNGL_EITHER:
2633 : : bond_char = 'v';
2634 : : break;
2635 : : #endif
2636 : 934 : default:
2637 : 934 : bond_char = 's';
2638 : 934 : break;
2639 : : }
2640 : 1294 : break;
2641 : 84 : case BOND_TYPE_DOUBLE:
2642 [ - + ]: 84 : switch (bond_stereo)
2643 : : {
2644 : 0 : case STEREO_DBLE_EITHER:
2645 : : case -STEREO_DBLE_EITHER:
2646 : 0 : bond_char = 'w';
2647 : 0 : break;
2648 : 84 : default:
2649 : 84 : bond_char = 'd';
2650 : 84 : break;
2651 : : }
2652 : 84 : break;
2653 : 0 : case BOND_TYPE_TRIPLE:
2654 : 0 : bond_char = 't';
2655 : 0 : break;
2656 : 0 : case BOND_TYPE_ALTERN:
2657 : 0 : bond_char = 'a';
2658 : 0 : break;
2659 : 46 : default:
2660 : 46 : bond_char = 's';
2661 : 46 : break;
2662 : : }
2663 : : /* check for allene/cumulene */
2664 : 1424 : k2 = (int)(is_in_the_list(at[j2].neighbor, (AT_NUMB)j, at[j2].valence) - at[j2].neighbor);
2665 : 1424 : chain_len = chain_len2 = 0;
2666 [ - + ]: 1424 : if (at[j].sb_parity[0])
2667 : : {
2668 [ # # # # ]: 0 : for (m1 = 0; m1 < MAX_NUM_STEREO_BONDS && at[j].sb_parity[m1]; m1++)
2669 : : {
2670 [ # # ]: 0 : if (k == at[j].sb_ord[m1])
2671 : : {
2672 : 0 : chain_len = get_opposite_sb_atom(at, j, k,
2673 : : &pnxt_atom, &pinxt2cur, &pinxt_sb_parity_ord);
2674 : 0 : break;
2675 : : }
2676 : : }
2677 : : }
2678 [ - + ]: 1424 : if (at[j2].sb_parity[0])
2679 : : {
2680 [ # # # # ]: 0 : for (m2 = 0; m2 < MAX_NUM_STEREO_BONDS && at[j2].sb_parity[m2]; m2++)
2681 : : {
2682 [ # # ]: 0 : if (k2 == at[j2].sb_ord[m2])
2683 : : {
2684 : 0 : chain_len2 = get_opposite_sb_atom(at, j2, k2,
2685 : : &pnxt_atom2, &pinxt2cur2, &pinxt_sb_parity_ord2);
2686 : 0 : break;
2687 : : }
2688 : : }
2689 : : }
2690 [ - + - - : 1424 : if ((chain_len == 1 && chain_len2 == 1) || /* regular stereobond */
- + ]
2691 [ # # ]: 0 : (chain_len > 1 && j > pnxt_atom)) /* djb-rwth: addressing LLVM warnings */
2692 : 0 : {
2693 : : /* j is a cumulene endpoint */
2694 : : int m;
2695 : 0 : pcur_atom = j; /* pcur_atom > pnxt_atom */
2696 : 0 : picur2nxt = k;
2697 : 0 : picur_sb_parity_ord = -1;
2698 [ # # # # ]: 0 : for (m = 0; m < MAX_NUM_STEREO_BONDS && at[pcur_atom].sb_parity[m]; m++)
2699 : : {
2700 [ # # ]: 0 : if (at[pcur_atom].sb_ord[m] == k)
2701 : : {
2702 : 0 : picur_sb_parity_ord = m;
2703 : 0 : break;
2704 : : }
2705 : : }
2706 : : /* djb-rwth: removing redundant code */
2707 : : }
2708 : : else
2709 : : {
2710 [ - + - - ]: 1424 : if (chain_len2 > 1 && j2 > pnxt_atom2)
2711 : 0 : { /* j2 is a cumulene endpoint */
2712 : : int m;
2713 : 0 : pcur_atom = j2;
2714 : 0 : picur2nxt = k2;
2715 : 0 : pnxt_atom = pnxt_atom2;
2716 : 0 : pinxt2cur = pinxt2cur2;
2717 : 0 : pinxt_sb_parity_ord = pinxt_sb_parity_ord2;
2718 : 0 : picur_sb_parity_ord = -1;
2719 [ # # # # ]: 0 : for (m = 0; m < MAX_NUM_STEREO_BONDS && at[pcur_atom].sb_parity[m]; m++)
2720 : : {
2721 [ # # ]: 0 : if (at[pcur_atom].sb_ord[m] == k2)
2722 : 0 : picur_sb_parity_ord = m;
2723 : : }
2724 : 0 : chain_len = chain_len2;
2725 : : /* djb-rwth: removing redundant code */
2726 : : }
2727 : : else
2728 : : {
2729 : 1424 : chain_len = 0; /* djb-rwth: removing redundant code */
2730 : : }
2731 : : }
2732 : : /*len += sprintf( szCurBonds + len, "%c%d", bond_char, val+1);*/
2733 [ - + ]: 1424 : if (chain_len)
2734 : : {
2735 : : /* both atoms belong to a stereo bond */
2736 : : int kc;
2737 : 0 : int p1 = 0, p2, p1NM = 0, p2NM, neigh, neigh1, neigh2, bHasMetal, bWellDef; /* djb-rwth: initialising p1 and p1NM */
2738 : : int bNeighSwitched1, bNeighSwitched2;
2739 : :
2740 : : /* djb-rwth: avoiding buffer overrun as picur_sb_parity_ord == -1 is possible */
2741 [ # # ]: 0 : if (picur_sb_parity_ord >= 0)
2742 : : {
2743 : 0 : p1 = SB_PARITY_1(at[pcur_atom].sb_parity[picur_sb_parity_ord]);
2744 : 0 : p1NM = SB_PARITY_2(at[pcur_atom].sb_parity[picur_sb_parity_ord]);
2745 : : }
2746 : :
2747 : 0 : p2 = SB_PARITY_1(at[pnxt_atom].sb_parity[pinxt_sb_parity_ord]);
2748 : 0 : p2NM = SB_PARITY_2(at[pnxt_atom].sb_parity[pinxt_sb_parity_ord]);
2749 : :
2750 [ # # # # : 0 : bWellDef = ATOM_PARITY_WELL_DEF(p1) && ATOM_PARITY_WELL_DEF(p2);
# # # # ]
2751 [ # # # # : 0 : bHasMetal = ATOM_PARITY_WELL_DEF(p1NM) && ATOM_PARITY_WELL_DEF(p2NM);
# # # # ]
2752 : :
2753 : 0 : bNeighSwitched1 = bNeighSwitched2 = 0;
2754 : :
2755 [ # # # # ]: 0 : if (bWellDef || bHasMetal)
2756 : : {
2757 : :
2758 : 0 : neigh1 = num_inp_atoms;
2759 [ # # ]: 0 : for (kc = 0; kc < at[pcur_atom].valence; kc++)
2760 : : {
2761 [ # # ]: 0 : if (kc == picur2nxt)
2762 : 0 : continue;
2763 : 0 : neigh = at[pcur_atom].neighbor[kc];
2764 [ # # # # ]: 0 : if (bHasMetal && is_el_a_metal(at[neigh].el_number))
2765 : 0 : continue;
2766 [ # # ]: 0 : if (neigh < neigh1)
2767 : 0 : neigh1 = neigh;
2768 : : }
2769 [ # # ]: 0 : if (neigh1 < num_inp_atoms)
2770 : : {
2771 : 0 : bNeighSwitched1 = (neigh1 != at[pcur_atom].neighbor[(int)at[pcur_atom].sn_ord[picur_sb_parity_ord]]);
2772 : : }
2773 : : else
2774 : : {
2775 : 0 : AddErrorMessage(sd->pStrErrStruct, "Cannot find 0D stereobond neighbor");
2776 : : /*
2777 : : sd->nStructReadError = 99;
2778 : : sd->nErrorType = _IS_ERROR;
2779 : : */
2780 : : }
2781 : :
2782 : 0 : neigh2 = num_inp_atoms;
2783 [ # # ]: 0 : for (kc = 0; kc < at[pnxt_atom].valence; kc++)
2784 : : {
2785 [ # # ]: 0 : if (kc == pinxt2cur)
2786 : 0 : continue;
2787 : 0 : neigh = at[pnxt_atom].neighbor[kc];
2788 [ # # # # ]: 0 : if (bHasMetal && is_el_a_metal(at[neigh].el_number))
2789 : 0 : continue;
2790 [ # # ]: 0 : if (neigh < neigh2)
2791 : 0 : neigh2 = neigh;
2792 : : }
2793 [ # # ]: 0 : if (neigh2 < num_inp_atoms)
2794 : : {
2795 : 0 : bNeighSwitched2 = (neigh2 != at[pnxt_atom].neighbor[(int)at[pnxt_atom].sn_ord[pinxt_sb_parity_ord]]);
2796 : : }
2797 : : else
2798 : : {
2799 : 0 : AddErrorMessage(sd->pStrErrStruct, "Cannot find 0D stereobond neighbor");
2800 : : /*
2801 : : sd->nStructReadError = 99;
2802 : : sd->nErrorType = _IS_ERROR;
2803 : : */
2804 : : }
2805 : :
2806 [ # # # # ]: 0 : if (neigh1 < num_inp_atoms && neigh2 < num_inp_atoms)
2807 : : {
2808 [ # # # # : 0 : if (ATOM_PARITY_WELL_DEF(p1) && ATOM_PARITY_WELL_DEF(p2))
# # # # ]
2809 : : {
2810 : 0 : bond_parity = 2 - (p1 + p2 + bNeighSwitched1 + bNeighSwitched2) % 2;
2811 : : }
2812 : : else
2813 : : {
2814 : 0 : bond_parity = inchi_min(p1, p2);
2815 : : }
2816 : :
2817 [ # # ]: 0 : if (bHasMetal)
2818 : : {
2819 : 0 : bond_parityNM = 2 - (p1NM + p2NM + bNeighSwitched1 + bNeighSwitched2) % 2;
2820 : : }
2821 : : else
2822 : : {
2823 [ # # # # ]: 0 : if (p1NM && p2NM)
2824 : : {
2825 : 0 : bond_parityNM = inchi_min(p1NM, p2NM);
2826 : : }
2827 : : }
2828 : : }
2829 : : }
2830 : : else
2831 : : {
2832 [ # # # # ]: 0 : if (p1 && p2)
2833 : : {
2834 : 0 : bond_parity = inchi_min(p1, p2);
2835 : : }
2836 [ # # # # ]: 0 : if (p1NM && p2NM)
2837 : : {
2838 : 0 : bond_parityNM = inchi_min(p1NM, p2NM);
2839 : : }
2840 [ # # # # ]: 0 : if (bond_parityNM && !bond_parity)
2841 : : {
2842 : 0 : bond_parity = AB_PARITY_UNDF;
2843 : : }
2844 : : }
2845 : : }
2846 : :
2847 [ + - + - ]: 4272 : len += sprintf(szCurBonds + len, "%c%s%s%d",
2848 : : bond_char,
2849 : :
2850 : : (bond_parity == AB_PARITY_ODD) ? "-" : (bond_parity == AB_PARITY_EVEN) ? "+"
2851 [ + - ]: 2848 : : (bond_parity == AB_PARITY_UNKN) ? "u"
2852 [ + - ]: 2848 : : (bond_parity == AB_PARITY_UNDF) ? "?"
2853 [ - + ]: 1424 : : "",
2854 : :
2855 : : (bond_parityNM == AB_PARITY_ODD) ? "-" : (bond_parityNM == AB_PARITY_EVEN) ? "+"
2856 [ + - ]: 2848 : : (bond_parityNM == AB_PARITY_UNKN) ? "u"
2857 [ + - ]: 2848 : : (bond_parityNM == AB_PARITY_UNDF) ? "?"
2858 [ - + ]: 1424 : : "",
2859 : :
2860 : : j2 + 1);
2861 : : }
2862 : : }
2863 [ + - ]: 1370 : if (len + cur_len + 2 < buf_len)
2864 : : {
2865 : 1370 : memcpy(szBuf + cur_len, szCurBonds, len);
2866 : 1370 : cur_len += len;
2867 : 1370 : szBuf[cur_len++] = ';';
2868 : 1370 : j++;
2869 : : }
2870 : : else
2871 : : {
2872 : 0 : break;
2873 : : }
2874 : : }
2875 : 318 : szBuf[cur_len] = '\0';
2876 [ + - ]: 318 : *i = num_inp_atoms > 0 ? j : 0;
2877 : :
2878 : 318 : return cur_len;
2879 : : }
2880 : :
2881 : : #define ORIG_STR_BUFLEN (7 * MAXVAL + 2) /* > 7*MAXVAL+2 = 142 */
2882 : :
2883 : : /****************************************************************************
2884 : : Fill out original input structure
2885 : : ****************************************************************************/
2886 : 122 : int OrigStruct_FillOut(CANON_GLOBALS *pCG,
2887 : : ORIG_ATOM_DATA *orig_inp_data,
2888 : : ORIG_STRUCT *pOrigStruct,
2889 : : STRUCT_DATA *sd)
2890 : : {
2891 : : char szBuf[ORIG_STR_BUFLEN];
2892 : : int i, len, len_coord, len_atoms, len_bonds;
2893 : :
2894 : 122 : pOrigStruct->polymer = NULL;
2895 : 122 : pOrigStruct->v3000 = NULL;
2896 : :
2897 : 122 : pOrigStruct->n_zy = orig_inp_data->n_zy;
2898 : : /* Coordinates */
2899 : 122 : len_coord = i = 0;
2900 : :
2901 [ + - ]: 122 : if (orig_inp_data->szCoord)
2902 : : {
2903 : :
2904 [ + + ]: 255 : while ((len = WriteOrigCoord(orig_inp_data->num_inp_atoms,
2905 : : orig_inp_data->szCoord, &i, szBuf, sizeof(szBuf)))) /* djb-rwth: addressing LLVM warning */
2906 : : {
2907 : 133 : len_coord += len;
2908 : : }
2909 : 122 : pOrigStruct->szCoord = (char *)inchi_malloc(((long long)len_coord + 1) * sizeof(pOrigStruct->szCoord[0])); /* djb-rwth: cast operator added */
2910 : 122 : i = 0;
2911 [ + - + - ]: 244 : if (pOrigStruct->szCoord &&
2912 : 122 : len_coord == WriteOrigCoord(orig_inp_data->num_inp_atoms,
2913 : 122 : orig_inp_data->szCoord, &i, pOrigStruct->szCoord, len_coord + 1) &&
2914 [ + - ]: 122 : i == orig_inp_data->num_inp_atoms)
2915 : : {
2916 : : /* success */
2917 [ + - ]: 122 : if (orig_inp_data->szCoord)
2918 : : {
2919 [ + - ]: 122 : inchi_free(orig_inp_data->szCoord);
2920 : 122 : orig_inp_data->szCoord = NULL;
2921 : : }
2922 : : }
2923 : : else
2924 : : {
2925 : 0 : return -1;
2926 : : }
2927 : : }
2928 : :
2929 : : /* Atoms */
2930 : 122 : len_atoms = i = 0;
2931 [ + + ]: 244 : while ((len = WriteOrigAtoms(pCG, orig_inp_data->num_inp_atoms,
2932 : : orig_inp_data->at, &i, szBuf, sizeof(szBuf), sd))) /* djb-rwth: addressing LLVM warning */
2933 : : {
2934 : 122 : len_atoms += len;
2935 [ - + ]: 122 : if (!orig_inp_data->num_inp_atoms)
2936 : 0 : break;
2937 : : }
2938 : 122 : pOrigStruct->szAtoms = (char *)inchi_malloc(((long long)len_atoms + 1) * sizeof(pOrigStruct->szAtoms[0])); /* djb-rwth: cast operator added */
2939 : 122 : i = 0;
2940 [ + - + - ]: 244 : if (pOrigStruct->szAtoms &&
2941 : 122 : len_atoms == WriteOrigAtoms(pCG, orig_inp_data->num_inp_atoms,
2942 : 122 : orig_inp_data->at, &i, pOrigStruct->szAtoms, len_atoms + 1, sd) &&
2943 [ + - ]: 122 : i == orig_inp_data->num_inp_atoms)
2944 : : {
2945 : : ; /* success */
2946 : : }
2947 : : else
2948 : : {
2949 : 0 : return -1;
2950 : : }
2951 : :
2952 : : /* Bonds */
2953 : 122 : len_bonds = 0;
2954 : 122 : i = 1;
2955 [ + + ]: 196 : while ((len = WriteOrigBonds(pCG, orig_inp_data->num_inp_atoms,
2956 : : #if (FIX_CURE53_ISSUE_OOB_ALREADY_HAVE_THIS_MESSAGE == 1)
2957 : : orig_inp_data->at, &i, szBuf, sizeof(szBuf), sd))) /* djb-rwth: addressing LLVM warning */
2958 : : #else
2959 : : orig_inp_data->at, &i, szBuf, sizeof(szBuf), NULL)))
2960 : : #endif
2961 : : {
2962 : 74 : len_bonds += len;
2963 [ - + ]: 74 : if (!orig_inp_data->num_inp_atoms)
2964 : : {
2965 : 0 : break;
2966 : : }
2967 : : }
2968 : :
2969 : 122 : pOrigStruct->szBonds = (char *)inchi_malloc(((long long)len_bonds + 2) * sizeof(pOrigStruct->szBonds[0])); /* djb-rwth: cast operator added */
2970 : 122 : i = 1;
2971 : :
2972 [ + - + - ]: 244 : if (pOrigStruct->szBonds &&
2973 : 122 : len_bonds == WriteOrigBonds(pCG, orig_inp_data->num_inp_atoms,
2974 : 122 : orig_inp_data->at, &i, pOrigStruct->szBonds, len_bonds + 2, sd) &&
2975 [ + - ]: 122 : i == orig_inp_data->num_inp_atoms)
2976 : : {
2977 : : ; /* success */
2978 : : }
2979 : : else
2980 : : {
2981 : 0 : return -1;
2982 : : }
2983 : 122 : pOrigStruct->num_atoms = orig_inp_data->num_inp_atoms;
2984 : :
2985 : : /* Extensions of v. 1.05 */
2986 [ + + + - : 122 : if (orig_inp_data->polymer != NULL && orig_inp_data->polymer->n > 0 && orig_inp_data->valid_polymer)
+ - ]
2987 : : {
2988 : 2 : pOrigStruct->polymer = orig_inp_data->polymer;
2989 : : /* pointer copy, do not free after use! */
2990 : : }
2991 [ + + ]: 122 : if (orig_inp_data->v3000 != NULL)
2992 : : {
2993 : 57 : pOrigStruct->v3000 = orig_inp_data->v3000;
2994 : : /* pointer copy, do not free after use! */
2995 : : }
2996 : :
2997 : 122 : return 0;
2998 : : }
2999 : :
3000 : : /****************************************************************************/
3001 : 122 : void OrigStruct_Free(ORIG_STRUCT *pOrigStruct)
3002 : : {
3003 [ + - ]: 122 : if (pOrigStruct)
3004 : : {
3005 [ + - ]: 122 : if (pOrigStruct->szAtoms)
3006 : : {
3007 [ + - ]: 122 : inchi_free(pOrigStruct->szAtoms);
3008 : : }
3009 [ + - ]: 122 : if (pOrigStruct->szBonds)
3010 : : {
3011 [ + - ]: 122 : inchi_free(pOrigStruct->szBonds);
3012 : : }
3013 [ + - ]: 122 : if (pOrigStruct->szCoord)
3014 : : {
3015 [ + - ]: 122 : inchi_free(pOrigStruct->szCoord);
3016 : : }
3017 : :
3018 : : /* For
3019 : :
3020 : : OAD_Polymer *polymer;
3021 : : OAD_V3000 *v3000;
3022 : :
3023 : : we used shallow (pointer) copy of analogs from orig_inp_data, so do not free these here */
3024 : :
3025 : : /*memset( pOrigStruct, 0, sizeof(*pOrigStruct) );*/
3026 : 122 : pOrigStruct->szAtoms = NULL;
3027 : 122 : pOrigStruct->szBonds = NULL;
3028 : 122 : pOrigStruct->szCoord = NULL;
3029 : : }
3030 : 122 : }
3031 : :
3032 : : /****************************************************************************
3033 : : GetSaveOptLetters
3034 : :
3035 : : Get the two letters encoding the saved InChI creation options.
3036 : :
3037 : : The first one encodes RecMet/FixedH/SUU/SLUUD options.
3038 : : Each of options is a binary switch {ON,OFF}, so it totals to 2*2*2*2=16 values
3039 : : which are encoded by capital letters 'A' through 'P'.
3040 : :
3041 : : The second character encodes experimental (InChI 1 extension)
3042 : : options KET and 15T.
3043 : : Each of these options is a binary switch ON/OFF, so there are 2*2=4 combinations,
3044 : : currently encoded by 'A' through 'D'.
3045 : : Note that anything but 'A' here would indicate "extended" InChI 1
3046 : : Also, there is a reservation for future needs: the 2nd memo char
3047 : : may accommodate two more ON/OFF
3048 : : ****************************************************************************/
3049 : 0 : void GetSaveOptLetters(unsigned char save_opt_bits, char *let1, char *let2)
3050 : : {
3051 : 0 : const char a2p[] = "ABCDEFGHIJKLMNOP";
3052 : : /* SaveOptBits layout: {unused|unused|Ket|15T|RecMet|FixedH|SUU|SLUUD} */
3053 : 0 : *let1 = a2p[(size_t)(save_opt_bits & 0x0f)];
3054 : 0 : *let2 = a2p[(size_t)((save_opt_bits & 0x30) >> 4)];
3055 : 0 : }
3056 : :
3057 : : /****************************************************************************
3058 : : Set line separators dependent on requested output mode
3059 : : ****************************************************************************/
3060 : 122 : void set_line_separators(int bINChIOutputOptions, char **pLF, char **pTAB)
3061 : : {
3062 : 122 : int bPlainTextCommnts = 0 != (bINChIOutputOptions & INCHI_OUT_PLAIN_TEXT_COMMENTS);
3063 : :
3064 [ - + ]: 122 : *pLF = (char *)(bPlainTextCommnts ? "\n" : "\0");
3065 : :
3066 : : #if (!defined(TARGET_API_LIB) && !defined(TARGET_LIB_FOR_WINCHI))
3067 : : {
3068 : : int bPlainText = 0 != (bINChIOutputOptions & (INCHI_OUT_PLAIN_TEXT | INCHI_OUT_PLAIN_TEXT_COMMENTS));
3069 : : int bPlainTabbedOutput = 0 != (bINChIOutputOptions & INCHI_OUT_TABBED_OUTPUT) &&
3070 : : bPlainText && !bPlainTextCommnts;
3071 : :
3072 : : *pTAB = bPlainTabbedOutput ? (char*)"\t" : (char*)"\n";
3073 : : }
3074 : : #else
3075 : 122 : *pTAB = "\n";
3076 : : #endif
3077 : :
3078 : 122 : return;
3079 : : }
3080 : :
3081 : : /****************************************************************************
3082 : : Output InChI: InChI version and kind
3083 : : ****************************************************************************/
3084 : 122 : int OutputINCHI_VersionAndKind(INCHI_IOSTREAM *out_file,
3085 : : INCHI_IOS_STRING *strbuf,
3086 : : int bINChIOutputOptions,
3087 : : int is_beta,
3088 : : char *pLF,
3089 : : char *pTAB)
3090 : : {
3091 : 122 : inchi_ios_print_nodisplay(out_file, "%s%s=%s", pLF, INCHI_NAME, pLF);
3092 : :
3093 : 122 : inchi_strbuf_reset(strbuf);
3094 : 122 : inchi_strbuf_printf(strbuf, "%s", x_curr_ver);
3095 : :
3096 : : /* - add 'Beta' flag if applicable */
3097 [ + + ]: 122 : if (is_beta)
3098 : : {
3099 : 71 : inchi_strbuf_printf(strbuf, "B");
3100 : : }
3101 : : /* - add 'Standard' flag if applicable */
3102 [ + - ]: 51 : else if (bINChIOutputOptions & INCHI_OUT_STDINCHI)
3103 : : {
3104 : 51 : inchi_strbuf_printf(strbuf, "S");
3105 : : }
3106 : :
3107 : 122 : inchi_ios_print_nodisplay(out_file, "%s%s", strbuf->pStr, pLF);
3108 : :
3109 : 122 : return 0;
3110 : : }
3111 : :
3112 : : /****************************************************************************
3113 : : Output InChI: main layer - formula, connections and hydrogens
3114 : : (incl. tautomeric info == mobile H)
3115 : : ***************************************************************************/
3116 : 122 : int OutputINCHI_MainLayerFormula(CANON_GLOBALS *pCG,
3117 : : INCHI_IOSTREAM *out_file,
3118 : : INCHI_IOS_STRING *strbuf,
3119 : : int num_components2[],
3120 : : int *INCHI_basic_or_INCHI_reconnected,
3121 : : INCHI_OUT_CTL *io,
3122 : : char *pLF,
3123 : : char *pTAB)
3124 : : {
3125 : :
3126 : : /* constitution ( dot-disconnected Hill formulas: <formula> ) */
3127 : :
3128 [ - + - - ]: 122 : if (num_components2[0] || num_components2[1])
3129 : : {
3130 [ - + ]: 122 : szGetTag(IdentLbl, io->nTag, io->bTag1 = *INCHI_basic_or_INCHI_reconnected == INCHI_REC ? IL_REC_ : IL_FML_, io->szTag1, &io->bAlways, 1);
3131 : 122 : inchi_strbuf_reset(strbuf);
3132 : 122 : io->tot_len = str_HillFormula(io->pINChISort, strbuf, &io->bOverflow, io->bOutType,
3133 : : io->num_components, io->bUseMulipliers);
3134 : :
3135 [ - + ]: 122 : if (str_LineEnd(io->szTag1, &io->bOverflow, strbuf, -1, 1))
3136 : : {
3137 : 0 : return 1;
3138 : : }
3139 [ - + - - ]: 122 : if (io->n_pzz > 0 && io->n_zy > 0)
3140 : : {
3141 : 0 : int retm = MergeZzInHillFormula(strbuf);
3142 [ # # ]: 0 : if (0 != retm)
3143 : : {
3144 : 0 : return -1;
3145 : : }
3146 : : }
3147 : 122 : inchi_ios_print_nodisplay(out_file, "%s%s", strbuf->pStr, pLF);
3148 : : }
3149 : :
3150 : : LOG_NO_ARGS("\n#################### (L3318:ichiprt1.c) ##########################\n");
3151 : : LOG_MULT_ARGS("This is the Chemical formula : %s\n", strbuf->pStr);
3152 : : LOG_NO_ARGS("####################################################################\n");
3153 : :
3154 : 122 : return 0;
3155 : : }
3156 : :
3157 : : /****************************************************************************/
3158 : 122 : int OutputINCHI_MainLayerConnections(CANON_GLOBALS *pCG,
3159 : : INCHI_IOSTREAM *out_file,
3160 : : INCHI_IOS_STRING *strbuf,
3161 : : int num_components2[],
3162 : : int *INCHI_basic_or_INCHI_reconnected,
3163 : : INCHI_OUT_CTL *io,
3164 : : char *pLF,
3165 : : char *pTAB)
3166 : : {
3167 : : /* connections ( semicolon/dot-disconnected connection tables ) */
3168 : :
3169 : 122 : szGetTag(IdentLbl, io->nTag, io->bTag1 = IL_CONN, io->szTag1, &io->bAlways, 1);
3170 : 122 : inchi_strbuf_reset(strbuf);
3171 : 122 : io->tot_len = 0;
3172 : 122 : io->tot_len2 = str_Connections(pCG, io->pINChISort, strbuf, &io->bOverflow, io->bOutType,
3173 : : io->ATOM_MODE, io->num_components, io->bUseMulipliers);
3174 : :
3175 : : /* current version does not output empty (";;;;") connectivity */
3176 : :
3177 [ + + ]: 122 : if (io->tot_len != io->tot_len2)
3178 : : { /* 2004-06-30: never output empty connection table */
3179 : 65 : io->tot_len = io->tot_len2;
3180 [ - + ]: 65 : if (str_LineEnd(io->szTag1, &io->bOverflow, strbuf, -2, io->bPlainTextTags))
3181 : : {
3182 : 0 : return 1; /* pStr overfow */
3183 : : }
3184 : 65 : inchi_ios_print_nodisplay(out_file, "%s%s", strbuf->pStr, pLF);
3185 : : }
3186 : :
3187 : : LOG_NO_ARGS("\n##################### (L3357:ichiprt1.c) #########################\n");
3188 : : LOG_MULT_ARGS("This is the Connection Layer : %s\n", strbuf->pStr);
3189 : : LOG_NO_ARGS("####################################################################\n");
3190 : :
3191 : 122 : return 0;
3192 : : }
3193 : :
3194 : : /****************************************************************************/
3195 : 122 : int OutputINCHI_MainLayerHydrogens(CANON_GLOBALS *pCG,
3196 : : INCHI_IOSTREAM *out_file,
3197 : : INCHI_IOS_STRING *strbuf,
3198 : : int num_components2[],
3199 : : int *INCHI_basic_or_INCHI_reconnected,
3200 : : INCHI_OUT_CTL *io,
3201 : : char *pLF,
3202 : : char *pTAB)
3203 : : {
3204 : :
3205 : : /* hydrogen atoms (do not output empty) */
3206 : :
3207 [ + + ]: 122 : if (INCHI_SEGM_FILL == INChI_SegmentAction(io->sDifSegs[io->nCurINChISegment][DIFS_h_H_ATOMS]))
3208 : : {
3209 : 84 : szGetTag(IdentLbl, io->nTag, io->bTag1 = IL_ALLH, io->szTag1, &io->bAlways, 1);
3210 : 84 : inchi_strbuf_reset(strbuf);
3211 : 84 : io->tot_len = 0;
3212 : 84 : io->tot_len2 = str_H_atoms(io->pINChISort, strbuf, &io->bOverflow, io->bOutType,
3213 : : io->ATOM_MODE, io->TAUT_MODE,
3214 : : io->num_components, io->bUseMulipliers);
3215 [ + - ]: 84 : if (io->tot_len != io->tot_len2)
3216 : : { /* 2004-06-21: never output empty */
3217 : 84 : io->tot_len = io->tot_len2;
3218 [ - + ]: 84 : if (str_LineEnd(io->szTag1, &io->bOverflow, strbuf, -2, 1))
3219 : : {
3220 : 0 : return 1;
3221 : : }
3222 : 84 : inchi_ios_print_nodisplay(out_file, "%s%s", strbuf->pStr, pLF);
3223 : : }
3224 : : }
3225 : :
3226 : : LOG_NO_ARGS("\n###################### (L3396:ichiprt1.c) ########################\n");
3227 : : LOG_MULT_ARGS("This is the Hydrogen Layer : %s\n", strbuf->pStr);
3228 : : LOG_NO_ARGS("####################################################################\n");
3229 : :
3230 : 122 : return 0;
3231 : : }
3232 : :
3233 : : /****************************************************************************
3234 : : Output InChI: charge and removed protons layers
3235 : : ****************************************************************************/
3236 : 122 : int OutputINCHI_ChargeAndRemovedAddedProtonsLayers(CANON_GLOBALS *pCG,
3237 : : INCHI_IOSTREAM *out_file,
3238 : : INCHI_IOS_STRING *strbuf,
3239 : : INCHI_OUT_CTL *io,
3240 : : char *pLF,
3241 : : char *pTAB)
3242 : : {
3243 : :
3244 : : /* charge */
3245 : :
3246 : 122 : io->nSegmAction = INChI_SegmentAction(io->sDifSegs[io->nCurINChISegment][DIFS_q_CHARGE]);
3247 [ + + ]: 122 : if (io->nSegmAction)
3248 : : {
3249 : 19 : szGetTag(IdentLbl, io->nTag, io->bTag1 = IL_CHRG | io->bFhTag, io->szTag1, &io->bAlways, 1);
3250 : 19 : inchi_strbuf_reset(strbuf);
3251 : 19 : io->tot_len = 0;
3252 [ + - ]: 19 : if (INCHI_SEGM_FILL == io->nSegmAction)
3253 : : {
3254 : 19 : io->tot_len = str_Charge2(io->pINChISort, io->pINChISort2,
3255 : : strbuf, &io->bOverflow, io->bOutType, io->num_components,
3256 : : io->bSecondNonTautPass, io->bOmitRepetitions, io->bUseMulipliers);
3257 : 19 : io->bNonTautNonIsoIdentifierNotEmpty += io->bSecondNonTautPass;
3258 : : }
3259 [ - + ]: 19 : if (str_LineEnd(io->szTag1, &io->bOverflow, strbuf, -io->nSegmAction, io->bPlainTextTags))
3260 : : {
3261 : 0 : return 1;
3262 : : }
3263 : 19 : inchi_ios_print_nodisplay(out_file, "%s%s", strbuf->pStr, pLF);
3264 : : }
3265 : :
3266 : : /* removed protons */
3267 : :
3268 [ + - + - ]: 122 : if (io->iCurTautMode == TAUT_YES && !io->bSecondNonTautPass)
3269 : : {
3270 : :
3271 : 122 : io->nSegmAction = INChI_SegmentAction(io->sDifSegs[io->nCurINChISegment][DIFS_p_PROTONS]);
3272 [ + + ]: 122 : if (io->nSegmAction)
3273 : : {
3274 : 11 : szGetTag(IdentLbl, io->nTag, io->bTag1 = IL_PROT | io->bFhTag, io->szTag1, &io->bAlways, 1);
3275 : 11 : inchi_strbuf_reset(strbuf);
3276 : 11 : io->tot_len = 0;
3277 : 11 : inchi_strbuf_printf(strbuf, "%+d", io->nNumRemovedProtons);
3278 [ - + ]: 11 : if (str_LineEnd(io->szTag1, &io->bOverflow, strbuf, -io->nSegmAction, io->bPlainTextTags))
3279 : : {
3280 : 0 : return 1;
3281 : : }
3282 : 11 : inchi_ios_print_nodisplay(out_file, "%s%s", strbuf->pStr, pLF);
3283 : : }
3284 : : else
3285 : : {
3286 [ - + ]: 111 : if (io->bPlainTextTags == 1)
3287 : 0 : inchi_ios_print_nodisplay(out_file, "/");
3288 : : }
3289 : : }
3290 : :
3291 : 122 : return 0;
3292 : : }
3293 : :
3294 : : /**
3295 : : * @brief Output InChI: stereo layer with sublayers.
3296 : : *
3297 : : * @param pCG Pointer to the CANON_GLOBALS structure containing global canonicalization data.
3298 : : * @param out_file Pointer to the INCHI_IOSTREAM output stream where the stereo layer will be written.
3299 : : * @param strbuf Pointer to an INCHI_IOS_STRING buffer used for string formatting and output.
3300 : : * @param io Pointer to the INCHI_OUT_CTL structure containing output control and state information.
3301 : : * @param pLF Pointer to a string used as the line feed (end-of-line) character(s).
3302 : : * @param pTAB Pointer to a string used as the tab or separator character(s).
3303 : : * @return Returns 0 on success, or a non-zero error code on failure.
3304 : : */
3305 : 75 : int OutputINCHI_StereoLayer( CANON_GLOBALS *pCG,
3306 : : INCHI_IOSTREAM *out_file,
3307 : : INCHI_IOS_STRING *strbuf,
3308 : : INCHI_OUT_CTL *io,
3309 : : char *pLF,
3310 : : char *pTAB )
3311 : : {
3312 : :
3313 [ + - + - ]: 150 : if (INChI_SegmentAction( io->sDifSegs[io->nCurINChISegment][DIFS_b_SBONDS] ) ||
3314 [ + - ]: 150 : INChI_SegmentAction( io->sDifSegs[io->nCurINChISegment][DIFS_t_SATOMS] ) ||
3315 [ - + ]: 150 : INChI_SegmentAction( io->sDifSegs[io->nCurINChISegment][DIFS_m_SP3INV] ) ||
3316 : 75 : INChI_SegmentAction( io->sDifSegs[io->nCurINChISegment][DIFS_s_STYPE] ))
3317 : : {
3318 : :
3319 : : /* stereo */
3320 : :
3321 : 0 : szGetTag(IdentLbl, io->nTag, io->bTag1 = IL_STER | io->bFhTag, io->szTag1, &io->bAlways, 1);
3322 : :
3323 : : /* sp2 */
3324 : :
3325 [ # # ]: 0 : if ((io->nSegmAction = INChI_SegmentAction( io->sDifSegs[io->nCurINChISegment][DIFS_b_SBONDS] )))
3326 : : {
3327 : 0 : szGetTag(IdentLbl, io->nTag, io->bTag2 = io->bTag1 | IL_DBND, io->szTag2, &io->bAlways, 1);
3328 : 0 : inchi_strbuf_reset(strbuf);
3329 : 0 : io->tot_len = 0;
3330 [ # # ]: 0 : if (INCHI_SEGM_FILL == io->nSegmAction)
3331 : : {
3332 : 0 : io->tot_len = str_Sp2( io->pINChISort, io->pINChISort2, strbuf, &io->bOverflow,
3333 : : io->bOutType, io->TAUT_MODE, io->num_components,
3334 : : io->bSecondNonTautPass, io->bOmitRepetitions, io->bUseMulipliers );
3335 : :
3336 : 0 : io->bNonTautNonIsoIdentifierNotEmpty += io->bSecondNonTautPass;
3337 : : }
3338 : :
3339 [ # # ]: 0 : if (str_LineEnd(io->szTag2, &io->bOverflow, strbuf, -io->nSegmAction, io->bPlainTextTags))
3340 : : {
3341 : 0 : return 1;
3342 : : }
3343 : 0 : inchi_ios_print_nodisplay(out_file, "%s%s", strbuf->pStr, pLF);
3344 : : }
3345 : : else
3346 : : {
3347 [ # # ]: 0 : if (io->bPlainTextTags == 1)
3348 : : {
3349 : 0 : inchi_ios_print_nodisplay(out_file, "/"); /* sp2 */
3350 : : }
3351 : : }
3352 : :
3353 : : /* sp3 */
3354 : :
3355 : : /* t-layer */
3356 [ # # ]: 0 : if ((io->nSegmAction = INChI_SegmentAction( io->sDifSegs[io->nCurINChISegment][DIFS_t_SATOMS] ))) /* djb-rwth: addressing LLVM warning */
3357 : : {
3358 [ # # # # ]: 0 : io->bRelRac = io->bRelativeStereo[io->iCurTautMode] || io->bRacemicStereo[io->iCurTautMode];
3359 : 0 : szGetTag(IdentLbl, io->nTag, io->bTag2 = io->bTag1 | IL_SP3S, io->szTag2, &io->bAlways, 1);
3360 : 0 : inchi_strbuf_reset(strbuf);
3361 : 0 : io->tot_len = 0;
3362 [ # # ]: 0 : if (INCHI_SEGM_FILL == io->nSegmAction)
3363 : : {
3364 : 0 : io->tot_len = str_Sp3( io->pINChISort, io->pINChISort2, strbuf, &io->bOverflow,
3365 : : io->bOutType, io->TAUT_MODE, io->num_components, io->bRelRac,
3366 : : io->bSecondNonTautPass, io->bOmitRepetitions, io->bUseMulipliers );
3367 : :
3368 : 0 : io->bNonTautNonIsoIdentifierNotEmpty += io->bSecondNonTautPass;
3369 : : }
3370 : :
3371 [ # # ]: 0 : if (str_LineEnd(io->szTag2, &io->bOverflow, strbuf, -io->nSegmAction, io->bPlainTextTags))
3372 : : {
3373 : 0 : return 2;
3374 : : }
3375 : 0 : inchi_ios_print_nodisplay(out_file, "%s%s", strbuf->pStr, pLF);
3376 : : }
3377 : : else
3378 : : {
3379 [ # # ]: 0 : if (io->bPlainTextTags == 1)
3380 : : {
3381 : 0 : inchi_ios_print_nodisplay( out_file, "/" ); /* sp3 */
3382 : : }
3383 : : }
3384 : :
3385 : : /* m-layer */
3386 [ # # ]: 0 : if ((io->nSegmAction = INChI_SegmentAction( io->sDifSegs[io->nCurINChISegment][DIFS_m_SP3INV] ))) /* djb-rwth: addressing LLVM warning */
3387 : : {
3388 : 0 : szGetTag(IdentLbl, io->nTag, io->bTag2 = io->bTag1 | IL_INVS, io->szTag2, &io->bAlways, 1);
3389 : 0 : inchi_strbuf_reset(strbuf);
3390 : 0 : io->tot_len = 0;
3391 [ # # ]: 0 : if (INCHI_SEGM_FILL == io->nSegmAction)
3392 : : {
3393 : 0 : io->tot_len = str_StereoAbsInv( io->pINChISort, strbuf,
3394 : : &io->bOverflow, io->bOutType, io->num_components );
3395 : 0 : io->bNonTautNonIsoIdentifierNotEmpty += io->bSecondNonTautPass;
3396 : : }
3397 : :
3398 [ # # ]: 0 : if (str_LineEnd(io->szTag2, &io->bOverflow, strbuf, -io->nSegmAction, io->bPlainTextTags))
3399 : : {
3400 : 0 : return 3;
3401 : : }
3402 : 0 : inchi_ios_print_nodisplay(out_file, "%s%s", strbuf->pStr, pLF);
3403 : : }
3404 : : else
3405 : : {
3406 [ # # ]: 0 : if (io->bPlainTextTags == 1)
3407 : : {
3408 : 0 : inchi_ios_print_nodisplay(out_file, "/"); /* stereo-abs-inv */
3409 : : }
3410 : : }
3411 : :
3412 : : /* stereo type */
3413 : :
3414 : : /* s-layer */
3415 [ # # ]: 0 : if ((io->nSegmAction = INChI_SegmentAction( io->sDifSegs[io->nCurINChISegment][DIFS_s_STYPE] )))
3416 : : {
3417 [ # # ]: 0 : const char *p_stereo = io->bRelativeStereo[io->iCurTautMode] ? x_rel : io->bRacemicStereo[io->iCurTautMode] ? x_rac
3418 [ # # ]: 0 : : x_abs;
3419 : 0 : szGetTag(IdentLbl, io->nTag, io->bTag2 = io->bTag1 | IL_TYPS, io->szTag2, &io->bAlways, 1);
3420 : 0 : inchi_strbuf_reset(strbuf);
3421 : 0 : io->tot_len = 0;
3422 [ # # ]: 0 : if (INCHI_SEGM_FILL == io->nSegmAction)
3423 : : {
3424 : 0 : (io->tot_len) += MakeDelim(p_stereo, strbuf, &io->bOverflow);
3425 : 0 : io->bNonTautNonIsoIdentifierNotEmpty += io->bSecondNonTautPass;
3426 : : }
3427 [ # # ]: 0 : if (str_LineEnd(io->szTag2, &io->bOverflow, strbuf, -io->nSegmAction, io->bPlainTextTags))
3428 : : {
3429 : 0 : return 1;
3430 : : }
3431 : 0 : inchi_ios_print_nodisplay(out_file, "%s%s", strbuf->pStr, pLF);
3432 : : }
3433 [ # # ]: 0 : if (io->bPlainTextTags == 1)
3434 : : {
3435 : 0 : inchi_ios_print_nodisplay(out_file, "/"); /* no abs, inv or racemic stereo */
3436 : : }
3437 : : }
3438 : : else
3439 : : {
3440 [ - + ]: 75 : if (io->bPlainTextTags == 1)
3441 : : {
3442 : 0 : inchi_ios_print_nodisplay( out_file, "////" ); /* sp2, sp3, abs-inv, stereo.type */
3443 : : }
3444 : : }
3445 : :
3446 : 75 : return 0;
3447 : : }
3448 : :
3449 : : /**
3450 : : * @brief Output InChI: stereo layer with sublayers for enhanced stereochemistry (absolute, relative, racemic).
3451 : : *
3452 : : * @param pCG Pointer to the CANON_GLOBALS structure containing global canonicalization data.
3453 : : * @param out_file Pointer to the INCHI_IOSTREAM output stream where the stereo layer will be written.
3454 : : * @param strbuf Pointer to an INCHI_IOS_STRING buffer used for string formatting and output.
3455 : : * @param io Pointer to the INCHI_OUT_CTL structure containing output control and state information.
3456 : : * @param orig_inp_data Pointer to the ORIG_ATOM_DATA containing e.g. atom information.
3457 : : * @param pLF Pointer to a string used as the line feed (end-of-line) character(s).
3458 : : * @param pTAB Pointer to a string used as the tab or separator character(s).
3459 : : * @return Returns 0 on success, or a non-zero error code on failure.
3460 : : */
3461 : 47 : int OutputINCHI_StereoLayer_EnhancedStereo(
3462 : : CANON_GLOBALS *pCG,
3463 : : INCHI_IOSTREAM *out_file,
3464 : : INCHI_IOS_STRING *strbuf,
3465 : : INCHI_OUT_CTL *io,
3466 : : ORIG_ATOM_DATA *orig_inp_data,
3467 : : char *pLF,
3468 : : char *pTAB )
3469 : : {
3470 : :
3471 [ + - + + ]: 94 : if (INChI_SegmentAction( io->sDifSegs[io->nCurINChISegment][DIFS_b_SBONDS] ) ||
3472 [ + - ]: 52 : INChI_SegmentAction( io->sDifSegs[io->nCurINChISegment][DIFS_t_SATOMS] ) ||
3473 [ - + ]: 10 : INChI_SegmentAction( io->sDifSegs[io->nCurINChISegment][DIFS_m_SP3INV] ) ||
3474 : 5 : INChI_SegmentAction( io->sDifSegs[io->nCurINChISegment][DIFS_s_STYPE] ))
3475 : : {
3476 : :
3477 : : /* stereo */
3478 : :
3479 : 42 : szGetTag( IdentLbl, io->nTag, io->bTag1 = IL_STER | io->bFhTag, io->szTag1, &io->bAlways, 1 );
3480 : :
3481 : : /* sp2 */
3482 : :
3483 [ - + ]: 42 : if ((io->nSegmAction = INChI_SegmentAction( io->sDifSegs[io->nCurINChISegment][DIFS_b_SBONDS] )))
3484 : : {
3485 : 0 : szGetTag( IdentLbl, io->nTag, io->bTag2 = io->bTag1 | IL_DBND, io->szTag2, &io->bAlways, 1 );
3486 : 0 : inchi_strbuf_reset( strbuf );
3487 : 0 : io->tot_len = 0;
3488 [ # # ]: 0 : if (INCHI_SEGM_FILL == io->nSegmAction)
3489 : : {
3490 : 0 : io->tot_len = str_Sp2( io->pINChISort, io->pINChISort2, strbuf, &io->bOverflow,
3491 : : io->bOutType, io->TAUT_MODE, io->num_components,
3492 : : io->bSecondNonTautPass, io->bOmitRepetitions, io->bUseMulipliers );
3493 : :
3494 : 0 : io->bNonTautNonIsoIdentifierNotEmpty += io->bSecondNonTautPass;
3495 : : }
3496 : :
3497 [ # # ]: 0 : if (str_LineEnd( io->szTag2, &io->bOverflow, strbuf, -io->nSegmAction, io->bPlainTextTags ))
3498 : : {
3499 : 0 : return 1;
3500 : : }
3501 : 0 : inchi_ios_print_nodisplay( out_file, "%s%s", strbuf->pStr, pLF );
3502 : : }
3503 : : else
3504 : : {
3505 [ - + ]: 42 : if (io->bPlainTextTags == 1)
3506 : : {
3507 : 0 : inchi_ios_print_nodisplay( out_file, "/" ); /* sp2 */
3508 : : }
3509 : : }
3510 : :
3511 : : /* sp3 */
3512 : :
3513 : : /* t-layer */
3514 [ + - ]: 42 : if ((io->nSegmAction = INChI_SegmentAction( io->sDifSegs[io->nCurINChISegment][DIFS_t_SATOMS] ))) /* djb-rwth: addressing LLVM warning */
3515 : : {
3516 [ + - - + ]: 42 : io->bRelRac = io->bRelativeStereo[io->iCurTautMode] || io->bRacemicStereo[io->iCurTautMode];
3517 : 42 : szGetTag( IdentLbl, io->nTag, io->bTag2 = io->bTag1 | IL_SP3S, io->szTag2, &io->bAlways, 1 );
3518 : 42 : inchi_strbuf_reset( strbuf );
3519 : 42 : io->tot_len = 0;
3520 [ + - ]: 42 : if (INCHI_SEGM_FILL == io->nSegmAction)
3521 : : {
3522 : 42 : io->tot_len = str_Sp3( io->pINChISort, io->pINChISort2, strbuf, &io->bOverflow,
3523 : : io->bOutType, io->TAUT_MODE, io->num_components, io->bRelRac,
3524 : : io->bSecondNonTautPass, io->bOmitRepetitions, io->bUseMulipliers );
3525 : :
3526 : 42 : io->bNonTautNonIsoIdentifierNotEmpty += io->bSecondNonTautPass;
3527 : : }
3528 : :
3529 [ - + ]: 42 : if (str_LineEnd( io->szTag2, &io->bOverflow, strbuf, -io->nSegmAction, io->bPlainTextTags ))
3530 : : {
3531 : 0 : return 2;
3532 : : }
3533 : 42 : inchi_ios_print_nodisplay( out_file, "%s%s", strbuf->pStr, pLF );
3534 : : }
3535 : : else
3536 : : {
3537 [ # # ]: 0 : if (io->bPlainTextTags == 1)
3538 : : {
3539 : 0 : inchi_ios_print_nodisplay( out_file, "/" ); /* sp3 */
3540 : : }
3541 : : }
3542 : :
3543 : : /* m-layer */
3544 [ + - ]: 42 : if ((io->nSegmAction = INChI_SegmentAction( io->sDifSegs[io->nCurINChISegment][DIFS_m_SP3INV] ))) /* djb-rwth: addressing LLVM warning */
3545 : : {
3546 : 42 : szGetTag( IdentLbl, io->nTag, io->bTag2 = io->bTag1 | IL_INVS, io->szTag2, &io->bAlways, 1 );
3547 : 42 : inchi_strbuf_reset( strbuf );
3548 : 42 : io->tot_len = 0;
3549 [ + - ]: 42 : if (INCHI_SEGM_FILL == io->nSegmAction)
3550 : : {
3551 : 42 : io->tot_len = str_StereoAbsInv( io->pINChISort, strbuf,
3552 : : &io->bOverflow, io->bOutType, io->num_components );
3553 : 42 : io->bNonTautNonIsoIdentifierNotEmpty += io->bSecondNonTautPass;
3554 : : }
3555 : :
3556 [ - + ]: 42 : if (str_LineEnd( io->szTag2, &io->bOverflow, strbuf, -io->nSegmAction, io->bPlainTextTags ))
3557 : : {
3558 : 0 : return 3;
3559 : : }
3560 : 42 : inchi_ios_print_nodisplay( out_file, "%s%s", strbuf->pStr, pLF );
3561 : : }
3562 : : else
3563 : : {
3564 [ # # ]: 0 : if (io->bPlainTextTags == 1)
3565 : : {
3566 : 0 : inchi_ios_print_nodisplay( out_file, "/" ); /* stereo-abs-inv */
3567 : : }
3568 : : }
3569 : :
3570 : : /* stereo type */
3571 : :
3572 : : /* s-layer */
3573 [ + - ]: 42 : if ((io->nSegmAction = INChI_SegmentAction( io->sDifSegs[io->nCurINChISegment][DIFS_s_STYPE] )))
3574 : : {
3575 [ + - ]: 84 : const char *p_stereo = io->bRelativeStereo[io->iCurTautMode] ? x_rel :
3576 [ - + ]: 42 : io->bRacemicStereo[io->iCurTautMode] ? x_rac : x_abs;
3577 : :
3578 : 42 : szGetTag( IdentLbl, io->nTag, io->bTag2 = io->bTag1 | IL_TYPS, io->szTag2, &io->bAlways, 1 );
3579 : 42 : inchi_strbuf_reset( strbuf ); io->tot_len = 0;
3580 : :
3581 : 42 : io->tot_len = 0;
3582 [ + - ]: 42 : if (INCHI_SEGM_FILL == io->nSegmAction)
3583 : : {
3584 [ + + ]: 42 : if (orig_inp_data->v3000->n_steabs > 0 ||
3585 [ + + ]: 20 : orig_inp_data->v3000->n_sterel > 0 ||
3586 [ + + ]: 16 : orig_inp_data->v3000->n_sterac > 0) {
3587 : 36 : io->tot_len += MakeSlayerString(
3588 : : orig_inp_data,
3589 : : io->pINChISort,
3590 : : strbuf,
3591 : : io->bOutType,
3592 : : io->num_components,
3593 : : io->TAUT_MODE,
3594 : : &io->bOverflow
3595 : 36 : );
3596 : : } else {
3597 : 6 : ( io->tot_len ) += MakeDelim( p_stereo, strbuf, &io->bOverflow );
3598 : : }
3599 : :
3600 : 42 : io->bNonTautNonIsoIdentifierNotEmpty += io->bSecondNonTautPass;
3601 : : }
3602 [ - + ]: 42 : if (str_LineEnd( io->szTag2, &io->bOverflow, strbuf, -io->nSegmAction, io->bPlainTextTags ))
3603 : : {
3604 : 0 : return 1;
3605 : : }
3606 : 42 : inchi_ios_print_nodisplay( out_file, "%s%s", strbuf->pStr, pLF );
3607 : : }
3608 [ - + ]: 42 : if (io->bPlainTextTags == 1)
3609 : : {
3610 : 0 : inchi_ios_print_nodisplay( out_file, "/" ); /* no abs, inv or racemic stereo */
3611 : : }
3612 : : }
3613 : : else
3614 : : {
3615 [ - + ]: 5 : if (io->bPlainTextTags == 1)
3616 : : {
3617 : 0 : inchi_ios_print_nodisplay( out_file, "////" ); /* sp2, sp3, abs-inv, stereo.type */
3618 : : }
3619 : : }
3620 : :
3621 : 47 : return 0;
3622 : : }
3623 : :
3624 : : /****************************************************************************
3625 : : Output InChI: isotopic layer and sublayers
3626 : : ****************************************************************************/
3627 : 122 : int OutputINCHI_IsotopicLayer( CANON_GLOBALS *pCG,
3628 : : INCHI_IOSTREAM *out_file,
3629 : : INCHI_IOS_STRING *strbuf,
3630 : : int *INCHI_basic_or_INCHI_reconnected,
3631 : : INCHI_OUT_CTL *io,
3632 : : char *pLF,
3633 : : char *pTAB )
3634 : : {
3635 : :
3636 [ - + ]: 122 : if (INChI_SegmentAction(io->sDifSegs[io->nCurINChISegment][DIFS_i_IATOMS]))
3637 : : {
3638 : : /* isotopic #1: composition -- atoms -- do not output in xml if empty */
3639 : 0 : szGetTag(IdentLbl, io->nTag, io->bTag1 = IL_ISOT | io->bFhTag, io->szTag1, &io->bAlways, 1);
3640 : : /* isotopic atoms without mobile H.
3641 : : * Fixed 2004-06-15: always output if not bXml. Note:
3642 : : * Previous condition if( bHasIsotopicAtoms[io->iCurTautMode] || bIsotopic && !bXml)
3643 : : * did not optput /i in case of only mobile isotopic H
3644 : : */
3645 [ # # ]: 0 : if ((io->nSegmAction = INChI_SegmentAction(io->sDifSegs[io->nCurINChISegment][DIFS_i_IATOMS]))) /* djb-rwth: addressing LLVM warning */
3646 : : {
3647 : 0 : szGetTag(IdentLbl, io->nTag, io->bTag2 = io->bTag1 | IL_ATMS, io->szTag2, &io->bAlways, 1);
3648 : 0 : inchi_strbuf_reset(strbuf);
3649 : 0 : io->tot_len = 0;
3650 : : /*if ( bHasIsotopicAtoms[io->iCurTautMode] )*/
3651 [ # # ]: 0 : if (INCHI_SEGM_FILL == io->nSegmAction)
3652 : : {
3653 : 0 : io->tot_len2 = str_IsoAtoms(io->pINChISort, io->pINChISort2, strbuf, &io->bOverflow,
3654 : : io->bOutType, io->TAUT_MODE, io->num_components, io->bAbcNumbers,
3655 : : io->bSecondNonTautPass, io->bOmitRepetitions, io->bUseMulipliers);
3656 : 0 : io->bNonTautIsoIdentifierNotEmpty += io->bSecondNonTautPass;
3657 : : }
3658 : : else
3659 : : {
3660 : 0 : io->tot_len2 = io->tot_len;
3661 : : }
3662 : :
3663 : 0 : io->tot_len = io->tot_len2;
3664 [ # # ]: 0 : if (str_LineEnd(io->szTag2, &io->bOverflow, strbuf, -io->nSegmAction, io->bPlainTextTags))
3665 : : {
3666 : 0 : return 1;
3667 : : }
3668 : 0 : inchi_ios_print_nodisplay(out_file, "%s%s", strbuf->pStr, pLF);
3669 : : }
3670 : :
3671 : : /* isotopic #1a: composition -- exchangeable isotopic H (mobile H only) */
3672 : : /*if ( !io->bSecondNonTautPass && bHasIsoH )*/
3673 [ # # ]: 0 : if ((io->nSegmAction = INChI_SegmentAction(io->sDifSegs[io->nCurINChISegment][DIFS_h_H_ATOMS]))) /* djb-rwth: addressing LLVM warning */
3674 : : {
3675 : 0 : szGetTag(IdentLbl, io->nTag, io->bTag2 = io->bTag1 | IL_XCGA, io->szTag2, &io->bAlways, 1);
3676 : 0 : inchi_strbuf_reset(strbuf);
3677 : 0 : io->tot_len = 0;
3678 : 0 : (io->tot_len) += MakeIsoHString(io->num_iso_H, strbuf, io->TAUT_MODE, &io->bOverflow);
3679 : 0 : io->bNonTautIsoIdentifierNotEmpty += io->bSecondNonTautPass;
3680 [ # # ]: 0 : if (str_LineEnd(io->szTag2, &io->bOverflow, strbuf, -io->nSegmAction, io->bPlainTextTags))
3681 : : {
3682 : 0 : return 2;
3683 : : }
3684 : 0 : inchi_ios_print_nodisplay(out_file, "%s%s", strbuf->pStr, pLF);
3685 : : }
3686 : :
3687 : : /***************************************************
3688 : : *
3689 : : * Isotopic stereo
3690 : : *
3691 : : ***************************************************/
3692 : :
3693 : : /*if ( bIsotopicStereo[io->iCurTautMode] )*/
3694 [ # # # # ]: 0 : if (INChI_SegmentAction(io->sDifSegs[io->nCurINChISegment][DIFS_b_SBONDS]) ||
3695 [ # # ]: 0 : INChI_SegmentAction(io->sDifSegs[io->nCurINChISegment][DIFS_t_SATOMS]) ||
3696 [ # # ]: 0 : INChI_SegmentAction(io->sDifSegs[io->nCurINChISegment][DIFS_m_SP3INV]) ||
3697 : 0 : INChI_SegmentAction(io->sDifSegs[io->nCurINChISegment][DIFS_s_STYPE]))
3698 : : {
3699 : : /* stereo */
3700 : 0 : szGetTag(IdentLbl, io->nTag, io->bTag2 = io->bTag1 | IL_STER, io->szTag2, &io->bAlways, 1);
3701 : :
3702 : : /************************
3703 : : isotopic #2: sp2
3704 : : ************************/
3705 : : /*if ( bIsotopicStereoSp2[io->iCurTautMode] )*/
3706 [ # # ]: 0 : if ((io->nSegmAction = INChI_SegmentAction(io->sDifSegs[io->nCurINChISegment][DIFS_b_SBONDS]))) /* djb-rwth: addressing LLVM warning */
3707 : : {
3708 : 0 : szGetTag(IdentLbl, io->nTag, io->bTag3 = io->bTag2 | IL_DBND, io->szTag3, &io->bAlways, 1);
3709 : 0 : inchi_strbuf_reset(strbuf);
3710 : 0 : io->tot_len = 0;
3711 [ # # ]: 0 : if (INCHI_SEGM_FILL == io->nSegmAction)
3712 : : {
3713 : 0 : io->tot_len = str_IsoSp2(io->pINChISort, io->pINChISort2, strbuf, &io->bOverflow,
3714 : : io->bOutType, io->TAUT_MODE, io->num_components,
3715 : : io->bSecondNonTautPass, io->bOmitRepetitions, io->bUseMulipliers);
3716 : 0 : io->bNonTautIsoIdentifierNotEmpty += io->bSecondNonTautPass;
3717 : : }
3718 [ # # ]: 0 : if (str_LineEnd(io->szTag3, &io->bOverflow, strbuf, -io->nSegmAction, io->bPlainTextTags))
3719 : : {
3720 : 0 : return 3;
3721 : : }
3722 : 0 : inchi_ios_print_nodisplay(out_file, "%s%s", strbuf->pStr, pLF);
3723 : : }
3724 : : else
3725 : : {
3726 [ # # ]: 0 : if (io->bPlainTextTags == 1)
3727 : 0 : inchi_ios_print_nodisplay(out_file, "/"); /* iso sp2 */
3728 : : }
3729 : :
3730 : : /************************
3731 : : isotopic #3: sp3
3732 : : ************************/
3733 : : /*if ( bIsotopicStereoSp3[io->iCurTautMode] )*/
3734 [ # # ]: 0 : if ((io->nSegmAction = INChI_SegmentAction(io->sDifSegs[io->nCurINChISegment][DIFS_t_SATOMS]))) /* djb-rwth: addressing LLVM warning */
3735 : : {
3736 [ # # # # ]: 0 : io->bRelRac = io->bIsotopicRelativeStereo[io->iCurTautMode] || io->bIsotopicRacemicStereo[io->iCurTautMode];
3737 : :
3738 : 0 : szGetTag(IdentLbl, io->nTag, io->bTag3 = io->bTag2 | IL_SP3S, io->szTag3, &io->bAlways, 1);
3739 : 0 : inchi_strbuf_reset(strbuf);
3740 : 0 : io->tot_len = 0;
3741 [ # # ]: 0 : if (INCHI_SEGM_FILL == io->nSegmAction)
3742 : : {
3743 : 0 : io->tot_len = str_IsoSp3(io->pINChISort, io->pINChISort2, strbuf, &io->bOverflow,
3744 : : io->bOutType, io->TAUT_MODE, io->num_components, io->bRelRac,
3745 : : io->bSecondNonTautPass, io->bOmitRepetitions, io->bUseMulipliers);
3746 : 0 : io->bNonTautIsoIdentifierNotEmpty += io->bSecondNonTautPass;
3747 : : }
3748 [ # # ]: 0 : if (str_LineEnd(io->szTag3, &io->bOverflow, strbuf, -io->nSegmAction, io->bPlainTextTags))
3749 : : {
3750 : 0 : return 5;
3751 : : }
3752 : 0 : inchi_ios_print_nodisplay(out_file, "%s%s", strbuf->pStr, pLF);
3753 : : }
3754 : : else
3755 : : {
3756 [ # # ]: 0 : if (io->bPlainTextTags == 1)
3757 : : {
3758 : 0 : inchi_ios_print_nodisplay(out_file, "/"); /* iso-sp3 */
3759 : : }
3760 : : }
3761 : :
3762 : : /* isotopic #4: abs inverted */
3763 [ # # ]: 0 : if ((io->nSegmAction = INChI_SegmentAction(io->sDifSegs[io->nCurINChISegment][DIFS_m_SP3INV]))) /* djb-rwth: addressing LLVM warning */
3764 : : {
3765 : 0 : szGetTag(IdentLbl, io->nTag, io->bTag3 = io->bTag2 | IL_INVS, io->szTag3, &io->bAlways, 1);
3766 : 0 : inchi_strbuf_reset(strbuf);
3767 : 0 : io->tot_len = 0;
3768 [ # # ]: 0 : if (INCHI_SEGM_FILL == io->nSegmAction)
3769 : : {
3770 : 0 : io->tot_len = str_IsoStereoAbsInv(io->pINChISort, strbuf,
3771 : : &io->bOverflow, io->bOutType, io->num_components);
3772 : 0 : io->bNonTautIsoIdentifierNotEmpty += io->bSecondNonTautPass;
3773 : : }
3774 [ # # ]: 0 : if (str_LineEnd(io->szTag3, &io->bOverflow, strbuf, -io->nSegmAction, io->bPlainTextTags))
3775 : : {
3776 : 0 : return 5;
3777 : : }
3778 : 0 : inchi_ios_print_nodisplay(out_file, "%s%s", strbuf->pStr, pLF);
3779 : : }
3780 : : else
3781 : : {
3782 [ # # ]: 0 : if (io->bPlainTextTags == 1)
3783 : : {
3784 : 0 : inchi_ios_print_nodisplay(out_file, "/");
3785 : : }
3786 : : }
3787 : :
3788 : : /* isotopic #5: stereo type. Do not output if it has already been output in non-iso */
3789 [ # # ]: 0 : if ((io->nSegmAction = INChI_SegmentAction(io->sDifSegs[io->nCurINChISegment][DIFS_s_STYPE]))) /* djb-rwth: addressing LLVM warning */
3790 : : {
3791 [ # # ]: 0 : const char *p_stereo = io->bIsotopicRelativeStereo[io->iCurTautMode] ? x_rel : io->bIsotopicRacemicStereo[io->iCurTautMode] ? x_rac
3792 [ # # ]: 0 : : x_abs;
3793 : 0 : szGetTag(IdentLbl, io->nTag, io->bTag3 = io->bTag2 | IL_TYPS, io->szTag3, &io->bAlways, 1);
3794 : 0 : inchi_strbuf_reset(strbuf);
3795 : 0 : io->tot_len = 0;
3796 [ # # ]: 0 : if (INCHI_SEGM_FILL == io->nSegmAction)
3797 : : {
3798 : 0 : io->tot_len += MakeDelim(p_stereo, strbuf, &io->bOverflow);
3799 : 0 : io->bNonTautIsoIdentifierNotEmpty += io->bSecondNonTautPass;
3800 : : }
3801 [ # # ]: 0 : if (str_LineEnd(io->szTag3, &io->bOverflow, strbuf, -io->nSegmAction, io->bPlainTextTags))
3802 : : {
3803 : 0 : return 6;
3804 : : }
3805 : 0 : inchi_ios_print_nodisplay(out_file, "%s%s", strbuf->pStr, pLF);
3806 : : }
3807 [ # # ]: 0 : if (io->bPlainTextTags == 1)
3808 : : {
3809 : 0 : inchi_ios_print_nodisplay(out_file, "/"); /* no abs, inv or racemic stereo */
3810 : : }
3811 : : }
3812 : : else
3813 : : {
3814 : : /* no isotopic stereo */
3815 [ # # ]: 0 : if (io->bPlainTextTags == 1)
3816 : : {
3817 : 0 : inchi_ios_print_nodisplay(out_file, "////"); /* sp3, sp2, abs-inv, stereo.type */
3818 : : }
3819 : : }
3820 : : }
3821 : : else
3822 : : {
3823 [ - + ]: 122 : if (io->bPlainTextTags == 1)
3824 : : {
3825 : 0 : inchi_ios_print_nodisplay(out_file, "///"); /* isotopic composition, sp2, sp3 */
3826 : : }
3827 [ - + ]: 122 : if (io->bPlainTextTags == 1)
3828 : : {
3829 : 0 : inchi_ios_print_nodisplay(out_file, "//"); /* inv or racemic stereo */
3830 : : }
3831 : : }
3832 : :
3833 : : #if (CANON_FIXH_TRANS == 1)
3834 [ - + - - : 122 : if (io->bOutType == OUT_NONTAUT && io->bOutputType == OUT_TN && io->bSecondNonTautPass &&
- - - - ]
3835 : 0 : INCHI_SEGM_FILL == INChI_SegmentAction(io->sDifSegs[DIFL_F][DIFS_o_TRANSP]))
3836 : : {
3837 : : /* find and print non-tautomeric components transposition, if non-trivial */
3838 : : AT_NUMB *nTrans_n, *nTrans_s;
3839 : :
3840 [ # # ]: 0 : if (0 < bin_AuxTautTrans(io->pINChISort, io->pINChISort2, &nTrans_n, &nTrans_s, io->bOutType, io->num_components))
3841 : : {
3842 : : /* a non-trivial transposition does exist; output start tag */
3843 : 0 : szGetTag(IdentLbl, io->nTag, io->bTag1 = IL_TRNS | io->bFhTag, io->szTag1, &io->bAlways, 1);
3844 : 0 : inchi_strbuf_reset(strbuf);
3845 : 0 : io->tot_len = 0;
3846 : : /* print the transposition, cycle after cycle */
3847 : 0 : io->tot_len = str_AuxTautTrans(pCG, nTrans_n, nTrans_s, strbuf,
3848 : : &io->bOverflow, io->TAUT_MODE, io->num_components);
3849 : 0 : io->bNonTautIsoIdentifierNotEmpty += io->bSecondNonTautPass;
3850 [ # # ]: 0 : if (str_LineEnd(io->szTag1, &io->bOverflow, strbuf, -1, io->bPlainTextTags))
3851 : : {
3852 : 0 : return 7;
3853 : : }
3854 : 0 : inchi_ios_print_nodisplay(out_file, "%s%s", strbuf->pStr, pLF);
3855 : : /* detected transposition */
3856 : 0 : (*io->pSortPrintINChIFlags) |=
3857 [ # # ]: 0 : (*INCHI_basic_or_INCHI_reconnected == INCHI_BAS) ? FLAG_SORT_PRINT_TRANSPOS_BAS : FLAG_SORT_PRINT_TRANSPOS_REC;
3858 : : }
3859 : : else
3860 : : {
3861 [ # # ]: 0 : if (io->bPlainTextTags == 1)
3862 : : {
3863 : 0 : inchi_ios_print_nodisplay(out_file, "/");
3864 : : }
3865 : : }
3866 : : }
3867 : : #endif
3868 : :
3869 : 122 : return 0;
3870 : : }
3871 : :
3872 : : /****************************************************************************
3873 : : Output InChI: FixedH layer and related sublayers
3874 : : ****************************************************************************/
3875 : 122 : int OutputINCHI_FixedHLayerWithSublayers(CANON_GLOBALS *pCG,
3876 : : INCHI_IOSTREAM *out_file,
3877 : : INCHI_IOS_STRING *strbuf,
3878 : : int *INCHI_basic_or_INCHI_reconnected,
3879 : : INCHI_OUT_CTL *io,
3880 : : char *pLF,
3881 : : char *pTAB,
3882 : : int *then_goto_repeat)
3883 : : {
3884 : :
3885 : 122 : *then_goto_repeat = 0;
3886 : :
3887 [ + - ]: 122 : if (io->bOutType == OUT_TN &&
3888 [ + - ]: 122 : !(io->bSecondNonTautPass) &&
3889 [ + - ]: 122 : io->bNonTautIsIdenticalToTaut &&
3890 [ + + ]: 122 : io->bTautomeric &&
3891 [ - + ]: 11 : io->bNonTautomeric)
3892 : : {
3893 : : /* Fixed-H layer is empty in the Identifier */
3894 : 0 : (*io->pSortPrintINChIFlags) |=
3895 [ # # ]: 0 : (*INCHI_basic_or_INCHI_reconnected == INCHI_BAS) ? FLAG_SORT_PRINT_NO_NFIX_H_BAS : FLAG_SORT_PRINT_NO_NFIX_H_REC;
3896 : 0 : (*io->pSortPrintINChIFlags) |=
3897 [ # # ]: 0 : (*INCHI_basic_or_INCHI_reconnected == INCHI_BAS) ? FLAG_SORT_PRINT_NO_IFIX_H_BAS : FLAG_SORT_PRINT_NO_IFIX_H_REC;
3898 : : }
3899 : :
3900 [ + - ]: 122 : if (io->bOutType == OUT_TN &&
3901 [ - + - - ]: 122 : !io->bNonTautIsIdenticalToTaut && /* added 2004-10-04 Fix16 */
3902 : : #ifdef OLD_ITEM_DISCOVERY
3903 : : io->bTautomeric &&
3904 : : io->bNonTautomeric &&
3905 : : #endif
3906 : 0 : INChI_SegmentAction(io->sDifSegs[DIFL_F][DIFS_f_FORMULA])
3907 : : /* special case: removed isolated H(+): */
3908 : : /* || io->iCurTautMode == TAUT_YES && num_comp[TAUT_YES] < num_comp[TAUT_NON] &&
3909 : : 0 < num_comp[TAUT_NON]*/
3910 : : )
3911 : :
3912 : : {
3913 : : /* add the second (non-tautomeric) output */
3914 : 0 : io->bOutType = OUT_NONTAUT; /* pick up only non-tautomeric representation of tautomeric */
3915 : 0 : io->iCurTautMode = TAUT_NON;
3916 : 0 : io->pINChISort = io->pINChISortTautAndNonTaut[TAUT_NON];
3917 : 0 : io->bSecondNonTautPass = 1;
3918 : 0 : io->nCurINChISegment = DIFL_F;
3919 : 0 : io->num_components = io->num_comp[io->iCurTautMode]; /* number of components could change due to removal of isolated H(+) from tautomeric */
3920 : 0 : io->bFhTag = IL_FIXH;
3921 : 0 : szGetTag(IdentLbl, io->nTag, io->bTag1 = io->bFhTag, io->szTag1, &io->bAlways, 1);
3922 : : /***** constitution non-taut: dot-disconnected Hill formulas: <formula> -- only if different */
3923 : 0 : szGetTag(IdentLbl, io->nTag, io->bTag1 = IL_FMLF | io->bFhTag, io->szTag1, &io->bAlways, 1);
3924 : 0 : inchi_strbuf_reset(strbuf);
3925 : 0 : io->tot_len = 0;
3926 : 0 : io->nSegmAction = INChI_SegmentAction(io->sDifSegs[io->nCurINChISegment][DIFS_f_FORMULA]);
3927 [ # # ]: 0 : if (INCHI_SEGM_FILL == io->nSegmAction)
3928 : : {
3929 : 0 : io->tot_len2 = str_HillFormula2(io->pINChISort, io->pINChISort2,
3930 : : strbuf, &io->bOverflow, io->bOutType,
3931 : : io->num_components, io->bUseMulipliers);
3932 [ # # # # ]: 0 : if (io->n_pzz > 0 && io->n_zy > 0)
3933 : : {
3934 : 0 : MergeZzInHillFormula(strbuf);
3935 : : }
3936 : 0 : io->bNonTautNonIsoIdentifierNotEmpty += io->bSecondNonTautPass;
3937 : : }
3938 : : else
3939 : : {
3940 : 0 : io->tot_len2 = io->tot_len;
3941 : : }
3942 : 0 : io->tot_len = io->tot_len2;
3943 [ # # ]: 0 : if (str_LineEnd(io->szTag1, &io->bOverflow, strbuf, -io->nSegmAction, io->bPlainTextTags))
3944 : : {
3945 : 0 : return 1;
3946 : : }
3947 : 0 : inchi_ios_print_nodisplay(out_file, "%s%s", strbuf->pStr, pLF);
3948 : :
3949 : 0 : io->nSegmAction = INChI_SegmentAction(io->sDifSegs[io->nCurINChISegment][DIFS_h_H_ATOMS]);
3950 : :
3951 [ # # ]: 0 : if (INCHI_SEGM_FILL == io->nSegmAction)
3952 : : {
3953 : 0 : szGetTag(IdentLbl, io->nTag, io->bTag1 = IL_HFIX | io->bFhTag, io->szTag1, &io->bAlways, 1);
3954 : 0 : inchi_strbuf_reset(strbuf);
3955 : 0 : io->tot_len = 0; /* open H-fixed */
3956 : : /* output the second non-tautomeric item: fixed H -- do not output in xml if empty */
3957 : 0 : io->tot_len2 = str_FixedH_atoms(io->pINChISort, strbuf,
3958 : : &io->bOverflow, io->bOutType, io->ATOM_MODE,
3959 : : io->num_components, io->bUseMulipliers);
3960 : 0 : io->tot_len = io->tot_len2;
3961 [ # # ]: 0 : if (str_LineEnd(io->szTag1, &io->bOverflow, strbuf, -io->nSegmAction, io->bPlainTextTags))
3962 : : {
3963 : 0 : return 2;
3964 : : }
3965 : 0 : inchi_ios_print_nodisplay(out_file, "%s%s", strbuf->pStr, pLF);
3966 : 0 : io->bNonTautNonIsoIdentifierNotEmpty += io->bSecondNonTautPass;
3967 : : }
3968 : 0 : *then_goto_repeat = 1;
3969 : 0 : return 0;
3970 : : }
3971 : :
3972 : : else
3973 : : {
3974 [ - + - - : 122 : if (io->bOutType == OUT_NONTAUT && io->bOutputType == OUT_TN && io->bSecondNonTautPass /* && io->bTautomeric && io->bNonTautomeric*/)
- - ]
3975 : : {
3976 : : /* the second (non-taut) output has been done; restore variables */
3977 : 0 : io->bOutType = OUT_TN;
3978 : 0 : io->iCurTautMode = TAUT_YES;
3979 : 0 : io->pINChISort = io->pINChISortTautAndNonTaut[TAUT_YES];
3980 : 0 : io->bSecondNonTautPass = 0;
3981 : 0 : io->num_components = io->num_comp[io->iCurTautMode];
3982 [ # # ]: 0 : if (!io->bNonTautNonIsoIdentifierNotEmpty)
3983 : : {
3984 : : /* Fixed-H layer is empty in the Identifier */
3985 [ # # ]: 0 : (*io->pSortPrintINChIFlags) |= (*INCHI_basic_or_INCHI_reconnected == INCHI_BAS) ? FLAG_SORT_PRINT_NO_NFIX_H_BAS : FLAG_SORT_PRINT_NO_NFIX_H_REC;
3986 : : }
3987 [ # # ]: 0 : if (!io->bNonTautIsoIdentifierNotEmpty)
3988 : : {
3989 : : /* Fixed-H layer is empty in the Identifier */
3990 [ # # ]: 0 : (*io->pSortPrintINChIFlags) |= (*INCHI_basic_or_INCHI_reconnected == INCHI_BAS) ? FLAG_SORT_PRINT_NO_IFIX_H_BAS : FLAG_SORT_PRINT_NO_IFIX_H_REC;
3991 : : }
3992 : 0 : io->bFhTag = 0;
3993 : : }
3994 : : }
3995 : :
3996 : 122 : return 0;
3997 : : }
3998 : :
3999 : : /****************************************************************************
4000 : : Output InChI: polymer layer
4001 : : ****************************************************************************/
4002 : 122 : static int OutputINCHI_PolymerLayer(CANON_GLOBALS *pCG,
4003 : : INCHI_IOSTREAM *out_file,
4004 : : INCHI_IOS_STRING *strbuf,
4005 : : int *INCHI_basic_or_INCHI_reconnected,
4006 : : ORIG_ATOM_DATA *orig_inp_data,
4007 : : ORIG_STRUCT *pOrigStruct,
4008 : : INCHI_OUT_CTL *io,
4009 : : char *pLF,
4010 : : char *pTAB)
4011 : : {
4012 : 122 : int i, err = 0;
4013 : 122 : int nunits2 = 0;
4014 : 122 : int n_used_stars = 0;
4015 : 122 : int *cano_nums = NULL, *compnt_nums = NULL, *unum = NULL, *old_stars = NULL;
4016 : 122 : OAD_PolymerUnit *u = NULL;
4017 : 122 : OAD_PolymerUnit **units2 = NULL;
4018 : 122 : OAD_Polymer *p = NULL;
4019 : 122 : OAD_AtProps *aprops = NULL;
4020 : : int nat, num_inp_bonds;
4021 : 122 : inp_ATOM *at = NULL;
4022 : 122 : int is_inchi2inchi = 0;
4023 : :
4024 [ - + ]: 122 : if (!orig_inp_data)
4025 : : {
4026 : 0 : goto exit_function;
4027 : : }
4028 : :
4029 : 122 : at = orig_inp_data->at;
4030 : 122 : nat = orig_inp_data->num_inp_atoms;
4031 : 122 : num_inp_bonds = orig_inp_data->num_inp_bonds;
4032 : :
4033 : :
4034 [ + - + + ]: 122 : if (pOrigStruct && !pOrigStruct->polymer)
4035 : : {
4036 : 120 : return 0;
4037 : : }
4038 : :
4039 [ + - ]: 2 : if (pOrigStruct)
4040 : : {
4041 : 2 : p = pOrigStruct->polymer;
4042 [ - + - - : 2 : is_inchi2inchi = !pOrigStruct->szAtoms && !pOrigStruct->szBonds && !pOrigStruct->szCoord;
- - ]
4043 : :
4044 [ - + ]: 2 : if (is_inchi2inchi)
4045 : : {
4046 : 0 : err = NOT_YET_I2I_FOR_POLYMERS;
4047 : 0 : goto exit_function;
4048 : : }
4049 : :
4050 : : /*OAD_Polymer_DebugTrace( p );*/
4051 : :
4052 : : /* Get canonical numbers and numbers-of-components for each original atom */
4053 : 2 : cano_nums = (int *)inchi_calloc((long long)pOrigStruct->num_atoms + 1, sizeof(int)); /* djb-rwth: cast operator added */
4054 [ - + ]: 2 : if (!cano_nums)
4055 : : {
4056 : 0 : err = 1;
4057 : 0 : goto exit_function;
4058 : : }
4059 : 2 : compnt_nums = (int *)inchi_calloc((long long)pOrigStruct->num_atoms + 1, sizeof(int)); /* djb-rwth: cast operator added */
4060 [ - + ]: 2 : if (!compnt_nums)
4061 : : {
4062 : 0 : err = 2;
4063 : 0 : goto exit_function;
4064 : : }
4065 : 2 : err = InternallyGetCanoNumsAndComponentNums(pCG,
4066 : : strbuf,
4067 : : io,
4068 : : pOrigStruct->num_atoms,
4069 : : cano_nums,
4070 : : compnt_nums);
4071 [ - + ]: 2 : if (err != 0)
4072 : : {
4073 : 0 : err = 3;
4074 : 0 : goto exit_function;
4075 : : }
4076 : :
4077 : : /* Set atom properties for sorting */
4078 : 2 : aprops = (OAD_AtProps *)inchi_calloc((long long)nat + 1, sizeof(OAD_AtProps)); /* djb-rwth: cast operator added */
4079 : : /* nat + 1: add extra element for possibe 1-based indexing */
4080 [ - + ]: 2 : if (!aprops)
4081 : : {
4082 : : /* djb-rwth: avoiding memory leak */
4083 [ # # ]: 0 : if (cano_nums)
4084 : : {
4085 [ # # ]: 0 : inchi_free(cano_nums);
4086 : : }
4087 [ # # ]: 0 : if (compnt_nums)
4088 : : {
4089 [ # # ]: 0 : inchi_free(compnt_nums);
4090 : : }
4091 [ # # ]: 0 : if (aprops)
4092 : : {
4093 [ # # ]: 0 : inchi_free(aprops);
4094 : : }
4095 : 0 : return 0;
4096 : : }
4097 : :
4098 : : /* Note that aprops[] is in orig_atoms domain (0-based) and */
4099 : : /* u (from units) are in cano_nums domain (1-based) */
4100 : : /* Supply non-NULL cano_nums to adjust the domains (base will be adjusted at place) */
4101 : 2 : OAD_Polymer_SetAtProps(p, at, nat, &num_inp_bonds, aprops, cano_nums);
4102 : :
4103 : : /* Make a working copy of polymer units data: units2 is a copy */
4104 : : /* of original polymer units (p->units) with atomic numbers changed */
4105 : : /* to curr canonical ones; atoms in alists sorted; atoms in blists */
4106 : : /* and blists themselves sorted */
4107 : 2 : units2 = (OAD_PolymerUnit **)inchi_calloc(p->n, sizeof(OAD_PolymerUnit *));
4108 : :
4109 [ - + ]: 2 : if (NULL == units2)
4110 : : {
4111 : 0 : err = 3;
4112 : 0 : goto exit_function;
4113 : : }
4114 : 2 : memset(units2, 0, sizeof(*units2)); /* djb-rwth: memset_s C11/Annex K variant? */
4115 : :
4116 : 2 : old_stars = (int *)inchi_calloc(pOrigStruct->polymer->n_pzz, sizeof(int));
4117 [ - + ]: 2 : if (NULL == old_stars)
4118 : : {
4119 : 0 : err = 3;
4120 : 0 : goto exit_function;
4121 : : }
4122 [ - + ]: 2 : for (i = 0; i < pOrigStruct->polymer->n_pzz; i++)
4123 : : {
4124 : 0 : old_stars[i] = pOrigStruct->polymer->pzz[i];
4125 : : }
4126 : :
4127 [ + + ]: 4 : for (i = 0; i < p->n; i++)
4128 : : {
4129 : 2 : units2[i] = OAD_PolymerUnit_CreateCopy(p->units[i]);
4130 [ - + ]: 2 : if (NULL == units2[i]) /* djb-rwth: unresolved issue -- revision required? -- units2 properly allocated, and loop index well defined */
4131 : : {
4132 : 0 : err = 4;
4133 : 0 : goto exit_function;
4134 : : }
4135 : 2 : nunits2 = i + 1;
4136 : : }
4137 : :
4138 : : /* unum contains numbers of units (0..p->n) as they go */
4139 : : /* when sorted by alist's in lexicographic order */
4140 : 2 : unum = (int *)inchi_calloc(p->n, sizeof(int));
4141 [ - + ]: 2 : if (NULL == unum)
4142 : : {
4143 : 0 : err = 4;
4144 : 0 : goto exit_function;
4145 : : }
4146 : :
4147 : 2 : err = OAD_Polymer_PrepareWorkingSet(p, cano_nums, compnt_nums, units2, unum);
4148 : :
4149 [ - + ]: 2 : if (err != 0)
4150 : : {
4151 : 0 : err = 5;
4152 : 0 : goto exit_function;
4153 : : }
4154 : :
4155 : : /* Prepare polymer substring */
4156 : :
4157 : : /* Mark layer beginning */
4158 : 2 : inchi_strbuf_printf(strbuf, "%s", "/z");
4159 : :
4160 : : /* Print polymer units data */
4161 : 2 : n_used_stars = 0;
4162 [ + + ]: 4 : for (i = 0; i < p->n; i++)
4163 : : {
4164 : : /* For each unit u ... */
4165 : 2 : u = units2[unum[i]];
4166 : : /* djb-rwth: addressing coverity ID #499574 -- all NULL checks already done above */
4167 : 2 : err = OutputINCHI_PolymerLayer_SingleUnit(u,
4168 : : io->bPolymers,
4169 : 2 : pOrigStruct->polymer->n_pzz,
4170 : : &n_used_stars, aprops,
4171 : : cano_nums,
4172 : : orig_inp_data,
4173 : : pOrigStruct, strbuf);
4174 [ - + ]: 2 : if (err)
4175 : : {
4176 : 0 : goto exit_function;
4177 : : }
4178 [ - + ]: 2 : if (i < p->n - 1)
4179 : : {
4180 : 0 : inchi_strbuf_printf(strbuf, ";");
4181 : : }
4182 : : }
4183 : 2 : inchi_ios_print_nodisplay(out_file, "%s%s", strbuf->pStr, pLF);
4184 : :
4185 : : LOG_NO_ARGS("\n******************* (L4184:ichiprt1.c) ********************\n");
4186 : : LOG_MULT_ARGS("Polymer Layer start: %s\n", strbuf->pStr);
4187 : : LOG_NO_ARGS("\n***********************************************************\n");
4188 : :
4189 : 2 : exit_function:
4190 [ + - ]: 2 : if (cano_nums)
4191 : : {
4192 [ + - ]: 2 : inchi_free(cano_nums);
4193 : : }
4194 [ + - ]: 2 : if (compnt_nums)
4195 : : {
4196 [ + - ]: 2 : inchi_free(compnt_nums);
4197 : : }
4198 [ + - ]: 2 : if (aprops)
4199 : : {
4200 [ + - ]: 2 : inchi_free(aprops);
4201 : : }
4202 [ + - ]: 2 : if (unum)
4203 : : {
4204 [ + - ]: 2 : inchi_free(unum);
4205 : : }
4206 [ + - ]: 2 : if (units2)
4207 : : {
4208 [ + + ]: 4 : for (i = 0; i < nunits2; i++)
4209 : : {
4210 : 2 : OAD_PolymerUnit_Free(units2[i]);
4211 : : }
4212 [ + - ]: 2 : inchi_free(units2);
4213 : : }
4214 [ + - ]: 2 : if (old_stars)
4215 : : {
4216 [ - + ]: 2 : for (i = 0; i < pOrigStruct->polymer->n_pzz; i++)
4217 : 0 : pOrigStruct->polymer->pzz[i] = old_stars[i];
4218 [ + - ]: 2 : inchi_free(old_stars);
4219 : : }
4220 : : }
4221 : 2 : return err;
4222 : : }
4223 : :
4224 : : /****************************************************************************
4225 : : Output InChI: polymer layer, single CRU data
4226 : : ****************************************************************************/
4227 : 2 : static int OutputINCHI_PolymerLayer_SingleUnit(OAD_PolymerUnit *u,
4228 : : int bPolymers,
4229 : : int total_star_atoms,
4230 : : int *n_used_stars,
4231 : : OAD_AtProps *aprops,
4232 : : int *cano_nums,
4233 : : ORIG_ATOM_DATA *orig_inp_data,
4234 : : ORIG_STRUCT *pOrigStruct,
4235 : : INCHI_IOS_STRING *strbuf)
4236 : : {
4237 : 2 : int j, k, tmp, a1 = 0, a2 = 0, a3 = 0, a4 = 0, b, curr_star_num;
4238 : 2 : int err = 0;
4239 : 2 : OAD_Polymer *p = orig_inp_data->polymer;
4240 : 2 : inp_ATOM *at = orig_inp_data->at;
4241 : :
4242 : : /* print unit type and subtype */
4243 : 2 : inchi_strbuf_printf(strbuf, "%-d%-d%-d-", u->type, u->subtype, u->conn);
4244 : :
4245 : : /* print unit atoms */
4246 : 2 : print_sequence_of_nums_compressing_ranges(u->na, u->alist, strbuf);
4247 : :
4248 : : /* Print the crossing bonds or frame-shiftable pattern */
4249 [ - + ]: 2 : if (u->nb > 2)
4250 : : {
4251 : : /* not supported yet, too many bonds in SBL */
4252 : 0 : err = 12;
4253 : 0 : goto exit_function;
4254 : : }
4255 : :
4256 : : /* Print crossing bonds "(cap1-partner1,cap2-partner2)" */
4257 [ + - + - : 2 : if (u->nb == 2 && (!u->cyclizable || !u->cyclized))
+ - ]
4258 : 2 : {
4259 : 2 : int swap = 0;
4260 : 2 : a1 = u->blist[0];
4261 : 2 : a2 = u->blist[1];
4262 : 2 : a3 = u->blist[2];
4263 : 2 : a4 = u->blist[3];
4264 : :
4265 [ - + ]: 2 : if (is_in_the_ilist( u->alist, a1, u->na ))
4266 : : {
4267 : 0 : tmp = a2;
4268 : 0 : a2 = a1;
4269 : 0 : a1 = tmp;
4270 : : }
4271 [ - + ]: 2 : if (is_in_the_ilist(u->alist, a3, u->na))
4272 : : {
4273 : 0 : tmp = a4;
4274 : 0 : a4 = a3;
4275 : 0 : a3 = tmp;
4276 : : }
4277 : :
4278 : : /* Always print first the crossing bond pointing to more senior CRU end ("head") */
4279 [ - + ]: 2 : if (bPolymers == POLYMERS_LEGACY)
4280 : : {
4281 : : /* old, v. 1.05 */
4282 : : /* The first printed is the crossing bond with higher canonical number of the cap */
4283 : 0 : swap = a3 < a1;
4284 : : }
4285 : : else
4286 : : {
4287 : : /* new in v. 1.06 */
4288 : : /* The first printed is the crossing bond pointing to more senior CRU end ("head") */
4289 : 2 : swap = (OAD_Polymer_IsFirstAtomRankLower(a2, a4, aprops) == 1);
4290 : : }
4291 : :
4292 [ + - ]: 2 : if (swap)
4293 : : {
4294 : 2 : inchi_strbuf_printf(strbuf, "(%-d-%-d,%-d-%-d)", a3, a4, a1, a2);
4295 : : }
4296 : : else
4297 : : {
4298 : 0 : inchi_strbuf_printf(strbuf, "(%-d-%-d,%-d-%-d)", a1, a2, a3, a4);
4299 : : }
4300 : : }
4301 : :
4302 [ # # # # : 0 : else if (u->nb <= 2 && (u->cyclizable || u->nbkbonds > 0))
# # ]
4303 : : {
4304 : : /* Print frame-shiftable pattern "cap1,cap2-(b1a1,b1a2, b2a1,b2a2, ... )" */
4305 : : /* where b1, b2, ... are CRU bonds potentially invilved in frame shift */
4306 : :
4307 : : /* Get actual star atoms numbers from all-units pool */
4308 : : /* NB: ordered according to already established in units2/unum */
4309 [ # # # # ]: 0 : if (u->cap1 > 0 || u->cap2 > 0)
4310 : : {
4311 : 0 : int n_expl_H = 0, pos = 0;
4312 : 0 : char *sza = pOrigStruct->szAtoms;
4313 [ # # ]: 0 : while (sza[pos])
4314 : : {
4315 [ # # ]: 0 : if (sza[pos] == 'H')
4316 : : {
4317 [ # # # # ]: 0 : if (isupper(UCINT sza[pos + 1]) || !sza[pos + 1]) /* if ( next_c is Uppercase or NUL ) */
4318 : : {
4319 : 0 : n_expl_H++;
4320 : : }
4321 [ # # ]: 0 : if (!sza[pos + 1])
4322 : : {
4323 : 0 : break;
4324 : : }
4325 : : }
4326 : 0 : pos++;
4327 : : }
4328 : :
4329 [ # # ]: 0 : if (u->cap1 > 0)
4330 : : {
4331 : 0 : curr_star_num = pOrigStruct->num_atoms - n_expl_H - total_star_atoms + *n_used_stars + 1;
4332 [ # # ]: 0 : if (curr_star_num > pOrigStruct->num_atoms)
4333 : : {
4334 : 0 : err = 11;
4335 : 0 : goto exit_function;
4336 : : }
4337 : 0 : a1 = curr_star_num;
4338 : 0 : (*n_used_stars)++;
4339 : : }
4340 [ # # ]: 0 : if (u->cap2 > 0)
4341 : : {
4342 : 0 : curr_star_num = pOrigStruct->num_atoms - n_expl_H - total_star_atoms + *n_used_stars + 1;
4343 [ # # ]: 0 : if (curr_star_num > pOrigStruct->num_atoms)
4344 : : {
4345 : 0 : err = 11;
4346 : 0 : goto exit_function;
4347 : : }
4348 : 0 : a2 = curr_star_num;
4349 : 0 : (*n_used_stars)++;
4350 : : }
4351 : : }
4352 : : /* a1 and a2 are number of star atoms associated (but actually */
4353 : : /* disconnected at this moment ) with SRU head and tail atoms */
4354 : 0 : inchi_strbuf_printf(strbuf, "(%-d,%-d-", a1, a2);
4355 : :
4356 [ # # ]: 0 : if (u->cyclizable == CLOSING_SRU_DIRADICAL)
4357 : : {
4358 : 0 : inchi_strbuf_printf(strbuf, "%-d)", u->end_atom1);
4359 : : }
4360 [ # # ]: 0 : else if (u->cyclizable == CLOSING_SRU_HIGHER_ORDER_BOND)
4361 : : {
4362 : 0 : a3 = u->end_atom1;
4363 : 0 : a4 = u->end_atom2;
4364 : 0 : inchi_sort_int_pair_ascending(&a3, &a4);
4365 : : /* if ( a3 > a4 ) { tmp = a4; a4 = a3; a3 = tmp; }*/
4366 : 0 : inchi_strbuf_printf(strbuf, "%-d.%-d)", a3, a4);
4367 : : }
4368 [ # # ]: 0 : else if (u->cyclizable == CLOSING_SRU_RING)
4369 : : {
4370 [ # # ]: 0 : if (u->nbkbonds == 0)
4371 : : {
4372 : : /* last resort */
4373 : 0 : a3 = u->end_atom1;
4374 : 0 : a4 = u->end_atom2;
4375 : 0 : inchi_sort_int_pair_ascending(&a3, &a4);
4376 : : /* if ( a3 > a4 ) { tmp = a4; a4 = a3; a3 = tmp; } */
4377 : 0 : inchi_strbuf_printf(strbuf, "%-d,%-d)", a3, a4);
4378 : : }
4379 : : else
4380 : : {
4381 : : /* Sort all backbone bonds in min-at-number order */
4382 [ # # ]: 0 : for (b = 1; b < u->nbkbonds; b++)
4383 : : {
4384 : 0 : int *tmp_psbond = u->bkbonds[b];
4385 : 0 : j = b - 1;
4386 [ # # # # ]: 0 : while (j >= 0 && IsBondAtomNumsLesser(u->bkbonds[j], tmp_psbond) > 0)
4387 : : {
4388 : 0 : u->bkbonds[j + 1] = u->bkbonds[j];
4389 : 0 : j--;
4390 : : }
4391 : 0 : u->bkbonds[j + 1] = tmp_psbond;
4392 : : }
4393 : :
4394 [ # # # # ]: 0 : if (p->treat == POLYMERS_MODERN || p->treat == POLYMERS_LEGACY_PLUS)
4395 : : {
4396 : : /* was #if DO_POLYMER_FRAME_SHIFT_AT_STRUCT_TO_INCHI_CONVERSION==1 */
4397 : : /* was: OAD_PolymerUnit_ReorderPolymerFrameShiftLinks( u, orig_inp_data, aprops, cano_nums );
4398 : : OAD_Polymer_DebugTrace(p);*/
4399 : :
4400 : : /* Find senior link and move it to the beginning of list
4401 : : If necessary, swap atoms in link so that the first
4402 : : points to SRU head and the next to SRU tail
4403 : :
4404 : : The net result of ordering is as follows:
4405 : : at1,at2, at3,at4, at5,at6, ...
4406 : : here
4407 : : at1, at2 is the most senior bond, and at1 is more senior than at2
4408 : : all other pairs at3,at4, at5,at6, ... are sorted just in increasing
4409 : : order of first number in pair, then second one, e.g.: at3<at4; at3<=at5
4410 : : (and if at3==at5 then at4<at6)
4411 : : */
4412 : :
4413 [ # # # # : 0 : if (p->frame_shift_scheme != FSS_NONE && u->nbkbonds >= 1 && u->cap1 >= 1 && u->cap2 >= 1)
# # # # ]
4414 : : {
4415 [ # # ]: 0 : if (OAD_PolymerUnit_SetReopeningDetails(u, at))
4416 : : {
4417 : : /* Find senior backbone bond and move it to the beginning of list */
4418 : : {
4419 : : int senior_bond, bond0at1, bond0at2;
4420 : 0 : OAD_PolymerUnit_SortBackboneBondsAndSetSeniors(u, at, aprops, &senior_bond);
4421 [ # # ]: 0 : if (senior_bond)
4422 : : {
4423 : 0 : bond0at1 = u->bkbonds[0][0];
4424 : 0 : bond0at2 = u->bkbonds[0][1];
4425 : 0 : u->bkbonds[0][0] = u->bkbonds[senior_bond][0];
4426 : 0 : u->bkbonds[0][1] = u->bkbonds[senior_bond][1];
4427 : 0 : u->end_atom1 = u->bkbonds[0][0];
4428 : 0 : u->end_atom2 = u->bkbonds[0][1];
4429 : 0 : u->bkbonds[senior_bond][0] = bond0at1;
4430 : 0 : u->bkbonds[senior_bond][1] = bond0at2;
4431 : : }
4432 : : }
4433 : : }
4434 : : }
4435 : : /* p->really_do_frame_shift = 0; */
4436 : : }
4437 : :
4438 [ # # ]: 0 : for (k = 0; k < u->nbkbonds; k++)
4439 : : {
4440 : 0 : a3 = u->bkbonds[k][0];
4441 : 0 : a4 = u->bkbonds[k][1];
4442 : : /*if ( a3 > a4 ) { tmp = a4; a4 = a3; a3 = tmp; }*/
4443 [ # # ]: 0 : inchi_strbuf_printf(strbuf, "%-d,%-d%-c", a3, a4, k == u->nbkbonds - 1 ? ')' : ',');
4444 : : }
4445 : : }
4446 : : }
4447 : : }
4448 : :
4449 : 0 : exit_function:
4450 : :
4451 : 2 : return err;
4452 : : }
4453 : :
4454 : : /****************************************************************************
4455 : : Output AuxInfo: header and normalization type
4456 : : ****************************************************************************/
4457 : 122 : int OutputAUXINFO_HeaderAndNormalization_type(CANON_GLOBALS *pCG,
4458 : : INCHI_IOSTREAM *out_file,
4459 : : INCHI_IOS_STRING *strbuf,
4460 : : int bINChIOutputOptions,
4461 : : int *INCHI_basic_or_INCHI_reconnected,
4462 : : int num_components2[],
4463 : : INCHI_OUT_CTL *io,
4464 : : char *pLF,
4465 : : char *pTAB)
4466 : : {
4467 : : /* AuxInfo header */
4468 [ + - ]: 122 : if (*INCHI_basic_or_INCHI_reconnected == INCHI_BAS)
4469 : : {
4470 : 122 : inchi_strbuf_printf(strbuf, "AuxInfo="); /* in wINChI window, separate INChI: from AuxInfo: with blank line */
4471 : 122 : inchi_ios_print(out_file, "%s%s%s",
4472 : : /* blank line before AuxInfo in winchi window unless it is an annotation */
4473 [ - + ]: 122 : (bINChIOutputOptions & INCHI_OUT_WINCHI_WINDOW) ? "\n" : "",
4474 : : strbuf->pStr, pLF);
4475 : 122 : szGetTag(AuxLbl, io->nTag, io->bTag1 = AL_VERS, io->szTag1, &io->bAlways, 0);
4476 : 122 : inchi_strbuf_reset(strbuf);
4477 : 122 : io->tot_len = 0;
4478 : 122 : inchi_strbuf_printf(strbuf, "%s", x_curr_ver);
4479 : : /* avoid leading slash in plain output */
4480 [ - + ]: 122 : if (str_LineEnd(io->szTag1, &io->bOverflow, strbuf, -1, io->bPlainTextTags))
4481 : : {
4482 : 0 : return 1;
4483 : : }
4484 : 122 : inchi_ios_print(out_file, "%s%s", strbuf->pStr, pLF);
4485 : : }
4486 : : else
4487 : : {
4488 [ # # ]: 0 : if (*INCHI_basic_or_INCHI_reconnected == INCHI_REC)
4489 : : {
4490 : 0 : szGetTag(AuxLbl, io->nTag, io->bTag1 = AL_REC_, io->szTag1, &io->bAlways, 0);
4491 : 0 : inchi_ios_print(out_file, "%s%s", io->szTag1, pLF);
4492 : : }
4493 : : }
4494 : :
4495 : : /* AuxInfo normalization type */
4496 [ - + - - ]: 122 : if (num_components2[0] || num_components2[1])
4497 : : {
4498 : 122 : szGetTag(AuxLbl, io->nTag, io->bTag1 = AL_NORM, io->szTag1, &io->bAlways, 0);
4499 : 122 : inchi_strbuf_reset(strbuf);
4500 : 122 : io->tot_len = 0;
4501 [ + + + - ]: 122 : inchi_strbuf_printf(strbuf, "%d", (io->bTautomeric && io->bTautomericOutputAllowed) ? io->bTautomeric : 0);
4502 [ - + ]: 122 : if (str_LineEnd(io->szTag1, &io->bOverflow, strbuf, -1, io->bPlainTextTags))
4503 : : {
4504 : 0 : return 1;
4505 : : }
4506 : 122 : inchi_ios_print(out_file, "%s%s", strbuf->pStr, pLF);
4507 : : }
4508 : :
4509 : 122 : return 0;
4510 : : }
4511 : :
4512 : : /****************************************************************************
4513 : : Output AuxInfo: original atom numbers and symmetry numbers (constit. equivalence /E: )
4514 : : ****************************************************************************/
4515 : 122 : int OutputAUXINFO_OriginalNumbersAndEquivalenceClasses(CANON_GLOBALS *pCG,
4516 : : INCHI_IOSTREAM *out_file,
4517 : : INCHI_IOS_STRING *strbuf,
4518 : : int num_components2[],
4519 : : INCHI_OUT_CTL *io,
4520 : : char *pLF,
4521 : : char *pTAB)
4522 : : {
4523 : : /* Original atom numbers in order of canonical numbers */
4524 [ - + - - ]: 122 : if (num_components2[0] || num_components2[1])
4525 : : {
4526 : 244 : szGetTag(AuxLbl, io->nTag,
4527 [ - + ]: 122 : io->bTag1 = (io->bSecondNonTautPass ? AL_FIXN : AL_ANBR) | io->bFhTag, io->szTag1, &io->bAlways, 0);
4528 : 122 : inchi_strbuf_reset(strbuf);
4529 : 122 : io->tot_len = 0;
4530 : : /* Original numbering output */
4531 : 122 : io->tot_len = str_AuxNumb(pCG, io->pINChISort, io->pINChISort2,
4532 : : strbuf, &io->bOverflow,
4533 : : io->bOutType, io->TAUT_MODE, io->num_components,
4534 : : io->bSecondNonTautPass, io->bOmitRepetitions);
4535 : :
4536 [ - + ]: 122 : if (str_LineEnd(io->szTag1, &io->bOverflow, strbuf, -1, io->bPlainTextTags))
4537 : : {
4538 : 0 : return 1;
4539 : : }
4540 : 122 : inchi_ios_print(out_file, "%s%s", strbuf->pStr, pLF);
4541 : : }
4542 : :
4543 : : /*
4544 : : Symmetry numbers (constit. equivalence) /E:
4545 : : */
4546 [ + + ]: 122 : if (io->bAtomEqu[io->iCurTautMode])
4547 : : {
4548 : : /* aux equ atoms */
4549 : : /* 1. Compare to tautomeric equivalence (in case of second, non-taut, pass only) */
4550 : : /* 2. Compare to the previous component if (1) failed to find equivalence */
4551 : 21 : szGetTag(AuxLbl, io->nTag, io->bTag1 = AL_AEQU | io->bFhTag, io->szTag1, &io->bAlways, 0);
4552 : 21 : inchi_strbuf_reset(strbuf);
4553 : 21 : io->tot_len = 0;
4554 : 21 : io->tot_len = str_AuxEqu(io->pINChISort, io->pINChISort2,
4555 : : strbuf, &io->bOverflow, io->bOutType, io->TAUT_MODE,
4556 : : io->num_components, io->bSecondNonTautPass,
4557 : : io->bOmitRepetitions, io->bUseMulipliers);
4558 : :
4559 [ - + ]: 21 : if (str_LineEnd(io->szTag1, &io->bOverflow, strbuf, -1, io->bPlainTextTags))
4560 : : {
4561 : 0 : return 1;
4562 : : }
4563 : 21 : inchi_ios_print(out_file, "%s%s", strbuf->pStr, pLF);
4564 : : }
4565 : : else
4566 : : {
4567 [ - + ]: 101 : if (io->bPlainTextTags == 1)
4568 : : {
4569 : 0 : inchi_ios_print(out_file, "/");
4570 : : }
4571 : : }
4572 : :
4573 : 122 : return 0;
4574 : : }
4575 : :
4576 : : /****************************************************************************
4577 : : Output AuxInfo: tautomeric groups equivalence
4578 : : ****************************************************************************/
4579 : 122 : int OutputAUXINFO_TautomericGroupsEquivalence(CANON_GLOBALS *pCG,
4580 : : INCHI_IOSTREAM *out_file,
4581 : : INCHI_IOS_STRING *strbuf,
4582 : : INCHI_OUT_CTL *io)
4583 : : {
4584 [ + - + + : 122 : if (io->bTautomericOutputAllowed && io->bTautomeric && io->bTautEqu[io->iCurTautMode] && !io->bSecondNonTautPass)
+ + + - ]
4585 : : {
4586 : : /*-- Tautomeric groups constitutional equivalence */
4587 : :
4588 : : /*-- aux tgroup equ */
4589 : 2 : szGetTag(AuxLbl, io->nTag, io->bTag1 = AL_GEQU | io->bFhTag, io->szTag1, &io->bAlways, 0);
4590 : 2 : inchi_strbuf_reset(strbuf);
4591 : 2 : io->tot_len = 0;
4592 : 2 : io->tot_len = str_AuxTgroupEqu(io->pINChISort,
4593 : : strbuf, &io->bOverflow, io->bOutType, io->TAUT_MODE,
4594 : : io->num_components, io->bUseMulipliers);
4595 [ - + ]: 2 : if (str_LineEnd(io->szTag1, &io->bOverflow, strbuf, -1, io->bPlainTextTags))
4596 : : {
4597 : 0 : return 1;
4598 : : }
4599 : 2 : inchi_ios_print(out_file, "%s", strbuf->pStr);
4600 : : }
4601 : : else
4602 : : {
4603 [ + - + + ]: 120 : if (io->bTautomericOutputAllowed && io->bTautomeric)
4604 : : {
4605 [ - + ]: 9 : if (io->bPlainTextTags == 1)
4606 : : {
4607 : 0 : inchi_ios_print(out_file, "/");
4608 : : }
4609 : : }
4610 : : }
4611 : :
4612 : 122 : return 0;
4613 : : }
4614 : :
4615 : : /****************************************************************************
4616 : : Output AuxInfo: stereo info
4617 : : ****************************************************************************/
4618 : 122 : int OutputAUXINFO_Stereo(CANON_GLOBALS *pCG,
4619 : : INCHI_IOSTREAM *out_file,
4620 : : INCHI_IOS_STRING *strbuf,
4621 : : INCHI_OUT_CTL *io,
4622 : : char *pLF,
4623 : : char *pTAB)
4624 : : {
4625 : : /*-- Inverted stereo -- sp3 only + canonical numbering
4626 : : */
4627 [ + + ]: 122 : if (io->bInvStereo[io->iCurTautMode])
4628 : : {
4629 : 42 : szGetTag(AuxLbl, io->nTag, io->bTag1 = AL_STER | io->bFhTag, io->szTag1, &io->bAlways, 0);
4630 : : /*-- inverted sp3 start tag */
4631 : 42 : szGetTag(AuxLbl, io->nTag, io->bTag2 = io->bTag1 | AL_SP3I, io->szTag2, &io->bAlways, 0);
4632 : 42 : inchi_strbuf_reset(strbuf);
4633 : 42 : io->tot_len = 0;
4634 : 42 : io->tot_len = str_AuxInvSp3(io->pINChISort, io->pINChISort2, strbuf,
4635 : : &io->bOverflow, io->bOutType, io->TAUT_MODE, io->num_components,
4636 : : io->bSecondNonTautPass, io->bOmitRepetitions, io->bUseMulipliers);
4637 [ - + ]: 42 : if (str_LineEnd(io->szTag2, &io->bOverflow, strbuf, -1, io->bPlainTextTags))
4638 : 0 : return 1;
4639 : 42 : inchi_ios_print(out_file, "%s%s", strbuf->pStr, pLF);
4640 : :
4641 : : /*-- inverted sp3 canonical numbering */
4642 [ - + ]: 42 : if (io->bInvStereoOrigNumb[io->iCurTautMode])
4643 : : {
4644 : 0 : szGetTag(AuxLbl, io->nTag, io->bTag2 = io->bTag1 | AL_SP3N, io->szTag2, &io->bAlways, 0);
4645 : 0 : inchi_strbuf_reset(strbuf);
4646 : 0 : io->tot_len = 0;
4647 : :
4648 : 0 : io->tot_len = str_AuxInvSp3Numb(pCG, io->pINChISort, io->pINChISort2,
4649 : : strbuf, &io->bOverflow, io->bOutType,
4650 : : io->TAUT_MODE, io->num_components,
4651 : : io->bSecondNonTautPass, io->bOmitRepetitions);
4652 : :
4653 [ # # ]: 0 : if (str_LineEnd(io->szTag2, &io->bOverflow, strbuf, -1, io->bPlainTextTags))
4654 : : {
4655 : 0 : return 1;
4656 : : }
4657 : 0 : inchi_ios_print(out_file, "%s%s", strbuf->pStr, pLF);
4658 : : }
4659 : : else
4660 : : {
4661 [ - + ]: 42 : if (io->bPlainTextTags == 1)
4662 : 0 : inchi_ios_print(out_file, "/");
4663 : : }
4664 : : }
4665 : : else
4666 : : {
4667 [ - + ]: 80 : if (io->bPlainTextTags == 1)
4668 : : {
4669 : 0 : inchi_ios_print(out_file, "//");
4670 : : }
4671 : : /* Inverted stereo -- sp3 only + canonical numbering */
4672 : : }
4673 : :
4674 : 122 : return 0;
4675 : : }
4676 : :
4677 : : /****************************************************************************
4678 : : Output AuxInfo: isotopic info
4679 : : ****************************************************************************/
4680 : 122 : int OutputAUXINFO_IsotopicInfo(CANON_GLOBALS *pCG,
4681 : : INCHI_IOSTREAM *out_file,
4682 : : INCHI_IOS_STRING *strbuf,
4683 : : int *INCHI_basic_or_INCHI_reconnected,
4684 : : INCHI_OUT_CTL *io,
4685 : : char *pLF,
4686 : : char *pTAB)
4687 : : {
4688 : : int i;
4689 : :
4690 : : /* if InChI Fixed-H isotopic is empty, then do not output corresponding AuxInfo */
4691 : :
4692 [ - + ]: 122 : i = io->bSecondNonTautPass &&
4693 [ # # # # ]: 0 : (*io->pSortPrintINChIFlags & ((*INCHI_basic_or_INCHI_reconnected == INCHI_BAS) ? FLAG_SORT_PRINT_NO_IFIX_H_BAS : FLAG_SORT_PRINT_NO_IFIX_H_REC));
4694 : :
4695 [ - + - - ]: 122 : if (io->bIsotopic && !i &&
4696 [ # # ]: 0 : (io->bIsotopicOrigNumb[io->iCurTautMode] ||
4697 [ # # ]: 0 : io->bIsotopicAtomEqu[io->iCurTautMode] ||
4698 [ # # # # : 0 : (io->bTautomericOutputAllowed && io->bTautomeric && io->bIsotopicTautEqu[io->iCurTautMode]) ||
# # ]
4699 [ # # # # : 0 : (io->bInvIsotopicStereo[io->iCurTautMode] && (io->bIgn_UU_Sp3_Iso[io->iCurTautMode])) || io->bIgn_UU_Sp2_Iso[io->iCurTautMode])) /* djb-rwth: addressing LLVM warnings */
# # ]
4700 : : {
4701 : : /*-- isotopic aux info header */
4702 : 0 : szGetTag(AuxLbl, io->nTag, io->bTag1 = AL_ISOT | io->bFhTag, io->szTag1, &io->bAlways, 0);
4703 : 0 : inchi_strbuf_reset(strbuf); /* pStr[io->tot_len = 0] = '\0'; */
4704 : : /*-- Original atom numbers in order of isotopic canonical numbers */
4705 : 0 : szGetTag(AuxLbl, io->nTag, io->bTag2 = io->bTag1 | AL_ISON, io->szTag2, &io->bAlways, 0);
4706 [ # # ]: 0 : if (io->bIsotopicOrigNumb[io->iCurTautMode])
4707 : : {
4708 : 0 : inchi_strbuf_reset(strbuf);
4709 : 0 : io->tot_len = 0;
4710 : 0 : io->tot_len = str_AuxIsoNumb(pCG, io->pINChISort, io->pINChISort2,
4711 : : strbuf, &io->bOverflow, io->bOutType,
4712 : : io->TAUT_MODE, io->num_components,
4713 : : io->bSecondNonTautPass, io->bOmitRepetitions);
4714 [ # # ]: 0 : if (str_LineEnd(io->szTag2, &io->bOverflow, strbuf, -1, io->bPlainTextTags))
4715 : : {
4716 : 0 : return 1;
4717 : : }
4718 : 0 : inchi_ios_print(out_file, "%s%s", strbuf->pStr, pLF);
4719 : : }
4720 : : else
4721 : : {
4722 : : /*if ( io->bPlainTextTags == 1 ) inchi_ios_print( out_file, "/" );*/
4723 : 0 : inchi_ios_print(out_file, "%s%s", io->szTag2, pLF); /* mark isotopic output */
4724 : : }
4725 : :
4726 : : /*-- Isotopic symmetry */
4727 [ # # ]: 0 : if (io->bIsotopicAtomEqu[io->iCurTautMode])
4728 : : {
4729 : : /*-- atoms */
4730 : 0 : szGetTag(AuxLbl, io->nTag, io->bTag2 = io->bTag1 | AL_AEQU, io->szTag2, &io->bAlways, 0);
4731 : 0 : inchi_strbuf_reset(strbuf);
4732 : 0 : io->tot_len = 0;
4733 : 0 : io->tot_len = str_AuxIsoEqu(io->pINChISort, io->pINChISort2,
4734 : : strbuf,
4735 : : &io->bOverflow, io->bOutType, io->TAUT_MODE, io->num_components,
4736 : : io->bSecondNonTautPass, io->bOmitRepetitions, io->bUseMulipliers);
4737 [ # # ]: 0 : if (str_LineEnd(io->szTag2, &io->bOverflow, strbuf, -2 /*was -1: Fix15*/, io->bPlainTextTags))
4738 : : {
4739 : 0 : return 1;
4740 : : }
4741 : 0 : inchi_ios_print(out_file, "%s%s", strbuf->pStr, pLF);
4742 : : }
4743 : : else
4744 : : {
4745 [ # # ]: 0 : if (io->bPlainTextTags == 1)
4746 : : {
4747 : 0 : inchi_ios_print(out_file, "/");
4748 : : }
4749 : : }
4750 : :
4751 : : /*-- Tautomeric groups, isotopic */
4752 [ # # # # : 0 : if (io->bTautomericOutputAllowed && io->bTautomeric && io->bIsotopicTautEqu[io->iCurTautMode])
# # ]
4753 : : {
4754 : : /*-- Isotopic tautomeric groups equivalence */
4755 : 0 : szGetTag(AuxLbl, io->nTag, io->bTag2 = io->bTag1 | AL_GEQU, io->szTag2, &io->bAlways, 0);
4756 : 0 : inchi_strbuf_reset(strbuf);
4757 : 0 : io->tot_len = 0;
4758 : 0 : io->tot_len = str_AuxIsoTgroupEqu(io->pINChISort,
4759 : : strbuf, &io->bOverflow,
4760 : : io->bOutType, io->TAUT_MODE, io->num_components,
4761 : : io->bOmitRepetitions, io->bUseMulipliers);
4762 [ # # ]: 0 : if (str_LineEnd(io->szTag2, &io->bOverflow, strbuf, -2 /*was -1: Fix15*/, io->bPlainTextTags))
4763 : : {
4764 : 0 : return 1;
4765 : : }
4766 : 0 : inchi_ios_print(out_file, "%s%s", strbuf->pStr, pLF);
4767 : : }
4768 : : else
4769 : : {
4770 [ # # # # ]: 0 : if (io->bTautomericOutputAllowed && io->bTautomeric)
4771 : : {
4772 [ # # ]: 0 : if (io->bPlainTextTags == 1)
4773 : : {
4774 : 0 : inchi_ios_print(out_file, "/");
4775 : : }
4776 : : }
4777 : : }
4778 : : /*-- Isotopic inverted stereo */
4779 [ # # ]: 0 : if (io->bInvIsotopicStereo[io->iCurTautMode])
4780 : : {
4781 : 0 : szGetTag(AuxLbl, io->nTag, io->bTag2 = io->bTag1 | AL_STER, io->szTag2, &io->bAlways, 0);
4782 : : /*-- inverted isotopic sp3 start tag */
4783 : 0 : szGetTag(AuxLbl, io->nTag, io->bTag3 = io->bTag2 | AL_SP3I, io->szTag3, &io->bAlways, 0);
4784 : 0 : inchi_strbuf_reset(strbuf);
4785 : 0 : io->tot_len = 0;
4786 : 0 : io->tot_len = str_AuxInvIsoSp3(io->pINChISort, io->pINChISort2,
4787 : : strbuf, &io->bOverflow,
4788 : : io->bOutType, io->TAUT_MODE, io->num_components,
4789 : : io->bSecondNonTautPass, io->bOmitRepetitions, io->bUseMulipliers);
4790 [ # # ]: 0 : if (str_LineEnd(io->szTag3, &io->bOverflow, strbuf, -1, io->bPlainTextTags))
4791 : : {
4792 : 0 : return 1;
4793 : : }
4794 : 0 : inchi_ios_print(out_file, "%s", strbuf->pStr);
4795 : : /*-- inverted isotopic sp3 canonical numbering */
4796 [ # # ]: 0 : if (io->bInvIsotopicStereoOrigNumb[io->iCurTautMode])
4797 : : {
4798 : 0 : szGetTag(AuxLbl, io->nTag, io->bTag3 = io->bTag2 | AL_SP3N, io->szTag3, &io->bAlways, 0);
4799 : 0 : inchi_strbuf_reset(strbuf);
4800 : 0 : io->tot_len = 0;
4801 : 0 : io->tot_len = str_AuxInvIsoSp3Numb(pCG, io->pINChISort, io->pINChISort2,
4802 : : strbuf, &io->bOverflow,
4803 : : io->bOutType, io->TAUT_MODE,
4804 : : io->num_components,
4805 : : io->bSecondNonTautPass,
4806 : : io->bOmitRepetitions);
4807 : :
4808 [ # # ]: 0 : if (str_LineEnd(io->szTag3, &io->bOverflow, strbuf, -1, io->bPlainTextTags))
4809 : : {
4810 : 0 : return 1;
4811 : : }
4812 : 0 : inchi_ios_print(out_file, "%s%s", strbuf->pStr, pLF);
4813 : : }
4814 : : else
4815 : : {
4816 [ # # ]: 0 : if (io->bPlainTextTags == 1)
4817 : : {
4818 : 0 : inchi_ios_print(out_file, "/");
4819 : : }
4820 : : }
4821 : : }
4822 : : else
4823 : : {
4824 [ # # ]: 0 : if (io->bPlainTextTags == 1)
4825 : : {
4826 : 0 : inchi_ios_print(out_file, "//");
4827 : : }
4828 : : }
4829 : : /*-- totally omitted undefined/unknown isotopic stereo */
4830 : : } /* Aux info isotopic */
4831 : :
4832 : 122 : return 0;
4833 : : }
4834 : :
4835 : : /****************************************************************************
4836 : : Output AuxInfo: charges, radicals, unusual valences
4837 : : ****************************************************************************/
4838 : 122 : int OutputAUXINFO_ChargesRadicalsAndUnusualValences(CANON_GLOBALS *pCG,
4839 : : INCHI_IOSTREAM *out_file,
4840 : : INCHI_IOS_STRING *strbuf,
4841 : : INCHI_OUT_CTL *io,
4842 : : char *pLF,
4843 : : char *pTAB)
4844 : : {
4845 [ + - + + ]: 122 : if (!io->bSecondNonTautPass && io->bChargesRadVal[io->iCurTautMode])
4846 : : {
4847 : : /* aux equ atoms */
4848 : : /* 1. Compare to tautomeric equivalence (in case of second, non-taut, pass only) */
4849 : : /* 2. Compare to the previous component if (1) failed to find equivalence */
4850 : 11 : szGetTag(AuxLbl, io->nTag, io->bTag1 = AL_CRV_ | io->bFhTag, io->szTag1, &io->bAlways, 0);
4851 : :
4852 : 11 : inchi_strbuf_reset(strbuf);
4853 : 11 : io->tot_len = 0;
4854 : :
4855 : 11 : io->tot_len = str_AuxChargeRadVal(io->pINChISort, strbuf,
4856 : : &io->bOverflow, io->bOutType, io->TAUT_MODE,
4857 : : io->num_components, io->bUseMulipliers);
4858 : :
4859 [ - + ]: 11 : if (str_LineEnd(io->szTag1, &io->bOverflow, strbuf, -1, io->bPlainTextTags))
4860 : : {
4861 : 0 : return 1;
4862 : : }
4863 : :
4864 : 11 : inchi_ios_print(out_file, "%s%s", strbuf->pStr, pLF);
4865 : : }
4866 : :
4867 : 122 : return 0;
4868 : : }
4869 : :
4870 : : /****************************************************************************
4871 : : Output AuxInfo: reversibility info (to restore orig. structure)
4872 : : ****************************************************************************/
4873 : 122 : int OutputAUXINFO_ReversibilityInfo(CANON_GLOBALS *pCG,
4874 : : INCHI_IOSTREAM *out_file,
4875 : : INCHI_IOS_STRING *strbuf,
4876 : : ORIG_STRUCT *pOrigStruct,
4877 : : INCHI_OUT_CTL *io,
4878 : : char *pLF,
4879 : : char *pTAB)
4880 : : {
4881 [ + - + - ]: 122 : if (!io->bSecondNonTautPass &&
4882 [ + - ]: 122 : pOrigStruct && pOrigStruct->num_atoms &&
4883 [ + - + - : 122 : pOrigStruct->szAtoms && pOrigStruct->szBonds && pOrigStruct->szCoord)
+ - ]
4884 : : {
4885 : : int length, cur_pos, line_len, last_pos, nMaxLineLen;
4886 : : char *p;
4887 : 122 : nMaxLineLen = inchi_min(80, strbuf->nAllocatedLength); /* restrict line length to 80 characters */
4888 : :
4889 : 122 : szGetTag(AuxLbl, io->nTag, io->bTag1 = AL_REVR | io->bFhTag, io->szTag1, &io->bAlways, 0);
4890 : :
4891 : : /* Atoms /A: */
4892 : 122 : szGetTag(AuxLbl, io->nTag, io->bTag2 = io->bTag1 | AL_ATMR, io->szTag2, &io->bAlways, 0);
4893 : 122 : inchi_strbuf_reset(strbuf);
4894 : 122 : inchi_ios_print(out_file, "%s%s", io->szTag2, strbuf->pStr);
4895 : 122 : p = pOrigStruct->szAtoms;
4896 : 122 : length = (int)strlen(p);
4897 : 122 : io->tot_len = strbuf->nUsedLength;
4898 : 122 : line_len = nMaxLineLen - io->tot_len;
4899 [ + + ]: 244 : for (cur_pos = 0; cur_pos < length; cur_pos = last_pos)
4900 : : {
4901 [ - + ]: 122 : if (length - cur_pos >= line_len)
4902 : : {
4903 : 0 : last_pos = cur_pos + line_len;
4904 : : /* search backward for the nearest first atom letter (always uppercase) */
4905 [ # # # # ]: 0 : while (cur_pos < last_pos && !isupper(UCINT p[last_pos]))
4906 : : {
4907 : 0 : last_pos--;
4908 : : }
4909 : : }
4910 : : else
4911 : : {
4912 : 122 : last_pos = length;
4913 : : }
4914 [ + - ]: 122 : if (last_pos > cur_pos)
4915 : : {
4916 : 122 : memcpy(strbuf->pStr + strbuf->nUsedLength, p + cur_pos, (long long)last_pos - (long long)cur_pos); /* djb-rwth: cast operators added */
4917 : 122 : strbuf->pStr[strbuf->nUsedLength + last_pos - cur_pos] = '\0';
4918 : : /*strbuf->nUsedLength = strbuf->nUsedLength + last_pos - cur_pos;*/
4919 : :
4920 : : if (1) /* always show "Zy" as "Zz" */
4921 : : {
4922 : 122 : char *pzy, *pstart = strbuf->pStr + strbuf->nUsedLength;
4923 [ - + ]: 122 : while ((pzy = strstr(pstart, "Zy"))) /* djb-rwth: addressing LLVM warning */
4924 : : {
4925 : 0 : *(++pzy) = 'z';
4926 : 0 : pstart = pzy;
4927 : : }
4928 : : }
4929 : :
4930 [ + - ]: 122 : inchi_ios_print(out_file, "%s%s", strbuf->pStr, io->bPlainTextTags ? "" : "\n");
4931 : : }
4932 : : else
4933 : : {
4934 : 0 : break;
4935 : : }
4936 : : }
4937 [ - + ]: 122 : if (pLF[0])
4938 : : {
4939 : 0 : inchi_ios_print(out_file, "%s", pLF);
4940 : : }
4941 : :
4942 : 122 : inchi_strbuf_reset(strbuf);
4943 : :
4944 : : /* Bonds /B: */
4945 : 122 : szGetTag(AuxLbl, io->nTag, io->bTag2 = io->bTag1 | AL_BNDR, io->szTag2, &io->bAlways, 0);
4946 : 122 : inchi_strbuf_reset(strbuf);
4947 : 122 : inchi_ios_print(out_file, "%s%s", io->szTag2, strbuf->pStr);
4948 : :
4949 : 122 : p = pOrigStruct->szBonds;
4950 : 122 : length = (int)strlen(p);
4951 : 122 : line_len = nMaxLineLen - io->tot_len;
4952 [ + + ]: 205 : for (cur_pos = 0; cur_pos < length; cur_pos = last_pos)
4953 : : {
4954 [ + + ]: 83 : if (length - cur_pos >= line_len)
4955 : : {
4956 : 9 : last_pos = cur_pos + line_len - 1;
4957 : : /* search backward for the nearest first bond delimiter ";" */
4958 [ + - + + ]: 28 : while (cur_pos < last_pos && p[last_pos] != ';')
4959 : : {
4960 : 19 : last_pos--;
4961 : : }
4962 [ + - ]: 9 : if (cur_pos < last_pos)
4963 : : {
4964 : 9 : last_pos++; /* include ';' at the end of the line */
4965 : : }
4966 : : }
4967 : : else
4968 : : {
4969 : 74 : last_pos = length;
4970 : : }
4971 [ + - ]: 83 : if (last_pos > cur_pos)
4972 : : {
4973 : 83 : memcpy(strbuf->pStr, p + cur_pos, (long long)last_pos - (long long)cur_pos); /* djb-rwth: cast operators added */
4974 : 83 : strbuf->pStr[last_pos - cur_pos] = '\0';
4975 : 83 : strbuf->nUsedLength = last_pos - cur_pos;
4976 [ + - ]: 83 : inchi_ios_print(out_file, "%s%s", strbuf->pStr, io->bPlainTextTags ? "" : "\n");
4977 : 83 : inchi_strbuf_reset(strbuf);
4978 : : }
4979 : : else
4980 : : {
4981 : 0 : break;
4982 : : }
4983 : : }
4984 [ - + ]: 122 : if (pLF[0])
4985 : : {
4986 : 0 : inchi_ios_print(out_file, "%s", pLF);
4987 : : }
4988 : :
4989 : : /* Coordinates /C: */
4990 : 122 : szGetTag(AuxLbl, io->nTag, io->bTag2 = io->bTag1 | AL_XYZR, io->szTag2, &io->bAlways, 0);
4991 : 122 : inchi_strbuf_reset(strbuf);
4992 : 122 : inchi_ios_print(out_file, "%s%s", io->szTag2, strbuf->pStr);
4993 : :
4994 : 122 : p = pOrigStruct->szCoord;
4995 : 122 : length = (int)strlen(p);
4996 : 122 : line_len = nMaxLineLen - io->tot_len;
4997 [ + + ]: 390 : for (cur_pos = 0; cur_pos < length; cur_pos = last_pos)
4998 : : {
4999 [ + + ]: 268 : if (length - cur_pos >= line_len)
5000 : : {
5001 : 146 : last_pos = cur_pos + line_len - 1;
5002 : : /* search backward for the nearest first coord. delimiter ";" */
5003 [ + - + + ]: 1124 : while (cur_pos < last_pos && p[last_pos] != ';')
5004 : : {
5005 : 978 : last_pos--;
5006 : : }
5007 [ + - ]: 146 : if (cur_pos < last_pos)
5008 : : {
5009 : 146 : last_pos++; /* include ';' at the end of the line */
5010 : : }
5011 : : }
5012 : : else
5013 : : {
5014 : 122 : last_pos = length;
5015 : : }
5016 [ + - ]: 268 : if (last_pos > cur_pos)
5017 : : {
5018 : 268 : memcpy(strbuf->pStr, p + cur_pos, (long long)last_pos - (long long)cur_pos); /* djb-rwth: cast operator added */
5019 : 268 : strbuf->pStr[last_pos - cur_pos] = '\0';
5020 : 268 : strbuf->nUsedLength = last_pos - cur_pos;
5021 [ + - ]: 268 : inchi_ios_print(out_file, "%s%s", strbuf->pStr, io->bPlainTextTags ? "" : "\n");
5022 : 268 : inchi_strbuf_reset(strbuf);
5023 : : }
5024 : : else
5025 : : {
5026 : 0 : break;
5027 : : }
5028 : : }
5029 : :
5030 [ - + ]: 122 : if (pLF[0])
5031 : : {
5032 : 0 : inchi_ios_print(out_file, "%s", pLF);
5033 : : }
5034 : : }
5035 : :
5036 : 122 : return 0;
5037 : : }
5038 : :
5039 : : /****************************************************************************/
5040 : 122 : int OutputAUXINFO_PolymerInfo(CANON_GLOBALS *pCG,
5041 : : INCHI_IOSTREAM *out_file,
5042 : : INCHI_IOS_STRING *strbuf,
5043 : : ORIG_STRUCT *pOrigStruct,
5044 : : INCHI_OUT_CTL *io,
5045 : : char *pLF,
5046 : : char *pTAB)
5047 : : {
5048 : : int k, i, q;
5049 : : OAD_Polymer *p;
5050 : : OAD_PolymerUnit *u;
5051 : :
5052 [ - + ]: 122 : if (!pOrigStruct)
5053 : : {
5054 : 0 : return 0;
5055 : : }
5056 : 122 : p = pOrigStruct->polymer;
5057 [ + + ]: 122 : if (!p)
5058 : : {
5059 : 120 : return 0;
5060 : : }
5061 : :
5062 : 2 : inchi_strbuf_reset(strbuf);
5063 : :
5064 : 2 : inchi_ios_print(out_file, "/Z:");
5065 : :
5066 : : /* Print polymer units data */
5067 [ + + ]: 4 : for (i = 0; i < p->n; i++)
5068 : : {
5069 : : /* For each unit u ... */
5070 : 2 : u = p->units[i];
5071 : :
5072 : : /* print kinds of unit */
5073 : 2 : inchi_strbuf_printf(strbuf, "%-d%-d%-d-", u->type, u->subtype, u->conn);
5074 [ + - ]: 2 : inchi_strbuf_printf(strbuf, "%-s-", u->smt[0] ? u->smt : "n");
5075 : :
5076 : : /* Print unit atoms */
5077 : 2 : print_sequence_of_nums_compressing_ranges(u->na, u->alist, strbuf);
5078 : :
5079 : : /* Print bonds from unit to otside */
5080 [ + - ]: 2 : if (u->nb > 0)
5081 : : {
5082 : 2 : inchi_strbuf_printf(strbuf, "(");
5083 [ + + ]: 8 : for (k = 0; k < 2 * u->nb - 1; k++)
5084 : : {
5085 : 6 : inchi_strbuf_printf(strbuf, "%-d,", u->blist[k]);
5086 : : }
5087 : 2 : inchi_strbuf_printf(strbuf, "%-d)", u->blist[2 * u->nb - 1]);
5088 : : }
5089 : :
5090 [ + - ]: 2 : if (fabs(-fabs(u->xbr1[0]) + 777777.777) > 1.e-7)
5091 : : {
5092 : 2 : inchi_strbuf_printf(strbuf, "[");
5093 [ + + ]: 8 : for (q = 0; q < 3; q++)
5094 : : {
5095 : 6 : inchi_strbuf_printf(strbuf, "%-f,", u->xbr1[q]);
5096 : : }
5097 : 2 : inchi_strbuf_printf(strbuf, "%-f]", u->xbr1[3]);
5098 : : }
5099 [ + - ]: 2 : if (fabs(-fabs(u->xbr2[0]) + 777777.777) > 1.e-7)
5100 : : {
5101 : 2 : inchi_strbuf_printf(strbuf, "[");
5102 [ + + ]: 8 : for (q = 0; q < 3; q++)
5103 : : {
5104 : 6 : inchi_strbuf_printf(strbuf, "%-f,", u->xbr2[q]);
5105 : : }
5106 : 2 : inchi_strbuf_printf(strbuf, "%-f]", u->xbr2[3]);
5107 : : }
5108 : :
5109 [ - + ]: 2 : if (i < p->n - 1)
5110 : : {
5111 : 0 : inchi_strbuf_printf(strbuf, ";");
5112 : : }
5113 : : }
5114 : :
5115 : 2 : inchi_ios_print(out_file, "%s%s", strbuf->pStr, pLF);
5116 : :
5117 : 2 : return 0;
5118 : : }
5119 : :
5120 : : /****************************************************************************/
5121 : 0 : int IsBondAtomNumsLesser(int *bond1, int *bond2)
5122 : : {
5123 : 0 : int min1 = inchi_min(bond1[0], bond1[1]);
5124 : 0 : int min2 = inchi_min(bond2[0], bond2[1]);
5125 : 0 : int max1 = inchi_max(bond1[0], bond1[1]);
5126 : 0 : int max2 = inchi_max(bond2[0], bond2[1]);
5127 : :
5128 [ # # ]: 0 : if (min1 < min2)
5129 : : {
5130 : 0 : return -1;
5131 : : }
5132 [ # # ]: 0 : if (min1 > min2)
5133 : : {
5134 : 0 : return 1;
5135 : : }
5136 [ # # ]: 0 : if (min1 == min2)
5137 : : {
5138 [ # # ]: 0 : if (max1 < max2)
5139 : : {
5140 : 0 : return -1;
5141 : : }
5142 [ # # ]: 0 : if (max1 > max2)
5143 : : {
5144 : 0 : return 1;
5145 : : }
5146 : : }
5147 : :
5148 : 0 : return 0;
5149 : : }
5150 : :
5151 : : /****************************************************************************/
5152 : 0 : void EditINCHI_HidePolymerZz(INCHI_IOSTREAM *out, int n_pzz, int n_zy)
5153 : : {
5154 : 0 : char *s = out->s.pStr, *s0, *buf = NULL;
5155 : 0 : char prev_layer_symbol = '0';
5156 : : int i, j, ii, nzz,
5157 : 0 : nzz1 = 0, nslash = 0, ncopied = 0,
5158 : 0 : start = 0, skip = 0, is_in_z_layer = 0,
5159 : 0 : eol_was_consumed = 0, pre_eol = 0,
5160 : 0 : nonprt_sym = 0, nonprt_prev = 0;
5161 : :
5162 [ # # ]: 0 : if (n_zy > 0)
5163 : : {
5164 : : /* We have some placeholder pseudo atoms which should not be removed below (if anyway they are allowed) */
5165 [ # # ]: 0 : if (n_pzz == 0)
5166 : : {
5167 : : /* Have nothing to remove, just exit */
5168 : 0 : return;
5169 : : }
5170 : : /* Have both polymer-related and placeholder pseudo atoms */
5171 [ # # ]: 0 : if (n_pzz < 2)
5172 : : {
5173 : : /* Something strange, should not arrive here, cowardly exit */
5174 : 0 : return;
5175 : : }
5176 : : }
5177 : :
5178 : : /* Ensure that polymeric layer is present */
5179 [ # # ]: 0 : if (!strstr(s, "/z"))
5180 : : {
5181 : 0 : return;
5182 : : }
5183 : 0 : s0 = strstr(s, "InChI=1B/");
5184 [ # # ]: 0 : if (!s0)
5185 : : {
5186 : 0 : return;
5187 : : }
5188 : :
5189 : : #if 0
5190 : : nzz1 = CountPseudoElementInFormula("Zz", s0 + strlen("InChI=1B/"));
5191 : : if (nzz1 == 0)
5192 : : {
5193 : : return;
5194 : : }
5195 : : if (nzz1 != (n_pzz + n_zy))
5196 : : {
5197 : : /* Something strange, should not arrive here, cowardly exit */
5198 : : return;
5199 : : }
5200 : : #endif
5201 : 0 : nzz1 = n_pzz;
5202 : :
5203 : : /* OK, we must hide n_pzz Zz's*/
5204 : 0 : buf = (char *)inchi_calloc((long long)out->s.nUsedLength + 1, sizeof(char)); /* djb-rwth: cast operator added */
5205 [ # # ]: 0 : if (!buf)
5206 : : {
5207 : 0 : return;
5208 : : }
5209 : :
5210 : : /* Consume '\n' temporarily */
5211 [ # # ]: 0 : if (s[out->s.nUsedLength - 1] == '\n')
5212 : : {
5213 : 0 : s[out->s.nUsedLength - 1] = '\0';
5214 : 0 : out->s.nUsedLength--;
5215 : 0 : eol_was_consumed = 1;
5216 : : }
5217 : :
5218 : 0 : start = s0 - s;
5219 : 0 : nzz = nzz1;
5220 : 0 : is_in_z_layer = skip = 0;
5221 [ # # ]: 0 : for (i = start; i < out->s.nUsedLength; i++)
5222 : : {
5223 : 0 : pre_eol = (i == out->s.nUsedLength - 1);
5224 [ # # # # : 0 : nonprt_sym = s[i] == '\n' || s[i] == '\r' || s[i] == '\t';
# # ]
5225 : :
5226 [ # # ]: 0 : if (!skip)
5227 : : {
5228 : 0 : buf[ncopied] = s[i];
5229 : 0 : ncopied++;
5230 [ # # # # ]: 0 : if (nonprt_sym && nonprt_prev)
5231 : : {
5232 : 0 : continue;
5233 : : }
5234 : : }
5235 : 0 : nonprt_prev = nonprt_sym;
5236 : :
5237 [ # # # # ]: 0 : if (is_in_z_layer && !skip)
5238 : : {
5239 [ # # ]: 0 : if (s[i] == '(')
5240 : : {
5241 : : /* Software version 1.07 : skip pattern "(cap,cap-bkbonds)" but not "(cap-end, cap-end)" */
5242 : : const char *q;
5243 : 0 : const char *p = out->s.pStr + i + 1;
5244 : 0 : AT_NUMB ia = (AT_NUMB)inchi_strtol(p, &q, 10); /* make compiler happy: */ /* djb-rwth: removing redundant code; ignoring LLVM warning: variable used to store function return value */
5245 [ # # ]: 0 : if (*q != '-')
5246 : : {
5247 : 0 : skip = 1;
5248 : : }
5249 : : }
5250 : : }
5251 [ # # # # ]: 0 : else if (is_in_z_layer && skip)
5252 : : {
5253 [ # # ]: 0 : if (s[i] == '-')
5254 : : {
5255 : 0 : skip = 0;
5256 : : }
5257 : : }
5258 : :
5259 [ # # # # : 0 : if (s[i] == '/' || pre_eol || nonprt_sym)
# # ]
5260 : : {
5261 [ # # ]: 0 : if (is_in_z_layer)
5262 : : {
5263 : 0 : is_in_z_layer = 0;
5264 : : }
5265 : :
5266 [ # # ]: 0 : if (s[i] == '/')
5267 : : {
5268 : 0 : nslash++;
5269 : : }
5270 : :
5271 [ # # # # ]: 0 : if (nslash == 2 ||
5272 [ # # # # ]: 0 : (nslash == 1 && pre_eol) ||
5273 : : (prev_layer_symbol == 'f'))
5274 : : {
5275 [ # # ]: 0 : if (nzz)
5276 : : {
5277 : : /* eat Zz's */
5278 : 0 : ii = i;
5279 [ # # ]: 0 : if (pre_eol)
5280 : : {
5281 : 0 : ii = i + 1;
5282 : : }
5283 [ # # # # ]: 0 : if (s[ii - 1] == 'z' && s[ii - 2] == 'Z')
5284 : : {
5285 : 0 : ncopied -= 2;
5286 [ # # ]: 0 : for (j = ii - 3; j >= 0; j--)
5287 : : {
5288 [ # # ]: 0 : if (s[j] == '.')
5289 : : {
5290 : 0 : break;
5291 : : }
5292 : 0 : ncopied--;
5293 : : }
5294 : 0 : ncopied--;
5295 [ # # ]: 0 : if (!pre_eol)
5296 : : {
5297 : 0 : buf[ncopied - 1] = '/';
5298 : : }
5299 : : else
5300 : : {
5301 : 0 : buf[ncopied - 1] = '\0';
5302 : : }
5303 : : }
5304 : : }
5305 : : }
5306 [ # # # # : 0 : else if (nslash > 2 || pre_eol || s[i] == '\n')
# # ]
5307 : : {
5308 [ # # ]: 0 : if (nzz)
5309 : : {
5310 [ # # # # ]: 0 : if (prev_layer_symbol != 'p' &&
5311 [ # # ]: 0 : prev_layer_symbol != 's' &&
5312 [ # # ]: 0 : prev_layer_symbol != 'f' &&
5313 : : prev_layer_symbol != 'z')
5314 : : {
5315 : : /* eat nzz last ; if any */
5316 : 0 : int n_eaten = 0;
5317 : 0 : char eatable = ';';
5318 [ # # ]: 0 : if (prev_layer_symbol == 'm')
5319 : : {
5320 : 0 : eatable = '.';
5321 : : }
5322 : 0 : ii = i;
5323 [ # # ]: 0 : if (pre_eol)
5324 : : {
5325 : 0 : ii = i + 1;
5326 : : }
5327 [ # # ]: 0 : for (j = ii - 1; j >= 0; j--)
5328 : : {
5329 [ # # # # ]: 0 : if (s[j] == eatable && n_eaten < nzz)
5330 : : {
5331 : 0 : ncopied--;
5332 : 0 : n_eaten++;
5333 : : }
5334 : : else
5335 : : {
5336 : : break;
5337 : : }
5338 : : }
5339 [ # # ]: 0 : if (!pre_eol)
5340 : : {
5341 [ # # ]: 0 : if (s[i] == '\n')
5342 : : {
5343 : 0 : buf[ncopied - 1] = '\n';
5344 : : }
5345 : : else
5346 : : {
5347 : 0 : buf[ncopied - 1] = '/';
5348 : : }
5349 : : }
5350 : : else
5351 : : {
5352 : 0 : buf[ncopied] = '\0';
5353 : 0 : break;
5354 : : }
5355 : : }
5356 : : }
5357 : : }
5358 : :
5359 : 0 : prev_layer_symbol = s[i + 1];
5360 [ # # ]: 0 : if (s[i + 1] == 'r')
5361 : : {
5362 [ # # # # ]: 0 : if (i + 3 < out->s.nUsedLength && s[i + 3] == ':')
5363 : : {
5364 : : /* ra: rB; rC: in AuxInfo */
5365 : : ;
5366 : : }
5367 : : else
5368 : : {
5369 : : /* reconnected layer */
5370 : 0 : nslash = 1;
5371 : : /* nzz = nzz2; paranoidal */
5372 : : }
5373 : : }
5374 [ # # ]: 0 : else if (s[i + 1] == 'z')
5375 : : {
5376 : 0 : is_in_z_layer = 1;
5377 : : }
5378 : : }
5379 : : }
5380 : :
5381 : 0 : out->s.nUsedLength = 0;
5382 [ # # ]: 0 : inchi_ios_print_nodisplay(out, "%s%s", buf, eol_was_consumed ? "\n" : "");
5383 [ # # ]: 0 : inchi_free(buf);
5384 : :
5385 : 0 : return;
5386 : : }
5387 : :
5388 : : /****************************************************************************/
5389 : 0 : int CountPseudoElementInFormula(const char *pseudo, char *s) /* djb-rwth: ignoring LLVM warning: function used */
5390 : : {
5391 : 0 : int npseudo = 0, mult = 1, index = 1, new_component = 1;
5392 : : const char *p, *q;
5393 : 0 : char prev = '/';
5394 : :
5395 : : /*
5396 : : format is
5397 : : [sequence of] [.[int_mult[Zz[int_index]]]]
5398 : : */
5399 : :
5400 [ # # ]: 0 : if (!s)
5401 : : {
5402 : 0 : return 0;
5403 : : }
5404 : :
5405 : 0 : p = s;
5406 [ # # ]: 0 : while (*p)
5407 : : /*for (p = s ; *p; p++)*/
5408 : : {
5409 [ # # ]: 0 : if (*p == '/')
5410 : : {
5411 : : /* end of formula layer */
5412 : 0 : break;
5413 : : }
5414 [ # # ]: 0 : else if (*p == '.')
5415 : : {
5416 : : /* start of new component subformula */
5417 : 0 : new_component = 1;
5418 : 0 : prev = *p;
5419 : 0 : p++;
5420 : 0 : continue;
5421 : : }
5422 : :
5423 [ # # ]: 0 : if (new_component)
5424 : : {
5425 : 0 : new_component = 0;
5426 [ # # ]: 0 : if (isdigit(*p))
5427 : : {
5428 : 0 : mult = (int)inchi_strtol(p, &q, 10);
5429 : 0 : p = q;
5430 : 0 : prev = *q--;
5431 : 0 : continue;
5432 : : }
5433 : : else
5434 : : {
5435 : 0 : mult = 1;
5436 : : }
5437 [ # # ]: 0 : if (!mult)
5438 : : {
5439 : 0 : break;
5440 : : }
5441 : : }
5442 [ # # # # ]: 0 : else if (*p == pseudo[1] && prev == pseudo[0])
5443 : : {
5444 : 0 : q = p++;
5445 [ # # # # ]: 0 : if (*q && isdigit(*q))
5446 : : {
5447 : 0 : index = (int)inchi_strtol(q, &p, 10);
5448 : : }
5449 : : else
5450 : : {
5451 : 0 : index = 1;
5452 : 0 : p = q;
5453 : : }
5454 : 0 : npseudo += mult * index;
5455 : : }
5456 : 0 : prev = *p;
5457 : 0 : p++;
5458 : : }
5459 : :
5460 : 0 : return npseudo;
5461 : : }
5462 : :
5463 : : /****************************************************************************
5464 : : Get canonical numbers and component numbers for each original atom
5465 : : NB: cano_nums[orig_num] - in orig_nums order,
5466 : : compnt_nums[cano_num] - in cano_nums order
5467 : : NB': orig_nums are 1-based
5468 : : cano_nums are 0-based
5469 : : compnt_nums are 1-based
5470 : : ****************************************************************************/
5471 : 2 : int InternallyGetCanoNumsAndComponentNums(CANON_GLOBALS *pCG,
5472 : : INCHI_IOS_STRING *strbuf,
5473 : : INCHI_OUT_CTL *io,
5474 : : int nat,
5475 : : int *cano_nums,
5476 : : int *compnt_nums)
5477 : : {
5478 : : int orig_num, cano_num, icompnt, i, k, ndigit, err;
5479 : : char c, cnum[8];
5480 : :
5481 [ + - + - : 2 : if (!cano_nums || !compnt_nums || !strbuf->pStr)
- + ]
5482 : : {
5483 : 0 : return 1;
5484 : : }
5485 : :
5486 : 2 : inchi_strbuf_reset(strbuf);
5487 : 2 : io->tot_len = str_AuxNumb(pCG, io->pINChISort, io->pINChISort2,
5488 : : strbuf, &io->bOverflow, io->bOutType,
5489 : : io->TAUT_MODE, io->num_components,
5490 : : io->bSecondNonTautPass, io->bOmitRepetitions);
5491 [ + + ]: 12 : for (i = 0; i < nat; i++)
5492 : : {
5493 : 10 : compnt_nums[i] = -1;
5494 : 10 : cano_nums[i + 1] = -1;
5495 : : }
5496 : :
5497 : 2 : ndigit = 0;
5498 : 2 : err = 0;
5499 : : /* djb-rwth: removing redundant code */
5500 : 2 : icompnt = 1;
5501 : 2 : cano_num = 0;
5502 [ + - ]: 20 : for (k = 0; k <= strbuf->nUsedLength; k++)
5503 : : {
5504 : 20 : c = strbuf->pStr[k];
5505 [ + + + - : 20 : if (c == ',' || c == ';' || c == '\0')
+ + ]
5506 : : {
5507 : 10 : cnum[ndigit] = '\0';
5508 : 10 : orig_num = atoi(cnum);
5509 : 10 : cano_nums[orig_num] = cano_num;
5510 : 10 : compnt_nums[cano_num] = icompnt;
5511 : 10 : cnum[0] = '\0';
5512 : 10 : ndigit = 0;
5513 : 10 : cano_num++;
5514 [ - + ]: 10 : if (c == ';')
5515 : : {
5516 : 0 : icompnt++;
5517 : : }
5518 [ + + ]: 10 : if (c == '\0')
5519 : : {
5520 : 2 : break;
5521 : : }
5522 : 8 : continue;
5523 : : }
5524 [ + - ]: 10 : else if (isdigit(c))
5525 : : {
5526 : 10 : cnum[ndigit] = c;
5527 : 10 : ndigit++;
5528 : : }
5529 : : else
5530 : : {
5531 : 0 : err = 2;
5532 : 0 : goto exit_function;
5533 : : }
5534 : : }
5535 : :
5536 : 0 : exit_function:
5537 : 2 : inchi_strbuf_reset(strbuf);
5538 : :
5539 : 2 : return err;
5540 : : }
5541 : :
5542 : : /***************************************************************************/
5543 : 0 : int MergeZzInHillFormula(INCHI_IOS_STRING *strbuf)
5544 : : {
5545 : 0 : char *p, *scopy = NULL, *stmp = NULL, *pend = NULL, *p0 = NULL; /* djb-rwth: removing redundant variables */
5546 : : size_t sublen; /* djb-rwth: removing redundant variables */
5547 : :
5548 [ # # # # ]: 0 : if (!strbuf->pStr || strbuf->nUsedLength < 1)
5549 : : {
5550 : 0 : return 0;
5551 : : }
5552 : 0 : scopy = (char *)inchi_calloc((long long)strbuf->nAllocatedLength + 1, sizeof(char)); /* djb-rwth: cast operator added */
5553 [ # # ]: 0 : if (!scopy)
5554 : : {
5555 [ # # ]: 0 : inchi_free(scopy); /* djb-rwth: avoiding memory leak */
5556 : 0 : return -1; /* failed */
5557 : : }
5558 : 0 : memcpy(scopy, strbuf->pStr, strbuf->nAllocatedLength);
5559 : 0 : stmp = (char *)inchi_calloc((long long)strbuf->nAllocatedLength + 1, sizeof(char)); /* djb-rwth: cast operator added */
5560 [ # # ]: 0 : if (!stmp)
5561 : : {
5562 [ # # ]: 0 : inchi_free(scopy); /* djb-rwth: avoiding memory leak */
5563 : 0 : return -1; /* failed */
5564 : : }
5565 : :
5566 : 0 : inchi_strbuf_reset(strbuf);
5567 : 0 : p0 = scopy;
5568 : 0 : p = p0;
5569 : : do
5570 : : {
5571 : : /* djb-rwth: removing redundant code */
5572 : 0 : pend = strchr(p, '.');
5573 [ # # ]: 0 : if (!pend)
5574 : : {
5575 : 0 : pend = strchr(p, '\0');
5576 : : }
5577 : 0 : sublen = pend - p;
5578 : 0 : memcpy(stmp, p, sublen);
5579 : 0 : stmp[sublen] = '\0';
5580 : 0 : MergeZzInStrHillFormulaComponent(stmp);
5581 [ # # ]: 0 : if (stmp)
5582 : : {
5583 : 0 : inchi_strbuf_printf(strbuf, "%-s%-c", stmp, *pend);
5584 : : }
5585 : : /* djb-rwth: removing redundant code */
5586 [ # # # # ]: 0 : } while (*pend && (p = pend + 1));
5587 : :
5588 [ # # ]: 0 : if (scopy)
5589 : : {
5590 [ # # ]: 0 : inchi_free(scopy);
5591 : : }
5592 [ # # ]: 0 : if (stmp)
5593 : : {
5594 [ # # ]: 0 : inchi_free(stmp);
5595 : : }
5596 : :
5597 : 0 : return 0;
5598 : : }
5599 : :
5600 : : /***************************************************************************/
5601 : 0 : void MergeZzInStrHillFormulaComponent(char *s)
5602 : : {
5603 : 0 : char *pz = strstr(s, "Zz");
5604 [ # # ]: 0 : if (pz)
5605 : : {
5606 : 0 : int n = 1, offset;
5607 : 0 : char *pz2 = pz + 2, *pd = pz + 2;
5608 [ # # # # ]: 0 : if (*pd && (isdigit(*pd)))
5609 : : {
5610 : 0 : n = strtol(pd, &pz2, 10);
5611 : : }
5612 : 0 : pz2 = strstr(pz2, "Zz");
5613 [ # # ]: 0 : if (pz2)
5614 : : {
5615 : 0 : int n2 = 1;
5616 : 0 : char *pd2 = pz2 + 2;
5617 [ # # # # ]: 0 : if (*pd2 && (isdigit(*pd2)))
5618 : : {
5619 : 0 : n2 = strtol(pd2, &pz2, 10);
5620 : : }
5621 : 0 : n += n2;
5622 : 0 : offset = (int)(pd - s);
5623 : 0 : sprintf(s + offset, "%d", n);
5624 : : }
5625 : : }
5626 : 0 : return;
5627 : : }
5628 : :
5629 : : /****************************************************************************/
5630 : 0 : static void inchi_sort_int_pair_ascending(int *a, int *b)
5631 : : {
5632 : : int tmp;
5633 [ # # ]: 0 : if (*a > *b)
5634 : : {
5635 : 0 : tmp = *b;
5636 : 0 : *b = *a;
5637 : 0 : *a = tmp;
5638 : : }
5639 : :
5640 : 0 : return;
5641 : : }
|