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;
}