/* Hello, Emacs, this is -*-C-*-
 * $Id: pslatex.trm,v 1.80.2.6 2013/04/11 00:08:58 sfeam Exp $
 */

/* GNUPLOT - pslatex.trm */

/*[
 * Copyright 1990 - 1993, 1998, 2004
 *
 * Permission to use, copy, and distribute this software and its
 * documentation for any purpose with or without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.
 *
 * Permission to modify the software is granted, but not the right to
 * distribute the complete modified source code.  Modifications are to
 * be distributed as patches to the released version.  Permission to
 * distribute binaries produced by compiling modified sources is granted,
 * provided you
 *   1. distribute the corresponding source modifications from the
 *    released version in the form of a patch file along with the binaries,
 *   2. add special version identification to distinguish your version
 *    in addition to the base release version number,
 *   3. provide your name and address as the primary contact for the
 *    support of your modified version, and
 *   4. retain our contact information in regard to use of the base
 *    software.
 * Permission to distribute the released version of the source code along
 * with corresponding source modifications in the form of a patch file is
 * granted with same provisions 2 through 4 for binary distributions.
 *
 * This software is provided "as is" without express or implied warranty
 * to the extent permitted by applicable law.
]*/

/*
 * This file is included by ../term.c.
 *
 * This file supplies the terminal drivers:
 *     pslatex  -- LaTeX with embedded postscript
 *     pstex    -- plain TeX with embedded postscript
 *     epslatex -- LaTeX using \includegraphics, postscript part in an 
 *                 external file
 *
 * AUTHORS
 *  George Phillips
 *  Russell Lang
 *  David Kotz
 *
 *  Petr Mikulik, May 2000: terminal entries for PM3D functionality
 *
 *  Dan Sebald, 5 March 2003: terminal entry for image functionality
 *
 *  Theo Hopman
 *      23 May 2003:
 *              - added epslatex support. Replaces epslatex.trm; pointtype
 *              and linetypes for epslatex terminal are now identical to
 *              those of pslatex terminal.
 *              - added arbitrary text rotations to all [e]ps[la]tex
 *              terminals.
 *      27 May 2004:
 *              - epslatex patch updated for gnuplot 4.0
 *      
 *  Harald Harders (h.harders@tu-bs.de), 2005-02-08:
 *  - Merged functionality of postscript, pslatex, pstex, and
 *    epslatex terminals. Therefore deleted epslatex.trm.
 *  - Added a standalone mode to the epslatex mode for standalone use without
 *    an additional LaTeX document.
 *  - Fixed text rotation of ps(la)tex terminals.
 *
 * Send your comments or suggestions to (gnuplot-info@lists.sourceforge.net).
 */

#include "driver.h"

#ifdef TERM_REGISTER
register_term(pslatex)
register_term(pstex)
register_term(epslatex)
#endif

#ifdef TERM_PROTO
/* Common functions for epslatex and ps(la)tex */
/* All these routines begin with PSLATEX_ */
TERM_PUBLIC void PSLATEX_reset __PROTO((void));

/* Functions for ps(la)tex */
/* All these routines begin with PSTEX_ */
TERM_PUBLIC void PSTEX_reopen_output __PROTO((void));
TERM_PUBLIC void PSTEX_common_init __PROTO((void));
TERM_PUBLIC void PSTEX_put_text __PROTO((unsigned int x, unsigned int y, const char *str));
TERM_PUBLIC void PSTEX_text __PROTO((void));

/* Functions for epslatex */
/* All these routines begin with EPSLATEX_ */
TERM_PUBLIC void EPSLATEX_reopen_output __PROTO((char *));
TERM_PUBLIC void EPSLATEX_common_init __PROTO((void));
TERM_PUBLIC void EPSLATEX_put_text __PROTO((unsigned int x, unsigned int y, const char *str));
TERM_PUBLIC void EPSLATEX_linetype __PROTO((int linetype));
TERM_PUBLIC void EPSLATEX_layer __PROTO((t_termlayer syncpoint));

/* additional LaTeX header information for epslatex terminal */
TERM_PUBLIC char *epslatex_header = NULL;

#endif /* TERM_PROTO */


#ifndef TERM_PROTO_ONLY

#ifdef TERM_BODY

#include "post.h"

struct pstex_text_command {
    int x, y, angle, justify;
    char *label;
    struct pstex_text_command *next;
};

static struct pstex_text_command *pstex_labels = NULL;
static int epslatex_text_layer = 0;

/* Support for optimization of set_color */
static t_colorspec tex_previous_colorspec = {-1, 0, 0.0};  /* Initialize to invalid type */
static char tex_current_color[64];
static TBOOLEAN tex_color_synced = FALSE;

/* support for cairolatex */
#ifdef HAVE_CAIROPDF
#define ISCAIROTERMINAL ((strcmp(term->name, "cairolatex") == 0))
TERM_PUBLIC void cairotrm_set_color __PROTO ((t_colorspec *colorspec));
#else
#define ISCAIROTERMINAL (FALSE)
#endif


/* Common functions for epslatex and ps(la)tex */

