utils/indigo-depict/main.c (1,119 lines of code) (raw):

/**************************************************************************** * Copyright (C) from 2009 to Present EPAM Systems. * * This file is part of Indigo toolkit. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ***************************************************************************/ #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "base_c/defs.h" #include "indigo-renderer.h" #include "indigo.h" void usage(void) { fprintf(stderr, "Indigo version: %s\n\n" "Usage:\n" " indigo-depict infile.{mol,rxn,cml,ket,smi} outfile.{png,svg,pdf} [parameters]\n" " indigo-depict infile.{sdf,rdf,cml,smi} outfile_%%s.{png,svg,pdf} [parameters]\n" " indigo-depict infile.{sdf,rdf}.gz outfile_%%s.{png,svg,pdf} [parameters]\n" " indigo-depict infile.smi outfile.{mol,rxn,cml} [parameters]\n" " indigo-depict infile.smi outfile.{sdf,rdf,cml} [parameters]\n" " indigo-depict - SMILES outfile.{png,svg,pdf} [parameters]\n" " indigo-depict - SMILES outfile.{mol,rxn,cml} [parameters]\n" " indigo-depict - InChI outfile.{png,svg,pdf} [parameters]\n" " indigo-depict - InChI outfile.{mol,rxn,cml} [parameters]\n" "\nParameters:\n" "-w <number>\n" " Picture width in pixels\n" "-h <number>\n" " Picture height in pixels\n" "-bond <number>\n" " Average bond length in pixels\n" "-margins <number> <number>\n" " Horizontal and vertical margins, in pixels. No margins by default\n" "-thickness <number>\n" " Set relative thickness factor. Default is 1.0\n" "-linewidth <number>\n" " Set bond line width factor. Default is 1.0\n" "-label <none|hetero|terminal-hetero|all>\n" " Set atom label display mode (default is terminal-hetero)\n" "-hydro <on|off>\n" " Show implicit hydrogens (default is on)\n" "-[de]arom\n" " Force [de]aromatization\n" "-stereo <old|ext|none>\n" " Stereogroups display mode (default is 'old')\n" "-cdbwsa\n" " Center double bonds which have an adjacent stereo bond (disabled by default)\n" "-query\n" " Treat the input as a query molecule or reaction (disabled by default)\n" "-smarts\n" " Treat the input as a SMARTS query molecule or reaction (disabled by default)\n" "-id <string>\n" " SDF/RDF field to be put in place of '%%s' in the names of saved files\n" " (default is molecule/reaction number)\n" "-catalysts [above|above-and-below]\n" " Reaction catalysts placement w.r.t. the arrow (default is above and below\n" "-comment <string>\n" " Text comment to be put above the molecule or reaction. No default value\n" "-commentoffset <number> \n" " Vertical space (in pixels) between the comment and the structure\n" "-commentfield <string>\n" " Use specified SDF/RDF field as a comment\n" "-commentname\n" " Use molecule/reaction name as a comment\n" "-commentsize <number>\n" " Text comment font size factor relative to bond thickness (default 6)\n" "-commentpos <top|bottom>\n" " Text comment position (bottom by default)\n" "-commentalign <0..1>\n" " Text comment alignment, a float value: 0 = left, 0.5 = center, 1 = right\n" "-coloring <on|off>\n" " Enable/disable coloring (enabled by default)\n" "-hlthick\n" " Enable highlighting with thick lines and bold characters\n" "-hlcolor <red> <green> <blue>\n" " Enable highlighting with color. Component values must be in range [0..255]\n" "-bgcolor <red> <green> <blue>\n" " Set the background color. Component values must be in range [0..255]\n" "-basecolor <red> <green> <blue>\n" " Set the default foreground color. Component values must be in range [0..255]\n" "-aamcolor <red> <green> <blue>\n" " Set the color of AAM indices. Component values must be in range [0..255]\n" "-dsgcolor <red> <green> <blue>\n" " Set the color of data SGroups. Component values must be in range [0..255]\n" "-commentcolor <red> <green> <blue>\n" " Set the color of the comment. Component values must be in range [0..255]\n" "-atomnumbers\n" " Show atom numbers (for debugging purposes only)\n" "-bondnumbers\n" " Show bond numbers (for debugging purposes only)\n" "-onebased\n" " Start atom and bond indices from one (default is from zero)\n" "-help\n" " Print this help message\n" "\n" "Examples:\n" " indigo-depict infile.mol outfile.png -coloring off -arom\n" " indigo-depict database.sdf molecule_%%s.png -id cdbregno -thickness 1.1\n" " indigo-depict database.smi database.sdf\n" " indigo-depict - \"CC.[O-][*-]([O-])=O\" query.png -query\n" " indigo-depict - \"OCO>>CC(C)N\" reaction.rxn\n", indigoVersion()); } #define USAGE() \ do \ { \ usage(); \ return -1; \ } while (0) #define ERROR(str) \ { \ fprintf(stderr, str); \ return -1; \ } int parseColor(char* argv[], int i, float* rr, float* gg, float* bb) { int r, g, b; if (sscanf(argv[i + 1], "%d", &r) != 1 || r < 0 || r > 255) { fprintf(stderr, "%s is not a valid color index\n", argv[i + 1]); return -1; } if (sscanf(argv[i + 2], "%d", &g) != 1 || g < 0 || g > 255) { fprintf(stderr, "%s is not a valid color index\n", argv[i + 2]); return -1; } if (sscanf(argv[i + 3], "%d", &b) != 1 || b < 0 || b > 255) { fprintf(stderr, "%s is not a valid color index\n", argv[i + 3]); return -1; } *rr = r / 255.f; *gg = g / 255.f; *bb = b / 255.f; return 0; } int _isMultiline(const char* filename, int* is_reaction) { FILE* f = fopen(filename, "rt"); int c; *is_reaction = 0; if (f == NULL) { fprintf(stderr, "Can not open %s for reading\n", filename); return -1; } while ((c = fgetc(f)) != EOF) { if (c == '>') *is_reaction = 1; if (c == '\n') break; } if (c == EOF) return 0; while ((c = fgetc(f)) != EOF) { if (!isspace(c)) return 1; } return 0; } int _isReaction(const char* smiles) { return strchr(smiles, '>') != NULL; } int _isMultipleCML(const char* filename, int* reaction) { int iter = indigoIterateCMLFile(filename); *reaction = 0; if (indigoHasNext(iter)) { int item = indigoNext(iter); if (strstr(indigoRawData(item), "<reaction") != NULL) *reaction = 1; if (indigoHasNext(iter)) { indigoFree(item); indigoFree(iter); return 1; } indigoFree(item); } indigoFree(iter); return 0; } enum { MODE_SINGLE_MOLECULE, MODE_SINGLE_REACTION, MODE_MULTILINE_SMILES, MODE_SDF, MODE_RDF, MODE_MULTIPLE_CML, }; enum { ACTION_RENDER, ACTION_LAYOUT }; enum { OEXT_MOL, OEXT_RXN, OEXT_SDF, OEXT_RDF, OEXT_CML, OEXT_KET, OEXT_KER, OEXT_RDR, OEXT_CDX, OEXT_CDX64, OEXT_CDR, OEXT_CDXML, OEXT_CDXMLR, OEXT_SMI, OEXT_SD1, OEXT_SEQ, OEXT_FASTA, OEXT_OTHER }; void onError(const char* message, void* context) { fprintf(stderr, "%s\n", message); exit(-1); } enum AROMATIZATION { NONE = 0, AROM, DEAROM }; int _prepare(int obj, int arom) { if (arom == AROM) return indigoAromatize(obj); if (arom == DEAROM) return indigoDearomatize(obj); return 0; } void renderToFile(int obj, const char* outfile) { int out = indigoWriteFile(outfile); indigoRender(obj, out); indigoFree(out); } typedef struct tagParams { const char* outfile; char outfile_ext[7], infile_ext[7]; int width; int height; int bond; int mode; int action; const char* id; const char* string_to_load; const char* file_to_load; int hydro_set, query_set, smarts_set; int aromatization; int out_ext; const char* comment; const char* comment_field; int comment_name; const char* seq_type; } Params; int parseParams(Params* p, int argc, char* argv[]) { int i; if (strcmp(argv[1], "-") == 0) { if (_isReaction(argv[2])) { p->mode = MODE_SINGLE_REACTION; p->string_to_load = argv[2]; } else { p->mode = MODE_SINGLE_MOLECULE; p->string_to_load = argv[2]; } if (argc <= 3) USAGE(); i = 3; } else { p->infile_ext[0] = 0; if (strlen(argv[1]) >= 4 && argv[1][strlen(argv[1]) - 4] == '.') { p->infile_ext[3] = 0; strncpy(p->infile_ext, argv[1] + strlen(argv[1]) - 3, 3); } else if (strlen(argv[1]) > 7 && argv[1][strlen(argv[1]) - 7] == '.') { p->infile_ext[6] = 0; strncpy(p->infile_ext, argv[1] + strlen(argv[1]) - 6, 6); } p->file_to_load = argv[1]; if (strcasecmp(p->infile_ext, "cdx") == 0 || strcasecmp(p->infile_ext, "b64") == 0 || strcasecmp(p->infile_ext, "mol") == 0 || strcasecmp(p->infile_ext, "ket") == 0 || strcasecmp(p->infile_ext, "xml") == 0 || strcasecmp(p->infile_ext, "sd1") == 0 || strcasecmp(p->infile_ext, "seq") == 0 || strcasecmp(p->infile_ext, "fst") == 0) p->mode = MODE_SINGLE_MOLECULE; else if (strcasecmp(p->infile_ext, "rxn") == 0 || strcasecmp(p->infile_ext, "ker") == 0 || strcasecmp(p->infile_ext, "cdr") == 0 || strcasecmp(p->infile_ext, "xmr") == 0 || strcasecmp(p->infile_ext, "r64") == 0 || strcasecmp(p->infile_ext, "rdr") == 0) { p->mode = MODE_SINGLE_REACTION; } else if (strcasecmp(p->infile_ext, "smi") == 0) { int reaction; if (_isMultiline(argv[1], &reaction)) p->mode = MODE_MULTILINE_SMILES; else { if (reaction) p->mode = MODE_SINGLE_REACTION; else p->mode = MODE_SINGLE_MOLECULE; } } else if (strcasecmp(p->infile_ext, "cml") == 0) { int reaction; if (_isMultipleCML(argv[1], &reaction)) p->mode = MODE_MULTIPLE_CML; else { if (reaction) p->mode = MODE_SINGLE_REACTION; else p->mode = MODE_SINGLE_MOLECULE; } } else if (strcasecmp(p->infile_ext, "sdf") == 0 || strcasecmp(p->infile_ext, "sdf.gz") == 0) p->mode = MODE_SDF; else if (strcasecmp(p->infile_ext, "rdf") == 0 || strcasecmp(p->infile_ext, "rdf.gz") == 0) p->mode = MODE_RDF; else { USAGE(); } i = 2; } p->outfile = argv[i++]; const char* ptr_dot = strstr(p->outfile, "."); if (!ptr_dot) USAGE(); strcpy(p->outfile_ext, ptr_dot + 1); indigoSetOptionBool("treat-x-as-pseudoatom", 1); indigoSetOptionBool("render-coloring", 1); indigoSetOptionBool("render-highlight-color-enabled", 1); for (; i < argc; i++) { if (strcmp(argv[i], "-w") == 0) { if (++i == argc) { fprintf(stderr, "expecting number after -w\n"); return -1; } if (sscanf(argv[i], "%d", &p->width) != 1 || p->width <= 0) { fprintf(stderr, "%s is not a valid width\n", argv[i]); return -1; } } else if (strcmp(argv[i], "-h") == 0) { if (++i == argc) { fprintf(stderr, "expecting number after -h\n"); return -1; } if (sscanf(argv[i], "%d", &p->height) != 1 || p->height <= 0) { fprintf(stderr, "%s is not a valid height\n", argv[i]); return -1; } } else if (strcmp(argv[i], "-margins") == 0) { int horz, vert; if (i + 2 >= argc) { fprintf(stderr, "expecting two numbers after -margins\n"); return -1; } if (sscanf(argv[i + 1], "%d", &horz) != 1 || horz < 0) { fprintf(stderr, "%s is not a valid horizontal margin\n", argv[i]); return -1; } if (sscanf(argv[i + 2], "%d", &vert) != 1 || vert < 0) { fprintf(stderr, "%s is not a valid vertical margin\n", argv[i + 1]); return -1; } indigoSetOptionXY("render-margins", horz, vert); i += 2; } else if (strcmp(argv[i], "-thickness") == 0) { float rt; if (++i == argc) { fprintf(stderr, "expecting number after -thickness\n"); return -1; } if (sscanf(argv[i], "%f", &rt) != 1 || rt < 0) { fprintf(stderr, "%s is not a valid relative thickness\n", argv[i]); return -1; } indigoSetOptionFloat("render-relative-thickness", rt); } else if (strcmp(argv[i], "-linewidth") == 0) { float rt; if (++i == argc) { fprintf(stderr, "expecting number after -linewidth\n"); return -1; } if (sscanf(argv[i], "%f", &rt) != 1 || rt < 0) { fprintf(stderr, "%s is not a valid line width value\n", argv[i]); return -1; } indigoSetOptionFloat("render-bond-line-width", rt); } else if (strcmp(argv[i], "-bond") == 0) { if (++i == argc) { fprintf(stderr, "expecting number after -bond\n"); return -1; } if (sscanf(argv[i], "%d", &p->bond) != 1 || p->bond <= 0) { fprintf(stderr, "%s is not a valid bond length\n", argv[i]); return -1; } } else if (strcmp(argv[i], "-coloring") == 0) { if (++i == argc) { fprintf(stderr, "expecting 'on' or 'off' after -coloring\n"); return -1; } if (strcasecmp(argv[i], "on") == 0) indigoSetOptionBool("render-coloring", 1); else if (strcasecmp(argv[i], "off") == 0) indigoSetOptionBool("render-coloring", 0); else { fprintf(stderr, "expecting 'on' or 'off' after -coloring\n"); return -1; } } else if (strcmp(argv[i], "-hlthick") == 0) { indigoSetOptionBool("render-highlight-thickness-enabled", 1); } else if (strcmp(argv[i], "-hlcolor") == 0) { float r, g, b; if (i + 3 >= argc) { fprintf(stderr, "expecting 3 numbers after -hlcolor\n"); return -1; } if (parseColor(argv, i, &r, &g, &b) != 0) return -1; indigoSetOptionBool("render-highlight-color-enabled", 1); indigoSetOptionColor("render-highlight-color", r, g, b); i += 3; } else if (strcmp(argv[i], "-bgcolor") == 0) { float r, g, b; if (i + 3 >= argc) { fprintf(stderr, "expecting 3 numbers after -bgcolor\n"); return -1; } if (parseColor(argv, i, &r, &g, &b) != 0) return -1; indigoSetOptionColor("render-background-color", r, g, b); i += 3; } else if (strcmp(argv[i], "-basecolor") == 0) { float r, g, b; if (i + 3 >= argc) { fprintf(stderr, "expecting 3 numbers after -basecolor\n"); return -1; } if (parseColor(argv, i, &r, &g, &b) != 0) return -1; indigoSetOptionColor("render-base-color", r, g, b); i += 3; } else if (strcmp(argv[i], "-aamcolor") == 0) { float r, g, b; if (i + 3 >= argc) { fprintf(stderr, "expecting 3 numbers after -aamcolor\n"); return -1; } if (parseColor(argv, i, &r, &g, &b) != 0) return -1; indigoSetOptionColor("render-aam-color", r, g, b); i += 3; } else if (strcmp(argv[i], "-dsgcolor") == 0) { float r, g, b; if (i + 3 >= argc) { fprintf(stderr, "expecting 3 numbers after -aamcolor\n"); return -1; } if (parseColor(argv, i, &r, &g, &b) != 0) return -1; indigoSetOptionColor("render-data-sgroup-color", r, g, b); i += 3; } else if (strcmp(argv[i], "-hydro") == 0) { if (++i == argc) { fprintf(stderr, "expecting an identifier after -hydro\n"); return -1; } indigoSetOption("render-implicit-hydrogens-visible", argv[i]); p->hydro_set = 1; } else if (strcmp(argv[i], "-label") == 0) { if (++i == argc) { fprintf(stderr, "expecting an identifier after -label\n"); return -1; } indigoSetOption("render-label-mode", argv[i]); } else if (strcmp(argv[i], "-arom") == 0) { p->aromatization = AROM; } else if (strcmp(argv[i], "-dearom") == 0) { p->aromatization = DEAROM; } else if (strcmp(argv[i], "-stereo") == 0) { if (++i == argc) { fprintf(stderr, "expecting an identifier after -stereo\n"); return -1; } indigoSetOption("render-stereo-style", argv[i]); } else if (strcmp(argv[i], "-cdbwsa") == 0) { indigoSetOptionBool("render-center-double-bond-when-stereo-adjacent", 1); } else if (strcmp(argv[i], "-query") == 0) { p->query_set = 1; } else if (strcmp(argv[i], "-smarts") == 0) { p->smarts_set = 1; } else if (strcmp(argv[i], "-id") == 0) { if (++i == argc) { fprintf(stderr, "expecting an identifier after -id\n"); return -1; } p->id = argv[i]; } else if (strcmp(argv[i], "-catalysts") == 0) { if (++i == argc) { fprintf(stderr, "expecting an identifier after -catalysts\n"); return -1; } indigoSetOption("render-catalysts-placement", argv[i]); } else if (strcmp(argv[i], "-comment") == 0) { if (++i == argc) { fprintf(stderr, "expecting an identifier after -comment\n"); return -1; } p->comment = argv[i]; } else if (strcmp(argv[i], "-seqtype") == 0) { if (++i == argc) { fprintf(stderr, "expecting an sequence type (RNA, DNA, PEPTIDE) after -seqtype\n"); return -1; } p->seq_type = argv[i]; } else if (strcmp(argv[i], "-commentoffset") == 0) { int offset; if (++i >= argc) { fprintf(stderr, "expecting an integer after -commentoffset\n"); return -1; } if (sscanf(argv[i], "%d", &offset) != 1 || offset < 0) { fprintf(stderr, "%s is not a valid comment offset\n", argv[i]); return -1; } indigoSetOptionInt("render-comment-offset", offset); } else if (strcmp(argv[i], "-commentfield") == 0) { if (++i == argc) { fprintf(stderr, "expecting an identifier after -commentfield\n"); return -1; } p->comment_field = argv[i]; } else if (strcmp(argv[i], "-commentname") == 0) { p->comment_name = 1; } else if (strcmp(argv[i], "-commentsize") == 0) { int commentsize; if (++i == argc) { fprintf(stderr, "expecting number after -commentsize\n"); return -1; } if (sscanf(argv[i], "%d", &commentsize) != 1 || commentsize <= 0) { fprintf(stderr, "%s is not a valid font size\n", argv[i]); return -1; } indigoSetOptionFloat("render-comment-font-size", (float)commentsize); } else if (strcmp(argv[i], "-commentcolor") == 0) { float r, g, b; if (i + 3 >= argc) { fprintf(stderr, "expecting 3 numbers after -commentcolor\n"); return -1; } if (parseColor(argv, i, &r, &g, &b) != 0) return -1; indigoSetOptionColor("render-comment-color", r, g, b); i += 3; } else if (strcmp(argv[i], "-commentalign") == 0) { if (++i == argc) { fprintf(stderr, "expecting an identifier after -commentalign\n"); return -1; } indigoSetOption("render-comment-alignment", argv[i]); } else if (strcmp(argv[i], "-commentpos") == 0) { if (++i == argc) { fprintf(stderr, "expecting an identifier after -commentpos\n"); return -1; } indigoSetOption("render-comment-position", argv[i]); } else if (strcmp(argv[i], "-atomnumbers") == 0) indigoSetOptionBool("render-atom-ids-visible", 1); else if (strcmp(argv[i], "-bondnumbers") == 0) indigoSetOptionBool("render-bond-ids-visible", 1); else if (strcmp(argv[i], "-onebased") == 0) indigoSetOptionBool("render-atom-bond-ids-from-one", 1); else if (strcmp(argv[i], "-help") == 0) { usage(); return 0; } else { fprintf(stderr, "unknown option: %s\n", argv[i]); return -1; } } if (p->bond > 0) indigoSetOptionFloat("render-bond-length", (float)p->bond); if (p->width > 0) indigoSetOptionInt("render-image-width", p->width); if (p->height > 0) indigoSetOptionInt("render-image-height", p->height); if (p->hydro_set && p->query_set) { fprintf(stderr, "-hydro conflicts with -query (implicit hydrogens do not exist in queries)\n"); } return 0; } void _setComment(int obj, Params* p) { if (p->comment_name) { const char* name = indigoName(obj); if (name != NULL && *name != 0) { indigoSetOption("render-comment", name); return; } } if (p->comment_field != NULL) { if (indigoHasProperty(obj, p->comment_field)) { const char* prop = indigoGetProperty(obj, p->comment_field); if (prop != NULL && *prop != 0) { indigoSetOption("render-comment", prop); return; } } } if (p->comment != NULL && *p->comment != 0) { indigoSetOption("render-comment", p->comment); return; } } int main(int argc, char* argv[]) { Params p; int obj = -1, reader = -1, writer = -1; int i = 0; char number[100]; char outfilename[4096]; const char* id; p.width = p.height = p.bond = p.mode = -1; p.id = p.string_to_load = p.file_to_load = NULL; p.hydro_set = p.query_set = p.smarts_set = 0; p.aromatization = NONE; p.comment_field = NULL; p.comment = NULL; p.comment_name = 0; p.seq_type = "PEPTIDE"; if (argc <= 2) USAGE(); const qword session = indigoAllocSessionId(); indigoRendererInit(session); indigoSetErrorHandler(onError, 0); indigoSetOption("ignore-stereochemistry-errors", "on"); indigoSetOption("ignore-bad-valence", "on"); indigoSetOption("molfile-saving-mode", "3000"); indigoSetOptionBool("json-saving-pretty", "on"); if (parseParams(&p, argc, argv) < 0) return -1; p.out_ext = OEXT_OTHER; if (strcmp(p.outfile_ext, "mol") == 0) p.out_ext = OEXT_MOL; else if (strcmp(p.outfile_ext, "sdf") == 0) p.out_ext = OEXT_SDF; else if (strcmp(p.outfile_ext, "rxn") == 0) p.out_ext = OEXT_RXN; else if (strcmp(p.outfile_ext, "rdf") == 0) p.out_ext = OEXT_RDF; else if (strcmp(p.outfile_ext, "cml") == 0) p.out_ext = OEXT_CML; else if (strcmp(p.outfile_ext, "ket") == 0) p.out_ext = OEXT_KET; else if (strcmp(p.outfile_ext, "ker") == 0) p.out_ext = OEXT_KER; else if (strcmp(p.outfile_ext, "rdr") == 0) p.out_ext = OEXT_RDR; else if (strcmp(p.outfile_ext, "smi") == 0) p.out_ext = OEXT_SMI; else if (strcmp(p.outfile_ext, "cdxml") == 0) p.out_ext = OEXT_CDXML; else if (strcmp(p.outfile_ext, "cdxmr") == 0) p.out_ext = OEXT_CDXMLR; else if (strcmp(p.outfile_ext, "cdx") == 0) p.out_ext = OEXT_CDX; else if (strcmp(p.outfile_ext, "b64") == 0) p.out_ext = OEXT_CDX64; else if (strcmp(p.outfile_ext, "cdr") == 0) p.out_ext = OEXT_CDR; else if (strcmp(p.outfile_ext, "sd1") == 0) p.out_ext = OEXT_SD1; else if (strcmp(p.outfile_ext, "seq") == 0) p.out_ext = OEXT_SEQ; else if (strcmp(p.outfile_ext, "fst") == 0) p.out_ext = OEXT_FASTA; // guess whether to layout or render by extension p.action = ACTION_LAYOUT; if (p.out_ext == OEXT_OTHER) { indigoSetOption("render-output-format", p.outfile_ext); p.action = ACTION_RENDER; } // read in the input reader = (p.file_to_load != NULL) ? indigoReadFile(p.file_to_load) : indigoReadString(p.string_to_load); int lib = indigoLoadMonomerLibraryFromString("{\"root\":{}}"); if (p.mode == MODE_SINGLE_MOLECULE) { if (p.id != NULL) ERROR("on single input, setting '-id' is not allowed\n"); if (p.out_ext == OEXT_RXN) ERROR("reaction output specified for molecule input\n"); if (p.smarts_set) obj = indigoLoadSmarts(reader); else if (p.query_set) obj = indigoLoadQueryMolecule(reader); else if (strcasecmp(p.infile_ext, "fst") == 0) { obj = indigoLoadFasta(reader, p.seq_type, lib); } else if (strcasecmp(p.infile_ext, "seq") == 0) { obj = indigoLoadSequence(reader, p.seq_type, lib); } else if (strcasecmp(p.infile_ext, "idt") == 0) { obj = indigoLoadIdt(reader, lib); } else if (strcasecmp(p.infile_ext, "helm") == 0) { obj = indigoLoadHelm(reader, lib); } else obj = indigoLoadMolecule(reader); _prepare(obj, p.aromatization); if (p.action == ACTION_LAYOUT) { indigoLayout(obj); if (p.out_ext == OEXT_MOL) indigoSaveMolfileToFile(obj, p.outfile); else if (p.out_ext == OEXT_KET) indigoSaveJsonToFile(obj, p.outfile); else if (p.out_ext == OEXT_SEQ) indigoSaveSequenceToFile(obj, p.outfile, lib); else if (p.out_ext == OEXT_FASTA) indigoSaveFastaToFile(obj, p.outfile, lib); else if (p.out_ext == OEXT_SMI) { char* pMol; if (p.query_set) pMol = indigoSmarts(obj); else pMol = indigoSmiles(obj); FILE* fp = fopen(p.outfile, "w+"); if (fp) { fputs(pMol, fp); fclose(fp); } else { fprintf(stderr, "can not write: %s\n", p.outfile); return -1; } } else if (p.out_ext == OEXT_CDXML) { indigoSaveCdxmlToFile(obj, p.outfile); } else if (p.out_ext == OEXT_CDX) { indigoSaveCdxToFile(obj, p.outfile); } else if (p.out_ext == OEXT_CDX64) { char* pMol = indigoCdxBase64(obj); FILE* fp = fopen(p.outfile, "w+"); if (fp) { fputs(pMol, fp); fclose(fp); } else { fprintf(stderr, "can not write: %s\n", p.outfile); return -1; } } else if (p.out_ext == OEXT_SD1) { auto buffer = indigoWriteBuffer(); auto comp_it = indigoIterateComponents(obj); while (indigoHasNext(comp_it)) { auto frag_id = indigoNext(comp_it); const auto mol_obj = indigoClone(frag_id); indigoSdfAppend(buffer, mol_obj); indigoFree(mol_obj); indigoFree(frag_id); } indigoFree(comp_it); char* pSdf = indigoToString(buffer); FILE* fp = fopen(p.outfile, "w+"); if (fp) { fputs(pSdf, fp); fclose(fp); } else { fprintf(stderr, "can not write: %s\n", p.outfile); return -1; } } else indigoSaveCmlToFile(obj, p.outfile); } else { _setComment(obj, &p); renderToFile(obj, p.outfile); } } else if (p.mode == MODE_SINGLE_REACTION) { if (p.id != NULL) ERROR("on single input, setting '-id' is not allowed\n"); if (p.out_ext == OEXT_MOL) ERROR("molecule output specified for reaction input\n"); if (p.smarts_set) obj = indigoLoadReactionSmarts(reader); else if (p.query_set) obj = indigoLoadQueryReaction(reader); else obj = indigoLoadReaction(reader); _prepare(obj, p.aromatization); if (p.action == ACTION_LAYOUT) { indigoLayout(obj); if (p.out_ext == OEXT_CML) indigoSaveCmlToFile(obj, p.outfile); else if (p.out_ext == OEXT_RXN) indigoSaveRxnfileToFile(obj, p.outfile); else if (p.out_ext == OEXT_CDXML || p.out_ext == OEXT_CDXMLR) indigoSaveCdxmlToFile(obj, p.outfile); else if (p.out_ext == OEXT_CDX || p.out_ext == OEXT_CDR) { indigoSaveCdxToFile(obj, p.outfile); } else if (p.out_ext == OEXT_SMI) { char* pReaction; if (p.query_set) pReaction = indigoSmarts(obj); else pReaction = indigoSmiles(obj); FILE* fp = fopen(p.outfile, "w+"); if (fp) { fputs(pReaction, fp); fclose(fp); } else { fprintf(stderr, "can not write: %s\n", p.outfile); return -1; } } else if (p.out_ext == OEXT_RDR) { writer = indigoWriteFile(p.outfile); indigoRdfHeader(writer); auto it_id = indigoIterateReactions(obj); while (indigoHasNext(it_id)) { const auto robj = indigoNext(it_id); const auto rxn_id = indigoClone(robj); auto rc = indigoRdfAppend(writer, rxn_id); } indigoFree(writer); } else { indigoSaveJsonToFile(obj, p.outfile); } } else { _setComment(obj, &p); renderToFile(obj, p.outfile); } } else { int item; int have_percent_s = (strstr(p.outfile, "%s") != NULL); if (p.mode == MODE_MULTILINE_SMILES) obj = indigoIterateSmiles(reader); else if (p.mode == MODE_SDF) obj = indigoIterateSDF(reader); else if (p.mode == MODE_MULTIPLE_CML) obj = indigoIterateCML(reader); else if (p.mode == MODE_RDF) obj = indigoIterateRDF(reader); else { fprintf(stderr, "internal error: wrong branch\n"); return -1; } if ((p.out_ext == OEXT_MOL || p.out_ext == OEXT_RXN || p.out_ext == OEXT_OTHER) && !have_percent_s) ERROR("on multiple output, output file name must have '%%s'\n"); if (p.out_ext == OEXT_SDF || p.out_ext == OEXT_RDF || (p.out_ext == OEXT_CML && !have_percent_s)) { writer = indigoWriteFile(p.outfile); if (p.out_ext == OEXT_RDF) indigoRdfHeader(writer); if (p.out_ext == OEXT_CML) indigoCmlHeader(writer); } i = -1; while ((item = indigoNext(obj))) { int rc; ++i; if (writer > 0) printf("saving item #%d... ", i); else { if (p.id) { if (!indigoHasProperty(item, p.id)) { fprintf(stderr, "item #%d does not have %s, skipping\n", i, p.id); continue; } id = indigoGetProperty(item, p.id); snprintf(outfilename, sizeof(outfilename), p.outfile, id); } else { snprintf(number, sizeof(number), "%d", i); snprintf(outfilename, sizeof(outfilename), p.outfile, number); } printf("saving %s... ", outfilename); } indigoSetErrorHandler(0, 0); if (_prepare(item, p.aromatization) < 0) { printf("%s\n", indigoGetLastError()); indigoSetErrorHandler(onError, 0); continue; } if (p.action == ACTION_LAYOUT) { if (indigoLayout(item) < 0) { printf("%s\n", indigoGetLastError()); indigoSetErrorHandler(onError, 0); continue; } } if (writer > 0) { if (p.out_ext == OEXT_SDF) rc = indigoSdfAppend(writer, item); else if (p.out_ext == OEXT_RDF) rc = indigoRdfAppend(writer, item); else rc = indigoCmlAppend(writer, item); } else { if (p.action == ACTION_LAYOUT) { if (p.out_ext == OEXT_MOL) rc = indigoSaveMolfileToFile(item, outfilename); else if (p.out_ext == OEXT_RXN) rc = indigoSaveRxnfileToFile(item, outfilename); else ERROR("extension unexpected"); } else { _setComment(item, &p); rc = indigoRenderToFile(item, outfilename); } } if (rc < 0) { printf("%s\n", indigoGetLastError()); indigoSetErrorHandler(onError, 0); continue; } indigoFree(item); indigoSetErrorHandler(onError, 0); printf("\n"); } if (writer > 0) { if (p.out_ext == OEXT_CML) indigoCmlFooter(writer); indigoFree(writer); } } indigoFree(reader); indigoFree(obj); indigoRendererDispose(session); indigoReleaseSessionId(session); return 0; }