/* Copyright (c) 2004-2010, Dirk Krause All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above opyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Dirk Krause nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file dkfigco.c Conversion job module. */ /** Inside the dkfigco module. */ #define DKFIGCO_C 1 #include "dkfig.h" #line 55 "dkfigco.ctr" /** System configuration directory (string constant). */ static char default_config_filename[] = { DK_SYSCONFDIR "/fig2vect.cfg" }; /** Confiration file name. */ static char short_config_filename[] = { "fig2vect.cfg" }; /** File open mode. */ static char str_r[] = { "r" }; /** Preference key to retrieve the output language. */ static char pk_language[] = { "/output-language" }; /** Preference key to retrieve make-mode flag. */ static char pk_make[] = { "/make" }; /** Preference key to retrieve maximum line length. */ static char pk_linelgt[] = { "/line-length" }; /** Preference key to retrieve UTF-8 handling flag. */ static char pk_utf8[] = { "/utf-8" }; /** Empty string, used when storing preferences. */ static char pv_empty[] = { "" }; /** Preference key to retrieve shared directory. */ static char pk_shdir[] = { "/dir/shared" }; /** Preference key to retrieve UTF-8 to LaTeX tables directory. */ static char str_uc2l[] = { "/uc2lat-t" }; /** Preference key to retrieve flag for suppressing info about alpha channels. */ static char pk_alph[] = { "/pdf/suppress-alpha-info" }; /** String to test values for on or off. */ static char *bool_val[] = { "off", "on", NULL }; /** Suffixes for different output file types. */ static char *output_suffixes[] = { ".mp", ".eps", ".svg", ".tex", ".bb", ".pdf", ".ps", ".java" }; /** Kkeywords for long options. */ static char *longopt_keywords[] = { /* 0 */ "v$ersion", /* 1 */ "h$elp", /* 2 */ "c$onfigure", /* 3 */ "u$nconfigure", /* 4 */ "sh$ow-configuration", /* 5 */ "m$ake", /* 6 */ "o$ption", /* 7 */ "l$anguage", /* 8 */ "r$eset", /* 9 */ "si$lently", /* 10 */ "configuration-file", /* 11 */ "write-configuration-file", NULL }; /** Flag: Have case insensitive file names. */ static int have_fncaseins = #if DK_HAVE_FNCASEINS 1 #else 0 #endif ; /** Key/value pairs to create the message array. */ static dk_key_value_t kv[] = { /* 0 */ { (char *)"/m/01", (char *)"on" }, /* 1 */ { (char *)"/m/02", (char *)"off" }, /* 2 */ { (char *)"/m/03", (char *)"behave like make when running on directories" }, /* 3 */ { (char *)"/m/04", (char *)"output language" }, /* 4 */ { (char *)"/m/05", (char *)"" }, /* 5 */ { (char *)"/m/06", (char *)"Current configuration:" }, /* 6 */ { (char *)"/m/07", (char *)"No gzip decompression available." }, /* 7 */ { (char *)"/m/08", (char *)"No bzip2 decompression available." }, /* 8 */ { (char *)"/m/09", (char *)"Failed to save configuration!" }, /* 9 */ { (char *)"/m/10", (char *)"Configuration file: " }, /* 10 */ { (char *)"/m/11", (char *)"." }, /* 11 */ { (char *)"/m/12", (char *)"Not enough memory!" }, /* 12 */ { (char *)"/m/13", (char *)"Syntax error!" }, /* 13 */ { (char *)"/m/14", (char *)"Mathematical error!" }, /* 14 */ { (char *)"/m/15", (char *)"Unknown base driver: " }, /* 15 */ { (char *)"/m/16", (char *)"!" }, /* 16 */ { (char *)"/m/17", (char *)"Reading input file \"" }, /* 17 */ { (char *)"/m/18", (char *)"\"." }, /* 18 */ { (char *)"/m/19", (char *)"The input file was read successfully." }, /* 19 */ { (char *)"/m/20", (char *)"Error while reading input file." }, /* 20 */ { (char *)"/m/21", (char *)"Writing output file \"" }, /* 21 */ { (char *)"/m/22", (char *)"\"." }, /* 22 */ { (char *)"/m/23", (char *)"Output file finished." }, /* 23 */ { (char *)"/m/24", (char *)"Failed to open stream for standard input!" }, /* 24 */ { (char *)"/m/25", (char *)"Failed to open stream for standard output!" }, /* 25 */ { (char *)"/m/26", (char *)"Base driver name \"" }, /* 26 */ { (char *)"/m/27", (char *)"\" unknown!" }, /* 27 */ { (char *)"/m/28", (char *)"Missing base driver name!" }, /* 28 */ { (char *)"/m/29", (char *)"Skipping \"" }, /* 29 */ { (char *)"/m/30", (char *)"\"." }, /* 30 */ { (char *)"/m/31", (char *)"Output file name \"" }, /* 31 */ { (char *)"/m/32", (char *)"\" too long!" }, /* 32 */ { (char *)"/m/33", (char *)"Invalid text handling \"" }, /* 33 */ { (char *)"/m/34", (char *)"\"!" }, /* 34 */ { (char *)"/m/35", (char *)"Invalid font chooser \"" }, /* 35 */ { (char *)"/m/36", (char *)"\"!" }, /* 36 */ { (char *)"/m/37", (char *)"Invalid size keyword \"" }, /* 37 */ { (char *)"/m/38", (char *)"\"!" }, /* 38 */ { (char *)"/m/39", (char *)"Invalid mbox specification!" }, /* 39 */ { (char *)"/m/40", (char *)"Invalid keyword \"" }, /* 40 */ { (char *)"/m/41", (char *)"\" in text handling!" }, /* 41 */ { (char *)"/m/42", (char *)"Option \"" }, /* 42 */ { (char *)"/m/43", (char *)"\" too long!" }, /* 43 */ { (char *)"/m/44", (char *)"Too many points!" }, /* 44 */ { (char *)"/m/45", (char *)"Internal setup error!" }, /* 45 */ { (char *)"/m/46", (char *)"Preamble file \"" }, /* 46 */ { (char *)"/m/47", (char *)"\" not found!" }, /* 47 */ { (char *)"/m/48", (char *)"Preamble file name \"" }, /* 48 */ { (char *)"/m/49", (char *)"\" too long!" }, /* 49 */ { (char *)"/m/50", (char *)"Failed to insert preamble file \"" }, /* 50 */ { (char *)"/m/51", (char *)"\"!" }, /* 51 */ { (char *)"/m/52", (char *)"Forward arrowhead removed." }, /* 52 */ { (char *)"/m/53", (char *)"Backward arrowhead removed." }, /* 53 */ { (char *)"/m/54", (char *)"Skipping included image." }, /* 54 */ { (char *)"/m/55", (char *)"Start of new output figure." }, /* 55 */ { (char *)"/m/56", (char *)"Gathering font information." }, /* 56 */ { (char *)"/m/57", (char *)"Starting output." }, /* 57 */ { (char *)"/m/58", (char *)"Output finished." }, /* 58 */ { (char *)"/m/59", (char *)"Very long line, possibly truncated." }, /* 59 */ { (char *)"/m/60", (char *)"Failed to create stream for output file!" }, /* 60 */ { (char *)"/m/61", (char *)"Error while executing \"" }, /* 61 */ { (char *)"/m/62", (char *)"\"!" }, /* 62 */ { (char *)"/m/63", (char *)"Processing included image \"" }, /* 63 */ { (char *)"/m/64", (char *)"\"." }, /* 64 */ { (char *)"/m/65", (char *)"Image finished." }, /* 65 */ { (char *)"/m/66", (char *)"Bitmap-to-EPS conversion failed for \"" }, /* 66 */ { (char *)"/m/67", (char *)"Unknown or unsupported file type!" }, /* 67 */ { (char *)"/m/68", (char *)"Failed to create temporary file name!" }, /* 68 */ { (char *)"/m/69", (char *)"NetPBM format not supported!" }, /* 69 */ { (char *)"/m/70", (char *)"JPEG format not supported!" }, /* 70 */ { (char *)"/m/71", (char *)"PNG format not supported!" }, /* 71 */ { (char *)"/m/72", (char *)"Problem while reading image file!" }, /* 72 */ { (char *)"/m/73", (char *)"Failed to create output streams!" }, /* 73 */ { (char *)"/m/74", (char *)"Failed to initialize encoded chunk!" }, /* 74 */ { (char *)"/m/75", (char *)"Failed to finish encoded chunk!" }, /* 75 */ { (char *)"/m/76", (char *)"Error while writing encoded data!" }, /* 76 */ { (char *)"/m/77", (char *)"Failed to create JPEG decompressor!" }, /* 77 */ { (char *)"/m/78", (char *)"Failed to assign file to JPEG decompressor!" }, /* 78 */ { (char *)"/m/79", (char *)"Failed to read JPEG header from file!" }, /* 79 */ { (char *)"/m/80", (char *)"Failed to start JPEG decompression!" }, /* 80 */ { (char *)"/m/81", (char *)"Error while reading JPEG file!" }, /* 81 */ { (char *)"/m/82", (char *)"Failed to allocate memory for image! (Not enough RAM/swap space)" }, /* 82 */ { (char *)"/m/83", (char *)"Failed to create PNG read structure!" }, /* 83 */ { (char *)"/m/84", (char *)"Failed to create PNG info structure!" }, /* 84 */ { (char *)"/m/85", (char *)"Missing bounding box for \"" }, /* 85 */ { (char *)"/m/86", (char *)"Driver does not support special text!" }, /* 86 */ { (char *)"/m/87", (char *)"Unknown key in special comment \"" }, /* 87 */ { (char *)"/m/88", (char *)"Special comment unused by this driver \"" }, /* 88 */ { (char *)"/m/89", (char *)"Option not configurable by special comments \"" }, /* 89 */ { (char *)"/m/90", (char *)"Error while processing special comment \"" }, /* 90 */ { (char *)"/m/91", (char *)"Unused command line option \"" }, /* 91 */ { (char *)"/m/92", (char *)"Unused configuration file option \"" }, /* 92 */ { (char *)"/m/93", (char *)"\"!" }, /* 93 */ { (char *)"/m/94", (char *)"Redefinition of \"" }, /* 94 */ { (char *)"/m/95", (char *)"JS libraries must be specfied at document level!" }, /* 95 */ { (char *)"/m/96", (char *)"Failed to obtain image dimensions for \"" }, /* 96 */ { (char *)"/m/97", (char *)"Error while reading PNG file \"" }, /* 97 */ { (char *)"/m/98", (char *)"\"!" }, /* 98 */ { (char *)"/m/99", (char *)"Gathering font, pattern and image information." }, /* 99 */ { (char *)"/m/100", (char *)"Starting PDF output." }, /* 100 */ { (char *)"/m/101", (char *)"Creating graphics stream." }, /* 101 */ { (char *)"/m/102", (char *)"Writing font objects." }, /* 102 */ { (char *)"/m/103", (char *)"Writing pattern objects." }, /* 103 */ { (char *)"/m/104", (char *)"Writing image objects." }, /* 104 */ { (char *)"/m/105", (char *)"Unknown object type in FIG file!" }, /* 105 */ { (char *)"/m/106", (char *)"Too few bytes in file!" }, /* 106 */ { (char *)"/m/107", (char *)"Failed to write pattern object!" }, /* 107 */ { (char *)"/m/108", (char *)"Failed to write image data for \"" }, /* 108 */ { (char *)"/m/109", (char *)"\"!" }, /* 109 */ { (char *)"/m/110", (char *)"Font number out of range!" }, /* 110 */ { (char *)"/m/111", (char *)"This driver can only handle left-aligned text!" }, /* 111 */ { (char *)"/m/112", (char *)"File type of included image is not supported!" }, /* 112 */ { (char *)"/m/113", (char *)"Bitmap-to-PDF conversion failed for \"" }, /* 113 */ { (char *)"/m/114", (char *)"Conversion failed, errors occured!" }, /* 114 */ { (char *)"/m/115", (char *)"Only PS allows the setpagedevice operator, EPS doesn't!" }, /* 115 */ { (char *)"/m/116", (char *)"Only PS allows the showpage operator, EPS doesn't!" }, /* 116 */ { (char *)"/m/117", (char *)"Failed to find shared directory name!" }, /* 117 */ { (char *)"/m/118", (char *)"Shared directory name too long!" }, /* 118 */ { (char *)"/m/119", (char *)"Failed to create converter from UTF-8 to LaTeX!" } , /* 119 */ { (char *)"/m/120", (char *)"Character out of range (must be 0x00 ... 0xFF)!" }, /* 120 */ { (char *)"/m/121", (char *)"Suggestion: Use combination of this driver and LaTeX driver." }, /* 121 */ { (char *)"/m/122", (char *)"Gathering infomation about fonts, images and fill patterns." }, /* 122 */ { (char *)"/m/123", (char *)"" }, /* 123 */ { (char *)"/m/124", (char *)"Failed to load LaTeX encoding table for " }, /* 124 */ { (char *)"/m/125", (char *)"!" }, /* 125 */ { (char *)"/m/126", (char *)"Failed to find LaTeX encoding for " }, /* 126 */ { (char *)"/m/127", (char *)"!" }, /* 127 */ { (char *)"/m/128", (char *)"Writing to output file \"" }, /* 128 */ { (char *)"/m/129", (char *)"\"." }, /* 129 */ { (char *)"/m/130", (char *)"The figure references images containing alpha channels." "\nYou should use\n" "\\ifpdf\\pdfpageattr{/Group <>}\\fi" "\n in the document preample of LaTeX files including this figure." }, /* 130 */ { (char *)"/m/131", (char *)"The file \"" }, /* 131 */ { (char *)"/m/132", (char *)"\" exists.\n Probably this file hides $HOME/.defauls/fig2vect.cfg, just written." }, /* 132 */ { (char *)"/m/133", (char *)"Suppress notices about alpha channels transferred to PDF." }, /* 133 */ { (char *)"/m/134", (char *)"Unable to place graphics on paper!" }, /* 134 */ { (char *)"/m/135", (char *)"Failed to load font configuration file \"" }, /* 135 */ { (char *)"/m/136", (char *)"\"!" }, /* 136 */ { (char *)"/m/137", (char *)"Resource needed by jar file: \"" }, /* 137 */ { (char *)"/m/138", (char *)"\"" }, /* 138 */ { (char *)"/m/139", (char *)"Please include the files listed above into the *.jar archive." }, /* 139 */ { (char *)"/m/140", (char *)"No special text processing in Java output driver!" }, /* 140 */ { (char *)"/m/141", (char *)"Fill pattern ignored by Java output driver!" }, /* 141 */ { (char *)"/m/142", (char *)"No fill for polylines or open splines!" }, }; /** Number of entries in the kv table. */ static size_t szkv = sizeof(kv)/sizeof(dk_key_value_t); /** Suffixes for XFig files we are willing to read. */ static char *figsuffixes[] = { ".fig", ".fig.gz", ".fig.bz2", NULL }; /** Compression suffixes we can possibly handle. */ static char *suffixes[] = { ".gz", ".bz2", ".svgz", NULL }; /** Driver base names. */ static char *base_driver_names[] = { /* 0 */ "mp", /* 1 */ "mmp", /* 2 */ "eps", /* 3 */ "svg", /* 4 */ "tex", /* 5 */ "bb", /* 6 */ "pdf", /* 7 */ "ps", /* 8 */ "java", NULL }; /** File name standard input. */ static char string_stdin[] = { "<<>>" }; /** File name for standard output. */ static char string_stdout[] = { "<<>>" }; /** Dot (string constant used to find the file name suffix). */ static char string_dot[] = { "." }; /** Maximum input line length. */ static size_t max_line_length = #ifdef DKFIG_MAX_LINE_LENGTH (size_t)(DKFIG_MAX_LINE_LENGTH) #else (size_t)0 #endif ; /** Builtin default options (1). */ static unsigned long builtin_default_options1 = DKFIG_OPT_METAPOST_ARROWHEADS | DKFIG_OPT_FILL_PATTERNS | DKFIG_OPT_FILL_CONTIGOUS | DKFIG_OPT_ALLOW_PSRL | DKFIG_OPT_REMOVE_BITMAP_BORDER | DKFIG_OPT_KEEP_BITMAP_WH_RATIO | DKFIG_OPT_USE_CSS | DKFIG_OPT_IGNORE_UNKNOWN_PAPER | DKFIG_OPT_DP_DOT_LW ; /** Builtin default options(2). */ static unsigned long builtin_default_options2 = DKFIG_OPT_FLIP_DIAGONAL | DKFIG_OPT_INTERPOLATE_IMAGES | DKFIG_OPT_SVG_FONTSIZE_UNIT | DKFIG_OPT_COLOR | DKFIG_OPT_JAVA_UNICODE ; /** File name format for temporary files: *.tex */ static char str_conv_format[] = { "f2v_%lu.tex" }; /** File name format for temporary files: *.dvi */ static char str_conv_dvi[] = { "f2v_%lu.dvi" }; /** File name format for temporary files: *.ps */ static char str_conv_ps[] = { "f2v_%lu.ps" }; /** File name format for temporary files: *.log */ static char str_conv_log[] = { "f2v_%lu.log" }; /** File name format for temporary files: *.aux */ static char str_conv_aux[] = { "f2v_%lu.aux" }; /** Name of string table to load for application. */ static char string_table_name[] = { "fig2vect" }; /** Mode string to open files for binary writing. */ static char default_write_mode[] = { "wb" }; /** Mode string to open files for writing. */ static char text_write_mode[] = { "w" }; /** Cleanup options storage. Release memory for options, storage and iterator of a conversion structure. This function is invoked from dkfig_co_cleanup(). @param s Storage. @param i Storage iterator. */ static void cleanup_options_iterator DK_P2(dk_storage_t *,s,dk_storage_iterator_t *,i) { dk_fig_opt *o; if((s) && (i)) { dksto_it_reset(i); while((o = (dk_fig_opt *)dksto_it_next(i)) != NULL) { dkfig_opt_delete(o); } dksto_it_close(i); } if(s) { dksto_close(s); } } /** Clean up conversion job structure before releasing the memory. This function is invoked from dkfig_co_delete() or dkfig_co_new(). @param c Conversion job structure. */ void dkfig_co_cleanup DK_P1(dk_fig_conversion *,c) { char *cp; if(c) { c->app = NULL; if(c->uc2lat) { dkle_close(c->uc2lat); c->uc2lat = NULL; } if(c->uc2ldir) { cp = c->uc2ldir; dk_delete(cp); c->uc2ldir = NULL; } cleanup_options_iterator(c->opt, c->opti); c->opt = NULL; c->opti = NULL; cleanup_options_iterator(c->optg, c->optgi); c->optg = NULL; c->optgi = NULL; cleanup_options_iterator(c->optb, c->optbi); c->optb = NULL; c->optbi = NULL; cleanup_options_iterator(c->optd, c->optdi); c->optd = NULL; c->optdi = NULL; c->optn = c->opt1 = c->opt2 = 0UL; c->image_align = 4 * DKFIG_ALIGN_V_CENTERED + DKFIG_ALIGN_H_CENTERED; if(c->tpfn) { cp = c->tpfn; dk_delete(cp); } c->tpfn = NULL; if(c->texn) { cp = c->texn; dk_delete(cp); } c->texn = NULL; if(c->dvin) { cp = c->dvin; dk_delete(cp); } c->dvin = NULL; if(c->psn) { cp = c->psn; dk_delete(cp); } c->psn = NULL; if(c->logn) { cp = c->logn; dk_delete(cp); } c->logn = NULL; if(c->auxn) { cp = c->auxn; dk_delete(cp); } c->auxn = NULL; if(c->fcfg) { cp = c->fcfg; dk_delete(cp); } c->fcfg = NULL; if(c->cfgfn) { cp = c->cfgfn; dk_delete(cp); } c->cfgfn = NULL; if(c->drn) { cp = c->drn; dk_delete(cp); } c->drn = NULL; if(c->defdr) { cp = c->defdr; dk_delete(cp); } c->defdr = NULL; if(c->basdr) { cp = c->basdr; dk_delete(cp); } c->basdr = NULL; c->ifn1 = c->ofn1 = c->ifn2 = c->ofn2 = NULL; c->normal_text = c->special_text = 0; if(c->msg1) { char **xp; xp = c->msg1; dk_delete(xp); } c->msg1 = NULL; c->istrm = NULL; c->ostrm = NULL; c->bdnum = 0; c->svgv = 0; c->svgs = 0; } } /** Cleanup up and release conversion job structure. @param c Conversion job structure. */ void dkfig_co_delete DK_P1(dk_fig_conversion *,c) { if(c) { dkfig_co_cleanup(c); dk_delete(c); } } /** Initialize options storage. This function is invoked during the initialization of a conversion job structure. @param c Conversion job structure. @param what Index, which storage to initialize. */ static void initialize_options_storage DK_P2(dk_fig_conversion *,c,int,what) { dk_storage_t *mys = NULL; dk_storage_iterator_t *myi = NULL; if((what >= 0) && (what <= 3)) { mys = dksto_open(3); if(mys) { dksto_set_comp(mys, dkfig_opt_compare, 0); myi = dksto_it_open(mys); if(!(myi)) { if(c->app) { dkapp_err_memory(c->app, sizeof(dk_storage_iterator_t), 1); } } } else { if(c->app) { dkapp_err_memory(c->app, sizeof(dk_storage_t), 1); } } switch(what) { case 0: c->opt = mys; c->opti = myi; break; case 1: c->optg = mys; c->optgi = myi; break; case 2: c->optb = mys; c->optbi = myi; break; case 3: c->optd = mys; c->optdi = myi; break; } } } /** Find names for temporary files. @param c Conversion job structure. @return 1 on success, 0 on error. */ static int set_tex_filenames DK_P1(dk_fig_conversion *,c) { /* As TeX produces *.dvi files in the current directory (there is no option to change this) we keep both *.tex and *.dvi in the current directory. The *.ps file is created here too. */ int back = 0; unsigned long mypid = 0UL; char buffer[64]; mypid = (unsigned long)dksf_getpid(); #if DK_HAVE_SNPRINTF snprintf(buffer, sizeof(buffer), str_conv_format, mypid); buffer[sizeof(buffer)-1] = '\0'; #else sprintf(buffer, str_conv_format, mypid); #endif c->texn = dkstr_dup(buffer); #if DK_HAVE_SNPRINTF snprintf(buffer, sizeof(buffer), str_conv_dvi, mypid); buffer[sizeof(buffer)-1] = '\0'; #else sprintf(buffer, str_conv_dvi, mypid); #endif c->dvin = dkstr_dup(buffer); #if DK_HAVE_SNPRINTF snprintf(buffer, sizeof(buffer), str_conv_ps, mypid); buffer[sizeof(buffer)-1] = '\0'; #else sprintf(buffer, str_conv_ps, mypid); #endif c->psn = dkstr_dup(buffer); #if DK_HAVE_SNPRINTF snprintf(buffer, sizeof(buffer), str_conv_log, mypid); buffer[sizeof(buffer)-1] = '\0'; #else sprintf(buffer, str_conv_log, mypid); #endif c->logn = dkstr_dup(buffer); #if DK_HAVE_SNPRINTF snprintf(buffer, sizeof(buffer), str_conv_aux, mypid); buffer[sizeof(buffer)-1] = '\0'; #else sprintf(buffer, str_conv_aux, mypid); #endif c->auxn = dkstr_dup(buffer); if((c->texn) && (c->dvin) && (c->psn) && (c->logn) && (c->auxn)) { back = 1; } return back; } /** Initialize newly created conversion job structure, use default values and preferences obtained from \arg a. @param c New conversion job structure. @param a Application structure. @return 1 on success, 0 on error. */ int dkfig_co_init DK_P2(dk_fig_conversion *,c,dk_app_t *,a) { int back = 0; char buffer[32], *p1; if(c) { c->app = a; c->opt = NULL; c->opti = NULL; c->optg = NULL; c->optgi = NULL; c->optb = NULL; c->optbi = NULL; c->optd = NULL; c->optdi = NULL; c->optn = 0UL; c->opt1 = builtin_default_options1; c->opt2 = builtin_default_options2; c->uc2lat = NULL; c->uc2ldir = NULL; c->af = 0x00; c->paper_width = 595; c->paper_height = 842; c->paper_xleft = 57; c->paper_xright = 538; c->paper_ytop = 814; c->paper_ybottom = 29; c->align_h = DKFIG_ALIGN_H_CENTERED; c->align_v = DKFIG_ALIGN_V_CENTERED; c->image_align = 4 * DKFIG_ALIGN_V_CENTERED + DKFIG_ALIGN_H_CENTERED; if(c->app) { long mpl; mpl = dksf_get_maxpathlen(); c->uc2ldir = dk_new(char,(size_t)mpl); if(c->uc2ldir) { (c->uc2ldir)[0] = '\0'; if(dkapp_get_pref(c->app, pk_shdir, c->uc2ldir, (size_t)mpl, 0)) { if((long)(strlen(c->uc2ldir) + strlen(str_uc2l)) < mpl) { strcat(c->uc2ldir, str_uc2l); c->uc2lat = dkle_open(c->uc2ldir); if(!(c->uc2lat)) { dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 118); } } else { /* ERROR: Shared directory name too large */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 117); } } else { /* ERROR: Failed to find shared directory */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 116); } } else { /* ERROR: Memory */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 12); } } c->nodcoord = 2; c->nodtrigo = 3; c->nodcolor = 3; c->circlesteps = 4; c->psl = 0; c->dscl = 0; c->istrm = NULL; c->ostrm = NULL; c->latfs = -1; c->drn = c->defdr = c->basdr = NULL; c->ifn1 = c->ofn1 = NULL; c->ifn2 = c->ofn2 = NULL; c->normal_text = c->special_text = 0; c->fsf = 1.0; c->msg1 = NULL; c->cfgfn = NULL; c->bdnum = -1; c->spseg = 8; c->texn = NULL; c->dvin = NULL; c->psn = NULL; c->logn = NULL; c->auxn = NULL; c->tpfn = NULL; c->incg = NULL; c->fcfg = NULL; c->patlw = 1L; c->patrp = 8L; c->ahlj = 0; c->minitsteps = 8UL; c->maxitsteps = 2048UL; c->svgv = DKFIG_SVG_VERS_11; /* SVG 1.1 by default */ initialize_options_storage(c,0); /* opt (command line) */ initialize_options_storage(c,1); /* optg (global options) */ initialize_options_storage(c,2); /* optb (base options) */ initialize_options_storage(c,3); /* optd (driver options) */ c->msg1 = dkapp_find_key_value(a, kv, szkv, string_table_name); if((c->opt) && (c->opti) && (c->msg1) && (c->optg) && (c->optgi) && (c->optb) && (c->optbi) && (c->optd) && (c->optdi) && (c->uc2ldir) && (c->uc2lat)) { back = set_tex_filenames(c); if(back) { if(c->app) { c->defdr = dkapp_get_str_pref(c->app, pk_language); switch(dkapp_get_bool_pref(c->app, pk_make)) { case 0: { c->opt1 &= (~DKFIG_OPT_MAKE); } break; case 1: { c->opt1 |= DKFIG_OPT_MAKE; } break; } if(dkapp_get_pref(c->app, pk_utf8, buffer,sizeof(buffer), 0)) { (void)dkfig_tool2_set_utf8(c, buffer, 1); } else { /* As jFig and XFig 3.2.5 do not write UTF-8 encoded text, * we do no longer inspect the LANG environment variable * automatically. The LANG test is done only on a users * request, i.e. if the user still uses XFig 3.2.4. */ (void)dkfig_tool2_utf8_auto(c); } if(dkapp_get_pref(c->app, pk_alph, buffer, sizeof(buffer), 0)) { p1 = dkstr_start(buffer, NULL); if(p1) { dkstr_chomp(p1, NULL); if(dkstr_is_bool(p1)) { if(dkstr_is_on(p1)) { c->opt2 |= DKFIG_OPT_SUPPRESS_ALPHA_INFO; } } } } } } } } return back; } /** Allocate new dk_fig_conversion structure and initialize it. @param a Application structure. @return Pointer to new conversion job structure on success, NULL on error. */ dk_fig_conversion * dkfig_co_new DK_P1(dk_app_t *,a) { dk_fig_conversion *back = NULL; back = dk_new(dk_fig_conversion,1); if(back) { if(!dkfig_co_init(back, a)) { dkfig_co_delete(back); back = NULL; } } if(!back) { if(a) { dkapp_err_memory(a, sizeof(dk_fig_conversion), 1); } } return back; } /** Set/reset one bit in an unsigned long depending on the string \arg p retrieved from the preference system. @param a Old option value. @param p String to inspcect. @param f Flag bit value to set or reset. @param d Default value. @return New flag set. */ static unsigned long check_bool_opts DK_P4(unsigned long,a,char *,p,unsigned long,f,int,d) { unsigned long back; int what; back = a; what = d; if(dkstr_is_bool(p)) { what = dkstr_is_on(p); } if(what) { back |= f; } else { back &= (~f); } return back; } /** Get base driver number. @param n Driver name. @return The base driver number (or -1 on error). */ static int get_base_driver DK_P1(char *,n) { int back = -1; if(n) { back = dkstr_array_index(base_driver_names, n, 1); } return back; } /** Add an option. @param c Conversion job structure. @param on Option number. @param p Option text (key=value). @param bck Pointer to variable for error code. */ static void add_opt DK_P4(dk_fig_conversion *,c,unsigned long,on,char *,p,int *,bck) { dk_fig_opt *opt; if(c->opt) { opt = dkfig_opt_new(on,p); if(opt) { if(!dksto_add(c->opt, (void *)opt)) { dkfig_opt_delete(opt); *bck = ((*bck) | DKFIG_WHAT_ERROR); if(c->app) { dkapp_err_memory(c->app, sizeof(dk_storage_node_t), 1); } } } else { *bck = ((*bck) | DKFIG_WHAT_ERROR); if(c->app) { dkapp_err_memory(c->app, sizeof(dk_fig_opt), 1); } } } else { *bck = ((*bck) | DKFIG_WHAT_ERROR); } } /** Set driver name. @param c Conversion job structure. @param drn Driver name. @param bck Pointer to variable for error code. */ static void set_driver DK_P3(dk_fig_conversion *,c,char *,drn,int *,bck) { if(c->drn) { *bck = ((*bck) | DKFIG_WHAT_ERROR); } else { c->drn = dkstr_dup(drn); if(!(c->drn)) { *bck = ((*bck) | DKFIG_WHAT_ERROR); if(c->app) { dkapp_err_memory(c->app, 1, (1+strlen(drn))); } } } } /** Apply command line arguments to conversion job. @param c Conversion job structure. @param argc Number of command line arguments. @param argv Command line arguments array. @return 1 on success, 0 on error. */ int dkfig_co_apply_args DK_P3(dk_fig_conversion *,c,int,argc,char **,argv) { int back = 0; int i, found; char *ptr, *xptr, **lfdptr; unsigned long onum; if(c) { if(argc > 0) { if(argv) { lfdptr = argv; lfdptr++; i=1; found = 0; onum = 0UL; while(i < argc) { ptr = *lfdptr; if(*ptr == '-') { ptr++; switch(*ptr) { case '-' : { ptr++; xptr = strchr(ptr, '='); if(xptr) { *(xptr++) = '\0'; } found = dkstr_array_abbr(longopt_keywords, ptr, (char)'$', 1); switch(found) { case 0: { back |= DKFIG_WHAT_VERSION; } break; case 1: { back |= DKFIG_WHAT_HELP; } break; case 2: { back |= DKFIG_WHAT_CONFIGURE; } break; case 3: { back |= DKFIG_WHAT_UNCONFIGURE; } break; case 4: { back |= DKFIG_WHAT_SHOWCONF; } break; case 5: { if(xptr) { c->opt1 = check_bool_opts(c->opt1, xptr, DKFIG_OPT_MAKE, 1); } else { c->opt1 = c->opt1 | DKFIG_OPT_MAKE; } } break; case 6: { if(xptr) { add_opt(c, onum++, xptr, &back); } else { back = DKFIG_WHAT_ERROR; } } break; case 7: { if(xptr) { set_driver(c, xptr, &back); } else { back = DKFIG_WHAT_ERROR; } } break; case 8: { c->opt1 = (c->opt1) | DKFIG_OPT_RESET | DKFIG_OPT_MAKE; if(c->drn) { char *mycptr; mycptr = c->drn; dk_delete(mycptr); c->drn = NULL; } } break; case 9: {} break; case 10: { back |= DKFIG_WHAT_CONFIG_FILE; } break; case 11: { back |= DKFIG_WHAT_WRITE_CONFIG_FILE; } break; default: { back |= DKFIG_WHAT_ERROR; } break; } } break; case 'C' : { back |= DKFIG_WHAT_SHOWCONF; } break; case 'c' : { back |= DKFIG_WHAT_CONFIGURE; } break; case 'u' : { back |= DKFIG_WHAT_UNCONFIGURE; } break; case 'h' : { back |= DKFIG_WHAT_HELP; } break; case 'v' : { back |= DKFIG_WHAT_VERSION; } break; case 'a' : { c->af = 0x01; } break; case 'm' : { ptr++; if(*ptr) { c->opt1 = check_bool_opts(c->opt1, ptr, DKFIG_OPT_MAKE, 1); } else { c->opt1 |= DKFIG_OPT_MAKE; } } break; case 'r' : { c->opt1 = (c->opt1) | DKFIG_OPT_RESET | DKFIG_OPT_MAKE; if(c->drn) { char *mycptr; mycptr = c->drn; dk_delete(mycptr); c->drn = NULL; } } break; case 'l' : { ptr++; if(!(*ptr)) { ptr = NULL; lfdptr++; i++; if(i < argc) { ptr = *lfdptr; } } if(ptr) { set_driver(c, ptr, &back); } else { back |= DKFIG_WHAT_ERROR; } } break; case 'o' : { ptr++; if(!(*ptr)) { ptr = NULL; lfdptr++; i++; if(i < argc) { ptr = *lfdptr; } } if(ptr) { add_opt(c, onum++, ptr, &back); } else { back |= DKFIG_WHAT_ERROR; } } break; case 's' : { } break; case 'i': { ptr++; if(!(*ptr)) { ptr = NULL; lfdptr++; i++; if(i < argc) { ptr = *lfdptr; } } if(ptr) { c->incg = ptr; } else { back |= DKFIG_WHAT_ERROR; } } break; case 'A': { ptr++; if(*ptr == '-') { c->opt2 &= (~(DKFIG_OPT_SUPPRESS_ALPHA_INFO)); } else { c->opt2 |= DKFIG_OPT_SUPPRESS_ALPHA_INFO; } } break; default: { back |= DKFIG_WHAT_ERROR; } break; } } else { if(c->ifn1) { if(c->ofn1) { back |= DKFIG_WHAT_ERROR; } else { c->ofn1 = ptr; } } else { c->ifn1 = ptr; } } lfdptr++; i++; } } } } return back; } /** Show current configuration. @param c Configuration job structure. */ void dkfig_co_showconf_app DK_P1(dk_fig_conversion *,c) { char *valptr1, *valptr2, *valptr3; size_t sz1, sz2, sz3, szx, i; if(c->msg1) { dkapp_stdout(c->app, (c->msg1)[5]); fputc('\n', stdout); valptr1 = (c->opt1 & DKFIG_OPT_MAKE) ? ((c->msg1)[0]) : ((c->msg1)[1]); valptr2 = (c->msg1)[4]; valptr3 = (c->opt2 & DKFIG_OPT_SUPPRESS_ALPHA_INFO) ? ((c->msg1)[0]) : ((c->msg1)[1]); if(c->drn) { valptr2 = c->drn; } else { if(!(c->opt1 & DKFIG_OPT_RESET)) { if(c->defdr) { valptr2 = c->defdr; } } } sz1 = dkapp_prlen(c->app, valptr1); sz2 = dkapp_prlen(c->app, valptr2); sz3 = dkapp_prlen(c->app, valptr3); if(sz1 > sz2) szx = sz1; else szx = sz2; if(szx < sz3) szx = sz3; dkapp_stdout(c->app, "-l "); dkapp_stdout(c->app, valptr2); for(i = sz2; i < szx; i++) fputc(' ', stdout); dkapp_stdout(c->app, " "); dkapp_stdout(c->app, (c->msg1)[3]); fputc('\n', stdout); dkapp_stdout(c->app, "-m "); dkapp_stdout(c->app, valptr1); for(i = sz1; i < szx; i++) fputc(' ', stdout); dkapp_stdout(c->app, " "); dkapp_stdout(c->app, (c->msg1)[2]); fputc('\n', stdout); dkapp_stdout(c->app, "-A "); dkapp_stdout(c->app, valptr3); for(i = sz1; i < szx; i++) fputc(' ', stdout); dkapp_stdout(c->app, " "); dkapp_stdout(c->app, (c->msg1)[132]); fputc('\n', stdout); } } /** Save current configuration. @param c Conversion job structure. @return 1 on success, 0 on error. */ int dkfig_co_configure_app DK_P1(dk_fig_conversion *,c) { int back = 0; char *valptr; if((c->app) && (c->msg1)) { back = 1; valptr = ((c->opt1) & DKFIG_OPT_MAKE) ? (c->msg1)[0] : (c->msg1)[1]; if(!dkapp_set_pref(c->app, pk_make, valptr)) { back = 0; } valptr = pv_empty; if(c->drn) { valptr = c->drn; } else { if((c->defdr) && (!(c->opt1 & DKFIG_OPT_RESET))) { valptr = c->defdr; } } if(!dkapp_set_pref(c->app, pk_language, valptr)) { back = 0; } if(!dkapp_set_pref( c->app, pk_alph, bool_val[((c->opt2) & DKFIG_OPT_SUPPRESS_ALPHA_INFO) ? 1 : 0] )) { back = 0; } dkfig_co_showconf_app(c); } if(!back) { /* ERROR: Failed to save new configuration! */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 8); } return back; } /** Find base driver name. @param c Conversion job structure. */ static void establish_base_driver_name DK_P1(dk_fig_conversion *,c) { char *cp = NULL; if(!(c->basdr)) { if(!(c->drn)) { if(c->ofn1) { cp = dksf_get_file_type_dot(c->ofn1); if(cp) { cp++; if(strlen(cp) > 0) { c->drn = dkstr_dup(cp); } } cp = NULL; } } if(c->drn) { c->basdr = dkstr_dup(c->drn); if(!(c->basdr)) { if(c->app) { dkapp_err_memory(c->app, sizeof(char), (1+strlen(c->drn))); } } } else { if(c->defdr) { c->basdr = dkstr_dup(c->defdr); if(!(c->basdr)) { if(c->app) { dkapp_err_memory(c->app, sizeof(char), (1+strlen(c->defdr))); } } } } } if(c->basdr) { cp = dkstr_chr(c->basdr, '.'); if(cp) { *cp = '\0'; } } } /** Process one line from configuration file. @param c Conversion job structure. @param l Line text. @param ln Line number. @param st Storage selector (0=global options, 1=base driver options, 2=driver options). @return 1 on success, 0 on error. */ static int add_option_line DK_P4(dk_fig_conversion *,c,char *,l,unsigned long,ln,int,st) { int back = 0; dk_storage_t *sto = NULL; dk_fig_opt *opt; switch(st) { case 0: sto = c->optg; break; case 1: sto = c->optb; break; case 2: sto = c->optd; break; } if(sto) { opt = dkfig_opt_new(ln,l); if(opt) { if(dksto_add(sto, (void *)opt)) { back = 1; } else { dkapp_err_memory(c->app, sizeof(dk_storage_node_t), 1); } } else { if(c->app) { dkapp_err_memory(c->app, sizeof(dk_fig_opt), 1); } } } return back; } /** Read configuration file and load contents to the storages. @param c Conversion job structure. @return 1 on success, 0 on error. */ static int dkfig_co_load_configuration DK_P1(dk_fig_conversion *,c) { int back = 0; int state; char *buffer, *cp, *cp2; dk_stream_t *cfgstr; long l; size_t sz; unsigned long lineno; establish_base_driver_name(c); if(c->app) { c->cfgfn = dkapp_find_file_dup(c->app, short_config_filename); } else { c->cfgfn = dkstr_dup(default_config_filename); } if(c->cfgfn) { /* DEBUG: Configuration file ... is used */ dkfig_tool2_msg3(c, DK_LOG_LEVEL_DEBUG, 9, 10, c->cfgfn); cp = dksf_get_file_type_dot(c->cfgfn); if(cp) { state = dkstr_array_index(suffixes, cp, have_fncaseins); } cfgstr = NULL; switch(state) { case 0: { #if DK_HAVE_ZLIB_H cfgstr = dkstream_opengz(c->cfgfn, str_r, 0, NULL); #else dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 6); #endif } break; case 1: { #if DK_HAVE_BZLIB_H cfgstr = dkstream_openbz2(c->cfgfn, str_r, 0, NULL); #else dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 7); #endif } break; default: { cfgstr = dkstream_openfile(c->cfgfn, str_r, 0, NULL); } break; } if(cfgstr) { l = 256L + dksf_get_maxpathlen(); sz = (size_t)l; buffer = dk_new(char,sz); if(buffer) { back = 1; state = -1; lineno = 0UL; while(dkstream_gets(cfgstr, buffer, sz)) { dkstr_delcomm(buffer, (char)'#'); lineno++; cp = dkstr_start(buffer, NULL); if(cp) { dkstr_chomp(cp, NULL); if(*cp == '[') { state = -1; cp2 = dkstr_rchr(cp, ']'); if(cp2) { *cp2 = '\0'; } cp++; cp = dkstr_start(cp, NULL); if(cp) { dkstr_chomp(cp, NULL); if(strcmp(cp, "*") == 0) { state = 0; } else { if(c->drn) { if(strcmp(cp, c->drn) == 0) { state = 2; } } else { if(c->defdr) { if(strcmp(cp, c->defdr) == 0) { state = 2; } } } if(state == -1) { if(c->basdr) { if(strcmp(cp, c->basdr) == 0) { state = 1; } } } } } } else { switch(state) { case 0: { /* general option */ if(!add_option_line(c,cp,lineno,state)) { back = 0; } } break; case 1: { /* base driver option */ if(!add_option_line(c,cp,lineno,state)) { back = 0; } } break; case 2: { /* driver option */ if(!add_option_line(c,cp,lineno,state)) { back = 0; } } break; } } } } dk_delete(buffer); buffer = NULL; } else { if(c->app) dkapp_err_memory(c->app, sizeof(char), sz); } dkstream_close(cfgstr); cfgstr = NULL; } else { if(c->app) dkapp_err_fopenr(c->app, c->cfgfn); } /* cp = c->cfgfn; dk_delete(c->cfgfn); c->cfgfn = NULL; */ } return back; } /** Find largest line size in a storage. @param sto Storage. @param it Storage iterator. @return Line size of the longest option. */ static size_t largest_of DK_P2(dk_storage_t *,sto,dk_storage_iterator_t *,it) { size_t sz = 0, back = 0; dk_fig_opt *o; if(sto && it) { dksto_it_reset(it); while((o = (dk_fig_opt *)dksto_it_next(it)) != NULL) { if(o->name) { sz = strlen(o->name); if(sz > back) { back = sz; } } } } return back; } /** Find largest line size for all option storages. @param c Conversion job structure. */ static void set_lcfge DK_P1(dk_fig_conversion *,c) { size_t back = 0; c->lcfge = 0; back = largest_of(c->opt, c->opti); if(back > c->lcfge) c->lcfge = back; back = largest_of(c->optg, c->optgi); if(back > c->lcfge) c->lcfge = back; back = largest_of(c->optb, c->optbi); if(back > c->lcfge) c->lcfge = back; back = largest_of(c->optd, c->optdi); if(back > c->lcfge) c->lcfge = back; } /** Add input stream contents to drawing. @param c Conversion job structure @return 1 on success, 0 on error. */ int dkfig_co_add_stream DK_P1(dk_fig_conversion *,c) { int back = 0; size_t sz = 512; char *buffer = NULL, *ptr; int cc; if(c->app) { sz = (size_t)dkapp_get_ul_pref(c->app, pk_linelgt); if(!sz) { sz = 512; } if(sz < 128) sz = 128; if(max_line_length) { if(sz > max_line_length) sz = max_line_length; } } buffer = dk_new(char,sz); if(buffer) { back = cc = 1; while(cc) { if(dkstream_gets(c->istrm, buffer, sz)) { if(strlen(buffer) == (sz - 1)) { if((c->app) && (c->msg1)) { dkapp_set_source_lineno( c->app, (1 + dkfig_rd_get_errl(c->drwng)) ); dkfig_tool2_msg1(c, DK_LOG_LEVEL_WARNING, 58); } } ptr = dkstr_start(buffer, NULL); if(ptr) { dkstr_chomp(ptr, NULL); if(!dkfig_read_add_line(c->drwng, ptr, c)) { back = cc = 0; if(c->app) { dkapp_set_source_lineno(c->app, dkfig_rd_get_errl(c->drwng)); } } } } else { cc = 0; } } if(back) { if(!dkfig_read_input_finished(c->drwng,c->normal_text,c->special_text,c)) { back = 0; if(c->app) { dkapp_set_source_lineno(c->app, dkfig_rd_get_errl(c->drwng)); } } } else { switch(dkfig_rd_get_errc(c->drwng)) { case DKFIG_ERROR_MEMORY: { /* ERROR: Memory allocation failed */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 11); } break; case DKFIG_ERROR_SYNTAX: { dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 12); } break; case DKFIG_ERROR_MATH: { /* ERROR: Math error in calculations */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 13); } break; } } dk_delete(buffer); buffer = NULL; } else { /* ERROR: Memory */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 11); } return back; } /** Run the conversion, write output. This is the place to add new drivers. @param c Conversion job structure. @return 1 on success, 0 on error. */ static int dkfig_co_out_to_stream DK_P1(dk_fig_conversion *,c) { int back = 0; switch(c->bdnum) { case DKFIG_DRIVER_MP: { back = dkfig_output_mp(c); } break; case DKFIG_DRIVER_MMP: { back = dkfig_output_mmp(c); } break; case DKFIG_DRIVER_EPS: { back = dkfig_output_eps(c); } break; case DKFIG_DRIVER_SVG: { back = dkfig_output_svg(c); } break; case DKFIG_DRIVER_TEX: { back = dkfig_output_tex(c); } break; case DKFIG_DRIVER_BB: { back = dkfig_output_bb(c); } break; case DKFIG_DRIVER_PDF: { back = dkfig_output_pdf(c); } break; case DKFIG_DRIVER_PS: { back = dkfig_output_ps(c); } break; case DKFIG_DRIVER_JAVA: { back = dkfig_output_java(c); } break; default: { /* ERROR: Unknown base driver ... */ if(c->app && c->msg1) { char buffer[32]; #if DK_HAVE_SNPRINTF snprintf(buffer, sizeof(buffer), "%d", c->bdnum); buffer[sizeof(buffer)-1] = '\0'; #else sprintf(buffer, "%d", c->bdnum); #endif dkfig_tool2_msg3(c, DK_LOG_LEVEL_ERROR, 14, 15, buffer); } } break; } return back; } /** Run for opened streams. Both input and output stream are opened. Wildcards in file names are expanded, the real file names are in inf2 and ofn2. @param c Conversion job structure. @return 1 on success, 0 on error. */ static int run_for_streams DK_P1(dk_fig_conversion *,c) { int back = 0; int use_web_palette = 0; if((c->opt1) & DKFIG_OPT_WEB_PALETTE) { use_web_palette = 1; } c->drwng = dkfig_new(use_web_palette); if(c->drwng) { if(c->ifn2) { dkfig_set_input_filename(c->drwng, c->ifn2); if(c->app) { dkapp_set_source_filename(c->app, c->ifn2); } } else { if(c->app) { dkapp_set_source_filename(c->app, string_stdin); } } if(c->app) { dkapp_set_source_lineno(c->app, 0UL); } dkfig_set_spline_segments(c->drwng, c->spseg); dkfig_rd_set_opts((dk_fig_drawing *)((c->drwng)->data), c->opt1); dkfig_rd_set_ahlj((dk_fig_drawing *)((c->drwng)->data), c->ahlj); dkfig_rd_set_it_steps( (dk_fig_drawing *)((c->drwng)->data), c->minitsteps, c->maxitsteps ); /* PROGRESS: Reading input file ... */ dkfig_tool2_msg3( c, DK_LOG_LEVEL_PROGRESS, 16, 17, ((c->ifn2) ? c->ifn2 : string_stdin) ); if(dkfig_co_add_stream(c)) { /* PROGRESS: Input file was read successfully */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_PROGRESS, 18); dkfig_tool_correct_for_plain_tex(c); /* PROGRESS: Writing output file ... */ dkfig_tool2_msg3( c, DK_LOG_LEVEL_PROGRESS, 20, 21, ((c->ofn2) ? c->ofn2 : string_stdout) ); back = dkfig_co_out_to_stream(c); if(c->app) { dkapp_set_source_lineno(c->app, 0UL); } /* PROGRESS: Finished writing output file */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_PROGRESS, 22); if(!back) { dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 113); } } else { /* PROGRESS: Finished reading input file, failure! */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_PROGRESS, 19); } if(c->app) { dkapp_set_source_filename(c->app, NULL); } dkfig_delete(c->drwng); c->drwng = NULL; } else { /* ERROR: Memory */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 11); } return back; } /** Run as filter (standard input, standard output). @param c Conversion job structure. @return 1 on success, 0 on error. */ static int run_for_stdio DK_P1(dk_fig_conversion *,c) { int back = 0; int old_stdout_binary = 0; c->istrm = dkstream_for_file(stdin); if(c->istrm) { /* dksf_set_file_binary(stdout); */ old_stdout_binary = dksf_fdesk_binary(1, 1); c->ostrm = dkstream_for_file(stdout); if(c->ostrm) { c->ifn2 = NULL; c->ofn2 = NULL; back = run_for_streams(c); dkstream_close(c->ostrm); c->ostrm = NULL; } else { /* ERROR: No stream */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 24); } dkstream_close(c->istrm); c->istrm = NULL; (void)dksf_fdesk_binary(1, old_stdout_binary); } else { /* ERROR: No stream */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 23); } return back; } /** Find suffix of input file to chech whether the file is plain text or compressed. @param n File name. @return Pointer to suffix or NULL. */ static char * find_fig_suffix DK_P1(char *,n) { char *back = NULL; char **xptr; size_t l1, l2, l3; int i; xptr = figsuffixes; l1 = strlen(n); while((!back) && (*xptr)) { l2 = strlen(*xptr); if(l1 > l2) { l3 = l1 - l2; if(have_fncaseins) { i = dkstr_casecmp(&(n[l3]), *xptr); } else { i = strcmp(&(n[l3]), *xptr); } if(i == 0) { back = &(n[l3]); } } xptr++; } return back; } /** Open output stream and continue. The output file name is fully known now. @param c Conversion job structure. @return 1 on success, 0 on error. */ static int run_with_ofn2 DK_P1(dk_fig_conversion *,c) { int back = 0; int ft = -1; int reason = 0; char *sp; char *sp2; char *write_mode; write_mode= default_write_mode; ft = -1; sp = dksf_get_file_type_dot(c->ofn2); if(sp) { ft = dkstr_array_index(suffixes, sp, have_fncaseins); if(c->bdnum < 1) { if(!(c->basdr)) { sp2 = NULL; if(ft >= 0) { *sp = '\0'; sp2 = dksf_get_file_type_dot(c->ofn2); if(sp2) { sp2++; c->basdr = dkstr_dup(sp2); if(!(c->basdr)) { /* ERROR: Memory */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 11); } } *sp = '.'; } else { sp2 = sp; sp2++; c->basdr = dkstr_dup(sp2); if(!(c->basdr)) { /* ERROR: Memory */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 11); } } } if(c->basdr) { c->bdnum = get_base_driver(c->basdr); } } } else { } if(c->basdr) { if(c->bdnum < 0) { c->bdnum = get_base_driver(c->basdr); } if(c->bdnum > -1) { switch(c->bdnum) { case 0: case 1: case 4: { write_mode = text_write_mode; } break; } switch(ft) { case 0: case 2: { #if DK_HAVE_ZLIB_H if(c->app) { c->ostrm = dkapp_stream_opengz(c->app, c->ofn2, write_mode); } else { c->ostrm = dkstream_opengz(c->ofn2, write_mode, 0, &reason); } if(c->ostrm) { back = run_for_streams(c); dkstream_close(c->ostrm); c->ostrm = NULL; } else { /* ERROR: Failed to write */ if(c->app) { dkapp_err_fopenw(c->app, c->ofn2); } } #else dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 6); #endif } break; case 1: { #if DK_HAVE_BZLIB_H if(c->app) { c->ostrm = dkapp_stream_openbz2(c->app, c->ofn2, write_mode); } else { c->ostrm = dkstream_openbz2(c->ofn2, write_mode, 0, &reason); } if(c->ostrm) { back = run_for_streams(c); dkstream_close(c->ostrm); c->ostrm = NULL; } else { /* ERROR: Failed to write */ if(c->app) { dkapp_err_fopenw(c->app, c->ofn2); } } #else dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 7); #endif } break; default: { if(c->app) { c->ostrm = dkapp_stream_openfile(c->app, c->ofn2, write_mode); } else { c->ostrm = dkstream_openfile(c->ofn2, write_mode, 0, &reason); } if(c->ostrm) { back = run_for_streams(c); dkstream_close(c->ostrm); c->ostrm = NULL; } else { /* ERROR: Failed to write file */ if(c->app) { dkapp_err_fopenw(c->app, c->ofn2); } } } break; } } else { /* ERROR: Unknown base driver */ dkfig_tool2_msg3(c, DK_LOG_LEVEL_ERROR, 25, 26, c->basdr); } } else { /* No base driver specified */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 27); } return back; } /** Run with opened input stream. @param c Conversion job structure. @return 1 on success, 0 on error. */ static int run_with_istream DK_P1(dk_fig_conversion *,c) { int back = 0; int old_stdout_binary = 0; dk_fne_t *fne = NULL; char *tc = NULL; if(c->ofn1) { if(dksf_must_expand_filename(c->ofn1)) { fne = dkfne_open(c->ofn1, 1, 0); if(fne) { if(dkfne_next(fne)) { tc = dkstr_dup(dkfne_get_fullname(fne)); if(tc) { if(dkfne_next(fne)) { /* ERROR: Too many file names */ if(c->app) { dkapp_err_multiple_files(c->app, c->ofn1); } } else { c->ofn2 = tc; back = run_with_ofn2(c); c->ofn2 = NULL; } dk_delete(tc); tc = NULL; } else { /* ERROR: Memory */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 11); } } else { /* ERROR: No such file */ if(c->app) { dkapp_err_no_such_file(c->app, c->ofn1); } } dkfne_close(fne); fne = NULL; } else { /* ERROR: No filename expander */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 11); } } else { c->ofn2 = c->ofn1; back = run_with_ofn2(c); } } else { if(c->basdr) { c->bdnum = get_base_driver(c->basdr); if(c->bdnum > -1) { c->ofn2 = NULL; /* dksf_set_file_binary(stdout); */ old_stdout_binary = dksf_fdesk_binary(1, 1); c->ostrm = dkstream_for_file(stdout); if(c->ostrm) { back = run_for_streams(c); dkstream_close(c->ostrm); c->ostrm = NULL; } else { /* ERROR: No stream */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 24); } (void)dksf_fdesk_binary(1, old_stdout_binary); } else { /* ERROR: Unknown base driver */ dkfig_tool2_msg3(c, DK_LOG_LEVEL_ERROR, 25, 26, c->basdr); } } else { /* ERROR: No base driver */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 27); } } return back; } /** Run with input file name (wildcards are resolved). @param c Conversion job structure. @return 1 on success, 0 on error. */ static int run_with_ifn2 DK_P1(dk_fig_conversion *,c) { int back = 0; int ft = -1; int reason = 0; char *sp; sp = dksf_get_file_type_dot(c->ifn2); if(sp) { ft = dkstr_array_index(suffixes, sp, have_fncaseins); } switch(ft) { case 0: { #if DK_HAVE_ZLIB_H if(c->app) { c->istrm = dkapp_stream_opengz(c->app, c->ifn2, str_r); } else { c->istrm = dkstream_opengz(c->ifn2, str_r, 0, &reason); } if(c->istrm) { back = run_with_istream(c); dkstream_close(c->istrm); c->istrm = NULL; } else { /* ERROR: Failed to read */ if(c->app) { dkapp_err_fopenr(c->app, c->ifn2); } } #else /* ERROR: No zlib support */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 6); #endif } break; case 1: { #if DK_HAVE_BZLIB_H if(c->app) { c->istrm = dkapp_stream_openbz2(c->app, c->ifn2, str_r); } else { c->istrm = dkstream_openbz2(c->ifn2, str_r, 0, &reason); } if(c->istrm) { back = run_with_istream(c); dkstream_close(c->istrm); c->istrm = NULL; } else { /* ERROR: Failed to read */ if(c->app) { dkapp_err_fopenr(c->app, c->ifn2); } } #else /* ERROR: No bzip2 support */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 7); #endif } break; default: { if(c->app) { c->istrm = dkapp_stream_openfile(c->app, c->ifn2, str_r); } else { c->istrm = dkstream_openfile(c->ifn2, str_r, 0, &reason); } if(c->istrm) { back = run_with_istream(c); dkstream_close(c->istrm); c->istrm = NULL; } else { /* ERROR: No stream */ if(c->app) { dkapp_err_fopenr(c->app, c->ifn2); } } } break; } return back; } /** Run with filenames possibly containing wildcards. @param c Conversion job structure. @return 1 on success, 0 on error. */ static int run_for_filenames DK_P1(dk_fig_conversion *,c) { int back = 0; dk_fne_t *fne = NULL; char *tc = NULL; c->ifn2 = NULL; if(c->ifn1) { if(dksf_must_expand_filename(c->ifn1)) { fne = dkfne_open(c->ifn1, 1, 0); if(fne) { if(dkfne_next(fne)) { tc = dkstr_dup(dkfne_get_fullname(fne)); if(tc) { if(dkfne_next(fne)) { /* ERROR: Too many file names match pattern */ if(c->app) { dkapp_err_multiple_files(c->app, c->ifn1); } } else { c->ifn2 = tc; back = run_with_ifn2(c); c->ifn2 = NULL; } dk_delete(tc); tc = NULL; } else { /* ERROR: Memory */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 11); } } else { /* ERROR: No matching file name */ if(c->app) { dkapp_err_no_such_file(c->app, c->ifn1); } } dkfne_close(fne); fne = NULL; } else { /* ERROR: No file name expander */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 11); } } else { c->ifn2 = c->ifn1; back = run_with_ifn2(c); c->ifn2 = NULL; } } else { if(c->basdr) { c->bdnum = get_base_driver(c->basdr); if(c->bdnum > -1) { back = run_for_stdio(c); } else { /* ERROR: Unknown base driver */ dkfig_tool2_msg3(c, DK_LOG_LEVEL_ERROR, 25, 26, c->basdr); } } else { /* ERROR: No base driver */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 27); } } c->ifn2 = NULL; return back; } /** Save conversion job settings. @param cd Destination structure. @param cs Source structure. */ static void save_co_settings DK_P2(dk_fig_conversion *,cd, dk_fig_conversion *,cs) { cd->normal_text = cs->normal_text; cd->special_text = cs->special_text; cd->ahlj = cs->ahlj; cd->latfs = cs->latfs; cd->svgv = cs->svgv; cd->psl = cs->psl; cd->dscl = cs->dscl; cd->spseg = cs->spseg; cd->lcfge = cs->lcfge; cd->patlw = cs->patlw; cd->patrp = cs->patrp; cd->nodcoord = cs->nodcoord; cd->nodtrigo = cs->nodtrigo; cd->nodcolor = cs->nodcolor; cd->circlesteps = cs->circlesteps; cd->maxitsteps = cs->maxitsteps; cd->minitsteps = cs->minitsteps; cd->fsf = cs->fsf; } /** Run for a directory, convert all Fig files found. @param c Conversion job structure. @return 1 on success, 0 on error. */ static int run_for_directory DK_P1(dk_fig_conversion *,c) { int back = 0; int ft = 0; int doit = 0; int dnt = 0; dk_dir_t *dir = NULL; long l; size_t sz; /* size for buffers */ char *iname = NULL; /* input file name */ char *oname = NULL; /* output file name */ char *nname = NULL; /* next full name obtained from directory */ char *sp = NULL; /* pointer to the file name suffix */ char *bck_tpfn; dk_fig_conversion backupco; if((c->basdr) && (c->bdnum > -1)) { l = dksf_get_maxpathlen(); sz = (size_t)l; iname = dk_new(char,sz); oname = dk_new(char,sz); if(iname && oname) { dir = dkdir_open(c->ifn1); if(dir) { bck_tpfn = NULL; while((dnt = dkdir_next(dir))) { if(dnt == 1) { nname = dkdir_get_fullname(dir); if(nname) { if(!(dksf_is_directory(nname))) { if(strlen(nname) < sz) { strcpy(iname, nname); strcpy(oname, nname); sp = find_fig_suffix(oname); if(sp) { ft = dkstr_array_index(figsuffixes,sp,have_fncaseins); if(ft >= 0) { sp++; *sp = '\0'; if(strlen(oname)+strlen(c->basdr) < sz) { strcpy(sp, c->basdr); doit = 1; if((c->opt1) & DKFIG_OPT_MAKE) { /* doit = check_must_run(iname, oname); */ doit = dksf_must_rebuild(oname, iname); } if(doit) { c->ifn2 = iname; c->ofn1 = oname; bck_tpfn = NULL; if(c->tpfn) { bck_tpfn = dkstr_dup(c->tpfn); if(!bck_tpfn) { /* ERROR: Memory */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 11); } } save_co_settings(&backupco, c); back = run_with_ifn2(c); save_co_settings(c, &backupco); if(bck_tpfn) { if(c->tpfn) { char *x; x = c->tpfn; dk_delete(x); c->tpfn = NULL; } c->tpfn = NULL; c->tpfn = bck_tpfn; bck_tpfn = NULL; } bck_tpfn = NULL; c->ifn2 = NULL; c->ofn1 = NULL; } else { /* not necessary to run */ /* PROGRESS: No need to run for ... -> ... */ dkfig_tool2_msg3(c, DK_LOG_LEVEL_PROGRESS, 28, 29, iname); } } else { /* ERROR: Output file name too long */ if(c->app && c->msg1) { char *msg[5]; msg[0] = (c->msg1)[30]; msg[1] = oname; msg[2] = string_dot; msg[3] = c->basdr; msg[4] = (c->msg1)[31]; dkapp_log_msg(c->app, DK_LOG_LEVEL_ERROR, msg, 5); } } } else { } } } else { } } } else { } } else { } } dkdir_close(dir); dir = NULL; } else { /* ERROR: Failed to open directory */ if(c->app) { dkapp_err_traverse_dir(c->app, c->ifn1 ); } } } else { /* ERROR: Memory */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 11); } if(oname) { dk_delete(oname); oname = NULL; } if(iname) { dk_delete(iname); iname = NULL; } } return back; } /** Check whether running on files or on a directory, run the conversion(s). @param c Conversion job structure. @return 1 on success, 0 on error. */ static int lets_go_now DK_P1(dk_fig_conversion *,c) { int back = 0; char *auto_file_name = NULL, *ptr = NULL; size_t lgt; c->bdnum = -1; if(c->ofn1) { back = run_for_filenames(c); } else { if(c->ifn1) { if(dksf_must_expand_filename(c->ifn1)) { back = run_for_filenames(c); } else { if(dksf_is_directory(c->ifn1)) { if(c->basdr) { c->bdnum = get_base_driver(c->basdr); if(c->bdnum >= 0) { back = run_for_directory(c); } else { /* ERROR: No such base driver */ dkfig_tool2_msg3(c, DK_LOG_LEVEL_ERROR, 25, 26, c->basdr); } } else { /* ERROR: No base driver specified */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 27); } } else { if(c->basdr) { c->bdnum = get_base_driver(c->basdr); } if(c->af) { if(c->bdnum >= 0) { lgt = 5 + strlen(c->ifn1); auto_file_name = dk_new(char,lgt); if(auto_file_name) { strcpy(auto_file_name, c->ifn1); ptr = dksf_get_file_type_dot(auto_file_name); if(ptr) { *ptr = '\0'; } switch(c->bdnum) { case DKFIG_DRIVER_MP: { strcat(auto_file_name, output_suffixes[0]); } break; case DKFIG_DRIVER_MMP: { strcat(auto_file_name, output_suffixes[0]); } break; case DKFIG_DRIVER_EPS: { strcat(auto_file_name, output_suffixes[1]); } break; case DKFIG_DRIVER_SVG: { strcat(auto_file_name, output_suffixes[2]); } break; case DKFIG_DRIVER_TEX: { strcat(auto_file_name, output_suffixes[3]); } break; case DKFIG_DRIVER_BB: { strcat(auto_file_name, output_suffixes[4]); } break; case DKFIG_DRIVER_PDF: { strcat(auto_file_name, output_suffixes[5]); } break; case DKFIG_DRIVER_PS: { strcat(auto_file_name, output_suffixes[6]); } break; case DKFIG_DRIVER_JAVA: { strcat(auto_file_name, output_suffixes[7]); } break; } c->ofn1 = auto_file_name; dkfig_tool2_msg3(c, DK_LOG_LEVEL_INFO, 127, 128, auto_file_name); back = run_for_filenames(c); c->ofn1 = NULL; dk_delete(auto_file_name); auto_file_name = NULL; } else { /* ERROR: Memory */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 11); } } else { /* ERROR: Internal error, bdnum not yet known */ } } else { back = run_for_filenames(c); } } } } else { if(c->basdr) { c->bdnum = get_base_driver(c->basdr); if(c->bdnum > -1) { back = run_for_stdio(c); } else { /* ERROR: Unknown base driver */ dkfig_tool2_msg3(c, DK_LOG_LEVEL_ERROR, 25, 26, c->basdr); } } else { /* ERROR: No base driver */ dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 27); } } } return back; } /** Load configuration file, process options and run conversion. @param c Conversion job structure. @return 1 on success, 0 on error. */ int dkfig_co_run DK_P1(dk_fig_conversion *,c) { int back = 0; if(c) { establish_base_driver_name(c); if(dkfig_co_load_configuration(c)) { set_lcfge(c); if(dkfig_opt_process_all(c)) { back = lets_go_now(c); /* Hey ho, let's go */ } } } return back; } /** Show the contents of the used configuration file on standard output. A GUI wrapped around fig2vect may run "fig2vect --configuration-file" to see the driver configurations and the configuration settings. @param c Conversion job structure. @return 1 on success, 0 on error. */ int dkfig_co_show_config_file DK_P1(dk_fig_conversion *,c) { int back = 0; if(c) { back = dkfig_opt_show_config_file(c, short_config_filename); } return back; } /** Save a configuration file read from standard input as user-specific configuration file. A GUI wrapped around fig2vect may allow the user to create driver configurations and passes the configuration file contents as standard input to "fig2vect --write-configuration-file". @param c Conversion job structure. @return 1 on success, 0 on error. */ int dkfig_co_write_config_file DK_P1(dk_fig_conversion *,c) { int back = 0; if(c) { back = dkfig_opt_write_config_file(c, short_config_filename); } return back; }