TERM_PUBLIC void
PSLATEX_reset()
{
    switch (ps_params->terminal) {
    case PSTERM_EPSLATEX:
        if (!ISCAIROTERMINAL)
            PS_reset();
        if (gpoutfile) {
	    fprintf(gpoutfile, "\
    \\gplbacktext\n\
    \\put(0,0){\\includegraphics{%s}}%%\n\
    \\gplfronttext\n\
  \\end{picture}%%\n\
\\endgroup\n", pslatex_auxname);
            if (ps_params->epslatex_standalone)
                fputs("\\end{document}\n", gpoutfile);
        }
        break;
    case PSTERM_PSLATEX:
        fputs("\
\\end{picture}%\n\
\\endgroup\n\
\\endinput\n", gpoutfile);
        break;
    case PSTERM_PSTEX:
        fputs("\
\\endGNUPLOTpicture\n\
\\endgroup\n\
\\endinput\n", gpoutfile);
        break;
    default:; /* do nothing, just avoid a compiler warning */
    }

    if (pslatex_auxname) {
        free(pslatex_auxname);
        pslatex_auxname = NULL;
    }
    if (gppsfile && (gppsfile != gpoutfile)) {
        fclose(gppsfile);
        gppsfile = NULL;
    }
}


/* Functions for ps(la)tex */

TERM_PUBLIC void
PSTEX_reopen_output()
{
    if (outstr) {
        char *dotIndex;

        /* if there's no extension, append ".ps" */
        if ((dotIndex = strrchr(outstr, '.')) == NULL)
            dotIndex = strchr(outstr, NUL);

        /* try to open the auxiliary file for the postscript parts. */
        if (ps_params->useauxfile) {
            /* length of outstr plus ('.' or '\0') plus "eps" plus '\0' */
            pslatex_auxname = gp_realloc(pslatex_auxname,dotIndex - outstr + 5,
                                          "pslatex aux filename");
            if (pslatex_auxname) {
                /* include period or '\0' */
                strncpy(pslatex_auxname, outstr, (dotIndex - outstr) + 1);
                /* period or '\0' is overwritten with period, and "ps" appended */
                strcpy(pslatex_auxname + (dotIndex - outstr), ".ps");
                gppsfile = fopen(pslatex_auxname, "w");
                if (gppsfile  == (FILE *) NULL) {
                    fprintf(stderr, "Cannot open aux file %s for output. Switching off auxfile option.\n",
                            pslatex_auxname);
                    free(pslatex_auxname);
                    pslatex_auxname = NULL;
                    ps_params->useauxfile = FALSE;
                    gppsfile = gpoutfile;
                }
            } else {
                fprintf(stderr, "Cannot make PostScript file name from %s\n",
                        outstr);
                fprintf(stderr, "Turning off auxfile option\n");
                ps_params->useauxfile = FALSE;
                gppsfile = gpoutfile;
            }
        } else
            gppsfile = gpoutfile;
    } else {
        if (ps_params->useauxfile) {
            fprintf(stderr, "Cannot use aux file on stdout. Switching off auxfile option.\n");
            ps_params->useauxfile = FALSE;
        }
        gppsfile = gpoutfile;
    }
}


TERM_PUBLIC void
PSTEX_common_init()
{
    switch (ps_params->terminal) {
    case PSTERM_PSLATEX:
        fprintf(gpoutfile,"\
%% GNUPLOT: LaTeX picture with Postscript\n\
\\begingroup%%\n\
\\makeatletter%%\n\
\\newcommand{\\GNUPLOTspecial}{%%\n\
  \\@sanitize\\catcode`\\%%=14\\relax\\special}%%\n\
\\setlength{\\unitlength}{%.4fbp}%%\n", 1.0 / (2*PS_SC));
        fprintf(gpoutfile, "\\begin{picture}(%d,%d)(0,0)%%\n",
                (int) (xsize * term->xmax), (int) (ysize * term->ymax));
        break;
    case PSTERM_PSTEX:
        /* write plain TeX header */
        fprintf(gpoutfile, "\
%% GNUPLOT: plain TeX with Postscript\n\
\\begingroup\n\
\\catcode`\\@=11\\relax\n\
\\def\\GNUPLOTspecial{%%\n\
  \\def\\do##1{\\catcode`##1=12\\relax}\\dospecials\n\
  \\catcode`\\{=1\\catcode`\\}=2\\catcode\\%%=14\\relax\\special}%%\n\
%%\n\
\\expandafter\\ifx\\csname GNUPLOTpicture\\endcsname\\relax\n\
  \\csname newdimen\\endcsname\\GNUPLOTunit\n\
  \\gdef\\GNUPLOTpicture(#1,#2){\\vbox to#2\\GNUPLOTunit\\bgroup\n\
    \\def\\put(##1,##2)##3{\\unskip\\raise##2\\GNUPLOTunit\n\
      \\hbox to0pt{\\kern##1\\GNUPLOTunit ##3\\hss}\\ignorespaces}%%\n\
    \\def\\ljust##1{\\vbox to0pt{\\vss\\hbox to0pt{##1\\hss}\\vss}}%%\n\
    \\def\\cjust##1{\\vbox to0pt{\\vss\\hbox to0pt{\\hss ##1\\hss}\\vss}}%%\n\
    \\def\\rjust##1{\\vbox to0pt{\\vss\\hbox to0pt{\\hss ##1}\\vss}}%%\n\
    \\def\\stack##1{\\let\\\\=\\cr\\tabskip=0pt\\halign{\\hfil ####\\hfil\\cr ##1\\crcr}}%%\n\
    \\def\\lstack##1{\\hbox to0pt{\\vbox to0pt{\\vss\\stack{##1}}\\hss}}%%\n\
    \\def\\cstack##1{\\hbox to0pt{\\hss\\vbox to0pt{\\vss\\stack{##1}}\\hss}}%%\n\
    \\def\\rstack##1{\\hbox to0pt{\\vbox to0pt{\\stack{##1}\\vss}\\hss}}%%\n\
    \\vss\\hbox to#1\\GNUPLOTunit\\bgroup\\ignorespaces}%%\n\
  \\gdef\\endGNUPLOTpicture{\\hss\\egroup\\egroup}%%\n\
\\fi\n\
\\GNUPLOTunit=%.4fbp\n", 1.0 / (2*PS_SC));
        fprintf(gpoutfile, "\\GNUPLOTpicture(%d,%d)\n",
                (int) (xsize * term->xmax), (int) (ysize * term->ymax));
        break;
    default:; /* do nothing, just avoid a compiler warning */
    }

    if (gppsfile != gpoutfile) {
        /* these are taken from the post.trm file computation
         * of the bounding box, but without the X_OFF and Y_OFF */
        int urx = (int) (xsize * term->xmax / (2*PS_SC) + 0.5);
        int ury = (int) (ysize * term->ymax / (2*PS_SC) + 0.5);

        /* pslatex_auxname is only != NULL with the `auxfile' option.
         * If pslatex_auxname is not a simple file name, but a path,
         * we need to strip the path off the auxiliary file name,
         * because tex file and ps aux file end up in the same directory! */
        char *psfile_basename = gp_basename(pslatex_auxname);

        /* generate special which xdvi and dvips can handle */
        fprintf(gpoutfile,
                "  \\special{psfile=%s llx=0 lly=0 urx=%d ury=%d rwi=%d}\n",
                psfile_basename, urx, ury, 10 * urx);
    } else
        fputs("  {\\GNUPLOTspecial{\"\n", gpoutfile);

    /* HH: really necessary?
    ps_ang = 0;
    ps_justify = 0;
    */
    pstex_labels = (struct pstex_text_command *) NULL;
}


