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