"Fossies" - the Fresh Open Source Software Archive

Member "epstool-3.08/src/epstool.c" (10 Jun 2005, 80499 Bytes) of package /linux/misc/old/ghost/ghostgum/epstool-3.08-os2.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* Copyright (C) 1995-2005 Ghostgum Software Pty Ltd.  All rights reserved.
    2 
    3   This software is provided AS-IS with no warranty, either express or
    4   implied.
    5 
    6   This software is distributed under licence and may not be copied,
    7   modified or distributed except as expressly authorised under the terms
    8   of the licence contained in the file LICENCE in this distribution.
    9 
   10   For more information about licensing, please refer to
   11   http://www.ghostgum.com.au/ or contact Ghostsgum Software Pty Ltd, 
   12   218 Gallaghers Rd, Glen Waverley VIC 3150, AUSTRALIA, 
   13   Fax +61 3 9886 6616.
   14 */
   15 
   16 /* $Id: epstool.c,v 1.69 2005/06/10 08:45:36 ghostgum Exp $ */
   17 
   18 #include "common.h"
   19 #include "dscparse.h"
   20 #include "errors.h"
   21 #include "iapi.h"
   22 #include "gdevdsp.h"
   23 #define DEFINE_COPT
   24 #include "copt.h"
   25 #define DEFINE_CAPP
   26 #include "capp.h"
   27 #include "cbmp.h"
   28 #define DEFINE_CDOC
   29 #include "cdoc.h"
   30 #include "cdll.h"
   31 #include "cgssrv.h"
   32 #include "cmac.h"
   33 #include "ceps.h"
   34 #include "cimg.h"
   35 #include "cpagec.h"
   36 #include "cres.h"
   37 #ifdef __WIN32__
   38 #include "wgsver.h"
   39 #endif
   40 #if defined(UNIX) || defined(OS2)
   41 #include <fcntl.h>
   42 #include <sys/wait.h>
   43 #include <errno.h>
   44 #endif
   45 
   46 const char *epstool_name = "epstool";
   47 const char *epstool_version = "3.08";  /* should be EPSTOOL_VERSION */
   48 const char *epstool_date = "2005-06-06"; /* should be EPSTOOL_DATE */
   49 const char *copyright = "Copyright 1995-2005 Ghostgum Software Pty Ltd";
   50 
   51 const char *cmd_help = "\
   52 Commands (one only):\n\
   53   --add-tiff4-preview        or  -t4\n\
   54   --add-tiff6u-preview       or  -t6u\n\
   55   --add-tiff6p-preview       or  -t6p\n\
   56   --add-tiff-preview         or  -tg\n\
   57   --add-interchange-preview  or  -i\n\
   58   --add-metafile-preview     or  -w\n\
   59   --add-pict-preview\n\
   60   --add-user-preview filename\n\
   61   --dcs2-multi\n\
   62   --dcs2-single\n\
   63   --dcs2-report\n\
   64   --extract-postscript       or  -p\n\
   65   --extract-preview          or  -v\n\
   66   --bitmap\n\
   67   --copy\n\
   68   --dump\n\
   69   --help                     or  -h\n\
   70   --test-eps\n\
   71   --version\n\
   72 ";
   73 
   74 const char *opt_help = "\
   75 Options:\n\
   76   --bbox                     or  -b\n\
   77   --combine-separations filename\n\
   78   --combine-tolerance pts\n\
   79   --custom-colours filename\n\
   80   --debug                    or  -d\n\
   81   --device name\n\
   82   --doseps-reverse\n\
   83   --dpi resolution\n\
   84   --dpi-render resolution\n\
   85   --ignore-information\n\
   86   --ignore-warnings\n\
   87   --ignore-errors\n\
   88   --gs command\n\
   89   --gs-args arguments\n\
   90   --mac-binary\n\
   91   --mac-double\n\
   92   --mac-rsrc\n\
   93   --mac-single\n\
   94   --missing-separations\n\
   95   --output filename\n\
   96   --page-number\n\
   97   --quiet\n\
   98   --rename-separation old_name new_name\n\
   99   --replace-composite\n\
  100 ";
  101 
  102 
  103 typedef enum {
  104     CMD_UNKNOWN,
  105     CMD_TIFF4,
  106     CMD_TIFF6U,
  107     CMD_TIFF6P,
  108     CMD_TIFF,
  109     CMD_INTERCHANGE,
  110     CMD_WMF,
  111     CMD_PICT,
  112     CMD_USER,
  113     CMD_DCS2_MULTI,
  114     CMD_DCS2_SINGLE,
  115     CMD_DCS2_REPORT,
  116     CMD_PREVIEW,
  117     CMD_POSTSCRIPT,
  118     CMD_BITMAP,
  119     CMD_COPY,
  120     CMD_DUMP,
  121     CMD_HELP,
  122     CMD_TEST,
  123     CMD_VERSION
  124 } CMD;
  125 
  126 typedef enum{
  127     CUSTOM_CMYK,
  128     CUSTOM_RGB
  129 } CUSTOM_COLOUR_TYPE;
  130 typedef struct CUSTOM_COLOUR_s CUSTOM_COLOUR;
  131 struct CUSTOM_COLOUR_s {
  132     char name[MAXSTR];
  133     CUSTOM_COLOUR_TYPE type;
  134     /* if type=CUSTOM_CMYK */
  135     float cyan;
  136     float magenta;
  137     float yellow;
  138     float black;
  139     /* if type=CUSTOM_RGB */
  140     float red;
  141     float green;
  142     float blue;
  143     /* Next colour */
  144     CUSTOM_COLOUR *next;
  145 };
  146 typedef struct OPT_s {
  147     CMD cmd;
  148     TCHAR device[64];   /* --device name for --bitmap or --add-tiff-preview */
  149     BOOL composite;     /* --replace-composite */
  150     BOOL bbox;          /* --bbox */
  151     int dscwarn;        /* --ignore-warnings etc. */
  152     TCHAR gs[MAXSTR];       /* --gs command */
  153     TCHAR gsargs[MAXSTR*4]; /* --gs-args arguments */
  154     TCHAR input[MAXSTR];    /* filename */
  155     TCHAR output[MAXSTR];   /* --output filename or (second) filename */
  156     TCHAR user_preview[MAXSTR]; /* --add-user-preview filename */
  157     BOOL quiet;         /* --quiet */
  158     BOOL debug;         /* --debug */
  159     BOOL doseps_reverse;    /* --doseps-reverse */
  160     float dpi;          /* --dpi resolution */
  161     float dpi_render;       /* --dpi-render resolution */
  162     BOOL help;          /* --help */
  163     TCHAR custom_colours[MAXSTR]; /* --custom-colours filename */
  164     CUSTOM_COLOUR *colours;
  165     BOOL missing_separations;   /* --missing-separations */
  166     TCHAR combine[MAXSTR];  /* --combine-separations filename */
  167     int tolerance;      /* --combine-tolerance pts */
  168     RENAME_SEPARATION *rename_sep; /* --rename-separation */
  169     CMAC_TYPE mac_type;     /* --mac-binary, --mac-double, --mac-single */
  170                 /* or --mac-rsrc */
  171     int page;           /* --page-number for --bitmap */
  172     int image_compress;     /* IMAGE_COMPRESS_NONE, RLE, LZW */
  173     int image_encode;       /* IMAGE_ENCODE_HEX, ASCII85 */
  174 } OPT;
  175 
  176 
  177 #define MSGOUT stdout
  178 #ifdef UNIX
  179 const char gsexe[] = "gs";
  180 #define COLOUR_DEVICE "ppmraw"
  181 #define GREY_DEVICE "pgmraw"
  182 #define MONO_DEVICE "pbmraw"
  183 #endif
  184 
  185 #ifdef OS2
  186 TCHAR gsexe[MAXSTR] = TEXT("gsos2.exe");
  187 #define COLOUR_DEVICE TEXT("bmp16m")
  188 #define GREY_DEVICE TEXT("bmpgray")
  189 #define MONO_DEVICE TEXT("bmpmono")
  190 #endif
  191 
  192 #ifdef _WIN32
  193 TCHAR gsexe[MAXSTR] = TEXT("gswin32c.exe");
  194 #define COLOUR_DEVICE TEXT("bmp16m")
  195 #define GREY_DEVICE TEXT("bmpgray")
  196 #define MONO_DEVICE TEXT("bmpmono")
  197 #endif
  198 
  199 
  200 static void print_help(void);
  201 static void print_version(void);
  202 static int parse_args(OPT *opt, int argc, TCHAR *argv[]);
  203 static Doc * epstool_open_document(GSview *app, OPT *opt, TCHAR *name);
  204 static int epstool_add_preview(Doc *doc, OPT *opt);
  205 static int epstool_dcs2_copy(Doc *doc, Doc *doc2, OPT *opt);
  206 static int epstool_dcs2_report(Doc *doc);
  207 static int epstool_dcs2_composite(Doc *doc, OPT *opt, GFile *compfile);
  208 static int epstool_dcs2_check_files(Doc *doc, OPT *opt);
  209 static int epstool_extract(Doc *doc, OPT *opt);
  210 static int epstool_bitmap(Doc *doc, OPT *opt);
  211 static int epstool_copy(Doc *doc, OPT *opt);
  212 static int epstool_copy_bitmap(Doc *doc, OPT *opt);
  213 static int epstool_test(Doc *doc, OPT *opt);
  214 static void epstool_dump_fn(void *caller_data, const char *str);
  215 
  216 static IMAGE *make_preview_image(Doc *doc, OPT *opt, int page, LPCTSTR device,
  217     CDSCBBOX *bbox, CDSCFBBOX *hires_bbox, int calc_bbox);
  218 static int make_preview_file(Doc *doc, OPT *opt, int page, 
  219     LPCTSTR preview, LPCTSTR device,
  220     float dpi, CDSCBBOX *bbox, CDSCFBBOX *hires_bbox, int calc_bbox);
  221 static int calculate_bbox(Doc *doc, OPT *opt, LPCTSTR psname, 
  222     CDSCBBOX *bbox, CDSCFBBOX *hires_bbox);
  223 static int calc_device_size(float dpi, CDSCBBOX *bbox, CDSCFBBOX *hires_bbox,
  224     int *width, int *height, float *xoffset, float *yoffset);
  225 static int exec_program(LPTSTR command,
  226     int hstdin, int hstdout, int hstderr,
  227     LPCTSTR stdin_name, LPCTSTR stdout_name, LPCTSTR stderr_name);
  228 static int custom_colours_read(OPT *opt);
  229 static CUSTOM_COLOUR *custom_colours_find(OPT *opt, const char *name);
  230 static void custom_colours_free(OPT *opt);
  231 static int colour_to_cmyk(CDSC *dsc, const char *name, 
  232    float *cyan, float *magenta, float *yellow, float *black);
  233 
  234 
  235 static void
  236 print_version(void)
  237 {
  238     fprintf(MSGOUT, "%s %s %s\n", epstool_name, epstool_version, epstool_date);
  239 }
  240 
  241 static void 
  242 print_help(void)
  243 {
  244     print_version();
  245     fprintf(MSGOUT, "%s\n", copyright);
  246     fprintf(MSGOUT, "Usage: epstool command [options] inputfile outputfile\n");
  247     fprintf(MSGOUT, "%s", cmd_help);
  248     fprintf(MSGOUT, "%s", opt_help);
  249 }
  250 
  251 /* return 0 on success, or argument index if there is a duplicated
  252  * command, a missing parameter, or an unknown argument.
  253  */
  254 static int
  255 parse_args(OPT *opt, int argc, TCHAR *argv[])
  256 {
  257     int arg;
  258     const TCHAR *p;
  259     memset(opt, 0, sizeof(OPT));
  260     opt->cmd = CMD_UNKNOWN;
  261     opt->dpi = 72.0;
  262     opt->dpi_render = 0.0;
  263     opt->mac_type = CMAC_TYPE_NONE;
  264     opt->dscwarn = CDSC_ERROR_NONE;
  265     opt->image_encode = IMAGE_ENCODE_ASCII85;
  266     opt->image_compress = IMAGE_COMPRESS_LZW;
  267     csncpy(opt->gs, gsexe, sizeof(opt->gs)/sizeof(TCHAR)-1);
  268     for (arg=1; arg<argc; arg++) {
  269     p = argv[arg];
  270     if ((cscmp(p, TEXT("--add-tiff4-preview")) == 0) ||
  271         (cscmp(p, TEXT("-t4")) == 0)) {
  272         if (opt->cmd != CMD_UNKNOWN)
  273         return arg;
  274         opt->cmd = CMD_TIFF4;
  275     }
  276     else if ((cscmp(p, TEXT("--add-tiff6u-preview")) == 0) ||
  277         (cscmp(p, TEXT("-t6u")) == 0)) {
  278         if (opt->cmd != CMD_UNKNOWN)
  279         return arg;
  280         opt->cmd = CMD_TIFF6U;
  281     }
  282     else if ((cscmp(p, TEXT("--add-tiff6p-preview")) == 0) ||
  283         (cscmp(p, TEXT("-t6p")) == 0)) {
  284         if (opt->cmd != CMD_UNKNOWN)
  285         return arg;
  286         opt->cmd = CMD_TIFF6P;
  287     }
  288     else if ((cscmp(p, TEXT("--add-tiff-preview")) == 0) ||
  289         (cscmp(p, TEXT("-tg")) == 0)) {
  290         if (opt->cmd != CMD_UNKNOWN)
  291         return arg;
  292         opt->cmd = CMD_TIFF;
  293     }
  294     else if ((cscmp(p, TEXT("--add-interchange-preview")) == 0) ||
  295         (cscmp(p, TEXT("-i")) == 0)) {
  296         if (opt->cmd != CMD_UNKNOWN)
  297         return arg;
  298         opt->cmd = CMD_INTERCHANGE;
  299     }
  300     else if ((cscmp(p, TEXT("--add-metafile-preview")) == 0) ||
  301         (cscmp(p, TEXT("-w")) == 0)) {
  302         if (opt->cmd != CMD_UNKNOWN)
  303         return arg;
  304         opt->cmd = CMD_WMF;
  305     }
  306     else if ((cscmp(p, TEXT("--add-pict-preview")) == 0) ||
  307         (cscmp(p, TEXT("-w")) == 0)) {
  308         if (opt->cmd != CMD_UNKNOWN)
  309         return arg;
  310         opt->cmd = CMD_PICT;
  311     }
  312     else if (cscmp(p, TEXT("--add-user-preview")) == 0) {
  313         if (opt->cmd != CMD_UNKNOWN)
  314         return arg;
  315         opt->cmd = CMD_USER;
  316         arg++;
  317         if (arg == argc)
  318         return arg;
  319         csncpy(opt->user_preview, argv[arg], 
  320         sizeof(opt->user_preview)/sizeof(TCHAR)-1);
  321     }
  322     else if (cscmp(p, TEXT("--dcs2-multi")) == 0) {
  323         if (opt->cmd != CMD_UNKNOWN)
  324         return arg;
  325         opt->cmd = CMD_DCS2_MULTI;
  326     }
  327     else if (cscmp(p, TEXT("--dcs2-single")) == 0) {
  328         if (opt->cmd != CMD_UNKNOWN)
  329         return arg;
  330         opt->cmd = CMD_DCS2_SINGLE;
  331     }
  332     else if (cscmp(p, TEXT("--dcs2-report")) == 0) {
  333         if (opt->cmd != CMD_UNKNOWN)
  334         return arg;
  335         opt->cmd = CMD_DCS2_REPORT;
  336     }
  337     else if (cscmp(p, TEXT("--dump")) == 0) {
  338         if (opt->cmd != CMD_UNKNOWN)
  339         return arg;
  340         opt->cmd = CMD_DUMP;
  341     }
  342     else if (cscmp(p, TEXT("--test-eps")) == 0) {
  343         if (opt->cmd != CMD_UNKNOWN)
  344         return arg;
  345         opt->cmd = CMD_TEST;
  346     }
  347     else if (cscmp(p, TEXT("--replace-composite")) == 0) {
  348         opt->composite = TRUE;
  349     }
  350     else if (cscmp(p, TEXT("--missing-separations")) == 0) {
  351         opt->missing_separations = TRUE;
  352     }
  353     else if (cscmp(p, TEXT("--combine-separations")) == 0) {
  354         arg++;
  355         if (arg == argc)
  356         return arg;
  357         csncpy(opt->combine, argv[arg], sizeof(opt->combine)/sizeof(TCHAR)-1);
  358     }
  359     else if (cscmp(p, TEXT("--combine-tolerance")) == 0) {
  360         char buf[MAXSTR];
  361         arg++;
  362         if (arg == argc)
  363         return arg;
  364         cs_to_narrow(buf, (int)sizeof(buf)-1, argv[arg], (int)cslen(argv[arg])+1);
  365         opt->tolerance = atoi(buf);
  366     }
  367     else if (cscmp(p, TEXT("--rename-separation")) == 0) {
  368         RENAME_SEPARATION *rs = opt->rename_sep;
  369         arg++;
  370         if (arg+1 == argc)
  371         return arg;
  372         if (rs) {
  373         while (rs && (rs->next != NULL))
  374             rs = rs->next;
  375         rs->next = 
  376             (RENAME_SEPARATION *)malloc(sizeof(RENAME_SEPARATION));
  377         rs = rs->next;
  378         }
  379         else {
  380         opt->rename_sep = rs = 
  381             (RENAME_SEPARATION *)malloc(sizeof(RENAME_SEPARATION));
  382         }
  383         if (rs) {
  384         char oldname[MAXSTR];
  385         char newname[MAXSTR];
  386         char *p;
  387         char *q;
  388         int len;
  389         memset(rs, 0, sizeof(RENAME_SEPARATION));
  390         rs->next = NULL;
  391         memset(oldname, 0, sizeof(oldname));
  392             cs_to_narrow(oldname, (int)sizeof(oldname)-1, 
  393             argv[arg], (int)cslen(argv[arg])+1);
  394         len = (int)strlen(oldname)+1;
  395         p = (char *)malloc(len);
  396         if (p) {
  397             memcpy(p, oldname, len);
  398             rs->oldname = p;
  399         }
  400         arg++;
  401         memset(newname, 0, sizeof(newname));
  402             cs_to_narrow(newname, (int)sizeof(newname)-1, 
  403             argv[arg], (int)cslen(argv[arg])+1);
  404         len = (int)strlen(newname)+1;
  405         q = (char *)malloc(len);
  406         if (q) {
  407             memcpy(q, newname, len);
  408             rs->newname = q;
  409         }
  410         if ((p == NULL) || (q == NULL)) {
  411             fprintf(stderr, "Out of memory\n");
  412             return arg;
  413         }
  414         }
  415         else {
  416         fprintf(stderr, "Out of memory\n");
  417         return arg;
  418         }
  419     }
  420     else if (cscmp(p, TEXT("--custom-colours")) == 0) {
  421         arg++;
  422         if (arg == argc)
  423         return arg;
  424         csncpy(opt->custom_colours, argv[arg], 
  425         sizeof(opt->custom_colours)/sizeof(TCHAR)-1);
  426     }
  427     else if ((cscmp(p, TEXT("--extract-preview")) == 0) ||
  428         (cscmp(p, TEXT("-v")) == 0)) {
  429         if (opt->cmd != CMD_UNKNOWN)
  430         return arg;
  431         opt->cmd = CMD_PREVIEW;
  432     }
  433     else if ((cscmp(p, TEXT("--extract-postscript")) == 0) ||
  434         (cscmp(p, TEXT("-p")) == 0)) {
  435         if (opt->cmd != CMD_UNKNOWN)
  436         return arg;
  437         opt->cmd = CMD_POSTSCRIPT;
  438     }
  439     else if (cscmp(p, TEXT("--bitmap")) == 0) {
  440         if (opt->cmd != CMD_UNKNOWN)
  441         return arg;
  442         opt->cmd = CMD_BITMAP;
  443     }
  444     else if (cscmp(p, TEXT("--copy")) == 0) {
  445         if (opt->cmd != CMD_UNKNOWN)
  446         return arg;
  447         opt->cmd = CMD_COPY;
  448     }
  449     else if (cscmp(p, TEXT("--device")) == 0) {
  450         arg++;
  451         if (arg == argc)
  452         return arg;
  453         csncpy(opt->device, argv[arg], sizeof(opt->device)/sizeof(TCHAR)-1);
  454     }
  455     else if (cscmp(p, TEXT("--page-number")) == 0) {
  456         char buf[MAXSTR];
  457         arg++;
  458         if (arg == argc)
  459         return arg;
  460         cs_to_narrow(buf, (int)sizeof(buf)-1, argv[arg], 
  461         (int)cslen(argv[arg])+1);
  462         opt->page = atoi(buf) - 1;
  463         if (opt->page < 0)
  464         opt->page = 0;
  465     }
  466     else if ((cscmp(p, TEXT("--bbox")) == 0) ||
  467         (cscmp(p, TEXT("-b")) == 0)) {
  468         opt->bbox = TRUE;
  469     }
  470     else if (cscmp(p, TEXT("--ignore-information")) == 0) {
  471         opt->dscwarn = CDSC_ERROR_INFORM;
  472     }
  473     else if (cscmp(p, TEXT("--ignore-warnings")) == 0) {
  474         opt->dscwarn = CDSC_ERROR_WARN;
  475     }
  476     else if (cscmp(p, TEXT("--ignore-errors")) == 0) {
  477         opt->dscwarn = CDSC_ERROR_ERROR;
  478     }
  479     else if (cscmp(p, TEXT("--gs")) == 0) {
  480         arg++;
  481         if (arg == argc)
  482         return arg;
  483         csncpy(opt->gs, argv[arg], sizeof(opt->gs)/sizeof(TCHAR)-1);
  484     }
  485     else if (cscmp(p, TEXT("--gs-args")) == 0) {
  486         arg++;
  487         if (arg == argc)
  488         return arg;
  489         csncpy(opt->gsargs, argv[arg], sizeof(opt->gsargs)/sizeof(TCHAR)-1);
  490     }
  491     else if (cscmp(p, TEXT("--mac-binary")) == 0) {
  492         opt->mac_type = CMAC_TYPE_MACBIN;
  493     }
  494     else if (cscmp(p, TEXT("--mac-double")) == 0) {
  495         opt->mac_type = CMAC_TYPE_DOUBLE;
  496     }
  497     else if (cscmp(p, TEXT("--mac-rsrc")) == 0) {
  498         opt->mac_type = CMAC_TYPE_RSRC;
  499     }
  500     else if (cscmp(p, TEXT("--mac-single")) == 0) {
  501         opt->mac_type = CMAC_TYPE_SINGLE;
  502     }
  503     else if (cscmp(p, TEXT("--output")) == 0) {
  504         arg++;
  505         if (arg == argc)
  506         return arg;
  507         csncpy(opt->output, argv[arg], 
  508         sizeof(opt->output)/sizeof(TCHAR)-1);
  509     }
  510     else if (cscmp(p, TEXT("--quiet")) == 0) {
  511         opt->quiet = TRUE;
  512     }
  513     else if ((cscmp(p, TEXT("--debug")) == 0) ||
  514         (cscmp(p, TEXT("-d")) == 0)) {
  515         opt->debug = TRUE;
  516     }
  517     else if ((cscmp(p, TEXT("--doseps-reverse")) == 0) ||
  518         (cscmp(p, TEXT("-d")) == 0)) {
  519         opt->doseps_reverse = TRUE;
  520     }
  521     else if (cscmp(p, TEXT("--dpi")) == 0) {
  522         char buf[MAXSTR];
  523         arg++;
  524         if (arg == argc)
  525         return arg;
  526         cs_to_narrow(buf, (int)sizeof(buf)-1, argv[arg], 
  527         (int)cslen(argv[arg])+1);
  528         opt->dpi = (float)atof(buf);
  529     }   
  530     else if (cscmp(p, TEXT("--dpi-render")) == 0) {
  531         char buf[MAXSTR];
  532         arg++;
  533         if (arg == argc)
  534         return arg;
  535         cs_to_narrow(buf, (int)sizeof(buf)-1, argv[arg], 
  536         (int)cslen(argv[arg])+1);
  537         opt->dpi_render = (float)atof(buf);
  538     }   
  539     else if (cscmp(p, TEXT("--image-encode")) == 0) {
  540         /* Not in user documentation - for debug purposes only */
  541         char buf[MAXSTR];
  542         arg++;
  543         if (arg == argc)
  544         return arg;
  545         cs_to_narrow(buf, (int)sizeof(buf)-1, argv[arg], 
  546         (int)cslen(argv[arg])+1);
  547         opt->image_encode = atoi(buf);
  548         if ((opt->image_encode < IMAGE_ENCODE_HEX) ||
  549             (opt->image_encode > IMAGE_ENCODE_ASCII85))
  550         opt->image_encode = IMAGE_ENCODE_ASCII85;
  551     }   
  552     else if (cscmp(p, TEXT("--image-compress")) == 0) {
  553         /* Not in user documentation - for debug purposes only */
  554         char buf[MAXSTR];
  555         arg++;
  556         if (arg == argc)
  557         return arg;
  558         cs_to_narrow(buf, (int)sizeof(buf)-1, argv[arg], 
  559         (int)cslen(argv[arg])+1);
  560         opt->image_compress = atoi(buf);
  561         if ((opt->image_compress < IMAGE_COMPRESS_NONE) ||
  562             (opt->image_compress > IMAGE_COMPRESS_LZW))
  563         opt->image_compress = IMAGE_COMPRESS_LZW;
  564     }
  565     else if ((cscmp(p, TEXT("--help")) == 0) || (cscmp(p, TEXT("-h"))==0)) {
  566         opt->help = TRUE;
  567         if (opt->cmd != CMD_UNKNOWN)
  568         return arg;
  569         opt->cmd = CMD_HELP;
  570     }
  571     else if (cscmp(p, TEXT("--version")) == 0) {
  572         if (opt->cmd != CMD_UNKNOWN)
  573         return arg;
  574         opt->cmd = CMD_VERSION;
  575     }
  576     else if (*p != '-') {
  577         if (opt->input[0] == 0)
  578         csncpy(opt->input, argv[arg], 
  579             sizeof(opt->input)/sizeof(TCHAR)-1);
  580         else if (opt->output[0] == 0)
  581         csncpy(opt->output, argv[arg], 
  582             sizeof(opt->output)/sizeof(TCHAR)-1);
  583         else
  584         return arg;
  585     }
  586     else {
  587         return arg;
  588     }
  589     }
  590     return 0;
  591 }
  592 
  593 
  594 static Doc *
  595 epstool_open_document(GSview *app, OPT *opt, TCHAR *name)
  596 {
  597     int code;
  598     Doc *doc;
  599     int require_eps = 1;
  600     /* Create a document */
  601     doc = doc_new(app);
  602     if (doc == NULL) {
  603     debug |= DEBUG_LOG;
  604     app_csmsgf(app, TEXT("Failed to create new Doc\n"));
  605     app_unref(app);
  606     return NULL;
  607     }
  608     /* Attach it to application */
  609     doc_add(doc, app);
  610     doc_dsc_warn(doc, opt->dscwarn);
  611     doc_verbose(doc, opt->debug);
  612 
  613     code = doc_open(doc, name);
  614     if (code < 0) {
  615     debug |= DEBUG_LOG;
  616     app_csmsgf(app, TEXT("Error opening file \042%s\042.\n"), name);
  617     code = -1;
  618     }
  619     else if (code > 0) {
  620     debug |= DEBUG_LOG;
  621     app_csmsgf(app, TEXT(
  622     "Input file \042%s\042 didn't have DSC comments.\n"), name);
  623     code = -1;
  624     }
  625 
  626     /* Some features don't require an EPS input */
  627     if (opt->cmd == CMD_DCS2_REPORT)
  628     require_eps = 0;
  629     if (opt->cmd == CMD_TEST)
  630     require_eps = 0;
  631     if (opt->cmd == CMD_DUMP)
  632     require_eps = 0;
  633     if ((opt->cmd == CMD_COPY) && (doc->doctype == DOC_BITMAP))
  634     require_eps = 0;
  635 
  636     if ((code == 0) && require_eps &&
  637        ((doc->dsc == NULL) || (!doc->dsc->epsf)) ) {
  638     debug |= DEBUG_LOG;
  639     app_csmsgf(app, 
  640         TEXT("Input file \042%s\042 is not EPSF.\n"), name);
  641     code = -1;
  642     }
  643     if ((code == 0) && require_eps && (doc->dsc != NULL)) {
  644     if ((doc->dsc->worst_error > CDSC_ERROR_INFORM) &&
  645         (doc->dsc->worst_error > opt->dscwarn)) {
  646         app_csmsgf(app, 
  647         TEXT("EPS had unacceptable warnings or errors.\n"));
  648         code = -1;
  649     }
  650     }
  651     if (code) {
  652     doc_close(doc);
  653     doc_remove(doc);
  654     doc_unref(doc);
  655     doc = NULL;
  656     }
  657     return doc;
  658 }
  659 
  660 
  661 #ifdef UNICODE
  662 int wmain(int argc, TCHAR *argv[])
  663 #else
  664 int main(int argc, char *argv[])
  665 #endif
  666 {
  667     GSview *app;
  668     Doc *doc = NULL;
  669     Doc *doc2 = NULL;
  670     int code = 0;
  671     int i, arg;
  672     OPT opt;
  673 
  674 #ifdef __WIN32__
  675     {   /* Find latest version of Ghostscript */
  676     char buf[MAXSTR];
  677     if (find_gs(buf, sizeof(buf)-1, 550, FALSE)) {
  678         narrow_to_cs(gsexe, (int)(sizeof(gsexe)/sizeof(TCHAR)-1),
  679         buf, (int)strlen(buf)+1);
  680     }
  681     }
  682 #endif
  683 
  684     memset(&opt, 0, sizeof(opt));
  685     arg = parse_args(&opt, argc, argv);
  686     debug = 0;
  687     if (opt.debug) {
  688     debug = DEBUG_LOG | DEBUG_MEM | DEBUG_GENERAL;
  689     opt.quiet = 0;
  690     }
  691     if (!opt.quiet)
  692     debug |= DEBUG_LOG; /* enable output */
  693     if (opt.help) {
  694     print_help();
  695     return 1;
  696     }
  697     if (opt.cmd == CMD_VERSION) {
  698     print_version();
  699     return 1;
  700     }
  701     if (opt.dpi_render < opt.dpi)
  702     opt.dpi_render = opt.dpi;
  703 
  704     app = app_new(NULL, FALSE);
  705     if (app == NULL) {
  706         fprintf(MSGOUT, "Can't create epstool app\n");
  707     return 1;
  708     }
  709 
  710     if (arg != 0) {
  711     debug |= DEBUG_LOG;
  712     app_csmsgf(app, TEXT("epstool: Error in command line arguments:\n  "));
  713     for (i=0; i<arg; i++)
  714         app_csmsgf(app, TEXT("%s "), argv[i]);
  715     app_csmsgf(app, TEXT("\n    The next argument is unrecognised, missing, or conflicts:\n  "));
  716     for (; i<argc; i++)
  717         app_csmsgf(app, TEXT("%s "), argv[i]);
  718     app_csmsgf(app, TEXT("\n"));
  719     app_unref(app);
  720     return 1;
  721     }
  722     
  723     if ((opt.cmd == CMD_TIFF) && (opt.device[0] == '\0')) {
  724     debug |= DEBUG_LOG;
  725     app_csmsgf(app, TEXT("--add-tiff-preview requires a device to be specified with --device\n"));
  726     code = -1;
  727     }
  728     if (opt.cmd == CMD_UNKNOWN) {
  729     debug |= DEBUG_LOG;
  730     app_csmsgf(app, TEXT("No command specified.\n"));
  731     code = -1;
  732     }
  733     if (opt.input[0] == '\0') {
  734     debug |= DEBUG_LOG;
  735     app_csmsgf(app, TEXT("Input file not specified.\n"));
  736     code = -1;
  737     }
  738     if (opt.custom_colours[0] != '\0') {
  739     FILE *f = csfopen(opt.custom_colours, TEXT("rb"));
  740     if (f == (FILE*)NULL) {
  741         debug |= DEBUG_LOG;
  742         app_csmsgf(app, TEXT("Failed to open \042%s\042.\n"), 
  743         opt.custom_colours);
  744         code = -1;
  745     }
  746     else
  747         fclose(f);
  748     }
  749     if (code == 0) {
  750     FILE *f = csfopen(opt.input, TEXT("rb"));
  751     if (f == (FILE*)NULL) {
  752         debug |= DEBUG_LOG;
  753         app_csmsgf(app, TEXT("Failed to open \042%s\042.\n"), opt.input);
  754         code = -1;
  755     }
  756     else
  757         fclose(f);
  758     }
  759     if ((opt.output[0] == '\0') && 
  760         !((opt.cmd == CMD_DCS2_REPORT) || 
  761       (opt.cmd == CMD_TEST) ||
  762       (opt.cmd == CMD_DUMP)) ) {
  763     debug |= DEBUG_LOG;
  764     app_csmsgf(app, TEXT("Output file not specified.\n"));
  765     code = -1;
  766     }
  767     if ((opt.output[0] == '-') && (opt.output[1] == '\0'))
  768         opt.output[0] = '\0';  /* use stdout */
  769     if (code != 0) {
  770     debug |= DEBUG_LOG;
  771     app_csmsgf(app, TEXT("Run \042epstool --help\042 for more details.\n"));
  772     app_unref(app);
  773     return 1;
  774     }
  775 
  776     if (opt.cmd == CMD_DUMP)
  777         dump_macfile(opt.input, 1);
  778 
  779     doc = epstool_open_document(app, &opt, opt.input);
  780     if (doc == NULL)
  781     code = -1;
  782 
  783     if (opt.combine[0]) {
  784     /* open second DCS2 input file */
  785     doc2 = epstool_open_document(app, &opt, opt.combine);
  786     if (doc2 == NULL)
  787         code = -1;
  788     }
  789 
  790     if ((code == 0) && opt.bbox) {
  791     switch (opt.cmd) {
  792         case CMD_TIFF4:
  793         case CMD_TIFF6U:
  794         case CMD_TIFF6P:
  795         case CMD_INTERCHANGE:
  796         case CMD_WMF:
  797         case CMD_COPY:
  798         if (doc->dsc->dcs2) {
  799             debug |= DEBUG_LOG;
  800             app_csmsgf(app, TEXT("Ignoring --bbox for DCS 2.0.\n"));
  801             opt.bbox = 0;
  802         }
  803         /* all others are these OK */
  804         break;
  805         default:
  806         debug |= DEBUG_LOG;
  807         app_csmsgf(app, TEXT(
  808           "Can't use --bbox with this command.  Ignoring --bbox.\n"));
  809         opt.bbox = 0;
  810     }
  811     }
  812 
  813     if (code == 0) {
  814       switch (opt.cmd) {
  815     case CMD_TIFF4:
  816     case CMD_TIFF6U:
  817     case CMD_TIFF6P:
  818     case CMD_TIFF:
  819     case CMD_INTERCHANGE:
  820     case CMD_WMF:
  821     case CMD_PICT:
  822         case CMD_USER:
  823         code = epstool_add_preview(doc, &opt);
  824         break;
  825     case CMD_DCS2_SINGLE:
  826     case CMD_DCS2_MULTI:
  827         if (doc->dsc->dcs2)
  828         code = epstool_dcs2_check_files(doc, &opt);
  829         if (code == 0)
  830         code = epstool_dcs2_copy(doc, doc2, &opt); 
  831         break;
  832     case CMD_DCS2_REPORT:
  833         code = epstool_dcs2_report(doc); 
  834         break;
  835     case CMD_PREVIEW:
  836     case CMD_POSTSCRIPT:
  837         code = epstool_extract(doc, &opt);
  838         break;
  839     case CMD_BITMAP:
  840         code = epstool_bitmap(doc, &opt);
  841         break;
  842     case CMD_COPY:
  843         code = epstool_copy(doc, &opt);
  844         break;
  845     case CMD_TEST:
  846         code = epstool_test(doc, &opt);
  847         break;
  848     case CMD_DUMP:
  849         if (doc && doc->dsc)
  850         dsc_display(doc->dsc, epstool_dump_fn);
  851         break;
  852     default:
  853     case CMD_UNKNOWN:
  854     case CMD_HELP:
  855         /* should reach here */
  856         code = -1;
  857         break;
  858       }
  859     }
  860 
  861 
  862     if (doc) {
  863     doc_close(doc);
  864     doc_remove(doc);    /* detach doc from app */
  865     doc_unref(doc);
  866     }
  867 
  868     app_unref(app);
  869 
  870 #ifdef DEBUG_MALLOC
  871     debug_memory_report();
  872 #endif
  873 
  874     debug &= ~DEBUG_MEM;
  875     while (opt.rename_sep) {
  876     RENAME_SEPARATION *rs = opt.rename_sep;
  877     if (rs->oldname)
  878         free((void *)rs->oldname);
  879     if (rs->newname)
  880         free((void *)rs->newname);
  881     opt.rename_sep = rs->next;
  882     free(rs);
  883     }
  884 
  885     if (!opt.quiet)
  886         fprintf(MSGOUT, "%s\n", code == 0 ? "OK" : "Failed");
  887     if (code != 0)
  888     return 1;
  889     return code;
  890 }
  891 
  892 /****************************************************************/
  893 
  894 static int
  895 epstool_add_preview(Doc *doc, OPT *opt)
  896 {
  897     int code = 0;
  898     CDSCBBOX devbbox = {0,0,595,842};
  899     CDSCBBOX bbox = {0, 0, 0, 0};
  900     CDSCFBBOX hires_bbox = {0.0, 0.0, 0.0, 0.0};
  901     CDSCFBBOX *phires_bbox = NULL;
  902     const TCHAR *device = COLOUR_DEVICE;
  903     FILE *f;
  904     TCHAR preview[MAXSTR];
  905     IMAGE *img = NULL;
  906     if (opt->device[0] != '\0')
  907     device = opt->device;
  908     else if (opt->cmd == CMD_INTERCHANGE)
  909     device = MONO_DEVICE;
  910     if (opt->cmd == CMD_TIFF4)
  911     device = MONO_DEVICE;
  912 
  913     if (doc->dsc->bbox) {
  914     bbox = *doc->dsc->bbox;
  915     }
  916     else
  917     opt->bbox = 1;
  918 
  919     if (doc->dsc->hires_bbox) {
  920     hires_bbox = *doc->dsc->hires_bbox;
  921     phires_bbox = &hires_bbox;
  922     }
  923 
  924     if (opt->cmd == CMD_USER) {
  925     /* Attempt to load BMP or PPM */
  926     /* If these fail, assume it is TIFF or WMF */
  927     img = bmpfile_to_image(opt->user_preview);
  928     if (img == NULL)
  929         img = pnmfile_to_image(opt->user_preview);
  930     }
  931     else if (opt->cmd == CMD_TIFF) {
  932     /* We'll use ghostscript to make the image. */
  933     }
  934     else {
  935     img = make_preview_image(doc, opt, 0, device, 
  936         &bbox, &hires_bbox, opt->bbox);
  937     if (img == NULL) {
  938         app_csmsgf(doc->app, TEXT("Couldn't make preview image\n"));
  939         return -1;
  940     }
  941     if ((hires_bbox.fllx < hires_bbox.furx) &&
  942         (hires_bbox.flly < hires_bbox.fury))
  943         phires_bbox = &hires_bbox;
  944     
  945     }
  946     if (img) {
  947     devbbox.llx = devbbox.lly = 0;
  948     devbbox.urx = img->width;
  949     devbbox.ury = img->height;
  950     }
  951 
  952     /* add preview to EPS file */
  953 
  954     switch (opt->cmd) {
  955     case CMD_TIFF4:
  956         code = make_eps_tiff(doc, img, devbbox, &bbox, phires_bbox, 
  957         opt->dpi, opt->dpi, TRUE, FALSE, opt->doseps_reverse,
  958         opt->output);
  959         break;
  960     case CMD_TIFF6U:
  961         code = make_eps_tiff(doc, img, devbbox, &bbox, phires_bbox, 
  962         opt->dpi, opt->dpi, FALSE, FALSE, opt->doseps_reverse,
  963         opt->output);
  964         break;
  965     case CMD_TIFF6P:
  966         code = make_eps_tiff(doc, img, devbbox, &bbox, phires_bbox, 
  967         opt->dpi, opt->dpi, FALSE, TRUE, opt->doseps_reverse,
  968         opt->output);
  969         break;
  970     case CMD_TIFF:
  971         /* create preview file */
  972         preview[0] = '\0';
  973         if ((f = app_temp_file(doc->app, preview, 
  974         sizeof(preview)/sizeof(TCHAR))) == (FILE *)NULL) {
  975         app_csmsgf(doc->app, 
  976             TEXT("Can't create temporary tiff file \042%s\042\n"),
  977             preview);
  978         code = -1;
  979         }
  980         else {
  981         fclose(f);
  982         if (code == 0)
  983             code = make_preview_file(doc, opt, 0, preview, 
  984             device, opt->dpi, &bbox, &hires_bbox, opt->bbox);
  985         if (code == 0)
  986             code = make_eps_user(doc, preview, opt->doseps_reverse,
  987             opt->output);
  988         if (!(debug & DEBUG_GENERAL))
  989             csunlink(preview);
  990         }
  991         break;
  992     case CMD_INTERCHANGE:
  993         code = make_eps_interchange(doc, img, devbbox, 
  994         &bbox, phires_bbox, opt->output);
  995         break;
  996     case CMD_WMF:
  997         code = make_eps_metafile(doc, img, devbbox, &bbox, phires_bbox, 
  998         opt->dpi, opt->dpi, opt->doseps_reverse, opt->output);
  999         break;
 1000     case CMD_PICT:
 1001         code = make_eps_pict(doc, img, &bbox, phires_bbox, 
 1002         opt->dpi, opt->dpi, opt->mac_type, opt->output);
 1003         break;
 1004         case CMD_USER:
 1005         if (img)
 1006         code = make_eps_tiff(doc, img, devbbox, &bbox, phires_bbox,
 1007             opt->dpi, opt->dpi, FALSE, TRUE, opt->doseps_reverse, 
 1008             opt->output);
 1009         else
 1010             code = make_eps_user(doc, opt->user_preview, 
 1011             opt->doseps_reverse, opt->output);
 1012         break;
 1013     default:
 1014         return 0;
 1015     }
 1016 
 1017     if (img)
 1018     bitmap_image_free(img);
 1019     return code;
 1020 }
 1021 
 1022 /****************************************************************/
 1023 
 1024 static int
 1025 epstool_extract(Doc *doc, OPT *opt)
 1026 {
 1027     int code;
 1028     if ((doc->dsc != (CDSC *)NULL) && 
 1029     (doc->dsc->macbin != (CDSCMACBIN *)NULL))
 1030     code = extract_macbin(doc, opt->output, opt->cmd == CMD_PREVIEW);
 1031     else
 1032         code = extract_doseps(doc, opt->output, opt->cmd == CMD_PREVIEW);
 1033     return code;
 1034 }
 1035 
 1036 /****************************************************************/
 1037 
 1038 static int 
 1039 epstool_bitmap(Doc *doc, OPT *opt)
 1040 {
 1041     int code = 0;
 1042     CDSCBBOX bbox;
 1043     CDSCFBBOX hires_bbox;
 1044     LPCTSTR device = COLOUR_DEVICE;
 1045     int page = opt->page;
 1046     if (opt->device[0] != '\0')
 1047     device = opt->device;
 1048 
 1049     if (doc->dsc->bbox)
 1050     bbox = *doc->dsc->bbox;
 1051     else {
 1052     bbox.llx = bbox.lly = bbox.urx = bbox.ury = 0;
 1053     opt->bbox = 1;
 1054     }
 1055 
 1056     if (doc->dsc->hires_bbox)
 1057     hires_bbox = *doc->dsc->hires_bbox;
 1058     else {
 1059     hires_bbox.fllx = (float)bbox.llx;
 1060     hires_bbox.flly = (float)bbox.lly;
 1061     hires_bbox.furx = (float)bbox.urx;
 1062     hires_bbox.fury = (float)bbox.ury;
 1063     }
 1064 
 1065     if (doc->dsc->page_count == 0)
 1066     page = 0;
 1067     else if ((opt->page < 0) || (opt->page >= (int)doc->dsc->page_count))
 1068     return -1;  /* invalid page */
 1069 
 1070     code = make_preview_file(doc, opt, page, opt->output,
 1071     device, opt->dpi, &bbox, &hires_bbox, opt->bbox);
 1072 
 1073     return code;
 1074 }
 1075 
 1076 /****************************************************************/
 1077 
 1078 static int 
 1079 epstool_copy(Doc *doc, OPT *opt)
 1080 {
 1081     int code = 0;
 1082  
 1083     /*
 1084      * "epstool --copy" can also convert a BMP, PBM or PNG to EPS
 1085      * for testing the DCS 2.0 composite image writing code.
 1086      * This isn't in the user documentation.
 1087      */
 1088     if (doc->doctype == DOC_BITMAP)
 1089     return epstool_copy_bitmap(doc, opt);
 1090 
 1091     /* Copy an EPS to another EPS */
 1092     if (opt->bbox) {
 1093     CDSCBBOX bbox;
 1094     CDSCFBBOX hires_bbox;
 1095     GFile *f;
 1096     TCHAR tpsname[MAXSTR];
 1097 
 1098     memset(tpsname, 0, sizeof(tpsname));
 1099     memset(&bbox, 0, sizeof(bbox));
 1100     memset(&hires_bbox, 0, sizeof(hires_bbox));
 1101     if (doc->dsc->bbox)
 1102         memcpy(&bbox, &doc->dsc->bbox, sizeof(bbox)); 
 1103     if (doc->dsc->hires_bbox)
 1104         memcpy(&hires_bbox, &doc->dsc->hires_bbox, sizeof(hires_bbox)); 
 1105 
 1106     /* Copy page to temporary file */
 1107     if ((f = app_temp_gfile(doc->app, tpsname, 
 1108         sizeof(tpsname)/sizeof(TCHAR))) == (GFile *)NULL) {
 1109         app_csmsgf(doc->app, 
 1110         TEXT("Can't create temporary ps file \042%s\042\n"),
 1111         tpsname);
 1112         return -1;
 1113     }
 1114     code = copy_page_temp(doc, f, 0);
 1115     gfile_close(f);
 1116     if (code != 0) {
 1117         if (!(debug & DEBUG_GENERAL))
 1118         csunlink(tpsname);
 1119         return -1;
 1120     }
 1121     code = calculate_bbox(doc, opt, tpsname, &bbox, &hires_bbox);
 1122 
 1123     if (code == 0)
 1124         code = copy_eps(doc, opt->output, &bbox, &hires_bbox, 0, FALSE); 
 1125 
 1126     /* delete temporary ps file */
 1127     if (!(debug & DEBUG_GENERAL))
 1128         csunlink(tpsname);
 1129     }
 1130     else {
 1131     code = copy_eps(doc, opt->output, doc->dsc->bbox, 
 1132         doc->dsc->hires_bbox, 0, FALSE); 
 1133     }
 1134 
 1135     return code;
 1136 }
 1137 
 1138 /* Save a BMP, PBM or PNG as an EPS file */
 1139 static int 
 1140 epstool_copy_bitmap(Doc *doc, OPT *opt)
 1141 {
 1142     int code = 0;
 1143     IMAGE *img;
 1144     img = bmpfile_to_image(doc->name);
 1145     if (img == NULL)
 1146     img = pnmfile_to_image(doc->name);
 1147     if (img == NULL)
 1148     img = pngfile_to_image(doc->name);
 1149     if (img == NULL) 
 1150     code = -1;
 1151 
 1152     if (code == 0) {
 1153     GFile *f = NULL;
 1154     double width = (img->width * 72.0 / opt->dpi);
 1155     double height = (img->height * 72.0 / opt->dpi);
 1156     
 1157     if ((img == NULL) || (img->image == NULL))
 1158         code = -1;
 1159     
 1160     if (code == 0) {
 1161         f = gfile_open(opt->output, gfile_modeWrite | gfile_modeCreate);
 1162         if (f == NULL) {
 1163         code = -1;
 1164         app_msgf(doc->app, 
 1165             "Failed to open \042%s\042 for writing\n", opt->output);
 1166         }
 1167     }
 1168 
 1169     if (code == 0)
 1170         code = image_to_eps(f, img, 0, 0, 
 1171             (int)(width + 0.999), (int)(height + 0.999), 
 1172         0.0, 0.0, (float)width, (float)height,
 1173         opt->image_encode, opt->image_compress);
 1174     if (f)
 1175         gfile_close(f);
 1176      }
 1177      return code;
 1178 }
 1179 
 1180 /****************************************************************/
 1181 
 1182 /* If multi is TRUE, write DCS 2.0 multiple file, otherwise
 1183  * write the single file version.
 1184  */
 1185 static int 
 1186 epstool_dcs2_copy(Doc *doc, Doc *doc2, OPT *opt)
 1187 {
 1188     GFile *infile = NULL;
 1189     GFile *doc2file = NULL;
 1190     GFile *outfile = NULL;
 1191     DSC_OFFSET complen = 0;
 1192     int code = 0;
 1193     GFile *compfile = NULL;
 1194     TCHAR compname[MAXSTR];
 1195     TCHAR temp_outname[MAXSTR];
 1196 
 1197     if (doc->dsc->dcs2 == NULL) {
 1198     app_csmsgf(doc->app, TEXT("Input file is not DCS 2.0\n"));
 1199     return -1;
 1200     }
 1201     memset(compname, 0, sizeof(compname));
 1202     if (opt->composite) {
 1203     /* Replace composite (first page) with a raster generated
 1204      * from the separations.
 1205      */
 1206     if ((compfile = app_temp_gfile(doc->app, compname, 
 1207         sizeof(compname)/sizeof(TCHAR))) == (GFile *)NULL) {
 1208         app_csmsgf(doc->app, 
 1209         TEXT("Can't create temporary composite EPS file \042%s\042\n"),
 1210         compname);
 1211         return -1;
 1212     }
 1213     custom_colours_read(opt);
 1214     code = epstool_dcs2_composite(doc, opt, compfile);
 1215     custom_colours_free(opt);
 1216     gfile_close(compfile);
 1217     if (code == 0) {
 1218         compfile = gfile_open(compname, gfile_modeRead);
 1219         if (compfile == (GFile *)NULL)
 1220         code = -1;
 1221     }
 1222     if (code) {
 1223         if (!(debug & DEBUG_GENERAL) && compname[0])
 1224         csunlink(compname);
 1225         return -1;
 1226     }
 1227     }
 1228 
 1229     /* Let's convert from single file to multi file */
 1230     if (code == 0)
 1231     code = (infile = gfile_open(doc_name(doc), gfile_modeRead)) 
 1232         == (GFile *)NULL;
 1233     if ((code == 0) && doc2)
 1234     code = (doc2file = gfile_open(doc_name(doc2), gfile_modeRead)) 
 1235         == (GFile *)NULL;
 1236     if (opt->cmd == CMD_DCS2_SINGLE) {
 1237     if (code == 0)  /* write first pass to temporary file, not opt->output */
 1238         code = (outfile = app_temp_gfile(doc->app, temp_outname, 
 1239         sizeof(temp_outname)/sizeof(TCHAR))) == (GFile *)NULL;
 1240     if (code == 0)
 1241         code = copy_dcs2(doc, infile, doc2, doc2file,
 1242         outfile, temp_outname,
 1243         0 /* offset */, 
 1244         FALSE /* multi */,
 1245         FALSE /* write all */, 
 1246         opt->missing_separations,
 1247         &complen, compfile, opt->rename_sep, opt->tolerance);
 1248     gfile_seek(infile, 0, gfile_begin);
 1249     if (compfile)
 1250         gfile_seek(compfile, 0, gfile_begin);
 1251     gfile_close(outfile);
 1252     outfile = NULL;
 1253         if (!(debug & DEBUG_GENERAL) && temp_outname[0])
 1254         csunlink(temp_outname);
 1255     }
 1256     if (code == 0) {
 1257     code = (outfile = gfile_open(opt->output, 
 1258         gfile_modeWrite | gfile_modeCreate)) == (GFile *)NULL;
 1259     if (code)
 1260         app_msgf(doc->app, 
 1261             "Failed to open \042%s\042 for writing\n", opt->output);
 1262     }
 1263     if (code == 0)
 1264     code = copy_dcs2(doc, infile, doc2, doc2file,
 1265         outfile, opt->output,
 1266         0 /* offset */, 
 1267         opt->cmd == CMD_DCS2_MULTI,
 1268         TRUE /* write all */, 
 1269         opt->missing_separations,
 1270         &complen, compfile, opt->rename_sep, opt->tolerance);
 1271     if (infile != (GFile *)NULL)
 1272     gfile_close(infile);
 1273     if (doc2file != (GFile *)NULL)
 1274     gfile_close(doc2file);
 1275     if (outfile != (GFile *)NULL)
 1276     gfile_close(outfile);
 1277     if (compfile != (GFile *)NULL)
 1278     gfile_close(compfile);
 1279     if (!(debug & DEBUG_GENERAL) && compname[0])
 1280     csunlink(compname);
 1281 
 1282     return code;
 1283 }
 1284 
 1285 static int 
 1286 epstool_dcs2_report(Doc *doc)
 1287 {
 1288     int i;
 1289     int code = 0;
 1290     CDSC *dsc = doc->dsc;
 1291     const char *type = "Unknown";
 1292     const char *preview = "Unknown";
 1293 
 1294     if (dsc && dsc->dcs2) {
 1295     DSC_OFFSET length = 0;
 1296     GFile *f;
 1297     /* Check for missing composite */
 1298     if ((dsc->page_count == 0) ||
 1299          (dsc->page[0].begin == dsc->page[0].end)) {
 1300         app_msgf(doc->app, TEXT("WARNING: Missing composite, so a separation offset is probably wrong.\n"));
 1301         code = 2;
 1302     }
 1303     /* Check for separations that extend beyond EOF */
 1304     if ((f = gfile_open(doc_name(doc), gfile_modeRead)) != (GFile *)NULL) {
 1305         length = gfile_get_length(f);
 1306         gfile_close(f);
 1307     }
 1308     for (i=0; i<(int)dsc->page_count; i++) {
 1309         if ((dsc->page[i].begin > length) ||
 1310             (dsc->page[i].end > length)) {
 1311         app_msgf(doc->app, 
 1312             TEXT("WARNING: separation %s extends beyond EOF\n"),
 1313             dsc->page[i].label);
 1314         code = 2;
 1315         }
 1316     }
 1317     }
 1318 
 1319     /* Document type */
 1320     if (dsc == NULL) {
 1321     if (doc->doctype == DOC_PDF)
 1322         type = "PDF";
 1323     else
 1324         type = "Unknown";
 1325     }
 1326     else if (dsc->dcs2) {
 1327     if (dsc->dcs1)
 1328         type = "DCS1.0";
 1329     else
 1330         type = "DCS2.0";
 1331     }
 1332     else if (dsc->epsf)
 1333     type = "EPSF";
 1334     else if (dsc->pdf)
 1335     type = "PDF";
 1336     else
 1337     type = "DSC";
 1338     fprintf(stdout, "Type\t%s\n", type);
 1339     if (dsc == NULL)
 1340     return 1;
 1341 
 1342     /* Preview type */
 1343     switch (dsc->preview) {
 1344     default:
 1345     case CDSC_NOPREVIEW:
 1346         preview = "None";
 1347         break;
 1348     case CDSC_EPSI:
 1349         preview = "Interchange";
 1350         break;
 1351     case CDSC_TIFF:
 1352         preview = "TIFF";
 1353         break;
 1354     case CDSC_WMF:
 1355         preview = "WMF";
 1356         break;
 1357     case CDSC_PICT:
 1358         preview = "PICT";
 1359         break;
 1360     }
 1361     fprintf(stdout, "Preview\t%s\n", preview);
 1362 
 1363     if (dsc->bbox)
 1364         fprintf(stdout, "BoundingBox\t%d\t%d\t%d\t%d\n", 
 1365         dsc->bbox->llx, dsc->bbox->lly,
 1366         dsc->bbox->urx, dsc->bbox->ury);
 1367     else
 1368         fprintf(stdout, "BoundingBox\n");
 1369     if (dsc->hires_bbox)
 1370         fprintf(stdout, "HiBoundingBox\t%g\t%g\t%g\t%g\n", 
 1371         dsc->hires_bbox->fllx, dsc->hires_bbox->flly,
 1372         dsc->hires_bbox->furx, dsc->hires_bbox->fury);
 1373     else
 1374         fprintf(stdout, "HiResBoundingBox\n");
 1375 
 1376 
 1377     if (!dsc->dcs2)
 1378     return 1;
 1379 
 1380     /* Pages */
 1381     for (i=0; i<(int)dsc->page_count; i++) {
 1382     int found = -1;
 1383     const char *name = dsc->page[i].label;
 1384     float cyan, magenta, yellow, black;
 1385     cyan = magenta = yellow = black = 0.0;
 1386     if (name == NULL)
 1387         name = "Unknown";
 1388     if (strcmp(name, "Composite") != 0)
 1389         found = colour_to_cmyk(dsc, name, &cyan, &magenta, &yellow, &black);
 1390     if (found == 0)
 1391         fprintf(stdout, "%s\t%lu\t%g\t%g\t%g\t%g\n", name, 
 1392         (unsigned long)(dsc->page[i].end - dsc->page[i].begin),
 1393         cyan, magenta, yellow, black);
 1394     else
 1395         fprintf(stdout, "%s\t%lu\n", name, 
 1396         (unsigned long)(dsc->page[i].end - dsc->page[i].begin));
 1397     }
 1398     return code;
 1399 }
 1400 
 1401 /* Check that all separations actually exist */
 1402 static int 
 1403 epstool_dcs2_check_files(Doc *doc, OPT *opt)
 1404 {
 1405     int code = 0;
 1406     int i;
 1407     CDSC *dsc = doc->dsc;
 1408     GFile *f;
 1409     const char *fname;
 1410     const char **renamed1 = NULL;
 1411     for (i=1; (i<(int)dsc->page_count); i++) {
 1412     /* First find length of separation */
 1413     fname = dsc_find_platefile(dsc, i);
 1414     if (fname) {
 1415         TCHAR wfname[MAXSTR];
 1416         narrow_to_cs(wfname, (int)(sizeof(wfname)/sizeof(TCHAR)-1),
 1417         fname, (int)strlen(fname)+1);
 1418         if ((f = gfile_open(wfname, gfile_modeRead)) != (GFile *)NULL) {
 1419         gfile_close(f);
 1420         }
 1421         else {
 1422         if (!opt->missing_separations)
 1423             code = -1;
 1424         if (!opt->quiet)
 1425             app_msgf(doc->app, 
 1426             "Separation \042%s\042 is missing file \042%s\042\n",
 1427             dsc->page[i].label, fname);
 1428         }
 1429     }
 1430     else {
 1431         if (dsc->page[i].end <= dsc->page[i].begin) {
 1432         if (!opt->quiet)
 1433                 app_msgf(doc->app, 
 1434             "Separation \042%s\042 is empty\n",
 1435             dsc->page[i].label);
 1436         if (!opt->missing_separations)
 1437             code = -1;
 1438         }
 1439     }
 1440     }
 1441     /* Test if duplicate separations would occur */
 1442     renamed1 = (const char **)malloc(sizeof(const char *) * dsc->page_count);
 1443     if (renamed1 != NULL) {
 1444     if (rename_separations(dsc, opt->rename_sep, renamed1) != 0) {
 1445         code = -1;
 1446         if (!opt->quiet)
 1447           app_msgf(doc->app, "Duplicate separations are not permitted.\n");
 1448     }
 1449     free((void *)renamed1);
 1450     }
 1451 
 1452     return code;
 1453 }
 1454 
 1455 /****************************************************************/
 1456 /* Read --custom-colours file etc. */
 1457 
 1458 static int 
 1459 custom_colours_read(OPT *opt)
 1460 {
 1461     FILE *f;
 1462     char line[MAXSTR];
 1463     CUSTOM_COLOUR colour;
 1464     CUSTOM_COLOUR *pcolour;
 1465     CUSTOM_COLOUR *tail = opt->colours;
 1466     int i;
 1467     char *s;
 1468     int code = 0;
 1469     if (opt->custom_colours[0]) {
 1470     /* read CMYK colours from file */
 1471     f =  csfopen(opt->custom_colours, TEXT("r"));
 1472     if (f == NULL)
 1473         return -1;
 1474     while (tail && tail->next)
 1475         tail = tail->next;
 1476     while (fgets(line, sizeof(line), f) != NULL) {
 1477         memset(&colour, 0, sizeof(colour));
 1478         i = 0;
 1479         s = line;
 1480         if (strncmp(line, "%%CMYKCustomColor:", 18) == 0) {
 1481         s += 18;
 1482         colour.type = CUSTOM_CMYK;
 1483         while (*s && (*s == ' '))
 1484             s++;
 1485         /* Get the colour values */
 1486         s = strtok(s, " \t\r\n");
 1487         if (s != NULL) {
 1488             colour.cyan = (float)atof(s);
 1489             s = strtok(NULL, " \t\r\n");
 1490         }
 1491         if (s != NULL) {
 1492             colour.magenta = (float)atof(s);
 1493             s = strtok(NULL, " \t\r\n");
 1494         }
 1495         if (s != NULL) {
 1496             colour.yellow = (float)atof(s);
 1497             s = strtok(NULL, " \t\r\n");
 1498         }
 1499         if (s != NULL) {
 1500             colour.black = (float)atof(s);
 1501             s = strtok(NULL, "\t\r\n");
 1502         }
 1503         }
 1504         else if (strncmp(line, "%%RGBCustomColor:", 17) == 0) {
 1505         s += 17;
 1506         colour.type = CUSTOM_RGB;
 1507         while (*s && (*s == ' '))
 1508             s++;
 1509         /* Get the colour values */
 1510         s = strtok(s, " \t\r\n");
 1511         if (s != NULL) {
 1512             colour.red = (float)atof(s);
 1513             s = strtok(NULL, " \t\r\n");
 1514         }
 1515         if (s != NULL) {
 1516             colour.green = (float)atof(s);
 1517             s = strtok(NULL, " \t\r\n");
 1518         }
 1519         if (s != NULL) {
 1520             colour.blue = (float)atof(s);
 1521             s = strtok(NULL, "\t\r\n");
 1522         }
 1523         }
 1524         else {
 1525         s = NULL;
 1526         }
 1527 
 1528         if (s != NULL) {
 1529         /* Get the colour name */
 1530         while (*s && (*s == ' '))
 1531             s++;
 1532         if (*s == '(') {
 1533             s++;
 1534             while (*s && (*s != ')')) {
 1535             if (i < (int)sizeof(colour.name)-1)
 1536                 colour.name[i++] = *s;
 1537             s++;
 1538             }
 1539             if (*s == ')')
 1540             s++;
 1541         }
 1542         else {
 1543             while (*s && (*s != ' ') && (*s != '\t') &&
 1544             (*s != '\r') && (*s != '\n')) {
 1545             if (i < (int)sizeof(colour.name)-1)
 1546                 colour.name[i++] = *s;
 1547             s++;
 1548             }
 1549         }
 1550         colour.name[i] = '\0';
 1551         }
 1552         if (debug & DEBUG_GENERAL) {
 1553         if (s == NULL)
 1554             fprintf(stdout, "Unrecognised line: %s\n", line);
 1555         else if (colour.type == CUSTOM_CMYK)
 1556             fprintf(stdout, "CMYK Colour: %g %g %g %g (%s)\n",
 1557             colour.cyan, colour.magenta, colour.yellow, 
 1558                 colour.black, colour.name);
 1559         else if (colour.type == CUSTOM_RGB)
 1560             fprintf(stdout, "RGB Colour: %g %g %g (%s)\n",
 1561             colour.red, colour.green, colour.blue, 
 1562                 colour.name);
 1563         else 
 1564             fprintf(stdout, "Unrecognised colour\n");
 1565         }
 1566         if (s == NULL) {
 1567         if (code == 0)
 1568             code = 1;
 1569         }
 1570         else {
 1571         pcolour = (CUSTOM_COLOUR *)malloc(sizeof(CUSTOM_COLOUR));
 1572         if (pcolour == NULL)
 1573             code = -1;
 1574         else {
 1575             /* append to list */
 1576             memcpy(pcolour, &colour, sizeof(colour));
 1577             if (tail) {
 1578             tail->next = pcolour;
 1579             tail = pcolour;
 1580             }
 1581             else
 1582             opt->colours = tail = pcolour;
 1583         }
 1584         }
 1585     }
 1586     fclose(f);
 1587     }
 1588     return code;
 1589 }
 1590 
 1591 static void 
 1592 custom_colours_free(OPT *opt)
 1593 {
 1594     CUSTOM_COLOUR *pcolour;
 1595     while (opt->colours) {
 1596     pcolour = opt->colours;
 1597     opt->colours = opt->colours->next;
 1598     free(pcolour);
 1599     }
 1600 }
 1601 
 1602 static CUSTOM_COLOUR *
 1603 custom_colours_find(OPT *opt, const char *name)
 1604 {
 1605     CUSTOM_COLOUR *pcolour = opt->colours;
 1606     while (pcolour) {
 1607     if (strcmp(name, pcolour->name) == 0)
 1608         break;
 1609     pcolour = pcolour->next;
 1610     }
 1611     return pcolour;
 1612 }
 1613 
 1614 /****************************************************************/
 1615 static float
 1616 round_float(float f, int n)
 1617 {
 1618     return  (float)( ((int)(f * n + 0.5)) / (float)n );
 1619 }
 1620 
 1621 /* Calculate the bounding box using the ghostscript bbox device */
 1622 static int
 1623 calculate_bbox(Doc *doc, OPT *opt, LPCTSTR psname, CDSCBBOX *bbox, CDSCFBBOX *hires_bbox)
 1624 {
 1625     FILE *bboxfile;
 1626     TCHAR bboxname[MAXSTR];
 1627     TCHAR command[MAXSTR*8];
 1628     char line[MAXSTR];
 1629     int got_bbox = 0;
 1630     int got_hires_bbox = 0;
 1631     int code = 0;
 1632     int llx, lly, urx, ury;
 1633     float fllx, flly, furx, fury;
 1634     const int pagesize = 9400; /* Must be < 9419 on 7.07, < 150976 on 8.x */
 1635     const int offset = 3000;
 1636     if ((bboxfile = app_temp_file(doc->app, bboxname, 
 1637     sizeof(bboxname)/sizeof(TCHAR))) == (FILE *)NULL) {
 1638     app_csmsgf(doc->app, TEXT("Can't create temporary bbox file \042%s\042\n"),
 1639         bboxname);
 1640     return -1;
 1641     }
 1642     fclose(bboxfile);
 1643 
 1644     csnprintf(command, sizeof(command)/sizeof(TCHAR), TEXT(
 1645     "\042%s\042 %s -dNOPAUSE -dBATCH -sDEVICE=bbox %s \
 1646  -c \042<</PageSize [%d %d] /PageOffset [%d %d]>> setpagedevice\042 -f \042%s\042"), 
 1647     opt->gs, opt->quiet ? TEXT("-dQUIET") : TEXT(""), opt->gsargs,
 1648     pagesize, pagesize, offset, offset, psname);
 1649     if (!opt->quiet)
 1650     app_csmsgf(doc->app, TEXT("%s\n"), command);
 1651     code = exec_program(command, -1, fileno(stdout), -1, NULL, NULL, bboxname);
 1652     if (code != 0)
 1653     app_csmsgf(doc->app, 
 1654         TEXT("Ghostscript failed to obtain bounding box\n"));
 1655 
 1656     /* Now scan for bounding box info */
 1657     if (code == 0) {
 1658     if ((bboxfile = csfopen(bboxname, TEXT("rb"))) == (FILE *)NULL) {
 1659         app_csmsgf(doc->app, 
 1660         TEXT("Can't open temporary bbox file \042%s\042\n"),
 1661         bboxname);
 1662         code = -1;
 1663     }
 1664     }
 1665 
 1666     if (code == 0) {
 1667     while (fgets(line, sizeof(line), bboxfile) != NULL) {
 1668         if (strncmp(line, "%%BoundingBox: ", 15) == 0) {
 1669         if (!opt->quiet)
 1670             app_msgf(doc->app, "%s", line);
 1671         if (sscanf(line+15, "%d %d %d %d", &llx, &lly, &urx, &ury) 
 1672             == 4) {
 1673             bbox->llx = llx-offset;
 1674             bbox->lly = lly-offset;
 1675             bbox->urx = urx-offset;
 1676             bbox->ury = ury-offset;
 1677             got_bbox = 1;
 1678         }
 1679         }
 1680         else if (strncmp(line, "%%HiResBoundingBox: ", 20) == 0) {
 1681         if (!opt->quiet)
 1682             app_msgf(doc->app, "%s", line);
 1683         if (sscanf(line+20, "%f %f %f %f", &fllx, &flly, &furx, &fury) 
 1684             == 4) {
 1685             hires_bbox->fllx = round_float(fllx-offset, 1000);
 1686             hires_bbox->flly = round_float(flly-offset, 1000);
 1687             hires_bbox->furx = round_float(furx-offset, 1000);
 1688             hires_bbox->fury = round_float(fury-offset, 1000);
 1689             got_hires_bbox = 1;
 1690         }
 1691         }
 1692         if (got_bbox && got_hires_bbox)
 1693         break;
 1694     }
 1695     }
 1696 
 1697     fclose(bboxfile);
 1698     if (!(debug & DEBUG_GENERAL))
 1699     csunlink(bboxname);
 1700 
 1701     if ((code == 0) && (!got_bbox)) {
 1702     app_csmsgf(doc->app, TEXT("Didn't get bounding box\n"));
 1703     code = -1;
 1704     }
 1705     if ((code == 0) && (!got_hires_bbox)) {
 1706     app_csmsgf(doc->app, TEXT("Didn't get hires bounding box\n"));
 1707     code = -1;
 1708     }
 1709     return code;
 1710 }
 1711 
 1712 static int
 1713 calc_device_size(float dpi, CDSCBBOX *bbox, CDSCFBBOX *hires_bbox,
 1714     int *width, int *height, float *xoffset, float *yoffset)
 1715 {
 1716     int code = 0;
 1717     int hires_bbox_valid = 1;
 1718     if ((bbox->llx >= bbox->urx) ||
 1719     (bbox->lly >= bbox->ury)) {
 1720     code = -1;
 1721     }
 1722 
 1723     if ((hires_bbox->fllx > hires_bbox->furx) ||
 1724     (hires_bbox->flly > hires_bbox->fury)) {
 1725     hires_bbox_valid = 0;
 1726     code = -1;
 1727     }
 1728     if ((hires_bbox->fllx == hires_bbox->furx) ||
 1729     (hires_bbox->flly == hires_bbox->fury)) {
 1730     hires_bbox_valid = 0;
 1731     /* ignore hires_bbox */
 1732     }
 1733 
 1734     /* Make the preview image */
 1735     if (hires_bbox_valid) {
 1736     *width = (int)((hires_bbox->furx - hires_bbox->fllx)*dpi/72.0+0.5);
 1737     *height = (int)((hires_bbox->fury - hires_bbox->flly)*dpi/72.0+0.5);
 1738     *xoffset = -hires_bbox->fllx;
 1739     *yoffset = -hires_bbox->flly;
 1740     }
 1741     else {
 1742     *width = (int)((bbox->urx - bbox->llx)*dpi/72.0+0.5);
 1743     *height = (int)((bbox->ury - bbox->lly)*dpi/72.0+0.5);
 1744     *xoffset = (float)(-bbox->llx);
 1745     *yoffset = (float)(-bbox->lly);
 1746     }
 1747     return 0;
 1748 }
 1749 
 1750 
 1751 static int
 1752 make_preview_file(Doc *doc, OPT *opt, int page, 
 1753     LPCTSTR preview, LPCTSTR device,
 1754     float dpi, CDSCBBOX *bbox, CDSCFBBOX *hires_bbox, int calc_bbox)
 1755 {
 1756     GFile *f;
 1757     int code = 0;
 1758     TCHAR tpsname[MAXSTR];
 1759     TCHAR command[MAXSTR*8];
 1760     int width, height;
 1761     float xoffset, yoffset;
 1762 
 1763     /* Copy page to temporary file */
 1764     if ((f = app_temp_gfile(doc->app, tpsname, 
 1765     sizeof(tpsname)/sizeof(TCHAR))) == (GFile *)NULL) {
 1766     app_csmsgf(doc->app, 
 1767         TEXT("Can't create temporary ps file \042%s\042\n"),
 1768         tpsname);
 1769     return -1;
 1770     }
 1771     code = copy_page_temp(doc, f, page);
 1772     gfile_close(f);
 1773     if (code != 0) {
 1774     if (!(debug & DEBUG_GENERAL))
 1775         csunlink(tpsname);
 1776     return -1;
 1777     }
 1778 
 1779     /* Get bbox */
 1780     if ((code == 0) && calc_bbox)
 1781     code = calculate_bbox(doc, opt, tpsname, bbox, hires_bbox);
 1782     width = height = 0;
 1783     xoffset = yoffset = 0.0;
 1784     if (code == 0)
 1785         code = calc_device_size(dpi, bbox, hires_bbox, &width, &height,
 1786         &xoffset, &yoffset);
 1787     if (code) {
 1788     app_csmsgf(doc->app, TEXT("BoundingBox is invalid\n"));
 1789     if (!(debug & DEBUG_GENERAL))
 1790         csunlink(tpsname);
 1791     return -1;
 1792     }
 1793     
 1794     /* Make the preview image */
 1795     csnprintf(command, sizeof(command)/sizeof(TCHAR),
 1796     TEXT("\042%s\042 %s -dNOPAUSE -dBATCH -sDEVICE=%s -sOutputFile=\042%s\042 -r%g -g%dx%d %s -c %f %f translate -f \042%s\042"), 
 1797     opt->gs, opt->quiet ? TEXT("-dQUIET") : TEXT(""), 
 1798     device, (preview[0]=='\0' ? TEXT("-") : preview), dpi, width, height, 
 1799     opt->gsargs, xoffset, yoffset, tpsname);
 1800     if (!opt->quiet)
 1801     app_csmsgf(doc->app, TEXT("%s\n"), command);
 1802     code = exec_program(command, -1, fileno(stdout), fileno(stderr),
 1803     NULL, NULL, NULL);
 1804     if (code != 0)
 1805     app_csmsgf(doc->app, 
 1806         TEXT("Ghostscript failed to create preview image\n"));
 1807 
 1808     /* delete temporary ps file */
 1809     if (!(debug & DEBUG_GENERAL))
 1810     csunlink(tpsname);
 1811 
 1812     return code;
 1813 }
 1814 
 1815 
 1816 static IMAGE *
 1817 make_preview_image(Doc *doc, OPT *opt, int page, LPCTSTR device,
 1818     CDSCBBOX *bbox, CDSCFBBOX *hires_bbox, int calc_bbox)
 1819 {
 1820     IMAGE *img = NULL;
 1821     IMAGE *newimg = NULL;
 1822     TCHAR preview[MAXSTR];
 1823     GFile *f;
 1824     int code = 0;
 1825 
 1826     /* Create a temporary file for ghostscript bitmap output */
 1827     if ((f = app_temp_gfile(doc->app, preview, 
 1828     sizeof(preview)/sizeof(TCHAR))) == (GFile *)NULL) {
 1829     app_csmsgf(doc->app, 
 1830         TEXT("Can't create temporary bitmap file \042%s\042\n"),
 1831         preview);
 1832     code = -1;
 1833     }
 1834     else
 1835     gfile_close(f);
 1836 
 1837     if (code == 0)
 1838     code = make_preview_file(doc, opt, page, 
 1839         preview, device, opt->dpi_render, bbox, hires_bbox, calc_bbox);
 1840 
 1841     if (code == 0) {
 1842     /* Load image */
 1843     img = bmpfile_to_image(preview);
 1844     if (img == NULL)
 1845         img = pnmfile_to_image(preview);
 1846     }
 1847 
 1848     if (img && (opt->dpi_render != opt->dpi)) {
 1849     /* downscale it */
 1850     newimg = (IMAGE *)malloc(sizeof(IMAGE));
 1851     if (newimg != NULL) {
 1852         int ncomp;
 1853         int width, height;
 1854         float xoffset, yoffset;
 1855         memset(newimg, 0, sizeof(newimg));
 1856         calc_device_size(opt->dpi, bbox, hires_bbox, &width, &height,
 1857          &xoffset, &yoffset);
 1858         newimg->width = width;
 1859         newimg->height = height;
 1860         newimg->format = img->format;
 1861         if ((newimg->format & DISPLAY_COLORS_MASK) 
 1862         == DISPLAY_COLORS_CMYK)
 1863         ncomp = 4;
 1864         else if ((newimg->format & DISPLAY_COLORS_MASK) 
 1865         == DISPLAY_COLORS_RGB)
 1866         ncomp = 3;
 1867         else
 1868         ncomp = 1;
 1869         newimg->raster = newimg->width * ncomp; /* bytes per row */
 1870         newimg->image = malloc(newimg->raster * newimg->height);
 1871         if (newimg->image == NULL) {
 1872         free(newimg);
 1873         newimg = NULL;
 1874         }
 1875     }
 1876     if (newimg != NULL) {
 1877         memset(newimg->image, 0, newimg->raster * newimg->height);
 1878         if (image_down_scale(newimg, img) != 0) {
 1879         bitmap_image_free(newimg);
 1880         newimg = NULL;
 1881         }
 1882     }
 1883     if (newimg != NULL) {
 1884         bitmap_image_free(img);
 1885         img = newimg;
 1886     }
 1887     }
 1888     
 1889     if (!(debug & DEBUG_GENERAL))
 1890     csunlink(preview);
 1891     return img;
 1892 }
 1893 
 1894 
 1895 /****************************************************************/
 1896 int
 1897 epstool_dcs2_composite(Doc *doc, OPT *opt, GFile *compfile)
 1898 {
 1899     CDSC *dsc = doc->dsc;
 1900     IMAGE img;
 1901     IMAGE *layer = NULL;
 1902     int width, height;
 1903     float xoffset, yoffset;
 1904     float cyan, magenta, yellow, black;
 1905     int code = 0;
 1906     int i;
 1907     CDSCBBOX bbox = {0, 0, 0, 0};
 1908     CDSCFBBOX hires_bbox = {0.0, 0.0, 0.0, 0.0};
 1909     int hires_bbox_valid = 0;
 1910 
 1911     /* Require original to be DCS 2.0 */ 
 1912     if (doc->dsc == NULL)
 1913     return -1;
 1914     if (doc->dsc->dcs2 == NULL)
 1915     return -1;
 1916 
 1917     if (dsc->bbox) {
 1918     bbox = *dsc->bbox;
 1919     }
 1920     else
 1921     return -1;
 1922     if (dsc->hires_bbox) {
 1923     hires_bbox = *dsc->hires_bbox;
 1924     hires_bbox_valid = 1;
 1925     }
 1926 
 1927     /* Make a CMYK image for the composite */
 1928     code = calc_device_size(opt->dpi, &bbox, &hires_bbox, &width, &height,
 1929         &xoffset, &yoffset);
 1930     if (code) {
 1931     app_csmsgf(doc->app, TEXT("BoundingBox is invalid\n"));
 1932     return -1;
 1933     }
 1934     memset(&img, 0, sizeof(img));
 1935     img.width = width;
 1936     img.height = height;
 1937     img.raster = img.width * 4;
 1938     img.format = DISPLAY_COLORS_CMYK | DISPLAY_ALPHA_NONE |
 1939        DISPLAY_DEPTH_8 | DISPLAY_BIGENDIAN | DISPLAY_TOPFIRST;
 1940     img.image = (unsigned char *)malloc(img.raster * img.height);
 1941     if (img.image == NULL)
 1942     return -1;
 1943     memset(img.image, 0, img.raster * img.height);
 1944  
 1945     /* For each plate, make an image, then merge it into
 1946      * the composite
 1947      */
 1948     for (i=1; i<(int)dsc->page_count; i++) {
 1949     /* find colour */
 1950     int found;
 1951     CUSTOM_COLOUR *ccolour = NULL;
 1952     const char *name = dsc->page[i].label;
 1953     if (name == NULL) {
 1954         app_msgf(doc->app, "Page %d doesn't have a label\n", i);
 1955         code = -1;
 1956         break;
 1957     }
 1958     found = colour_to_cmyk(dsc, name, &cyan, &magenta, &yellow, &black);
 1959     if ((ccolour = custom_colours_find(opt, name)) != NULL) {
 1960         /* Use local colour overrides from --custom-colours */
 1961         found = 0;
 1962         if (ccolour->type == CUSTOM_RGB) {
 1963         cyan = (float)(1.0 - ccolour->red);
 1964         magenta = (float)(1.0 - ccolour->green);
 1965         yellow = (float)(1.0 - ccolour->blue);
 1966         black = min(cyan, min(magenta, yellow));
 1967         if (black > 0.0) {
 1968             cyan -= black;
 1969             magenta -= black;
 1970             yellow -= black;
 1971         }
 1972         }
 1973         else {
 1974         cyan = ccolour->cyan;
 1975         magenta = ccolour->magenta;
 1976         yellow = ccolour->yellow;
 1977         black = ccolour->black;
 1978         }
 1979     }
 1980     if (found < 0) {
 1981         app_msgf(doc->app, "Unrecognised colour (%s)\n", name);
 1982         code = -1;
 1983         break;
 1984     }
 1985 
 1986     if ((cyan == 0.0) && (magenta == 0.0) && (yellow == 0.0) && 
 1987         (black == 0.0)) {
 1988         if (!opt->quiet)
 1989         app_msgf(doc->app, "Skipping blank separation %s\n", name);
 1990         continue;
 1991     }
 1992     if (!opt->quiet)
 1993         app_msgf(doc->app, "Creating image from separation %s\n", name);
 1994     /* Now get the separation image */
 1995         layer = make_preview_image(doc, opt, i, GREY_DEVICE,
 1996             &bbox, &hires_bbox, FALSE);
 1997     if (layer == NULL) {
 1998         app_msgf(doc->app, "Failed to make image for separation (%s)\n",
 1999         name);
 2000         code = -1;
 2001         break;
 2002     }
 2003     else {
 2004         if (!opt->quiet)
 2005         app_msgf(doc->app, "Merging separation %g %g %g %g  %s\n", 
 2006             cyan, magenta, yellow, black, name);
 2007         code = image_merge_cmyk(&img, layer, cyan, magenta, yellow, black);
 2008         bitmap_image_free(layer);
 2009         if (code < 0) {
 2010             app_msgf(doc->app, "Failed to merge separation (%s)\n", name);
 2011         code = -1;
 2012         break;
 2013         }
 2014     }
 2015     
 2016     } 
 2017 
 2018 
 2019     if (code == 0) {
 2020     if (!opt->quiet)
 2021         app_msgf(doc->app, "Writing composite as EPS\n");
 2022     code = image_to_eps(compfile, &img, 
 2023         bbox.llx, bbox.lly, bbox.urx, bbox.ury, 
 2024         hires_bbox.fllx, hires_bbox.flly, 
 2025         hires_bbox.furx, hires_bbox.fury, 
 2026         opt->image_encode, 
 2027         opt->image_compress);
 2028     }
 2029 
 2030     free(img.image);
 2031     return code;
 2032 }
 2033 
 2034 /* Return 0 if CMYK set from the DSC comments, -1 if not set */
 2035 static int
 2036 colour_to_cmyk(CDSC *dsc, const char *name, 
 2037    float *cyan, float *magenta, float *yellow, float *black)
 2038 {
 2039     int code = 0;
 2040     CDSCCOLOUR *colour = dsc->colours;
 2041     if (name == NULL)
 2042     return -1;
 2043     while (colour) {
 2044     if (colour->name && (dsc_stricmp(colour->name, name)==0))
 2045         break;
 2046     colour = colour->next;
 2047     }
 2048 
 2049     if (colour && (colour->custom == CDSC_CUSTOM_COLOUR_CMYK)) {
 2050     *cyan = colour->cyan;
 2051     *magenta = colour->magenta;
 2052     *yellow = colour->yellow;
 2053     *black = colour->black;
 2054     }
 2055     else if (colour && (colour->custom == CDSC_CUSTOM_COLOUR_RGB)) {
 2056     *cyan = (float)(1.0 - colour->red);
 2057     *magenta = (float)(1.0 - colour->green);
 2058     *yellow = (float)(1.0 - colour->blue);
 2059     *black = min(*cyan, min(*magenta, *yellow));
 2060     if (*black > 0.0) {
 2061         *cyan -= *black;
 2062         *magenta -= *black;
 2063         *yellow -= *black;
 2064     }
 2065     }
 2066     else {
 2067     if (dsc_stricmp(name, "Cyan") == 0) {
 2068         *cyan = 1.0;
 2069         *magenta = *yellow = *black = 0.0;
 2070     }
 2071     else if (dsc_stricmp(name, "Magenta") == 0) {
 2072         *magenta = 1.0;
 2073         *cyan = *yellow = *black = 0.0;
 2074     }
 2075     else if (dsc_stricmp(name, "Yellow") == 0) {
 2076         *yellow = 1.0;
 2077         *cyan = *magenta = *black = 0.0;
 2078     }
 2079     else if (dsc_stricmp(name, "Black") == 0) {
 2080         *black = 1.0;
 2081         *cyan = *yellow = *magenta = 0.0;
 2082     }
 2083     else {
 2084         code = -1;
 2085     }
 2086     }
 2087     return code;
 2088 }
 2089 
 2090 const char *epswarn_prolog[] = {
 2091 "%!\n",
 2092 "% This code is wrapped around an EPS file to partly test if it complies\n",
 2093 "% with the EPS specfication.\n",
 2094 "\n",
 2095 "/eps_warn_file (%stdout) (w) file def\n",
 2096 "\n",
 2097 "globaldict begin /eps_warn_ok true def end\n",
 2098 "\n",
 2099 "/eps_write_only { % name string -- name\n",
 2100 "  eps_warn_file exch writestring\n",
 2101 "  eps_warn_file ( /) writestring\n",
 2102 "  dup eps_warn_file exch 32 string cvs writestring\n",
 2103 "  eps_warn_file (\\n) writestring \n",
 2104 "  eps_warn_file flushfile\n",
 2105 "} bind def\n",
 2106 "\n",
 2107 "/eps_write { % name string -- name\n",
 2108 "  eps_write_only\n",
 2109 "  //globaldict /eps_warn_ok false put\n",
 2110 "} bind def\n",
 2111 "\n",
 2112 "/eps_warn { % name --\n",
 2113 "  (EPSWARN FAIL: EPS file must not use) \n",
 2114 "  eps_write\n",
 2115 "  //systemdict exch get exec\n",
 2116 "} bind def\n",
 2117 "\n",
 2118 "% Prohibited operators in systemdict\n",
 2119 "/banddevice {/banddevice eps_warn} def\n",
 2120 "/clear {/clear eps_warn} def\n",
 2121 "/cleardictstack {/cleardictstack eps_warn} def\n",
 2122 "/copypage {/copypage eps_warn} def\n",
 2123 "/erasepage {/erasepage eps_warn} def\n",
 2124 "/exitserver {/exitserver eps_warn} def % this won't work - exitserver is in serverdict\n",
 2125 "/serverdict {/serverdict eps_warn} def % so use this to provide warnings instead\n",
 2126 "/statusdict {/statusdict eps_warn} def\n",
 2127 "/framedevice {/framedevice eps_warn} def\n",
 2128 "/grestoreall {/grestoreall eps_warn} def\n",
 2129 "/initclip {/initclip eps_warn} def\n",
 2130 "/initgraphics {/initgraphics eps_warn} def\n",
 2131 "/initmatrix {/initmatrix eps_warn} def\n",
 2132 "/renderbands {/renderbands eps_warn} def\n",
 2133 "/setglobal {/setglobal eps_warn} def\n",
 2134 "/setpagedevice {/setpagedevice eps_warn} def\n",
 2135 "/setpageparams {/setpageparams eps_warn} def\n",
 2136 "/setshared {/setshared eps_warn} def\n",
 2137 "/startjob {/startjob eps_warn} def\n",
 2138 "% If quit is executed, then epswarn_check will never be run.\n",
 2139 "/quit {\n",
 2140 "  % systemdict /quit doesn't work when it has been redefined in userdict\n",
 2141 "  /quit (EPSWARN FAIL: EPS file must not use) eps_write\n",
 2142 "  //globaldict /eps_warn_ok false put\n",
 2143 "  //systemdict begin quit \n",
 2144 "} def\n",
 2145 "\n",
 2146 "% These page sizes are defined in userdict, not systemdict\n",
 2147 "/eps_pagesize_warn {\n",
 2148 "  (EPSWARN FAIL: EPS file must not set page size:)\n",
 2149 "  eps_write pop\n",
 2150 "} def\n",
 2151 "/11x17 {/11x17 eps_pagesize_warn} def\n",
 2152 "/a3 {/a3 eps_pagesize_warn} def\n",
 2153 "/a4 {/a4 eps_pagesize_warn} def\n",
 2154 "/a4small {/a4small eps_pagesize_warn} def\n",
 2155 "/a5 {/a5 eps_pagesize_warn} def\n",
 2156 "/ledger {/ledger eps_pagesize_warn} def\n",
 2157 "/legal {/legal eps_pagesize_warn} def\n",
 2158 "/letter {/letter eps_pagesize_warn} def\n",
 2159 "/lettersmall {/lettersmall eps_pagesize_warn} def\n",
 2160 "/note {/note eps_pagesize_warn} def\n",
 2161 "\n",
 2162 "% These operators can only be used if the parameter\n",
 2163 "% is saved and restored afterwards, or if setting\n",
 2164 "% them takes into account their previous value.\n",
 2165 "% For example 'matrix setmatrix' is not permitted,\n",
 2166 "% but 'matrix current matrix setmatrix' is allowed.\n",
 2167 "/eps_warntwo {\n",
 2168 "  (EPSWARN WARNING: EPS file should be careful using) \n",
 2169 "  eps_write_only\n",
 2170 "  //systemdict exch get exec\n",
 2171 "} def\n",
 2172 "/nulldevice {/nulldevice eps_warntwo} def % can't test this\n",
 2173 "/setgstate {/setgstate eps_warntwo} def % can't test this\n",
 2174 "/sethalftone {/sethalftone eps_warntwo} def\n",
 2175 "/setmatrix {/setmatrix eps_warntwo} def\n",
 2176 "/setscreen {/setscreen eps_warntwo} def\n",
 2177 "/settransfer {/settransfer eps_warntwo} def\n",
 2178 "/setcolortransfer {/setcolortransfer eps_warntwo} def\n",
 2179 "\n",
 2180 "% Take snapshot of some items\n",
 2181 "count /eps_count exch def\n",
 2182 "countdictstack /eps_countdictstack exch def\n",
 2183 "currentpagedevice /PageCount get /eps_pagecount exch def\n",
 2184 "/eps_showpage_count 0 def\n",
 2185 "\n",
 2186 "\n",
 2187 "/epswarn_check_write { % string --\n",
 2188 "  eps_warn_file exch writestring\n",
 2189 "  eps_warn_file flushfile\n",
 2190 "  //globaldict /eps_warn_ok false put\n",
 2191 "} def\n",
 2192 "\n",
 2193 "/epswarn_check {\n",
 2194 "  % count\n",
 2195 "  count eps_count ne {\n",
 2196 "    (EPSWARN FAIL: EPS file altered operand stack count\\n) epswarn_check_write \n",
 2197 "  } if\n",
 2198 "  //systemdict /clear get exec\n",
 2199 "  % countdictstack\n",
 2200 "  countdictstack eps_countdictstack ne {\n",
 2201 "   (EPSWARN FAIL: EPS file altered dictionary stack count\\n) \n",
 2202 "   epswarn_check_write\n",
 2203 "  } if\n",
 2204 "  countdictstack eps_countdictstack sub {end} repeat\n",
 2205 "  % real page count\n",
 2206 "  currentpagedevice /PageCount get eps_pagecount ne {\n",
 2207 "    (EPSWARN FAIL: EPS file forcibly output a page\\n) epswarn_check_write\n",
 2208 "  } if\n",
 2209 "  % showpage count\n",
 2210 "  eps_showpage_count 1 gt {\n",
 2211 "    (EPSWARN FAIL: EPS file used showpage more than once\\n) epswarn_check_write\n",
 2212 "  } if\n",
 2213 "} def\n",
 2214 "\n",
 2215 "% EPS files are normally encapsulated inside a save/restore\n",
 2216 "save /epswarn_save exch def\n",
 2217 "\n",
 2218 "% redefine showpage, and count how many times it is called\n",
 2219 "/showpage { userdict dup /eps_showpage_count get 1 add \n",
 2220 "  /eps_showpage_count exch put \n",
 2221 "} def\n",
 2222 "\n",
 2223 "% Now for something to test this\n",
 2224 "\n",
 2225 NULL};
 2226 
 2227 const char epswarn_epilog[] = "\
 2228 %!\n\
 2229 % Check that all is well\n\
 2230 epswarn_check\n\
 2231 %epswarn_save restore\n\
 2232 //globaldict /eps_warn_ok get not \n\
 2233  {eps_warn_file (\nEPSWARN FAIL\\n) writestring} \n\
 2234  {eps_warn_file (\nEPSWARN PASS\\n) writestring} \n\
 2235  ifelse\n\
 2236 systemdict begin % so quit works...\n\
 2237 ";
 2238 
 2239 
 2240 /* Test if an EPS file really is EPS compliant */
 2241 static int
 2242 epstool_test(Doc *doc, OPT *opt)
 2243 {
 2244     GFile *f;
 2245     int code = 0;
 2246     TCHAR tpsname[MAXSTR];
 2247     TCHAR command[MAXSTR*8];
 2248     unsigned int len;
 2249     FILE *testfile = NULL;
 2250     TCHAR testname[MAXSTR];
 2251     CDSCBBOX bbox;
 2252     CDSCFBBOX hires_bbox;
 2253     BOOL found_error = FALSE;
 2254     BOOL found_warning = FALSE;
 2255     BOOL found_pass = FALSE;
 2256     BOOL bbox_valid = FALSE;
 2257     char line[256];
 2258     int i;
 2259     BOOL dsc_error = FALSE;
 2260     BOOL dsc_warning = FALSE;
 2261 
 2262     if (doc->dsc) {
 2263     dsc_error = (doc->dsc->worst_error ==  CDSC_ERROR_ERROR);
 2264     dsc_warning = (doc->dsc->worst_error ==  CDSC_ERROR_WARN);
 2265     }
 2266 
 2267     /* Copy prolog, page and epilog to a temporary file */
 2268     if ((f = app_temp_gfile(doc->app, tpsname, 
 2269     sizeof(tpsname)/sizeof(TCHAR))) == (GFile *)NULL) {
 2270     app_csmsgf(doc->app, 
 2271         TEXT("Can't create temporary ps file \042%s\042\n"),
 2272         tpsname);
 2273     return -1;
 2274     }
 2275     for (i=0; epswarn_prolog[i]; i++) {
 2276         len = (int)strlen(epswarn_prolog[i]);
 2277         if (!code && (len != gfile_write(f, epswarn_prolog[i], len)))
 2278         code = -1;
 2279     }
 2280     code = copy_page_nosave(doc, f, 0);
 2281     len = (int)strlen(epswarn_epilog);
 2282     if (len != gfile_write(f, epswarn_epilog, len))
 2283     code = -1;
 2284     gfile_close(f);
 2285     if (code != 0) {
 2286     if (!(debug & DEBUG_GENERAL))
 2287         csunlink(tpsname);
 2288     return -1;
 2289     }
 2290 
 2291     if ((testfile = app_temp_file(doc->app, testname, 
 2292     sizeof(testname)/sizeof(TCHAR))) == (FILE *)NULL) {
 2293     app_csmsgf(doc->app, TEXT("Can't create temporary file \042%s\042\n"),
 2294         testname);
 2295     if (!(debug & DEBUG_GENERAL))
 2296         csunlink(tpsname);
 2297     return -1;
 2298     }
 2299     fclose(testfile);
 2300     testfile = NULL;
 2301 
 2302     /* Interpret the file to test it */
 2303     csnprintf(command, sizeof(command)/sizeof(TCHAR),
 2304     TEXT("\042%s\042 %s -dNOEPS -dNOPAUSE -dBATCH -dNODISPLAY %s \042%s\042"), 
 2305     opt->gs, opt->quiet ? TEXT("-dQUIET") : TEXT(""), 
 2306     opt->gsargs, tpsname);
 2307     if (!opt->quiet)
 2308     app_csmsgf(doc->app, TEXT("%s\n"), command);
 2309     code = exec_program(command, -1, -1 , fileno(stderr),
 2310     NULL, testname, NULL);
 2311     if (code != 0)
 2312     app_csmsgf(doc->app, 
 2313         TEXT("Ghostscript failed to interpret file\n"));
 2314     /* delete temporary ps file */
 2315     if (!(debug & DEBUG_GENERAL))
 2316     csunlink(tpsname);
 2317 
 2318     /* Now check testfile for reports of problems */
 2319     if (code == 0) {
 2320     if ((testfile = csfopen(testname, TEXT("rb"))) == (FILE *)NULL) {
 2321         app_csmsgf(doc->app, 
 2322         TEXT("Can't open temporary file \042%s\042\n"),
 2323         testname);
 2324         code = -1;
 2325     }
 2326     }
 2327 
 2328     if (code == 0) {
 2329     while (fgets(line, sizeof(line), testfile) != NULL) {
 2330         if (!opt->quiet)
 2331         app_msgf(doc->app, "%s", line);
 2332         if (strncmp(line, "EPSWARN FAIL: ", 14) == 0)
 2333         found_error = TRUE;
 2334         else if (strncmp(line, "EPSWARN WARNING: ", 17) == 0)
 2335         found_warning = TRUE;
 2336         else if (strncmp(line, "EPSWARN PASS", 12) == 0)
 2337         found_pass = TRUE;
 2338     }
 2339     }
 2340     if (testfile)
 2341         fclose(testfile);
 2342     if (!(debug & DEBUG_GENERAL))
 2343     csunlink(testname);
 2344     if (!opt->quiet)
 2345     app_csmsg(doc->app, TEXT("\n"));
 2346 
 2347     if ((code == 0) && (doc->dsc) && (doc->dsc->bbox)) {
 2348     /* Copy page to temporary file */
 2349     if ((f = app_temp_gfile(doc->app, tpsname, 
 2350         sizeof(tpsname)/sizeof(TCHAR))) == (GFile *)NULL) {
 2351         app_csmsgf(doc->app, 
 2352         TEXT("Can't create temporary ps file \042%s\042\n"),
 2353         tpsname);
 2354         return -1;
 2355     }
 2356     code = copy_page_temp(doc, f, 0);
 2357     gfile_close(f);
 2358     if (code != 0) {
 2359         if (!(debug & DEBUG_GENERAL))
 2360         csunlink(tpsname);
 2361         return -1;
 2362     }
 2363     code = calculate_bbox(doc, opt, tpsname, &bbox, &hires_bbox);
 2364         if (!opt->quiet)
 2365         app_csmsg(doc->app, TEXT("\n"));
 2366     if (code == 0) {
 2367         if ( (bbox.llx >= doc->dsc->bbox->llx-1) &&
 2368              (bbox.lly >= doc->dsc->bbox->lly-1) &&
 2369              (bbox.urx <= doc->dsc->bbox->urx+1) &&
 2370              (bbox.ury <= doc->dsc->bbox->ury+1)) {
 2371         bbox_valid = TRUE;
 2372         }
 2373         if (!opt->quiet) {
 2374             app_csmsgf(doc->app, 
 2375                 TEXT("File has   %%%%BoundingBox: %d %d %d %d\n"),
 2376             doc->dsc->bbox->llx, doc->dsc->bbox->lly,
 2377             doc->dsc->bbox->urx, doc->dsc->bbox->ury);
 2378             app_csmsgf(doc->app, 
 2379                 TEXT("Correct is %%%%BoundingBox: %d %d %d %d\n"),
 2380             bbox.llx, bbox.lly, bbox.urx, bbox.ury);
 2381         if (!bbox_valid)
 2382             app_csmsgf(doc->app, 
 2383             TEXT("File bounding box needs to be larger\n"));
 2384         }
 2385     }
 2386     else  {
 2387         if (!opt->quiet)
 2388            app_csmsgf(doc->app, 
 2389                TEXT("Failed to calculate bounding box\n"));
 2390     }
 2391 
 2392     /* delete temporary ps file */
 2393     if (!(debug & DEBUG_GENERAL))
 2394         csunlink(tpsname);
 2395     }
 2396     else {
 2397     if (!opt->quiet)
 2398        app_csmsgf(doc->app, 
 2399            TEXT("Missing %%%%BoundingBox\n"));
 2400     }
 2401 
 2402     if (found_error || !found_pass || !bbox_valid || 
 2403     dsc_error || dsc_warning ||
 2404     !doc->dsc || !doc->dsc->epsf)
 2405     code = -1;
 2406 
 2407     if (!opt->quiet) {
 2408     if (found_warning)
 2409        app_csmsgf(doc->app, TEXT("File used operators that sometimes cause problems in an EPS file.\n"));
 2410         if (found_error)
 2411        app_csmsgf(doc->app, TEXT("File used PostScript operators that are prohibited in an EPS file.\n"));
 2412     if (found_pass)
 2413        app_csmsgf(doc->app, TEXT("PostScript appears well behaved.\n"));
 2414         if (doc->dsc && doc->dsc->epsf)
 2415         app_csmsgf(doc->app, TEXT("File claims to be EPS.\n"));
 2416     else
 2417         app_csmsgf(doc->app, TEXT("File is not EPS.\n"));
 2418     }
 2419 
 2420     if (code != 0)
 2421         fprintf(MSGOUT, "FAIL: File does not comply with EPS specification.\n");
 2422     else
 2423     fprintf(MSGOUT, "PASS: File appears to be well behaved EPS.\n");
 2424 
 2425     return code;
 2426 }
 2427 
 2428 static void epstool_dump_fn(void *caller_data, const char *str)
 2429 {
 2430     fputs(str, stdout);
 2431 }
 2432 
 2433 
 2434 /****************************************************************/
 2435 /* Functions from GSview app that we need. */
 2436 /* Some of these should be moved from capp.c to a separate file. */
 2437 
 2438 #ifdef _MSC_VER
 2439 # pragma warning(disable:4100) /* ignore "Unreferenced formal parameter" */
 2440 #endif
 2441 
 2442 int
 2443 app_platform_init(GSview *a)
 2444 {
 2445     return 0;
 2446 }
 2447 
 2448 int
 2449 app_platform_finish(GSview *a)
 2450 {
 2451     return 0;
 2452 }
 2453 
 2454 int
 2455 app_lock(GSview *a)
 2456 {
 2457     return 0;
 2458 }
 2459 
 2460 int
 2461 app_unlock(GSview *a)
 2462 {
 2463     return 0;
 2464 }
 2465 
 2466 void
 2467 app_log(const char *str, int len)
 2468 {
 2469     fwrite(str, 1, len, MSGOUT);
 2470 }
 2471 
 2472 int
 2473 cs_to_narrow(char *nstr, int nlen, LPCTSTR wstr, int wlen)
 2474 {
 2475 #ifdef UNICODE
 2476     return WideCharToMultiByte(CP_ACP, 0, wstr, wlen, nstr, nlen, NULL, NULL);
 2477 #else
 2478     return char_to_narrow(nstr, nlen, wstr, wlen);
 2479 #endif
 2480 }
 2481 
 2482 int 
 2483 narrow_to_cs(TCHAR *wstr, int wlen, const char *nstr, int nlen)
 2484 {
 2485 #ifdef UNICODE
 2486     return MultiByteToWideChar(CP_ACP, 0, nstr, nlen, wstr, wlen);
 2487 #else
 2488     return narrow_to_char(wstr, wlen, nstr, nlen);
 2489 #endif
 2490 }
 2491 
 2492 int get_dsc_response(GSview *app, LPCTSTR str)
 2493 {
 2494     app_csmsgf(app, TEXT("\n%s\n"), str);
 2495     return CDSC_RESPONSE_OK;
 2496 }
 2497 
 2498 int 
 2499 load_string(GSview *a, int id, TCHAR *buf, int len)
 2500 {
 2501     char msg[MAXSTR];
 2502     const char *s = NULL;
 2503     int reslen;
 2504     int dscmsg = (id - CDSC_RESOURCE_BASE) / 2;
 2505     if (buf && len)
 2506     buf[0] = '\0';
 2507     /* CDSC_MESSAGE_INCORRECT_USAGE should be dsc->max_error */
 2508     if (a /* ignore unused parameter GSview *a */
 2509     && (dscmsg >= 0) && (dscmsg <= CDSC_MESSAGE_INCORRECT_USAGE)) {
 2510     if (((id - CDSC_RESOURCE_BASE) & 1) == 0)
 2511         s = dsc_message[dscmsg];
 2512     else
 2513         s = "";
 2514     }
 2515     else 
 2516     switch (id) {
 2517     case IDS_DSC_LINEFMT:
 2518         s = "%sAt line %d:";
 2519         break;
 2520     case IDS_DSC_INFO:
 2521         s = "DSC Information\n";
 2522         break;
 2523     case IDS_DSC_WARN:
 2524         s = "DSC Warning\n";
 2525         break;
 2526     case IDS_DSC_ERROR:
 2527         s = "DSC Error\n";
 2528         break;
 2529     }
 2530 
 2531     if (s == NULL) {
 2532     snprintf(msg, sizeof(msg), "String %d\n", id);
 2533     s = msg;
 2534     }
 2535 
 2536     reslen = narrow_to_cs(NULL, 0, s, (int)strlen(s)+1);
 2537     if (reslen > len)
 2538     return reslen;
 2539     return narrow_to_cs(buf, len, s, (int)strlen(s)+1);
 2540 }
 2541 
 2542 int app_msg_box(GSview *a, LPCTSTR str, int icon)
 2543 {
 2544     app_csmsgf(a, TEXT("%s\n"), str);
 2545     return 0;
 2546 }
 2547 
 2548 int 
 2549 gssrv_request(GSSRV *s, GSREQ *reqnew)
 2550 {
 2551     return -1;
 2552 }
 2553 
 2554 int 
 2555 pagecache_unref_all(GSview *a) 
 2556 {
 2557     return 0;
 2558 }
 2559 
 2560 
 2561 void
 2562 doc_savestat(Doc *doc)
 2563 {
 2564 }
 2565 
 2566 int 
 2567 image_platform_init(IMAGE *img)
 2568 {
 2569     return 0;
 2570 }
 2571 
 2572 unsigned int 
 2573 image_platform_format(unsigned int format)
 2574 {
 2575     return format;
 2576 }
 2577 
 2578 #ifdef _MSC_VER
 2579 # pragma warning(default:4100)
 2580 #endif
 2581 
 2582 /****************************************************************/
 2583 /* platform specific code for running another program */
 2584 
 2585 /*
 2586  * If hstdin not -1, duplicate handle and give to program,
 2587  * else if stdin_name not NULL, open filename and give to program.
 2588  * Same for hstdout/stdout_name and hstderr/stderr_name.
 2589  */
 2590 #ifdef __WIN32__
 2591 int
 2592 exec_program(LPTSTR command,
 2593     int hstdin, int hstdout, int hstderr,
 2594     LPCTSTR stdin_name, LPCTSTR stdout_name, LPCTSTR stderr_name)
 2595 {
 2596     int code = 0;
 2597     HANDLE hChildStdinRd = INVALID_HANDLE_VALUE;
 2598     HANDLE hChildStdoutWr = INVALID_HANDLE_VALUE;
 2599     HANDLE hChildStderrWr = INVALID_HANDLE_VALUE;
 2600     HANDLE hStdin = INVALID_HANDLE_VALUE;
 2601     HANDLE hStderr = INVALID_HANDLE_VALUE;
 2602     HANDLE hStdout = INVALID_HANDLE_VALUE;
 2603     SECURITY_ATTRIBUTES saAttr;
 2604     STARTUPINFO siStartInfo;
 2605     PROCESS_INFORMATION piProcInfo;
 2606     DWORD exitcode = (DWORD)-1;
 2607 
 2608     /* Set the bInheritHandle flag so pipe handles are inherited. */
 2609     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
 2610     saAttr.bInheritHandle = TRUE;
 2611     saAttr.lpSecurityDescriptor = NULL;
 2612 
 2613     /* if handles are provided, use them */
 2614     if ((hstdin != -1)) {
 2615     INTPTR handle;
 2616     handle = _get_osfhandle(hstdin);
 2617     if (handle == -1)
 2618         code = -1;
 2619     if (code == 0) {
 2620         hStdin = (HANDLE)handle;
 2621         if (!DuplicateHandle(GetCurrentProcess(), hStdin,
 2622         GetCurrentProcess(), &hChildStdinRd, 0,
 2623         TRUE,       /* inherited */
 2624         DUPLICATE_SAME_ACCESS))
 2625             code = -1;
 2626     }
 2627     }
 2628     if ((code==0) && (hstdout != -1)) {
 2629     INTPTR handle;
 2630     handle = _get_osfhandle(hstdout);
 2631     if (handle == -1)
 2632         code = -1;
 2633     if (code == 0) {
 2634         hStdout = (HANDLE)handle;
 2635         if (!DuplicateHandle(GetCurrentProcess(), hStdout,
 2636         GetCurrentProcess(), &hChildStdoutWr, 0,
 2637         TRUE,       /* inherited */
 2638         DUPLICATE_SAME_ACCESS))
 2639             code = -1;
 2640     }
 2641     }
 2642     if ((code==0) && (hstderr != -1)) {
 2643     INTPTR handle;
 2644     handle = _get_osfhandle(hstderr);
 2645     if (handle == -1)
 2646         code = -1;
 2647     if (code == 0) {
 2648         hStderr = (HANDLE)handle;
 2649         if (!DuplicateHandle(GetCurrentProcess(), hStderr,
 2650         GetCurrentProcess(), &hChildStderrWr, 0,
 2651         TRUE,       /* inherited */
 2652         DUPLICATE_SAME_ACCESS))
 2653             code = -1;
 2654     }
 2655     }
 2656 
 2657     /* If files are requested, create them */
 2658     if ((code==0) && stdin_name && (hChildStdinRd == INVALID_HANDLE_VALUE)) {
 2659     hChildStdinRd = CreateFile(stdin_name, GENERIC_READ, 
 2660         0  /* no file sharing */,
 2661         &saAttr /* allow handle to be inherited */,
 2662         OPEN_EXISTING, 0, NULL);
 2663     if (hChildStdinRd == INVALID_HANDLE_VALUE)
 2664         code = -1;
 2665     }
 2666     if ((code==0) && stdout_name && (hChildStdoutWr == INVALID_HANDLE_VALUE)) {
 2667     hChildStdoutWr = CreateFile(stdout_name, GENERIC_WRITE, 
 2668         0  /* no file sharing */,
 2669         &saAttr /* allow handle to be inherited */,
 2670         OPEN_ALWAYS, 0, NULL);
 2671     if (hChildStdoutWr == INVALID_HANDLE_VALUE)
 2672         code = -1;
 2673     }
 2674     if ((code==0) && stderr_name && (hChildStderrWr == INVALID_HANDLE_VALUE)) {
 2675     hChildStderrWr = CreateFile(stderr_name, GENERIC_WRITE, 
 2676         0  /* no file sharing */,
 2677         &saAttr /* allow handle to be inherited */,
 2678         OPEN_ALWAYS, 0, NULL);
 2679     if (hChildStderrWr == INVALID_HANDLE_VALUE)
 2680         code = -1;
 2681     }
 2682 
 2683     /* Set up members of STARTUPINFO structure. */
 2684     siStartInfo.cb = sizeof(STARTUPINFO);
 2685     siStartInfo.lpReserved = NULL;
 2686     siStartInfo.lpDesktop = NULL;
 2687     siStartInfo.lpTitle = NULL;  /* use executable name as title */
 2688     /* next two lines ignored */
 2689     siStartInfo.dwX = siStartInfo.dwY = (DWORD)CW_USEDEFAULT;
 2690     siStartInfo.dwXSize = siStartInfo.dwYSize = (DWORD)CW_USEDEFAULT;
 2691     siStartInfo.dwXCountChars = 80;
 2692     siStartInfo.dwYCountChars = 25;
 2693     siStartInfo.dwFillAttribute = 0;            /* ignored */
 2694     siStartInfo.dwFlags = STARTF_USESTDHANDLES;
 2695     siStartInfo.wShowWindow = SW_SHOWNORMAL;        /* ignored */
 2696     siStartInfo.cbReserved2 = 0;
 2697     siStartInfo.lpReserved2 = NULL;
 2698     siStartInfo.hStdInput = hChildStdinRd;
 2699     siStartInfo.hStdOutput = hChildStdoutWr;
 2700     siStartInfo.hStdError = hChildStderrWr;
 2701     memset(&piProcInfo, 0, sizeof(piProcInfo));
 2702 
 2703     if ((code == 0) && !CreateProcess(NULL,
 2704         command,
 2705         NULL,          /* process security attributes        */
 2706         NULL,          /* primary thread security attributes */
 2707         TRUE,          /* handles are inherited              */
 2708     0,             /* creation flags                     */
 2709     NULL,          /* environment                        */
 2710         NULL,          /* use parent's current directory     */
 2711         &siStartInfo,  /* STARTUPINFO pointer                */
 2712         &piProcInfo)) { /* receives PROCESS_INFORMATION  */
 2713     code = -1;
 2714     }
 2715 
 2716     /* close our copy of the handles */
 2717     if (hChildStdinRd != INVALID_HANDLE_VALUE)
 2718     CloseHandle(hChildStdinRd);
 2719     if (hChildStdoutWr != INVALID_HANDLE_VALUE)
 2720     CloseHandle(hChildStdoutWr);
 2721     if (hChildStderrWr != INVALID_HANDLE_VALUE)
 2722     CloseHandle(hChildStderrWr);
 2723 
 2724     if (code == 0) {
 2725     /* wait for process to finish */
 2726     WaitForSingleObject(piProcInfo.hProcess, 300000);
 2727     GetExitCodeProcess(piProcInfo.hProcess, &exitcode);
 2728     CloseHandle(piProcInfo.hProcess);
 2729     CloseHandle(piProcInfo.hThread);
 2730     }
 2731 
 2732     if (code)
 2733     return code;
 2734     return (int)exitcode;
 2735 }
 2736 #endif
 2737 
 2738 #if defined(UNIX)
 2739 int
 2740 exec_program(LPTSTR command,
 2741     int hstdin, int hstdout, int hstderr,
 2742     LPCTSTR stdin_name, LPCTSTR stdout_name, LPCTSTR stderr_name)
 2743 {
 2744     int code = 0;
 2745     int hChildStdinRd = -1;
 2746     int hChildStdoutWr = -1;
 2747     int hChildStderrWr = -1;
 2748     int handle;
 2749     pid_t pid;
 2750     int exitcode;
 2751 #define MAXARG 64
 2752     char *argv[MAXARG+1];
 2753     int argc = 0;
 2754     char *args, *d, *e, *p;
 2755 
 2756     /* Parse command line handling quotes. */
 2757     memset(argv, 0, sizeof(argv));
 2758     argc = 0;
 2759     args = (char *)malloc(strlen(command)+1);
 2760     if (args == (char *)NULL)
 2761     return -1;
 2762     p = command;
 2763     d = args;
 2764     while (*p) {
 2765     /* for each argument */
 2766     if (argc >= MAXARG - 1) {
 2767         fprintf(stderr, "Too many arguments\n");
 2768         free(args);
 2769         return -1;
 2770     }
 2771 
 2772         e = d;
 2773         while ((*p) && (*p != ' ')) {
 2774         if (*p == '\042') {
 2775         /* Remove quotes, skipping over embedded spaces. */
 2776         /* Doesn't handle embedded quotes. */
 2777         p++;
 2778         while ((*p) && (*p != '\042'))
 2779             *d++ =*p++;
 2780         }
 2781         else 
 2782         *d++ = *p;
 2783         if (*p)
 2784         p++;
 2785         }
 2786     *d++ = '\0';
 2787     argv[argc++] = e;
 2788 
 2789     while ((*p) && (*p == ' '))
 2790         p++;    /* Skip over trailing spaces */
 2791     }
 2792     argv[argc] = NULL;
 2793 
 2794     pid = fork();
 2795     if (pid == (pid_t)-1) {
 2796     /* fork failed */
 2797     fprintf(stderr, "Failed to fork, error=%d\n", errno);
 2798     return -1;
 2799     }
 2800     else if (pid == 0) {
 2801     /* child */
 2802     /* if handles are provided, use them */
 2803     if ((code == 0) && (hstdin != -1)) {
 2804         hChildStdinRd = dup2(hstdin, 0);
 2805         if (hChildStdinRd == -1)
 2806         code = -1;
 2807     }
 2808     if ((code==0) && (hstdout != -1)) {
 2809         hChildStdoutWr = dup2(hstdout, 1);
 2810         if (hChildStdoutWr == -1)
 2811         code = -1;
 2812     }
 2813     if ((code==0) && (hstderr != -1)) {
 2814         hChildStderrWr = dup2(hstderr, 2);
 2815         if (hChildStderrWr == -1)
 2816         code = -1;
 2817     }
 2818     if ((code==0) && stdin_name && (hChildStdinRd == -1)) {
 2819         handle = open(stdin_name, O_RDONLY);
 2820         hChildStdinRd = dup2(handle, 0);
 2821         if (handle != -1)
 2822         close(handle);
 2823         if (hChildStdinRd == -1)
 2824         code = -1;
 2825     }
 2826     if ((code==0) && stdout_name && (hChildStdoutWr == -1)) {
 2827         handle = open(stdout_name, O_WRONLY | O_CREAT);
 2828         hChildStdoutWr = dup2(handle, 1);
 2829         if (handle != -1)
 2830         close(handle);
 2831         if (hChildStdoutWr == -1)
 2832         code = -1;
 2833     }
 2834     if ((code==0) && stderr_name && (hChildStderrWr == -1)) {
 2835         handle = open(stderr_name, O_WRONLY | O_CREAT);
 2836         hChildStderrWr = dup2(handle, 2);
 2837         if (handle != -1)
 2838         close(handle);
 2839         if (hChildStderrWr == -1)
 2840         code = -1;
 2841     }
 2842 
 2843     if (code) {
 2844         fprintf(stderr, "Failed to open stdin/out/err, error=%d\n", errno);
 2845         if (hChildStdinRd)
 2846         close(hChildStdinRd);
 2847         if (hChildStdoutWr)
 2848         close(hChildStdoutWr);
 2849         if (hChildStderrWr)
 2850         close(hChildStderrWr);
 2851         exit(1);
 2852     }
 2853 
 2854     /* Now execute it */
 2855     if (execvp(argv[0], argv) == -1) {
 2856         fprintf(stderr, "Failed to execute ghostscript, error=%d\n", errno);
 2857         exit(1);
 2858     }
 2859     }
 2860 
 2861     /* parent - wait for child to finish */
 2862     free(args);
 2863     wait(&exitcode);
 2864     return exitcode;
 2865 }
 2866 #endif
 2867 
 2868 /*
 2869  * If hstdin not -1, duplicate handle and give to program,
 2870  * else if stdin_name not NULL, open filename and give to program.
 2871  * Same for hstdout/stdout_name and hstderr/stderr_name.
 2872  */
 2873 #ifdef OS2
 2874 int
 2875 exec_program(LPTSTR command,
 2876     int hstdin, int hstdout, int hstderr,
 2877     LPCTSTR stdin_name, LPCTSTR stdout_name, LPCTSTR stderr_name)
 2878 {
 2879     HFILE hStdin = 0;
 2880     HFILE hStdout = 1;
 2881     HFILE hStderr = 2;
 2882     HFILE hOldStdin;
 2883     HFILE hOldStdout;
 2884     HFILE hOldStderr;
 2885     HFILE hNewStdin = -1;
 2886     HFILE hNewStdout = -1;
 2887     HFILE hNewStderr = -1;
 2888     APIRET rc = 0;
 2889     ULONG action;
 2890     CHAR szFailName[CCHMAXPATH];
 2891     RESULTCODES resc;
 2892     PSZ cmd;
 2893     PSZ args;
 2894     int cmdlen;
 2895 
 2896     /* Copy command into format needed by DosExecPgm */
 2897     cmdlen = strlen(command)+1;
 2898     cmd = (char *)malloc(cmdlen+1);
 2899     if (cmd) {
 2900     char *p;
 2901     memset(cmd, 0, cmdlen+1);
 2902     strncpy(cmd, command, cmdlen);
 2903     p = args = cmd;
 2904     if (*p == '"') {
 2905        p++;
 2906        args = p;
 2907        while (*p && (*p != '"'))
 2908          p++;
 2909     }
 2910     else  {
 2911        while (*p && (*p != 0))
 2912          p++;
 2913     }
 2914     *p = '\0';
 2915     }
 2916     else
 2917     return -1;
 2918 
 2919     /* save existing stdio handles */
 2920     hOldStdin = 0xffffffff; /* allocate new handle */
 2921     if (rc == 0)
 2922     rc = DosDupHandle(hStdin, &hOldStdin);
 2923     hOldStdout = 0xffffffff; /* allocate new handle */
 2924     if (rc == 0)
 2925         rc = DosDupHandle(hStdout, &hOldStdout);
 2926     hOldStderr = 0xffffffff; /* allocate new handle */
 2927     if (rc == 0)
 2928         rc = DosDupHandle(hStderr, &hOldStderr);
 2929     if (rc != 0) {
 2930     free(cmd);
 2931     return -1;
 2932     }
 2933 
 2934     /* if handles or files are provided, use them */
 2935     if ((hstdin != -1)) {
 2936     if (rc == 0)
 2937         DosDupHandle((HFILE)hstdin, &hStdin);
 2938     }
 2939     else if ((rc == 0) && stdin_name) {
 2940     rc = DosOpen((PCSZ)stdin_name,  /* filename */
 2941         &hNewStdin, /* pointer to handle */
 2942         &action,    /* pointer to result */
 2943         0,      /* initial length */
 2944         FILE_NORMAL,    /* normal file */
 2945         OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
 2946         OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE,
 2947         0);
 2948     if (rc == 0)
 2949         rc= DosDupHandle(hNewStdin, &hStdin);
 2950     }
 2951 
 2952     if ((hstdout != -1)) {
 2953     if (rc == 0)
 2954         DosDupHandle((HFILE)hstdout, &hStdout);
 2955     }
 2956     else if ((rc == 0) && stdout_name) {
 2957     rc = DosOpen((PCSZ)stdout_name, /* filename */
 2958         &hNewStdout,    /* pointer to handle */
 2959         &action,    /* pointer to result */
 2960         0,      /* initial length */
 2961         FILE_NORMAL,    /* normal file */
 2962         OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS,
 2963         OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE,
 2964         0);
 2965     if (rc == 0)
 2966         rc= DosDupHandle(hNewStdout, &hStdout);
 2967     }
 2968     if ((hstderr != -1)) {
 2969     if (rc == 0)
 2970         DosDupHandle((HFILE)hstderr, &hStderr);
 2971     }
 2972     else if ((rc == 0) && stderr_name) {
 2973     rc = DosOpen((PCSZ)stderr_name, /* filename */
 2974         &hNewStderr,    /* pointer to handle */
 2975         &action,    /* pointer to result */
 2976         0,      /* initial length */
 2977         FILE_NORMAL,    /* normal file */
 2978         OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS,
 2979         OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE,
 2980         0);
 2981     if (rc == 0)
 2982         rc= DosDupHandle(hNewStderr, &hStderr);
 2983     }
 2984     if (rc != 0) {
 2985     free(cmd);
 2986     return -1;
 2987     }
 2988 
 2989     rc = DosExecPgm(szFailName, sizeof(szFailName),
 2990     EXEC_SYNC, args, (PSZ)NULL, &resc, args);
 2991 
 2992     /* Put stdio back to original handles */
 2993     DosDupHandle(hOldStdin, &hStdin);
 2994     DosDupHandle(hOldStdout, &hStdout);
 2995     DosDupHandle(hOldStderr, &hStderr);
 2996     DosClose(hOldStdin);
 2997     DosClose(hOldStdout);
 2998     DosClose(hOldStderr);
 2999     if (hNewStdin != -1)
 3000         DosClose(hNewStdin);
 3001     if (hNewStdout != -1)
 3002         DosClose(hNewStdout);
 3003     if (hNewStderr != -1)
 3004         DosClose(hNewStderr);
 3005 
 3006     if (rc)
 3007     return -1;
 3008     return (int)resc.codeResult;
 3009 }
 3010 #endif