TERM_PUBLIC void
PSTEX_put_text(unsigned int x, unsigned int y, const char *str)
{
    struct pstex_text_command *tc;

    /* ignore empty strings */
    if (str[0] == NUL)
        return;

    /* Save the text for later printing after the core graphics */
    tc = (struct pstex_text_command *) gp_alloc(sizeof(struct pstex_text_command),
                                                term->name);
    tc->x = x;
    tc->y = y;
    tc->label = (char *) gp_alloc(strlen(str) + 1, term->name);
    strcpy(tc->label, str);
    tc->justify = ps_justify;
    tc->angle = ps_ang;

    tc->next = pstex_labels;
    pstex_labels = tc;
}

TERM_PUBLIC void
PSTEX_text()
{
    struct pstex_text_command *tc;

    PS_text();
    if (gppsfile == gpoutfile)
        fputs("  }}%\n", gpoutfile);

    if (ps_params->fontsize) {
        if (ps_params->terminal == PSTERM_PSLATEX)
            fprintf(gpoutfile, "\\fontsize{%g}{\\baselineskip}\\selectfont\n",
                    ps_params->fontsize);
        /* Should have an else clause here to handle pstex equivalent */
    }

    for (tc = pstex_labels;
         tc != (struct pstex_text_command *) NULL;
         tc = tc->next) {
        fprintf(gpoutfile, "  \\put(%d,%d){", tc->x, tc->y);
        if ((ps_params->rotate) && (tc->angle != 0))
            fprintf(gpoutfile, "\
%%\n  \\special{ps: gsave currentpoint currentpoint translate\n\
%d rotate neg exch neg exch translate}%%\n  ", 360 - tc->angle);
        if ((ps_params->terminal == PSTERM_PSLATEX) &&
            ((tc->label[0] == '{') || (tc->label[0] == '['))) {
            fprintf(gpoutfile, "\\makebox(0,0)%s", tc->label);
        } else
            switch (tc->justify) {
            case LEFT:
                fprintf(gpoutfile, (ps_params->terminal == PSTERM_PSLATEX
                                    ? "\\makebox(0,0)[l]{\\strut{}%s}"
                                    : "\\ljust{\\strut{}%s}"), tc->label);
                break;
            case CENTRE:
                fprintf(gpoutfile, (ps_params->terminal == PSTERM_PSLATEX
                                    ? "\\makebox(0,0){\\strut{}%s}"
                                    : "\\cjust{\\strut{}%s}"), tc->label);
                break;
            case RIGHT:
                fprintf(gpoutfile, (ps_params->terminal == PSTERM_PSLATEX
                                    ? "\\makebox(0,0)[r]{\\strut{}%s}"
                                    : "\\rjust{\\strut{}%s}"), tc->label);
                break;
            }
        if ((ps_params->rotate) && (tc->angle != 0))
            fputs("%\n  \\special{ps: currentpoint grestore moveto}%\n  ",
                  gpoutfile);
        fputs("}%\n", gpoutfile);
    }

    while (pstex_labels) {
        tc = pstex_labels->next;
        free(pstex_labels->label);
        free(pstex_labels);
        pstex_labels = tc;
    }

}


/* Functions for epslatex */

