summaryrefslogtreecommitdiff
path: root/Build/source/texk/dvipsk/dospecial.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/dvipsk/dospecial.c')
-rw-r--r--Build/source/texk/dvipsk/dospecial.c1120
1 files changed, 1120 insertions, 0 deletions
diff --git a/Build/source/texk/dvipsk/dospecial.c b/Build/source/texk/dvipsk/dospecial.c
new file mode 100644
index 00000000000..33d3a1cc23e
--- /dev/null
+++ b/Build/source/texk/dvipsk/dospecial.c
@@ -0,0 +1,1120 @@
+/* $Id$
+ * This routine handles special commands;
+ * predospecial() is for the prescan, dospecial() for the real thing.
+ */
+#include "dvips.h" /* The copyright notice in that file is included too! */
+
+#ifdef KPATHSEA
+#include <kpathsea/c-ctype.h>
+#include <kpathsea/tex-hush.h>
+#else /* ! KPATHSEA */
+#include <ctype.h>
+#include <stdlib.h>
+#ifndef WIN32
+extern int atoi();
+extern int system();
+#endif /* WIN32*/
+#endif
+/*
+ * The external declarations:
+ */
+#include "protos.h"
+
+static int specialerrors = 20;
+
+struct bangspecial {
+ struct bangspecial *next;
+ char *actualstuff;
+} *bangspecials = NULL;
+
+void
+specerror(const char *s)
+{
+ if (specialerrors > 0
+#ifdef KPATHSEA
+ && !kpse_tex_hush ("special")
+#endif
+ ) {
+ error(s);
+ specialerrors--;
+ } else if (specialerrors == 0
+#ifdef KPATHSEA
+ && !kpse_tex_hush ("special")
+#endif
+ ) {
+ error("more errors in special, being ignored . . .");
+ error("(perhaps dvips doesn't support your macro package?)");
+ specialerrors--;
+ }
+}
+
+static void
+outputstring(register char *p)
+{
+ putc('\n', bitfile);
+ while(*p) {
+ putc(*p, bitfile);
+ p++;
+ }
+ putc('\n', bitfile);
+}
+
+static void
+trytobreakout(register char *p)
+{
+ register int i;
+ register int instring = 0;
+ int lastc = 0;
+
+ i = 0;
+ putc('\n', bitfile);
+
+ if(*p == '%') {
+ while(*p) {
+ putc(*p, bitfile);
+ p++;
+ }
+ putc('\n', bitfile);
+ return;
+ }
+
+ while (*p) {
+ if (i > 65 && *p == ' ' && instring == 0) {
+ putc('\n', bitfile);
+ i = 0;
+ } else {
+ putc(*p, bitfile);
+ i++;
+ }
+ if (*p == '(' && lastc != '\\')
+ instring = 1;
+ else if (*p == ')' && lastc != '\\')
+ instring = 0;
+ lastc = *p;
+ p++;
+ }
+ putc('\n', bitfile);
+}
+
+static void
+dobs(register struct bangspecial *q)
+{
+ if (q) {
+ dobs(q->next);
+ trytobreakout(q->actualstuff);
+ }
+}
+
+/* added for dvi2ps & jdvi2kps format */
+static char *mfgets(char *buf, unsigned int bytes, FILE *fp);
+
+static void
+fgetboundingbox(char *f, float *llx_p, float *lly_p, float *urx_p, float *ury_p)
+{
+ FILE *fp;
+ char buf[BUFSIZ+1];
+
+ fp = search(figpath, f, READ);
+ if (fp == 0)
+ fp = search(headerpath, f, READ);
+ if (fp) {
+ while (mfgets(buf, BUFSIZ, fp) != 0) {
+ if (buf[0] == '%' && buf[1] == '%'
+ && strncmp(buf+2, "BoundingBox:", 12) == 0) {
+ if (sscanf(buf+14, "%f %f %f %f", llx_p, lly_p, urx_p, ury_p) == 4) {
+ fclose(fp);
+ return;
+ }
+ }
+ }
+ fclose(fp);
+ }
+ sprintf(errbuf, "Couldn't get BoundingBox of %.500s: assuming full A4 size", f);
+ specerror(errbuf);
+ *llx_p = 0.0;
+ *lly_p = 0.0;
+ *urx_p = 595.0;
+ *ury_p = 842.0;
+}
+
+static char *
+mfgets(char *buf, unsigned int bytes, FILE *fp)
+{
+ int i, cc;
+
+ for (i = 0; i < bytes; i++) {
+ cc = fgetc(fp);
+ if (cc == 0x0a || cc == 0x0d) {
+ if (cc == 0x0d) {
+ cc = fgetc(fp);
+ if (cc != 0x0a) {
+ ungetc(cc, fp);
+ }
+ }
+ cc = 0x0a;
+ buf[i] = cc;
+ buf[i+1] = '\0';
+ return buf;
+ } else if (cc == EOF) {
+ buf[i] = '\0';
+ if (i == 0) return NULL;
+ else return buf;
+ } else {
+ buf[i] = cc;
+ }
+ }
+ buf[i] = '\0';
+ return buf;
+}
+
+static void
+floatroundout(float f)
+{
+ integer i;
+ i = (integer)(f<0 ? f-0.5 : f+0.5);
+ if (i-f < 0.001 && i-f > -0.001) {
+ numout((integer)i);
+ } else {
+ floatout(f);
+ }
+}
+/* end of addition */
+
+void
+outbangspecials(void) {
+ if (bangspecials) {
+ cmdout("TeXDict");
+ cmdout("begin");
+ cmdout("@defspecial\n");
+ dobs(bangspecials);
+ cmdout("\n@fedspecial");
+ cmdout("end");
+ }
+}
+
+/* We recommend that new specials be handled by the following general
+ * (and extensible) scheme, in which the user specifies one or more
+ * `key=value' pairs separated by spaces.
+ * The known keys are given in KeyTab; they take values
+ * of one of the following types:
+ *
+ * None: no value, just a keyword (in which case the = sign is omitted)
+ * String: the value should be "<string without double-quotes"
+ * or '<string without single-quotes'
+ * Integer: the value should be a decimal integer (%d format)
+ * Number: the value should be a decimal integer or real (%f format)
+ * Dimension: like Number, but will be multiplied by the scaledsize
+ * of the current font and converted to default PostScript units
+ * (Actually, strings are allowed in all cases; the delimiting quotes
+ * are simply stripped off if present.)
+ *
+ */
+
+typedef enum {None, String, Integer, Number, Dimension} ValTyp;
+typedef struct {
+ const char *Entry;
+ ValTyp Type;
+} KeyDesc;
+
+#define NKEYS (sizeof(KeyTab)/sizeof(KeyTab[0]))
+
+KeyDesc KeyTab[] = {{"psfile", String}, /* j==0 in the routine below */
+ {"ifffile", String}, /* j==1 */
+ {"tekfile", String}, /* j==2 */
+ {"hsize", Number},
+ {"vsize", Number},
+ {"hoffset", Number},
+ {"voffset", Number},
+ {"hscale", Number},
+ {"vscale", Number},
+ {"angle", Number},
+ {"llx", Number},
+ {"lly", Number},
+ {"urx", Number},
+ {"ury", Number},
+ {"rwi", Number},
+ {"rhi", Number},
+ {"clip", None}};
+
+#ifndef KPATHSEA
+#define TOLOWER Tolower
+#ifdef VMS
+#ifndef __GNUC__ /* GNUC tolower is too simple */
+#define Tolower tolower
+#endif
+#else
+#ifdef VMCMS /* IBM: VM/CMS */
+#define Tolower __tolower
+#else
+#ifdef MVSXA /* IBM: MVS/XA */
+#define Tolower __tolower
+#else
+/*
+ * compare strings, ignore case
+ */
+char
+Tolower(register char c)
+{
+ if ('A' <= c && c <= 'Z')
+ return(c+32);
+ else
+ return(c);
+}
+#endif
+#endif /* IBM: VM/CMS */
+#endif
+#endif /* !KPATHSEA */
+static int
+IsSame(const char *a, const char *b)
+{
+ for(; *a != '\0'; ) {
+ if( TOLOWER(*a) != TOLOWER(*b) )
+ return( 0 );
+ a++;
+ b++;
+ }
+ return( *b == '\0' );
+}
+
+char *KeyStr; /* Key and ... */
+const char *ValStr; /* ... String values found */
+long ValInt; /* Integer value found */
+float ValNum; /* Number or Dimension value found */
+
+static char *
+GetKeyVal(char *str, int *tno) /* returns NULL if none found, else next scan point */
+ /* str : starting point for scan */
+ /* tno : table entry number of keyword, or -1 if keyword not found */
+{
+ unsigned char *s;
+ register int i;
+ register char t;
+
+ for (s=str; *s <= ' ' && *s; s++); /* skip over blanks */
+ if (*s == '\0')
+ return (NULL);
+ KeyStr = s;
+ while (*s>' ' && *s!='=') s++;
+ if (0 != (t = *s))
+ *s++ = 0;
+
+ for(i=0; i<NKEYS; i++)
+ if( IsSame(KeyStr, KeyTab[i].Entry) )
+ goto found;
+ *tno = -1;
+ return (s);
+
+found: *tno = i;
+ if (KeyTab[i].Type == None)
+ return (s);
+
+ if (t && t <= ' ') {
+ for (; *s <= ' ' && *s; s++); /* now look for the value part */
+ if ((t = *s)=='=')
+ s++;
+ }
+ ValStr = "";
+ if ( t == '=' ) {
+ while (*s <= ' ' && *s)
+ s++;
+ if (*s=='\'' || *s=='\"')
+ t = *s++; /* get string delimiter */
+ else t = ' ';
+ ValStr = s;
+ while (*s!=t && *s)
+ s++;
+ if (*s)
+ *s++ = 0;
+ }
+ switch (KeyTab[i].Type) {
+ case Integer:
+ if(sscanf(ValStr,"%ld",&ValInt)!=1) {
+ sprintf(errbuf,"Non-integer value (%.500s) given for keyword %.500s",
+ ValStr, KeyStr);
+ specerror(errbuf);
+ ValInt = 0;
+ }
+ break;
+ case Number:
+ case Dimension:
+ if(sscanf(ValStr,"%f",&ValNum)!=1) {
+ sprintf(errbuf,"Non-numeric value (%.500s) given for keyword %.500s",
+ ValStr, KeyStr);
+ specerror(errbuf);
+ ValNum = 0.0;
+ }
+ if (KeyTab[i].Type==Dimension) {
+ if (curfnt==NULL)
+ error("! No font selected");
+ ValNum = ValNum * ((double)curfnt->scaledsize) * conv * 72 / DPI;
+ }
+ break;
+ default: break;
+ }
+ return (s);
+}
+
+/*
+ * Now our routines. We get the number of bytes specified and place them
+ * into the string buffer, and then parse it. Numerous conventions are
+ * supported here for historical reasons.
+ *
+ * To support GNUplot's horribly long specials, we go ahead and malloc a
+ * new string buffer if necessary.
+ */
+
+void
+predospecial(integer numbytes, Boolean scanning)
+{
+ register char *p = nextstring;
+ register int i = 0;
+ int j;
+ static int omega_specials = 0;
+
+ if (numbytes < 0 || numbytes > maxstring - nextstring) {
+ if (numbytes < 0 || numbytes > (INT_MAX - 1000) / 2 ) {
+ error("! Integer overflow in predospecial");
+ exit(1);
+ }
+ p = nextstring = mymalloc(1000 + 2 * numbytes);
+ maxstring = nextstring + 2 * numbytes + 700;
+ }
+ for (i=numbytes; i>0; i--)
+#ifdef VMCMS /* IBM: VM/CMS */
+ *p++ = ascii2ebcdic[(char)dvibyte()];
+#else
+#ifdef MVSXA /* IBM: MVS/XA */
+ *p++ = ascii2ebcdic[(char)dvibyte()];
+#else
+ *p++ = (char)dvibyte();
+#endif /* IBM: VM/CMS */
+#endif
+ if (pprescan)
+ return;
+ while (p[-1] <= ' ' && p > nextstring)
+ p--; /* trim trailing blanks */
+ if (p==nextstring) return; /* all blank is no-op */
+ *p = 0;
+ p = nextstring;
+ while (*p <= ' ')
+ p++;
+#ifdef DEBUG
+ if (dd(D_SPECIAL))
+ fprintf_str(stderr, "Preprocessing special: %s\n", p);
+#endif
+
+/*
+ * We use strncmp() here to also pass things like landscape()
+ * or landscape: or such.
+ */
+
+ switch (*p) {
+case 'o':
+ if (strncmp(p, "om:", 3)==0) { /* Omega specials ignored */
+ if (omega_specials==0) {
+ fprintf(stderr, "Omega specials are currently ignored\n");
+ omega_specials++;
+ }
+ return;
+ }
+ break;
+case 'l':
+ if (strncmp(p, "landscape", 9)==0) {
+ if (hpapersize || vpapersize)
+ error(
+ "both landscape and papersize specified: ignoring landscape");
+ else
+ landscape = 1;
+ return;
+ }
+ break;
+case 'p':
+ if (strncmp(p, "pos:", 4)==0) return; /* positional specials */
+ if (strncmp(p, "papersize", 9)==0) {
+ p += 9;
+ while (*p == '=' || *p == ' ')
+ p++;
+ if (lastpsizwins || hpapersize == 0 || vpapersize == 0) {
+ if (landscape) {
+ error(
+ "both landscape and papersize specified: ignoring landscape");
+ landscape = 0;
+ }
+ handlepapersize(p, &hpapersize, &vpapersize);
+ }
+ return;
+ }
+ break;
+case 'x':
+ if (strncmp(p, "xtex:", 5)==0) return;
+ break;
+case 's':
+ if (strncmp(p, "src:", 4)==0) return; /* source specials */
+ break;
+
+case 'h':
+ if (strncmp(p, "header", 6)==0) {
+ char *q, *r, *pre = NULL, *post = NULL;
+ p += 6;
+ while ((*p <= ' ' || *p == '=' || *p == '(') && *p != 0)
+ p++;
+ if(*p == '{') {
+ p++;
+ while ((*p <= ' ' || *p == '=' || *p == '(') && *p != 0)
+ p++;
+ q = p;
+ while (*p != '}' && *p != 0)
+ p++;
+ r = p-1;
+ while ((*r <= ' ' || *r == ')') && r >= q)
+ r--;
+ if (*p != 0) p++;
+ r[1] = 0; /* q is the file name */
+ while ((*p <= ' ' || *p == '=' || *p == '(') && *p != 0)
+ p++;
+ if(strncmp(p, "pre", 3) == 0) {
+ int bracecount = 1, num_bytes = 0;
+ while(*p != '{' && *p != 0)
+ p++;
+ if (*p != 0) p++;
+ for(r = p; *r != 0; r++) {
+ if (*r == '{') bracecount++;
+ else if (*r == '}') bracecount--;
+ if (bracecount == 0) break;
+ num_bytes++;
+ }
+ pre = (char *)malloc(num_bytes+1);
+ r = pre;
+ for (j=0; j < num_bytes; j++)
+ *r++ = *p++;
+ *r = 0;
+ if (*p != 0) p++;
+ }
+ while ((*p <= ' ' || *p == '=' || *p == '(') && *p != 0)
+ p++;
+ if(strncmp(p, "post", 4) == 0) {
+ int bracecount = 1, num_bytes = 0;
+ while(*p != '{' && *p != 0)
+ p++;
+ if (*p != 0) p++;
+ for(r = p; *r != 0; r++) {
+ if (*r == '{') bracecount++;
+ else if (*r == '}') bracecount--;
+ if (bracecount == 0) break;
+ num_bytes++;
+ }
+ post = (char *)malloc(num_bytes+1);
+ r = post;
+ for (j=0; j < num_bytes; j++)
+ *r++ = *p++;
+ *r = 0;
+ }
+ if (strlen(q) > 0)
+ add_header_general(q, pre, post);
+ } else {
+ q = p; /* we will remove enclosing parentheses */
+ p = p + strlen(p) - 1;
+ while ((*p <= ' ' || *p == ')') && p >= q)
+ p--;
+ p[1] = 0;
+ if (p >= q)
+ add_header(q);
+ }
+ }
+ break;
+/* IBM: color - added section here for color header and color history */
+/* using strncmp in this fashion isn't perfect; if later someone wants
+ to introduce a verb like colorspace, well, just checking
+ strcmp(p, "color", 5) will not do. But we leave it alone for the moment.
+ --tgr */
+case 'b':
+ if (strncmp(p, "background", 10) == 0) {
+ usescolor = 1;
+ p += 10;
+ while ( *p && *p <= ' ' ) p++;
+ background(p);
+ return;
+ }
+ break;
+case 'c':
+ if (strncmp(p, "color", 5) == 0) {
+ usescolor = 1;
+ p += 5;
+ while ( *p && *p <= ' ' ) p++;
+ if (strncmp(p, "push", 4) == 0 ) {
+ p += 4;
+ while ( *p && *p <= ' ' ) p++;
+ pushcolor(p, 0);
+ } else if (strncmp(p, "pop", 3) == 0 ) {
+ popcolor(0);
+ } else {
+ resetcolorstack(p,0);
+ }
+ } /* IBM: color - end changes */
+ break;
+case '!':
+ {
+ register struct bangspecial *q;
+ p++;
+ q = (struct bangspecial *)mymalloc((integer)(sizeof(struct bangspecial)));
+ q->actualstuff = mymalloc(strlen(p) + 1);
+ strcpy(q->actualstuff, p);
+ q->next = bangspecials;
+ bangspecials = q;
+ usesspecial = 1;
+ return;
+ }
+ break;
+default:
+ break;
+ }
+ usesspecial = 1; /* now the special prolog will be sent */
+ if (scanning && *p != '"' && (p=GetKeyVal(p, &j)) != NULL && j==0
+ && *ValStr != '`') /* Don't bother to scan compressed files. */
+ scanfontcomments(ValStr);
+}
+
+/* Return 1 if S is readable along figpath, 0 if not. */
+static int
+maccess(char *s)
+{
+ FILE *f = search(figpath, s, "r");
+ int found = (f != 0);
+ if (found)
+ (*close_file) (f);
+ return found;
+}
+
+const char *tasks[] = { 0, "iff2ps", "tek2ps" };
+
+#define PSFILESIZ 511
+static char psfile[PSFILESIZ];
+
+void
+dospecial(integer numbytes)
+{
+ register char *p = nextstring;
+ register int i = 0;
+ int j, systemtype = 0;
+ register const char *q;
+ Boolean psfilewanted = 1;
+ const char *task = 0;
+ char cmdbuf[111];
+#ifdef HPS
+if (HPS_FLAG && PAGEUS_INTERUPPTUS) {
+ HREF_COUNT--;
+ start_new_box();
+ PAGEUS_INTERUPPTUS = 0;
+ }
+if (HPS_FLAG && NEED_NEW_BOX) {
+ vertical_in_hps();
+ NEED_NEW_BOX = 0;
+ }
+#endif
+ if (nextstring + numbytes > maxstring)
+ error("! out of string space in dospecial");
+ for (i=numbytes; i>0; i--)
+#ifdef VMCMS /* IBM: VM/CMS */
+ *p++ = ascii2ebcdic[(char)dvibyte()];
+#else
+#ifdef MVSXA /* IBM: MVS/XA */
+ *p++ = ascii2ebcdic[(char)dvibyte()];
+#else
+ *p++ = (char)dvibyte();
+#endif /* IBM: VM/CMS */
+#endif
+ while (p[-1] <= ' ' && p > nextstring)
+ p--; /* trim trailing blanks */
+ if (p==nextstring) return; /* all blank is no-op */
+ *p = 0;
+ p = nextstring;
+ while (*p <= ' ')
+ p++;
+#ifdef DEBUG
+ if (dd(D_SPECIAL))
+ fprintf_str(stderr, "Processing special: %s\n", p);
+#endif
+
+ switch (*p) {
+case 'o':
+ if (strncmp(p, "om:", 3)==0) { /* Omega specials ignored */
+ return;
+ }
+ break;
+case 'e':
+ if (strncmp(p, "em:", 3)==0) { /* emTeX specials in emspecial.c */
+ emspecial(p);
+ return;
+ }
+
+/* added for dvi2ps special */
+ if (strncmp(p, "epsfile=", 8)==0) { /* epsf.sty for dvi2ps-j */
+ float llx, lly, urx, ury;
+ unsigned psfilelen = 0;
+
+ p += 8;
+ while (*p && !isspace((unsigned char)*p)) {
+ if (psfilelen < PSFILESIZ - 1) {
+ psfile[psfilelen] = *p;
+ psfilelen++;
+ p++;
+ } else {
+ psfile[psfilelen] = 0; /* should not strictly be necessary */
+ sprintf(errbuf,
+ "! epsfile=%.20s... argument longer than %d characters",
+ psfile, PSFILESIZ);
+ error(errbuf);
+ }
+ }
+ if (psfilelen == 0) {
+ error ("! epsfile= argument empty");
+ }
+ psfile[psfilelen] = 0;
+ p += strlen(psfile);
+ fgetboundingbox(psfile, &llx, &lly, &urx, &ury);
+ hvpos();
+ cmdout("@beginspecial");
+ floatroundout(llx);
+ cmdout("@llx");
+ floatroundout(lly);
+ cmdout("@lly");
+ floatroundout(urx);
+ cmdout("@urx");
+ floatroundout(ury);
+ cmdout("@ury");
+
+ while ((p = GetKeyVal(p, &j))) {
+ switch (j) {
+ case 3: /* hsize */
+ floatroundout(ValNum*10);
+ cmdout("@rwi");
+ break;
+ case 4: /* vsize */
+ floatroundout(ValNum*10);
+ cmdout("@rhi");
+ break;
+ case 7: /* hscale */
+ floatroundout((urx-llx)*ValNum*10);
+ cmdout("@rwi");
+ break;
+ case 8: /* vscale */
+ floatroundout((ury-lly)*ValNum*10);
+ cmdout("@rhi");
+ break;
+ default:
+ sprintf(errbuf, "Unknown keyword `%.500s' in \\special{epsfile=%.500s...} will be ignored\n",
+ KeyStr, psfile);
+ specerror(errbuf);
+ break;
+ }
+ }
+ cmdout("@setspecial");
+ numout((integer)0);
+ cmdout("lly");
+ cmdout("ury");
+ cmdout("sub");
+ cmdout("TR");
+ figcopyfile(psfile, 0);
+ cmdout("\n@endspecial");
+ return;
+ }
+/* end addition */
+ break;
+case 'p':
+ if (strncmp(p, "pos:", 4)==0) return; /* positional specials */
+ if (strncmp(p, "ps:", 3)==0) {
+ psflush(); /* now anything can happen. */
+ if (p[3]==':') {
+ if (strncmp(p+4, "[nobreak]", 9) == 0) {
+ hvpos();
+ outputstring(&p[13]);
+ } else if (strncmp(p+4, "[begin]", 7) == 0) {
+ hvpos();
+ trytobreakout(&p[11]);
+ } else if (strncmp(p+4, "[end]", 5) == 0)
+ trytobreakout(&p[9]);
+ else trytobreakout(&p[4]);
+ } else if (strncmp(p+3, " plotfile ", 10) == 0) {
+ char *sfp;
+ hvpos();
+ p += 13;
+ /*
+ * Fixed to allow popen input for plotfile
+ * TJD 10/20/91
+ */
+ while (*p == ' ') p++;
+ if (*p == '"') {
+ p++;
+ for (sfp = p; *sfp && *sfp != '"'; sfp++);
+ } else {
+ for (sfp = p; *sfp && *sfp != ' '; sfp++);
+ }
+ *sfp = '\0';
+ if (*p == '`')
+ figcopyfile(p+1, 1);
+ else
+ figcopyfile (p, 0);
+ /* End TJD changes */
+ } else {
+ hvpos();
+ trytobreakout(&p[3]);
+ psflush();
+ hvpos();
+ }
+ return;
+ }
+ if (strncmp(p, "papersize", 9) == 0)
+ return;
+#ifdef TPIC
+ if (strncmp(p, "pn ", 3) == 0) {setPenSize(p+2); return;}
+ if (strncmp(p, "pa ", 3) == 0) {addPath(p+2); return;}
+#endif
+
+/* added for jdvi2kps special */
+ if (strncmp(p, "postscriptbox", 13)==0) { /* epsbox.sty for jdvi2kps */
+ float w, h;
+ float llx, lly, urx, ury;
+ if (strlen(p)-13-6 >= PSFILESIZ) { /* -6 for the braces */
+ /* We're not allowing as long a name as we could, since however
+ many characters the two {%fpt} arguments consume is not
+ taken into account. But parsing it all so we know the
+ character length is too much work for this obscure special. */
+ sprintf(errbuf,
+ "! postscriptbox{} arguments longer than %d characters",
+ PSFILESIZ);
+ error(errbuf);
+ }
+ if (sscanf(p+13, "{%fpt}{%fpt}{%[^}]}", &w, &h, psfile) != 3)
+ break;
+ fgetboundingbox(psfile, &llx, &lly, &urx, &ury);
+ hvpos();
+ cmdout("@beginspecial");
+ floatroundout(llx);
+ cmdout("@llx");
+ floatroundout(lly);
+ cmdout("@lly");
+ floatroundout(urx);
+ cmdout("@urx");
+ floatroundout(ury);
+ cmdout("@ury");
+ floatroundout(w*10*72/72.27);
+ cmdout("@rwi");
+ floatroundout(h*10*72/72.27);
+ cmdout("@rhi");
+ cmdout("@setspecial");
+ figcopyfile(psfile, 0);
+ cmdout("\n@endspecial");
+ return;
+ }
+/* end addition */
+ break;
+case 'l':
+ if (strncmp(p, "landscape", 9)==0) return;
+ break;
+case '!':
+ return;
+case 'h':
+ if (strncmp(p, "header", 6)==0) return;
+#ifdef HPS
+ if (strncmp(p, "html:", 5)==0) {
+ if (! HPS_FLAG) return;
+ p += 5;
+ while (isspace((unsigned char)*p))
+ p++;
+ if (*p == '<') {
+ char *sp = p;
+ char *str;
+ int ii=0, len, lower_len;
+
+ while ((*p) && (*p != '>')) {
+ ii++;
+ p++;
+ }
+ str = (char *)mymalloc(ii+2);
+ strncpy(str,sp+1,ii-1);
+ str[ii-1] = 0;len=strlen(str);
+ if(len>6) lower_len=6; else lower_len=len;
+ for(ii=0;ii<lower_len;ii++) str[ii]=tolower((unsigned char)str[ii]);
+ do_html(str);
+ free(str);
+ } else
+#ifdef KPATHSEA
+ if (!kpse_tex_hush ("special"))
+#endif
+ {
+
+ sprintf(errbuf,"Error in html special\n");
+ error(errbuf);
+ return;
+ }
+ return;
+ }
+#else
+ if (strncmp(p, "html:", 5)==0) return;
+#endif
+case 'w':
+case 'W':
+ if (strncmp(p+1, "arning", 6) == 0) {
+ static int maxwarns = 50;
+ if (maxwarns > 0) {
+ error(p);
+ maxwarns--;
+ } else if (maxwarns == 0) {
+ error(". . . rest of warnings suppressed");
+ maxwarns--;
+ }
+ return;
+ }
+#ifdef TPIC
+ if (strcmp(p, "wh") == 0) {whitenLast(); return;}
+#endif
+ break;
+case 'b':
+ if ( strncmp(p, "background", 10) == 0 )
+ return; /* already handled in prescan */
+#ifdef TPIC
+ if (strcmp(p, "bk") == 0) {blackenLast(); return;}
+#endif
+ break;
+case 'c':
+ if (strncmp(p, "color", 5) == 0) {
+ p += 5;
+ while ( *p && *p <= ' ' ) p++;
+ if (strncmp(p, "push", 4) == 0 ) {
+ p += 4;
+ while ( *p && *p <= ' ' ) p++;
+ pushcolor(p,1);
+ } else if (strncmp(p, "pop", 3) == 0 ) {
+ popcolor(1);
+ } else {
+ resetcolorstack(p,1);
+ }
+ return;
+ } /* IBM: color - end changes*/
+ break;
+case 'f':
+#ifdef TPIC
+ if (strcmp(p, "fp") == 0) {flushPath(0); return;}
+#endif
+ break;
+case 'i':
+#ifdef TPIC
+ if (strcmp(p, "ip") == 0) {flushPath(1); return;} /* tpic 2.0 */
+ if (strncmp(p, "ia ", 3) == 0) {arc(p+2, 1); return;} /* tpic 2.0 */
+#endif
+ break;
+case 'd':
+#ifdef TPIC
+ if (strncmp(p, "da ", 3) == 0) {flushDashed(p+2, 0); return;}
+ if (strncmp(p, "dt ", 3) == 0) {flushDashed(p+2, 1); return;}
+#endif
+ break;
+case 's':
+ if (strncmp(p, "src:", 4) == 0) return; /* source specials */
+#ifdef TPIC
+ if (strcmp(p, "sp") == 0) {flushSpline(p+2); return;} /* tpic 2.0 */
+ if (strncmp(p, "sp ", 3) == 0) {flushSpline(p+3); return;} /* tpic 2.0 */
+ if (strcmp(p, "sh") == 0) {shadeLast(p+2); return;} /* tpic 2.0 */
+ if (strncmp(p, "sh ", 3) == 0) {shadeLast(p+3); return;} /* tpic 2.0 */
+#endif
+ break;
+case 'a':
+#ifdef TPIC
+ if (strncmp(p, "ar ", 3) == 0) {arc(p+2, 0); return;} /* tpic 2.0 */
+#endif
+ break;
+case 't':
+#ifdef TPIC
+ if (strncmp(p, "tx ", 3) == 0) {SetShade(p+3); return;}
+#endif
+ break;
+case '"':
+ hvpos();
+ cmdout("@beginspecial");
+ cmdout("@setspecial");
+ trytobreakout(p+1);
+ cmdout("\n@endspecial");
+ return;
+ break;
+default:
+ break;
+ }
+/* At last we get to the key/value conventions */
+ psfile[0] = '\0';
+ hvpos();
+ cmdout("@beginspecial");
+
+ while( (p=GetKeyVal(p,&j)) != NULL )
+ switch (j) {
+ case -1: /* for compatibility with old conventions, we allow a file name
+ * to be given without the 'psfile=' keyword */
+ if (!psfile[0] && maccess(KeyStr)==1) { /* yes we can read it */
+ if (strlen(KeyStr) >= PSFILESIZ) {
+ sprintf(errbuf,
+ "! Bare filename (%.20s...) in \\special longer than %d characters",
+ KeyStr, PSFILESIZ);
+ }
+ strcpy(psfile,KeyStr);
+ } else {
+ if (strlen(KeyStr) < 40) {
+ sprintf(errbuf,
+ "Unknown keyword (%s) in \\special will be ignored",
+ KeyStr);
+ } else {
+ sprintf(errbuf,
+ "Unknown keyword (%.40s...) in \\special will be ignored",
+ KeyStr);
+ }
+ specerror(errbuf);
+ }
+ break;
+ case 0: case 1: case 2: /* psfile */
+ if (psfile[0]) {
+ sprintf(errbuf, "More than one \\special %s given; %.40s ignored",
+ "psfile", ValStr);
+ specerror(errbuf);
+ } else {
+ if (strlen(ValStr) >= PSFILESIZ) {
+ sprintf(errbuf,
+ "! PS filename (%.20s...) in \\special longer than %d characters",
+ ValStr, PSFILESIZ);
+ error(errbuf);
+ }
+ strcpy(psfile, ValStr);
+ }
+ task = tasks[j];
+ break;
+ default: /* most keywords are output as PostScript procedure calls */
+ if (KeyTab[j].Type == Integer)
+ numout((integer)ValInt);
+ else if (KeyTab[j].Type == String)
+ for (q=ValStr; *q; q++)
+ scout(*q);
+ else if (KeyTab[j].Type == None);
+ else { /* Number or Dimension */
+ ValInt = (integer)(ValNum<0? ValNum-0.5 : ValNum+0.5);
+ if (ValInt-ValNum < 0.001 && ValInt-ValNum > -0.001)
+ numout((integer)ValInt);
+ else {
+ snprintf(cmdbuf, sizeof(cmdbuf), "%f", ValNum);
+ cmdout(cmdbuf);
+ }
+ }
+ snprintf(cmdbuf, sizeof(cmdbuf), "@%s", KeyStr);
+ cmdout(cmdbuf);
+ }
+
+ cmdout("@setspecial");
+
+ if(psfile[0]) {
+ if (task == 0) {
+ systemtype = (psfile[0]=='`');
+ figcopyfile(psfile+systemtype, systemtype);
+ } else {
+ fprintf (stderr, "dvips: iff2ps and tek2ps are not supported.\n");
+ }
+ } else if (psfilewanted
+#ifdef KPATHSEA
+ && !kpse_tex_hush ("special")
+#endif
+ )
+ specerror("No \\special psfile was given; figure will be blank");
+
+ cmdout("@endspecial");
+}
+
+/*
+ * Handles specials encountered during bounding box calculations.
+ * Currently we only deal with psfile's or PSfiles and only those
+ * that do not use rotations.
+ */
+static float rbbox[4];
+float *
+bbdospecial(int nbytes)
+{
+ char *p = nextstring;
+ int i, j;
+ char seen[NKEYS];
+ float valseen[NKEYS];
+
+ if (nbytes < 0 || nbytes > maxstring - nextstring) {
+ if (nbytes < 0 || nbytes > (INT_MAX - 1000) / 2 ) {
+ error("! Integer overflow in bbdospecial");
+ exit(1);
+ }
+ p = nextstring = mymalloc(1000 + 2 * nbytes);
+ maxstring = nextstring + 2 * nbytes + 700;
+ }
+ if (nextstring + nbytes > maxstring)
+ error("! out of string space in bbdospecial");
+ for (i=nbytes; i>0; i--)
+#ifdef VMCMS /* IBM: VM/CMS */
+ *p++ = ascii2ebcdic[(char)dvibyte()];
+#else
+#ifdef MVSXA /* IBM: MVS/XA */
+ *p++ = ascii2ebcdic[(char)dvibyte()];
+#else
+ *p++ = (char)dvibyte();
+#endif /* IBM: VM/CMS */
+#endif
+ while (p[-1] <= ' ' && p > nextstring)
+ p--; /* trim trailing blanks */
+ if (p==nextstring) return NULL; /* all blank is no-op */
+ *p = 0;
+ p = nextstring;
+ while (*p && *p <= ' ')
+ p++;
+ if (strncmp(p, "psfile", 6)==0 || strncmp(p, "PSfile", 6)==0) {
+ float originx = 0, originy = 0, hscale = 1, vscale = 1,
+ hsize = 0, vsize = 0;
+ for (j=0; j<NKEYS; j++)
+ seen[j] = 0;
+ j = 0;
+ while ((p=GetKeyVal(p, &j))) {
+ if (j >= 0 && j < NKEYS && KeyTab[j].Type == Number) {
+ seen[j]++;
+ valseen[j] = ValNum;
+ }
+ }
+ /*
+ * This code mimics what happens in @setspecial.
+ */
+ if (seen[3])
+ hsize = valseen[3];
+ if (seen[4])
+ vsize = valseen[4];
+ if (seen[5])
+ originx = valseen[5];
+ if (seen[6])
+ originy = valseen[6];
+ if (seen[7])
+ hscale = valseen[7] / 100.0;
+ if (seen[8])
+ vscale = valseen[8] / 100.0;
+ if (seen[10] && seen[12])
+ hsize = valseen[12] - valseen[10];
+ if (seen[11] && seen[13])
+ vsize = valseen[13] - valseen[11];
+ if (seen[14] || seen[15]) {
+ if (seen[14] && seen[15] == 0) {
+ hscale = vscale = valseen[14] / (10.0 * hsize);
+ } else if (seen[15] && seen[14] == 0) {
+ hscale = vscale = valseen[15] / (10.0 * vsize);
+ } else {
+ hscale = valseen[14] / (10.0 * hsize);
+ vscale = valseen[15] / (10.0 * vsize);
+ }
+ }
+ /* at this point, the bounding box in PostScript units relative to
+ the current dvi point is
+ originx originy originx+hsize*hscale originy+vsize*vscale
+ We'll let the bbox routine handle the remaining math.
+ */
+ rbbox[0] = originx;
+ rbbox[1] = originy;
+ rbbox[2] = originx+hsize*hscale;
+ rbbox[3] = originy+vsize*vscale;
+ return rbbox;
+ }
+ return 0;
+}