/* the common init function for the epslatex driver */
TERM_PUBLIC void
EPSLATEX_common_init()
{
    char *fontfamily = NULL;
    char *fontseries = NULL;
    char *fontshape = NULL;

    if (!gpoutfile) {
        char *temp = gp_alloc(strlen(outstr) + 1, "temp file string");
        if (temp) {
            strcpy(temp, outstr);
            term_set_output(temp);  /* will free outstr */
            if (temp != outstr) {
                if (temp)
                    free(temp);
                temp = outstr;
            }
        } else
            os_error(c_token, "Cannot reopen output files");
    }
    if (!outstr)
        os_error(c_token,
                 "epslatex terminal cannot write to standard output");
    if (gpoutfile) {
        char *inputenc = NULL;

        fprintf(gpoutfile, "%% GNUPLOT: LaTeX picture with Postscript\n");

        switch(encoding) {
        case S_ENC_DEFAULT:
            break;
        case S_ENC_ISO8859_1:
            inputenc = "latin1";
            break;
        case S_ENC_ISO8859_2:
            inputenc = "latin2";
            break;
        case S_ENC_ISO8859_9:	/* ISO8859-9 is Latin5 */
            inputenc = "latin5";
            break;
        case S_ENC_ISO8859_15:	/* ISO8859-15 is Latin9 */
            inputenc = "latin9";
            break;
        case S_ENC_CP437:
            inputenc = "cp437de";
            break;
        case S_ENC_CP850:
            inputenc = "cp850";
            break;
        case S_ENC_CP852:
            inputenc = "cp852";
            break;
        case S_ENC_CP1250:
            inputenc = "cp1250";
            break;
        case S_ENC_CP1251:
            inputenc = "cp1251";
            break;
        case S_ENC_KOI8_R:
            inputenc = "koi8-r";
            break;
        case S_ENC_KOI8_U:
            inputenc = "koi8-u";
            break;
        case S_ENC_INVALID:
            int_error(NO_CARET, "invalid input encoding used");
            break;
        default:
            /* do nothing */
            break;
        }

	/* Clear previous state */
	tex_previous_colorspec.type = -1;

	/* Clear any leftover text-layering state */
	EPSLATEX_layer(TERM_LAYER_RESET);

        /* Analyse LaTeX font name 'family,series,shape' */
        if ((strlen(ps_params->font) > 0) &&
            (strcmp(ps_params->font,"default") != 0)) {
            char *comma = NULL;
            fontfamily = gp_alloc(strlen(ps_params->font)+1,
                                  "EPSLATEX_common_init");
            fontseries = gp_alloc(strlen(ps_params->font)+1,
                                  "EPSLATEX_common_init");
            fontshape = gp_alloc(strlen(ps_params->font)+1,
                                 "EPSLATEX_common_init");
            strcpy(fontfamily,ps_params->font);
            *fontseries = '\0';
            *fontshape = '\0';
            if ((comma = strchr(fontfamily, ',')) != NULL) {
                *comma = '\0';
                strcpy(fontseries,comma+1);
                if ((comma = strchr(fontseries, ',')) != NULL) {
                    *comma = '\0';
                    strcpy(fontshape,comma+1);
                }
            }
        }
            
        if (ps_params->epslatex_standalone) {
            fprintf(gpoutfile, "\
\\documentclass{minimal}\n\
%% Set font size\n\
\\makeatletter\n\
\\def\\@ptsize{%d}\n\
\\InputIfFileExists{size%d.clo}{}{%%\n\
   \\GenericError{(gnuplot) \\space\\space\\space\\@spaces}{%%\n\
      Gnuplot Error: File `size%d.clo' not found! Could not set font size%%\n\
   }{See the gnuplot documentation for explanation.%%\n\
   }{For using a font size a file `size<fontsize>.clo' has to exist.\n\
        Falling back ^^Jto default fontsize 10pt.}%%\n\
  \\def\\@ptsize{0}\n\
  \\input{size10.clo}%%\n\
}%%\n\
\\makeatother\n",
                    (int)(ps_params->fontsize-10),
                    (int)(ps_params->fontsize),
                    (int)(ps_params->fontsize));

            if (fontfamily && strlen(fontfamily) > 0)
                fprintf(gpoutfile, "\\renewcommand*\\rmdefault{%s}%%\n",
                        fontfamily);
            if (fontseries && strlen(fontseries) > 0)
                fprintf(gpoutfile, "\\renewcommand*\\mddefault{%s}%%\n",
                        fontseries);
            if (fontshape && strlen(fontshape) > 0)
                fprintf(gpoutfile, "\\renewcommand*\\updefault{%s}%%\n",
                        fontshape);

            fputs("\
% Load packages\n\
\\usepackage{graphicx}\n\
\\usepackage{color}\n", gpoutfile);

            if (inputenc)
                fprintf(gpoutfile, "\\usepackage[%s]{inputenc}\n", inputenc);

            fprintf(gpoutfile, "\
\\makeatletter\n\
%% Select an appropriate default driver (from TeXLive graphics.cfg)\n\
\\begingroup\n\
  \\chardef\\x=0 %%\n\
  %% check pdfTeX\n\
  \\@ifundefined{pdfoutput}{}{%%\n\
    \\ifcase\\pdfoutput\n\
    \\else\n\
      \\chardef\\x=1 %%\n\
    \\fi\n\
  }%%\n\
  %% check VTeX\n\
  \\@ifundefined{OpMode}{}{%%\n\
    \\chardef\\x=2 %%\n\
  }%%\n\
\\expandafter\\endgroup\n\
\\ifcase\\x\n\
  %% default case\n\
  \\PassOptionsToPackage{dvips}{geometry}\n\
\\or\n\
  %% pdfTeX is running in pdf mode\n\
  \\PassOptionsToPackage{pdftex}{geometry}\n\
\\else\n\
  %% VTeX is running\n\
  \\PassOptionsToPackage{vtex}{geometry}\n\
\\fi\n\
\\makeatother\n\
%% Set papersize\n\
\\usepackage[papersize={%.2fbp,%.2fbp},text={%.2fbp,%.2fbp}]{geometry}\n\
%% No page numbers and no paragraph indentation\n\
\\pagestyle{empty}\n\
\\setlength{\\parindent}{0bp}%%\n\
%% Load configuration file\n\
\\InputIfFileExists{gnuplot.cfg}{%%\n\
  \\typeout{Using configuration file gnuplot.cfg}%%\n\
}{%%\n\
 \\typeout{No configuration file gnuplot.cfg found.}%%\n\
}%%\n\
%s\n\
\\begin{document}\n",
                    term->xmax * xsize / (2.0*PS_SC),
                    term->ymax * ysize / (2.0*PS_SC),
                    term->xmax * xsize / (2.0*PS_SC),
                    term->ymax * ysize / (2.0*PS_SC),
                    epslatex_header ? epslatex_header : "%" );
        }

        fputs("\\begingroup\n", gpoutfile);
        
        if (inputenc)
            fprintf(gpoutfile, "\
  %% Encoding inside the plot.  In the header of your document, this encoding\n\
  %% should to defined, e.g., by using\n\
  %% \\usepackage[%s,<other encodings>]{inputenc}\n\
  \\inputencoding{%s}%%\n", inputenc, inputenc);

        if (!ps_params->epslatex_standalone) {
            if (fontfamily && strlen(fontfamily) > 0)
                fprintf(gpoutfile, "  \\fontfamily{%s}%%\n",
                        fontfamily);
            if (fontseries && strlen(fontseries) > 0)
                fprintf(gpoutfile, "  \\fontseries{%s}%%\n",
                        fontseries);
            if (fontshape && strlen(fontshape) > 0)
                fprintf(gpoutfile, "  \\fontshape{%s}%%\n",
                        fontshape);
            if (fontfamily || fontseries || fontshape)
                fputs("  \\selectfont\n", gpoutfile);
            if (epslatex_header)
                fprintf(gpoutfile, "%s\n", epslatex_header );
        }

        fprintf(gpoutfile, "\
  \\makeatletter\n\
  \\providecommand\\color[2][]{%%\n\
    \\GenericError{(gnuplot) \\space\\space\\space\\@spaces}{%%\n\
      Package color not loaded in conjunction with\n\
      terminal option `colourtext'%%\n\
    }{See the gnuplot documentation for explanation.%%\n\
    }{Either use 'blacktext' in gnuplot or load the package\n\
      color.sty in LaTeX.}%%\n\
    \\renewcommand\\color[2][]{}%%\n\
  }%%\n\
  \\providecommand\\includegraphics[2][]{%%\n\
    \\GenericError{(gnuplot) \\space\\space\\space\\@spaces}{%%\n\
      Package graphicx or graphics not loaded%%\n\
    }{See the gnuplot documentation for explanation.%%\n\
    }{The gnuplot epslatex terminal needs graphicx.sty or graphics.sty.}%%\n\
    \\renewcommand\\includegraphics[2][]{}%%\n\
  }%%\n\
  \\providecommand\\rotatebox[2]{#2}%%\n\
  \\@ifundefined{ifGPcolor}{%%\n\
    \\newif\\ifGPcolor\n\
    \\GPcolor%s\n\
  }{}%%\n\
  \\@ifundefined{ifGPblacktext}{%%\n\
    \\newif\\ifGPblacktext\n\
    \\GPblacktext%s\n\
  }{}%%\n\
  %% define a \\g@addto@macro without @ in the name:\n\
  \\let\\gplgaddtomacro\\g@addto@macro\n\
  %% define empty templates for all commands taking text:\n\
  \\gdef\\gplbacktext{}%%\n\
  \\gdef\\gplfronttext{}%%\n\
  \\makeatother\n",
                (ps_params->color?"true":"false"),
                (ps_params->blacktext?"true":"false") );

        /* use \expandafter\def\csname LT0\endcsname{...} 
         * instead of \def\LT0{...} because digits may not be part of
         * \... sequences */
        fputs("\
  \\ifGPblacktext\n\
    % no textcolor at all\n\
    \\def\\colorrgb#1{}%\n\
    \\def\\colorgray#1{}%\n\
  \\else\n\
    % gray or color?\n\
    \\ifGPcolor\n\
      \\def\\colorrgb#1{\\color[rgb]{#1}}%\n\
      \\def\\colorgray#1{\\color[gray]{#1}}%\n\
      \\expandafter\\def\\csname LTw\\endcsname{\\color{white}}%\n\
      \\expandafter\\def\\csname LTb\\endcsname{\\color{black}}%\n\
      \\expandafter\\def\\csname LTa\\endcsname{\\color{black}}%\n",
              gpoutfile);
        if (ps_params->oldstyle) {
            fputs("\
      \\expandafter\\def\\csname LT0\\endcsname{\\color[rgb]{1,0,0}}%\n\
      \\expandafter\\def\\csname LT1\\endcsname{\\color[rgb]{0,0,1}}%\n\
      \\expandafter\\def\\csname LT2\\endcsname{\\color[rgb]{0,1,1}}%\n\
      \\expandafter\\def\\csname LT3\\endcsname{\\color[rgb]{1,0,1}}%\n",
                  gpoutfile);
        } else {
            fputs("\
      \\expandafter\\def\\csname LT0\\endcsname{\\color[rgb]{1,0,0}}%\n\
      \\expandafter\\def\\csname LT1\\endcsname{\\color[rgb]{0,1,0}}%\n\
      \\expandafter\\def\\csname LT2\\endcsname{\\color[rgb]{0,0,1}}%\n\
      \\expandafter\\def\\csname LT3\\endcsname{\\color[rgb]{1,0,1}}%\n\
      \\expandafter\\def\\csname LT4\\endcsname{\\color[rgb]{0,1,1}}%\n\
      \\expandafter\\def\\csname LT5\\endcsname{\\color[rgb]{1,1,0}}%\n\
      \\expandafter\\def\\csname LT6\\endcsname{\\color[rgb]{0,0,0}}%\n\
      \\expandafter\\def\\csname LT7\\endcsname{\\color[rgb]{1,0.3,0}}%\n\
      \\expandafter\\def\\csname LT8\\endcsname{\\color[rgb]{0.5,0.5,0.5}}%\n",
                  gpoutfile);
        }
        fputs("\
    \\else\n\
      % gray\n\
      \\def\\colorrgb#1{\\color{black}}%\n\
      \\def\\colorgray#1{\\color[gray]{#1}}%\n\
      \\expandafter\\def\\csname LTw\\endcsname{\\color{white}}%\n\
      \\expandafter\\def\\csname LTb\\endcsname{\\color{black}}%\n\
      \\expandafter\\def\\csname LTa\\endcsname{\\color{black}}%\n\
      \\expandafter\\def\\csname LT0\\endcsname{\\color{black}}%\n\
      \\expandafter\\def\\csname LT1\\endcsname{\\color{black}}%\n\
      \\expandafter\\def\\csname LT2\\endcsname{\\color{black}}%\n\
      \\expandafter\\def\\csname LT3\\endcsname{\\color{black}}%\n\
      \\expandafter\\def\\csname LT4\\endcsname{\\color{black}}%\n\
      \\expandafter\\def\\csname LT5\\endcsname{\\color{black}}%\n\
      \\expandafter\\def\\csname LT6\\endcsname{\\color{black}}%\n\
      \\expandafter\\def\\csname LT7\\endcsname{\\color{black}}%\n\
      \\expandafter\\def\\csname LT8\\endcsname{\\color{black}}%\n\
    \\fi\n\
  \\fi\n", gpoutfile);

        fprintf(gpoutfile,"\
  \\setlength{\\unitlength}{%.4fbp}%%\n\
  \\begin{picture}(%.2f,%.2f)%%\n",
                1.0 / (2*PS_SC), term->xmax * xsize, term->ymax * ysize);
    }
    if (ps_params->background.r >= 0) {
	fprintf(gpoutfile, "\\definecolor{gpBackground}{rgb}{%.3f, %.3f, %.3f}%%\n",
		ps_params->background.r, ps_params->background.g, ps_params->background.b);
	fprintf(gpoutfile, "\\put(0,0){\\colorbox{gpBackground}{\\makebox(%.2f,%.2f)[]{}}}%%\n",
		term->xmax * xsize, term->ymax * ysize);
    }

    if (fontfamily)
        free(fontfamily);
    if (fontseries)
        free(fontseries);
    if (fontshape)
        free(fontshape);
}


TERM_PUBLIC void
EPSLATEX_put_text(unsigned int x, unsigned int y, const char *str)
{
    if (gpoutfile) {
	if (!tex_color_synced) {
	    fputs(tex_current_color, gpoutfile);
	    tex_color_synced = TRUE;
	}
	fprintf(gpoutfile, "      \\put(%d,%d){", x, y);
        if (ps_ang)
            fprintf(gpoutfile,"\\rotatebox{%d}{", ps_ang);
        if (((str[0] == '{') || (str[0] == '['))) {
            fprintf(gpoutfile, "\\makebox(0,0)%s", str);
        } else
            switch (ps_justify) {
            case LEFT:
                fprintf(gpoutfile, "\\makebox(0,0)[l]{\\strut{}%s}", str);
                break;
            case CENTRE:
                fprintf(gpoutfile, "\\makebox(0,0){\\strut{}%s}", str);
                break;
            case RIGHT:
                fprintf(gpoutfile, "\\makebox(0,0)[r]{\\strut{}%s}", str);
                break;
            }
        if (ps_ang) {
            fputs("}", gpoutfile);
        }
        fputs("}%\n", gpoutfile);
    }
}


/* assigns dest to outstr, so it must be allocated or NULL
 * and it must not be outstr itself !
 */
void
EPSLATEX_reopen_output(char * ext)
{
    char *psoutstr = NULL;

    if (outstr) {
        unsigned int outstrlen = strlen(outstr);
        if (strrchr(outstr, '.') != &outstr[outstrlen-4] ) {
            int_error(NO_CARET,
                      "epslatex output file name must be of the form filename.xxx");
        }

        /* copy filename to postsript output */
        psoutstr = gp_alloc(outstrlen+5, "epslatex eps filename");
        strcpy( psoutstr, outstr);

        if ((!strncmp( &outstr[outstrlen-4], ".eps", 4 )) ||
            (!strncmp( &outstr[outstrlen-4], ".EPS", 4 ))) {
            if (ps_params->epslatex_standalone)
                int_error(NO_CARET,
                          "For epslatex standalone mode, you have to %s",
                          "give the tex filename as output");
            /* rename primary output (tex) */
            strncpy( &outstr[outstrlen-4], ".tex", 4);
            /* redirect FILE stream */
            gppsfile = gpoutfile;
            gpoutfile = fopen(outstr,"w");
            int_warn(NO_CARET, "Resetting primary output file to %s,\n\
                  PostScript output to %s", outstr, psoutstr);
            if (!gpoutfile)
                int_error(NO_CARET, "--- reopen failed");
        } else {
            char suffix[PATH_MAX];
            if (ps_params->epslatex_standalone)
                sprintf(suffix, "-inc.%s", ext);
            else
                sprintf(suffix, ".%s", ext);
            strncpy(&psoutstr[outstrlen - 4], suffix, strlen(suffix) + 1);
            /* BM: Need binary output for PDF files. Does this have negative side effects for EPS? */
            gppsfile = fopen(psoutstr, "wb");
        }
        if (!gppsfile)
            int_error(NO_CARET, "open of postscipt output file %s failed",
                      psoutstr);

        /* set the name for the \includegraphics command */
        pslatex_auxname = gp_alloc(strlen(psoutstr)-3,
                                   "epslatex TeX filename");
        strncpy( pslatex_auxname, psoutstr, strlen(psoutstr)-4 );
        pslatex_auxname[strlen(psoutstr)-4] = '\0';

        free(psoutstr);
    }
}


TERM_PUBLIC void
EPSLATEX_set_color(t_colorspec *colorspec)
{
    double gray;

#ifdef HAVE_CAIROPDF
    /* Fancy footwork to deal with mono/grayscale plots */
    if (ISCAIROTERMINAL) {
        cairotrm_set_color(colorspec);
    } else 
#endif
    {
	/* Filter out duplicate requests */
	if (!memcmp(&tex_previous_colorspec, colorspec, sizeof(t_colorspec)))
	    return;
	else
	    memcpy(&tex_previous_colorspec, colorspec, sizeof(t_colorspec));
        if (colorspec->type == TC_LT && !ps_params->color)
            PS_linetype(colorspec->lt);
        else
            PS_set_color(colorspec);
    }

    /* Many [most? all?] of the set_color commands only affect the *.eps     */
    /* output stream.  So rather than printing them all to the *.tex stream, */
    /* we update the current color and set a flag to say it has changed.     */
    /* Only when some TeX object is output do we sync the current color by   */
    /* writing it out.                                                       */
    tex_color_synced = FALSE;

    if (colorspec->type == TC_RGB) {
        double r = (double)((colorspec->lt >> 16 ) & 255) / 255.;
        double g = (double)((colorspec->lt >> 8 ) & 255) / 255.;
        double b = (double)(colorspec->lt & 255) / 255.;
	sprintf(tex_current_color, "      \\colorrgb{%3.2f,%3.2f,%3.2f}%%\n",r,g,b);
    }

    if (colorspec->type == TC_LT) {
        int linetype = colorspec->lt;
        if (ps_params->oldstyle)
            linetype = (linetype % 4) + 3;
        else
            linetype = (linetype % 9) + 3;

	sprintf(tex_current_color, "      \\csname LT%c\\endcsname%%\n",
                "wba012345678"[linetype]);
    }

    if (colorspec->type != TC_FRAC)
        return;

/* map [0;1] to gray/colors */
    gray = colorspec->value;

    if (ps_params->blacktext) {
	if (gray <= 0)
	    sprintf(tex_current_color, "      \\color{black}%%\n");
	else if (gray >= 1)
	    sprintf(tex_current_color, "      \\color{white}%%\n");
        else
	    sprintf(tex_current_color, "      \\colorgray{%s}%%\n",save_space(gray));
    } else {
	rgb_color color;
	rgb1_from_gray( colorspec->value, &color );
	sprintf(tex_current_color, "      \\colorrgb{%3.2f,%3.2f,%3.2f}%%\n",color.r,color.g,color.b);
    }
}

TERM_PUBLIC void
EPSLATEX_linetype(int linetype)
{
    t_colorspec tempcol = {TC_LT, 0, 0.0};
    tempcol.lt = linetype;
    PS_linetype(linetype);

    /* This leads to redundant *.eps output */
    EPSLATEX_set_color(&tempcol);
}

/*
 * The TERM_LAYER mechanism is used here to signal a difference between
 * "front" text and "back" text.
 */
TERM_PUBLIC void
EPSLATEX_layer(t_termlayer syncpoint)
{
    switch (syncpoint) {

    case TERM_LAYER_RESET:        /* Start of plot; reset flag */
	epslatex_text_layer = 0;
	break;

    case TERM_LAYER_BACKTEXT: /* Start of "back" text layer */
	if (epslatex_text_layer == 1)
	    break;
	if (epslatex_text_layer == 2)
	    fputs("    }%\n", gpoutfile);
	epslatex_text_layer = 1;
	fputs("    \\gplgaddtomacro\\gplbacktext{%\n", gpoutfile);
	tex_color_synced = FALSE;
	break;

    case TERM_LAYER_FRONTTEXT:/* Start of "front" text layer */
	if (epslatex_text_layer == 2)
	    break;
	if (epslatex_text_layer == 1)
	    fputs("    }%\n", gpoutfile);
	epslatex_text_layer = 2;
	fputs("    \\gplgaddtomacro\\gplfronttext{%\n", gpoutfile);
	tex_color_synced = FALSE;
	break;

    case TERM_LAYER_END_TEXT:     /* Close off front or back macro before leaving */
	if (epslatex_text_layer == 1 || epslatex_text_layer == 2)
	    fputs("    }%\n", gpoutfile);
	epslatex_text_layer = 0;
	break;

    case TERM_LAYER_BEGIN_PM3D_MAP:
	if (gppsfile && (gppsfile != gpoutfile))
	    fprintf(gppsfile, "%%pm3d_map_begin\n");
	break;
    
    case TERM_LAYER_END_PM3D_MAP:
	if (gppsfile && (gppsfile != gpoutfile))
	    fprintf(gppsfile, "%%pm3d_map_end\n");
	break;

    default:
	break;
    }
}

#endif /* TERM_BODY */

#ifdef TERM_TABLE

#ifndef GOT_POST_PROTO
#define TERM_PROTO_ONLY
#include "post.trm"
#undef TERM_PROTO_ONLY
#endif /* GOT_POST_PROTO */

TERM_TABLE_START(epslatex_driver)
    "epslatex", "LaTeX picture environment using graphicx package",
    PS_XMAX, PS_YMAX, EPSLATEX_VCHAR, EPSLATEX_HCHAR,
    PS_VTIC, PS_HTIC, PS_options, PS_init, PSLATEX_reset,
    PS_text, null_scale, PS_graphics, PS_move,
    PS_vector, EPSLATEX_linetype, EPSLATEX_put_text, PS_text_angle,
    PS_justify_text, PS_point, do_arrow, PS_set_font,
    PS_pointsize, TERM_BINARY|TERM_IS_POSTSCRIPT|TERM_CAN_CLIP|TERM_IS_LATEX /*flags */,
    0 /*suspend */, 0 /*resume */,
    PS_fillbox, PS_linewidth,
#ifdef USE_MOUSE
    0, 0, 0, 0, 0, /* no mouse support for postscript */
#endif
    PS_make_palette, PS_previous_palette,
    EPSLATEX_set_color, PS_filled_polygon,
    PS_image,
    0, 0, 0, /* Enhanced text mode not used */
    EPSLATEX_layer, /* Used to signal front/back text */
    PS_path
TERM_TABLE_END(epslatex_driver)
#undef LAST_TERM
#define LAST_TERM epslatex_driver

TERM_TABLE_START(pslatex_driver)
    "pslatex", "LaTeX picture environment with PostScript \\specials",
    PS_XMAX, PS_YMAX, PSTEX_VCHAR, PSTEX_HCHAR,
    PS_VTIC, PS_HTIC, PS_options, PS_init, PSLATEX_reset,
    PSTEX_text, null_scale, PS_graphics, PS_move,
    PS_vector, PS_linetype, PSTEX_put_text, PS_text_angle,
    PS_justify_text, PS_point, PS_arrow, set_font_null,
    PS_pointsize, TERM_CAN_CLIP|TERM_IS_LATEX /*flags */ , 0 /*suspend */
    , 0 /*resume */ ,
    PS_fillbox, PS_linewidth
#ifdef USE_MOUSE
   , 0, 0, 0, 0, 0 /* no mouse support for postscript */
#endif
   , PS_make_palette,
   PS_previous_palette, /* write grestore */
   PS_set_color,
   PS_filled_polygon
    , PS_image
    , 0, 0, 0	/* No enhanced text mode because this is LaTeX */
    , 0         /* layer */
    , PS_path
TERM_TABLE_END(pslatex_driver)
#undef LAST_TERM
#define LAST_TERM pslatex_driver

TERM_TABLE_START(pstex_driver)
    "pstex", "plain TeX with PostScript \\specials",
    PS_XMAX, PS_YMAX, PSTEX_VCHAR, PSTEX_HCHAR,
    PS_VTIC, PS_HTIC, PS_options, PS_init, PSLATEX_reset,
    PSTEX_text, null_scale, PS_graphics, PS_move,
    PS_vector, PS_linetype, PSTEX_put_text, PS_text_angle,
    PS_justify_text, PS_point, PS_arrow, set_font_null,
    PS_pointsize, TERM_CAN_CLIP|TERM_IS_LATEX /*flags */ , 0 /*suspend */
    , 0 /*resume */ ,
    PS_fillbox, PS_linewidth
#ifdef USE_MOUSE
   , 0, 0, 0, 0, 0 /* no mouse support for postscript */
#endif
   , PS_make_palette,
   PS_previous_palette, /* write grestore */
   PS_set_color,
   PS_filled_polygon
    , PS_image
    , 0, 0, 0	/* No enhanced text mode because this is LaTeX */
    , 0         /* layer */
    , PS_path
TERM_TABLE_END(pstex_driver)
#undef LAST_TERM
#define LAST_TERM pstex_driver

#endif /* TERM_TABLE */
#endif /* TERM_PROTO_ONLY */


