1 /*
2  *   emspecial.c
3  *   This routine handles the emTeX special commands.
4  */
5 #include "dvips.h" /* The copyright notice in that file is included too!*/
6 
7 #include <ctype.h>
8 #include <stdlib.h>
9 /*
10  *   The external declarations:
11  */
12 #include "protos.h"
13 
14 #ifdef EMTEX
15 /* emtex specials, added by rjl */
16 
17 #ifndef TRUE
18 #define TRUE 1
19 #define FALSE 0
20 #endif
21 
22 static long emmax = 161;
23 
24 /*
25  *   We define these seek constants if they don't have their
26  *   values already defined.
27  */
28 #ifndef SEEK_SET
29 #define SEEK_SET (0)
30 #endif
31 #ifndef SEEK_END
32 #define SEEK_END (2)
33 #endif
34 
35 struct empt {
36    struct empt *next;
37    shalfword point;
38    integer x, y;
39 };
40 
41 static struct empt **empoints = NULL;
42 boolean emused = FALSE;  /* true if em points used on this page */
43 integer emx, emy;
44 
45 struct emunit {
46    const char *unit;
47    float factor;
48 };
49 struct emunit emtable[] = {
50   {"pt",72.27},
51   {"pc",72.27/12},
52   {"in",1.0},
53   {"bp",72.0},
54   {"cm",2.54},
55   {"mm",25.4},
56   {"dd",72.27/(1238.0/1157)},
57   {"cc",72.27/12/(1238.0/1157)},
58   {"sp",72.27*65536},
59   {0,0.0}
60 };
61 
62 static void emgraph(char *filename, float emwidth, float emheight);
63 
64 /* clear the empoints array if necessary */
65 void
emclear(void)66 emclear(void)
67 {
68    int i;
69    if (emused && empoints)
70       for (i=0; i<emmax; i++)
71          empoints[i] = 0;
72    emused = FALSE;
73 }
74 
75 /* put an empoint into the empoints array */
76 static struct empt *
emptput(shalfword point,integer x,integer y)77 emptput(shalfword point, integer x, integer y)
78 {
79    struct empt *p;
80    int start;
81 
82    emused = TRUE;
83    start = point % emmax;
84    p = empoints[start];
85    while ( p ) {
86       if ( p->point == point )
87          break;
88       p = p->next;
89    }
90    if (p == 0) {
91       p = (struct empt *)mymalloc(sizeof(struct empt));
92       p->next = empoints[start];
93       empoints[start] = p;
94    }
95    p->point = point;
96    p->x = x;
97    p->y = y;
98    return(p);
99 }
100 
101 /* get an empoint from the empoints array */
102 static struct empt *
emptget(shalfword point)103 emptget(shalfword point)
104 {
105    struct empt *p;
106    int start;
107 
108    start = point % emmax;
109    if (emused == TRUE) {
110       p = empoints[start];
111       while (p) {
112 	 if (p->point == point)
113 	    return p;
114 	 p = p->next;
115       }
116    }
117    sprintf(errbuf,"!em: point %d not defined",point);
118    specerror(errbuf);
119    return(NULL); /* never returns due to error */
120 }
121 
122 
123 /* convert width into dpi units */
124 static float
emunits(float width,char * unit)125 emunits(float width, char *unit)
126 {
127 struct emunit *p;
128 	for (p=emtable; p->unit; p++) {
129 	   if (strcmp(p->unit,unit)==0)
130 		return( width * actualdpi / p->factor );
131 	}
132 	return (-1.0); /* invalid unit */
133 }
134 
135 /* The main routine for \special{em:graph ...} called from dospecial.c */
136 /* the line cut parameter is not supported (and is ignored) */
137 
138 void
emspecial(char * p)139 emspecial(char *p)
140 {
141 float emwidth, emheight;
142 shalfword empoint1, empoint2;
143 struct empt *empoint;
144 char emunit[30];
145 char emstr[500];
146 char *emp;
147 
148         hvpos();
149 	for (emp = p+3; *emp && isspace((unsigned char)*emp); emp++); /* skip blanks */
150 	if (strncmp(emp, "linewidth", 9) == 0) {
151 	   /* code for linewidth */
152 	   for (emp = emp+9; *emp && isspace((unsigned char)*emp); emp++); /* skip blanks */
153 	   sscanf(emp, "%f%2s", &emwidth, emunit);
154 	   emwidth = emunits(emwidth,emunit);
155 	   if (emwidth!=-1.0) {
156 	      snprintf(emstr, sizeof(emstr), "%.1f setlinewidth", emwidth);
157 	      cmdout(emstr);
158 #ifdef DEBUG
159    if (dd(D_SPECIAL))
160       fprintf(stderr, "em special: Linewidth set to %.1f dots\n",
161 		emwidth);
162 #endif
163 	   } else {
164 	      sprintf(errbuf,"Unknown em: special width");
165 	      specerror(errbuf);
166 	   }
167 	}
168         else if (strncmp(emp, "moveto", 6) == 0) {
169 #ifdef DEBUG
170    if (dd(D_SPECIAL))
171 #ifdef SHORTINT
172       fprintf(stderr, "em special: moveto %ld,%ld\n", hh, vv);
173 #else
174       fprintf(stderr, "em special: moveto %d,%d\n", hh, vv);
175 #endif
176 #endif
177            emx = hh;
178            emy = vv;
179         }
180         else if (strncmp(emp, "lineto", 6) == 0) {
181 #ifdef DEBUG
182    if (dd(D_SPECIAL))
183 #ifdef SHORTINT
184       fprintf(stderr, "em special: lineto %ld,%ld\n", hh, vv);
185 #else
186       fprintf(stderr, "em special: lineto %d,%d\n", hh, vv);
187 #endif
188 #endif
189 	   cmdout("np");
190 	   numout(emx);
191 	   numout(emy);
192 	   cmdout("a");
193 	   numout(hh);
194 	   numout(vv);
195 	   cmdout("li");
196 	   cmdout("st");
197            emx = hh;
198            emy = vv;
199         }
200 	else if (strncmp(emp, "point", 5) == 0) {
201            if (empoints == NULL) {
202               empoints =
203               (struct empt **)mymalloc((integer)emmax * sizeof(struct empt *));
204               emused = TRUE;
205               emclear();
206            }
207 	   for (emp = emp+5; *emp && isspace((unsigned char)*emp); emp++); /* skip blanks */
208            empoint1 = (shalfword)atoi(emp);
209            empoint = emptput(empoint1,hh,vv);
210 #ifdef DEBUG
211    if (dd(D_SPECIAL))
212 #ifdef SHORTINT
213       fprintf(stderr, "em special: Point %d is %ld,%ld\n",
214 #else
215       fprintf(stderr, "em special: Point %d is %d,%d\n",
216 #endif
217 		empoint->point, empoint->x, empoint->y);
218 #endif
219 	}
220 	else if (strncmp(emp, "line", 4) == 0) {
221 	   for (emp = emp+4; *emp && isspace((unsigned char)*emp); emp++); /* skip blanks */
222            empoint1 = (shalfword)atoi(emp);
223 	   for (; *emp && isdigit((unsigned char)*emp); emp++); /* skip point 1 */
224 	   if ( *emp && strchr("hvp",*emp)!=0 )
225 	      emp++;  /* skip line cut */
226 	   for (; *emp && isspace((unsigned char)*emp); emp++); /* skip blanks */
227 	   if ( *emp && (*emp==',') )
228 	      emp++; /*  skip comma separator */
229 	   for (; *emp && isspace((unsigned char)*emp); emp++); /* skip blanks */
230            empoint2 = (shalfword)atoi(emp);
231 	   for (; *emp && isdigit((unsigned char)*emp); emp++); /* skip point 2 */
232 	   if ( *emp && strchr("hvp",*emp)!=0 )
233 	      emp++;  /* skip line cut */
234 	   for (; *emp && isspace((unsigned char)*emp); emp++); /* skip blanks */
235 	   if ( *emp && (*emp==',') )
236 	      emp++; /*  skip comma separator */
237 	   emwidth = -1.0;
238 	   emunit[0]='\0';
239 	   sscanf(emp, "%f%2s", &emwidth, emunit);
240 	   emwidth = emunits(emwidth,emunit);
241 #ifdef DEBUG
242    if (dd(D_SPECIAL))
243       fprintf(stderr, "em special: Line from point %d to point %d\n",
244 		empoint1, empoint2);
245 #endif
246 	   cmdout("np");
247 	   if (emwidth!=-1.0) {
248 #ifdef DEBUG
249    if (dd(D_SPECIAL))
250    fprintf(stderr,"em special: Linewidth temporarily set to %.1f dots\n",
251 		emwidth);
252 #endif
253 	   	strcpy(emstr,"currentlinewidth");
254 	   	cmdout(emstr);
255 	        snprintf(emstr, sizeof(emstr), "%.1f setlinewidth", emwidth);
256 	        cmdout(emstr);
257 	   }
258            empoint = emptget(empoint1);
259 	   numout(empoint->x);
260 	   numout(empoint->y);
261 	   cmdout("a");
262            empoint = emptget(empoint2);
263 	   numout(empoint->x);
264 	   numout(empoint->y);
265 	   cmdout("li");
266 	   cmdout("st");
267 	   if (emwidth!=-1.0) {
268 	   	strcpy(emstr,"setlinewidth");
269 	   	cmdout(emstr);
270 	   }
271 	}
272 	else if (strncmp(emp, "message", 7) == 0) {
273            fprintf(stderr, "em message: %s\n", emp+7);
274 	}
275 	else if (strncmp(emp, "graph", 5) == 0) {
276 	   int i;
277 	   for (emp = emp+5; *emp && isspace((unsigned char)*emp); emp++); /* skip blanks */
278 	   for (i=0; *emp && !isspace((unsigned char)*emp) && !(*emp==','); emp++) {
279 	      if (strlen(emstr) - 2 >= sizeof(emstr)) {
280                 fprintf(stderr, "em:graph: special too long, truncating\n");
281                 break;
282 	      }
283 	      emstr[i++] = *emp; /* copy filename */
284 	   }
285 	   emstr[i] = '\0';
286 	   /* now get optional width and height */
287 	   emwidth = emheight = -1.0;	/* no dimension is <= 0 */
288 	   for (; *emp && ( isspace((unsigned char)*emp) || (*emp==',') ); emp++)
289 	    ;  /* skip blanks and comma */
290 	   if (*emp) {
291 	      sscanf(emp, "%f%2s", &emwidth, emunit); /* read width */
292 	      emwidth = emunits(emwidth,emunit); /* convert to pixels */
293 	      for (; *emp && (*emp=='.'||isdigit((unsigned char)*emp)||isalpha((unsigned char)*emp)); emp++)
294 	       ; /* skip width dimension */
295 	      for (; *emp && ( isspace((unsigned char)*emp) || (*emp==',') ); emp++)
296 	       ;  /* skip blanks and comma */
297 	      if (*emp) {
298 	         sscanf(emp, "%f%2s", &emheight, emunit); /* read height */
299 	         emheight = emunits(emheight,emunit)*vactualdpi/actualdpi;
300 	      }
301 	   }
302 	   if (emstr[0]) {
303 	      emgraph(emstr,emwidth,emheight);
304 	   }
305 	   else {
306               fprintf(stderr, "em:graph: no file given\n");
307 	   }
308 	}
309 	else {
310            sprintf(errbuf,
311 	      "Unknown em: command (%s) in \\special will be ignored", p);
312            specerror(errbuf);
313 	}
314 	return;
315    }
316 
317 
318 /* em:graph routines */
319 
320 /* The graphics routines currently decode 3 types of IBM-PC based graphics   */
321 /* files: .pcx, .bmp, .msp. The information on the formats has occasionally  */
322 /* been sketchy, and subject to interpretation. I have attempted to implement*/
323 /* these routines to correctly decode the graphics file types mentioned.     */
324 /* The compressed .bmp file type has not been tested fully due to a lack of  */
325 /* test files.                                                               */
326 /*                                                                           */
327 /* The method of reading in the headers of the binary files is ungainly, but */
328 /* portable. Failure to use a byte by byte read and convert method will      */
329 /* result in portability problems. Specifically there is no requirement that */
330 /* elements of a C structure be contiguous, only that they have an ascending */
331 /* order of addresses.                                                       */
332 /*                                                                           */
333 /* The current implementations of the graphics format to postscript          */
334 /* conversion are not the most efficient possible. Specifically: color       */
335 /* formats are converted to RGB ratios prior to using a simple thresholding  */
336 /* method to determine if the postscript bit is to be set. The thresholding  */
337 /* method is compabible with that used in emtex's drivers.                   */
338 /*                                                                           */
339 /* Please send bug reports relating to the em:graph routines to:             */
340 /*                maurice@bruce.cs.monash.edu.au                             */
341 /*                                                                           */
342 /* My thanks to Russell Lang for his assistance with the implementation of   */
343 /* these routines in a manner compatible with dvips and for the optimization */
344 /* of some routines.                                                         */
345 /*                                                                           */
346 /*                                                   Maurice Castro          */
347 /*                                                   8 Oct 92                */
348 
349 /* Routines to read binary numbers from IBM PC file types */
350 static integer
readinteger(FILE * f)351 readinteger(FILE *f)
352 {
353    integer i;
354    int r;
355 
356    i = 0;
357    for (r = 0; r < 4; r++)
358    {
359       i = i |  ( ((integer) fgetc(f)) << (8*r) );
360    }
361    return(i);
362 }
363 
364 static halfword
readhalfword(FILE * f)365 readhalfword(FILE *f)
366 {
367    halfword i;
368    int r;
369 
370    i = 0;
371    for (r = 0; r < 2; r++)
372    {
373      i = i |  ( ((halfword) fgetc(f)) << (8*r) );
374    }
375    return(i);
376 }
377 
378 #define readquarterword(f) ((unsigned char)fgetc(f))
379 #define tobyte(x) ((x/8) + (x%8 ? 1 : 0))
380 
381 /* These routines will decode PCX files produced by Microsoft
382  * Windows Paint.  Other programs may not produce files which
383  * will be successfully decoded, most notably version 1.xx of
384  * PC Paint. */
385 
386 /*
387  *   Type declarations.  integer must be a 32-bit signed; shalfword must
388  *   be a sixteen-bit signed; halfword must be a sixteen-bit unsigned;
389  *   quarterword must be an eight-bit unsigned.
390  */
391 typedef struct
392 {
393 	quarterword man;
394 	quarterword ver;
395 	quarterword enc;
396 	quarterword bitperpix;
397 	halfword xmin;
398 	halfword ymin;
399 	halfword xmax;
400 	halfword ymax;
401 	halfword hres;
402 	halfword vres;
403 	quarterword pal[48];
404 	quarterword reserved;
405 	quarterword colorplanes;
406 	halfword byteperline;
407 	halfword paltype;
408 	quarterword fill[58];
409 } PCXHEAD;
410 
411 static int
PCXreadhead(FILE * pcxf,PCXHEAD * pcxh)412 PCXreadhead(FILE *pcxf, PCXHEAD *pcxh)
413 {
414 	pcxh->man = readquarterword(pcxf);
415 	pcxh->ver = readquarterword(pcxf);
416 	pcxh->enc = readquarterword(pcxf);
417 	pcxh->bitperpix = readquarterword(pcxf);
418 	pcxh->xmin = readhalfword(pcxf);
419 	pcxh->ymin = readhalfword(pcxf);
420 	pcxh->xmax = readhalfword(pcxf);
421 	pcxh->ymax = readhalfword(pcxf);
422 	pcxh->hres = readhalfword(pcxf);
423 	pcxh->vres = readhalfword(pcxf);
424 	fread(pcxh->pal, 1, 48, pcxf);
425 	pcxh->reserved = readquarterword(pcxf);
426 	pcxh->colorplanes = readquarterword(pcxf);
427 	pcxh->byteperline = readhalfword(pcxf);
428 	pcxh->paltype = readhalfword(pcxf);
429 	fread(pcxh->fill, 1, 58, pcxf);
430 
431 	if (feof(pcxf))
432 		return(0);				/* fail */
433 	if (pcxh->man != 0x0a)
434 		return(0);				/* fail */
435 	if (pcxh->enc != 0x1)
436 		return(0);				/* fail */
437 	return(1);					/* success */
438 	}
439 
440 static int
PCXreadline(FILE * pcxf,unsigned char * pcxbuf,unsigned int byteperline)441 PCXreadline(FILE *pcxf,
442 	    unsigned char *pcxbuf,
443 	    unsigned int byteperline)
444 {
445 	int n;
446 	int c;
447 	int i;
448 
449 	n = 0;
450 	memset(pcxbuf,0,byteperline);
451 	do {
452 		c = fgetc(pcxf);
453 		if ((c & 0xc0) == 0xc0) {
454 			i = c & 0x3f;
455 			c = fgetc(pcxf) & 0xff;
456 			while ((i--) && (n < byteperline)) pcxbuf[n++] = c;
457 		}
458 		else {
459 			pcxbuf[n++] = c & 0xff;
460 		}
461 	} while (n < byteperline);
462 	if (c==EOF) n=0;
463 	return(n);
464 }
465 
466 static void
PCXgetpalette(FILE * pcxf,PCXHEAD * pcxh,unsigned char * r,unsigned char * g,unsigned char * b)467 PCXgetpalette(FILE *pcxf, PCXHEAD *pcxh,
468 	      unsigned char *r,
469 	      unsigned char *g,
470 	      unsigned char *b)
471 {
472 	int i;
473 
474 	/* clear palette */
475 	for (i=0; i < 256; i++) {
476 		r[i] = 0;
477 		g[i] = 0;
478 		b[i] = 0;
479 	}
480 
481 	switch (pcxh->ver) {
482 		case 0:
483 			/* version 2.5 of PC Paint Brush */
484 			for (i=0; i < 16; i++) {
485 				r[i] = pcxh->pal[i*3];
486 				g[i] = pcxh->pal[i*3+1];
487 				b[i] = pcxh->pal[i*3+2];
488 			}
489 			break;
490 		case 2:
491 			if (pcxh->colorplanes != 1) {
492 			    /* version 2.8 of PC Paint Brush with valid Palette */
493 			for (i=0; i < 16; i++) {
494 				r[i] = pcxh->pal[i*3];
495 				g[i] = pcxh->pal[i*3+1];
496 				b[i] = pcxh->pal[i*3+2];
497 			    }
498 			}
499 			else {	/* not sure if this is correct - rjl */
500 				/* mono palette */
501 				r[0] = 0x00; g[0] = 0x00; b[0] = 0x00;
502 				r[1] = 0xff; g[1] = 0xff; b[1] = 0xff;
503 			}
504 			break;
505 		case 3:
506 			/* version 2.8 of PC Paint Brush with no valid Palette */
507 			/* either mono or default */
508 
509 			if (pcxh->colorplanes != 1) {
510 				/* Color default palette - should be checked */
511 				r[0] = 0x00;		g[0] = 0x00;		b[0] = 0x00;
512 				r[1] = 0x80;		g[1] = 0x00; 		b[1] = 0x00;
513 				r[2] = 0x00; 		g[2] = 0x80; 		b[2] = 0x00;
514 				r[3] = 0x80;		g[3] = 0x80;	 	b[3] = 0x00;
515 				r[4] = 0x00;		g[4] = 0x00; 		b[4] = 0x80;
516 				r[5] = 0x80;		g[5] = 0x00; 		b[5] = 0x80;
517 				r[6] = 0x00;		g[6] = 0x80;	 	b[6] = 0x80;
518 				r[7] = 0x80;		g[7] = 0x80; 		b[7] = 0x80;
519 				r[8] = 0xc0;		g[8] = 0xc0;		b[8] = 0xc0;
520 				r[9] = 0xff;		g[9] = 0x00; 		b[9] = 0x00;
521 				r[10] = 0x00; 		g[10] = 0xff; 		b[10] = 0x00;
522 				r[11] = 0xff; 		g[11] = 0xff; 		b[11] = 0x00;
523 				r[12] = 0x00; 		g[12] = 0x00; 		b[12] = 0xff;
524 				r[13] = 0xff; 		g[13] = 0x00; 		b[13] = 0xff;
525 				r[14] = 0x00; 		g[14] = 0xff; 		b[14] = 0xff;
526 				r[15] = 0xff; 		g[15] = 0xff; 		b[15] = 0xff;
527 			}
528 			else {
529 				/* mono palette */
530 				r[0] = 0x00;		g[0] = 0x00;		b[0] = 0x00;
531 				r[1] = 0xff;		g[1] = 0xff; 		b[1] = 0xff;
532 			}
533 			break;
534 		case 5:
535 		default:
536 			/* version 3.0 of PC Paint Brush or Better */
537 			fseek(pcxf, -769L, SEEK_END);
538 			/* if signature byte is correct then read the palette */
539 			/* otherwise copy the existing palette */
540 			if (fgetc(pcxf) == 12) {
541 				for (i=0; i < 256; i++) {
542 					r[i] = fgetc(pcxf);
543 					g[i] = fgetc(pcxf);
544 					b[i] = fgetc(pcxf);
545 				}
546 			}
547 			else {
548 				for (i=0; i < 16; i++) {
549 					r[i] = pcxh->pal[i*3];
550 					g[i] = pcxh->pal[i*3+1];
551 					b[i] = pcxh->pal[i*3+2];
552 				}
553 			}
554 			break;
555 	}
556 }
557 
558 static void
PCXshowpicture(FILE * pcxf,int wide,int high,int bytes,int cp,int bp,unsigned char * r,unsigned char * g,unsigned char * b)559 PCXshowpicture(FILE *pcxf, int wide, int high, int bytes,
560 	       int cp, int bp, unsigned char *r,
561 	       unsigned char *g, unsigned char *b)
562 {
563 	int x;
564 	int y;
565 	int c;
566 	unsigned char *rowa[4];				/* row array */
567 	unsigned char *row;
568 	int p;
569 	unsigned char *pshexa;
570 	int xdiv, xmod, xbit;
571 	int width;
572 	int bytewidth;
573 
574 	bytewidth = tobyte(wide);
575 	width = bytewidth * 8;
576 
577 	/* output the postscript image size preamble */
578 	cmdout("/picstr ");
579 	numout((integer)tobyte(wide));
580 	cmdout("string def");
581 
582 	numout((integer)width);
583 	numout((integer)high);
584 	numout((integer)1);
585 	newline();
586 
587 	cmdout("[");
588 	numout((integer)width);
589 	numout((integer)0);
590 	numout((integer)0);
591 	numout((integer)-high);
592 	numout((integer)0);
593 	numout((integer)0);
594 	cmdout("]");
595 
596 	nlcmdout("{currentfile picstr readhexstring pop} image");
597 
598 	/* allocate the postscript hex output array */
599 	pshexa = (unsigned char *) mymalloc((integer)bytewidth);
600 
601 	/* make sure that you start at the right point in the file */
602 	fseek(pcxf, (long) sizeof(PCXHEAD), SEEK_SET);
603 
604 	/* malloc the lines */
605 	row = (unsigned char *) mymalloc((integer)bytes * cp);
606 	for (c = 0; c < cp; c++)
607 		rowa[c] = row + bytes*c;
608 
609 	for (y = 0; y < high; y++) {
610 		/* clear the postscript hex array */
611 		memset(pshexa,0xff,bytewidth);
612 
613 		/* read in all the color planes for a row of pixels */
614 		PCXreadline(pcxf, rowa[0], bytes*cp);
615 
616 		/* process each pixel */
617 		for (x = 0; x < wide; x++) {
618 			/* build up the pixel value from color plane entries */
619 			p = 0;
620 			xdiv = x>>3;
621 			xmod = 7 - (x&7);
622 			xbit = 1 << xmod;
623 			switch(bp) {
624 				case 1:
625 					for (c = 0; c < cp; c++) {
626 						row = rowa[c];
627 						p |= ( (unsigned)(row[xdiv] & xbit) >> xmod ) << c;
628 					}
629 					break;
630 				case 4:  /* untested - most programs use 1 bit/pixel, 4 planes */
631 					row = rowa[0]; /* assume single plane */
632 					p = ( x & 1 ? row[xdiv] : row[xdiv]>>4 ) & 0x0f;
633 					break;
634 				case 8:
635 					row = rowa[0]; /* assume single plane */
636 					p = (unsigned) (row[x]);
637 					break;
638 				default:
639 					fprintf(stderr, "em:graph: Unable to Decode this PCX file\n");
640 					return;
641 			}
642 			if ((r[p] < 0xff) || (g[p] < 0xff) || (b[p] < 0xff))
643 				pshexa[xdiv] &= (~xbit);
644 			else
645 				pshexa[xdiv] |= xbit;
646 		}
647 		newline();
648 		mhexout(pshexa,(long)bytewidth);
649 	}
650 	free(pshexa);
651 	free(rowa[0]);
652 }
653 
654 static void
imagehead(char * filename,int wide,int high,float emwidth,float emheight)655 imagehead(char *filename, int wide, int high,
656 	  float emwidth, float emheight)
657 {
658 	char *fullname = NULL, *name;
659 	if (!quiet) {
660 #ifdef KPATHSEA
661 	    fullname = (char *)kpse_find_file (filename, pictpath, 0);
662 #endif
663 	    if (!fullname)
664 		name = filename;
665 	    else
666 		name = fullname;
667 	    if (strlen(name) + prettycolumn > STDOUTSIZE) {
668 		fprintf(stderr,"\n");
669 		prettycolumn = 0;
670 	    }
671 	    fprintf(stderr,"<%s",name);
672 	    fflush(stderr);
673 	    prettycolumn += 2+strlen(name);
674 	    if (fullname) free (fullname);
675 	}
676 	hvpos();
677 	nlcmdout("@beginspecial @setspecial");
678 	if (!disablecomments) {
679 		cmdout("%%BeginDocument: em:graph");
680 		cmdout(filename);
681 		newline();
682 	}
683 	/* set the image size */
684 	if (emwidth <= 0.0)  emwidth = (float)wide;
685 	if (emheight <= 0.0)  emheight = (float)high;
686 	floatout(emwidth*72/actualdpi);
687 	floatout(emheight*72/vactualdpi);
688 	newline();
689 	cmdout("scale");
690 #ifdef DEBUG
691 	if (dd(D_SPECIAL)) {
692 	  fprintf(stderr,
693 	    "\nem:graph: %s width  %d pixels scaled to %.1f pixels\n",
694 	    filename, wide, emwidth);
695 	  fprintf(stderr,
696 	    "em:graph: %s height %d pixels scaled to %.1f pixels\n",
697 	    filename, high, emheight);
698    	}
699 #endif
700 }
701 
702 static void
imagetail(void)703 imagetail(void)
704 {
705 	if (!disablecomments) {
706 	    fprintf(bitfile, "\n%%%%EndDocument\n");
707 	    linepos = 0;
708 	}
709 	nlcmdout("@endspecial");
710 	if (!quiet) {
711 	    fprintf(stderr,">");
712 	    fflush(stderr);
713 	}
714 }
715 
716 static void
pcxgraph(FILE * pcxf,char * filename,float emwidth,float emheight)717 pcxgraph(FILE *pcxf, char *filename,
718 	 float emwidth, float  emheight /* dimension in pixels */ )
719 {
720 	PCXHEAD pcxh;
721 	unsigned char red[256];
722 	unsigned char green[256];
723 	unsigned char blue[256];
724 	int wide;
725 	int high;
726 	int bytes;
727 	int cp;
728 	int bpp;
729 
730 	if (!PCXreadhead(pcxf, &pcxh)) {
731 		sprintf(errbuf,"em:graph: Unable to Read Valid PCX Header");
732 		specerror(errbuf);
733 	}
734 	PCXgetpalette(pcxf, &pcxh, red, green, blue);
735 
736 	/* picture size calculation */
737 	wide = (pcxh.xmax - pcxh.xmin) + 1;
738 	high = (pcxh.ymax - pcxh.ymin) + 1;
739 	bytes = pcxh.byteperline;
740 	cp = pcxh.colorplanes;
741 	bpp = pcxh.bitperpix;
742 
743 	imagehead(filename,wide,high,emwidth,emheight);
744 	PCXshowpicture(pcxf, wide, high, bytes, cp, bpp, red, green, blue);
745 	imagetail();
746 }
747 
748 /* Microsoft Paint routines */
749 struct wpnt_1 {
750 	quarterword id[4];
751 	halfword width;
752 	halfword high;
753 	halfword x_asp;
754 	halfword y_asp;
755 	halfword x_asp_prn;
756 	halfword y_asp_prn;
757 	halfword width_prn;
758 	halfword high_prn;
759 	integer chk_sum;
760 	halfword chk_head;
761 };
762 
763 #define WPAINT_1 1
764 #define WPAINT_2 2
765 
766 static void
MSP_2_ps(FILE * f,int wide,int high)767 MSP_2_ps(FILE *f, int wide, int high)
768 {
769 	char *line;
770 	char *l;
771 	int i;
772 	int j;
773 	unsigned char a, b, c;
774 	int d;
775 	int width;
776 	halfword *linelen;
777 
778 	/* an undocumented format - based on a type of run length encoding    */
779 	/* the format is made up of a list of line lengths, followed by a set */
780 	/* of lines. Each line is made up of 2 types of entries:              */
781 	/* 	1) A 3 term entry (0 a b): the byte b is repeated a times     */
782 	/*	2) A variable length entry (a xxxx....xxxx): a bytes are read */
783 	/*	   from the file.                                             */
784 	/* These entries are combined to build up a line                      */
785 
786 	width = tobyte(wide)*8;
787 
788 	/* output the postscript image size preamble */
789 	cmdout("/picstr");
790 	numout((integer)tobyte(wide));
791 	cmdout("string def");
792 
793 	numout((integer)width);
794 	numout((integer)high);
795 	numout((integer)1);
796 
797 	cmdout("[");
798 	numout((integer)width);
799 	numout((integer)0);
800 	numout((integer)0);
801 	numout((integer)-high);
802 	numout((integer)0);
803 	numout((integer)0);
804 	cmdout("]");
805 
806 	nlcmdout("{currentfile picstr readhexstring pop} image");
807 
808 	fseek(f, 32, SEEK_SET);
809 
810 	/* read in the table of line lengths */
811 	linelen = (halfword *) mymalloc((integer)sizeof(halfword) * high);
812 	for (i = 0; i < high; i++) {
813 		linelen[i] = readhalfword(f);
814 		if (feof(f))
815 			return;
816 	}
817 
818 	line = (char *) mymalloc((integer)tobyte(wide));
819 	for (i = 0; i < high; i++) {
820 		memset(line, 0xff, tobyte(wide));
821 		l = line;
822 		if (linelen[i] != 0) {
823 			d = linelen[i];
824 			while (d) {
825 				a = fgetc(f);
826 				d--;
827 				if (a == 0) {
828 					b = fgetc(f);
829 					c = fgetc(f);
830 					d -= 2;
831 					for (j = 0; j < b; j++)
832 						*l++ = c;
833 				}
834 				else {
835 					for (j = 0; j < a; j++)
836 						*l++ = fgetc(f);
837 					d -= j;
838 				}
839 			}
840 		}
841 		newline();
842 		mhexout((unsigned char *) line,(long)tobyte(wide));
843 	}
844 	free(linelen);
845 	free(line);
846 }
847 
848 static void
MSP_1_ps(FILE * f,int wide,int high)849 MSP_1_ps(FILE *f, int wide, int high)
850 {
851 	char *line;
852 	int i;
853 	int width;
854 
855 	width = tobyte(wide)*8;
856 	/* an partly documented format - see The PC Sourcebook                */
857 	/* the format is made up of a simple bitmap.                          */
858 
859 	/* output the postscript image size preamble */
860 	cmdout("/picstr");
861 	numout((integer)tobyte(wide));
862 	cmdout("string def");
863 
864 	numout((integer)width);
865 	numout((integer)high);
866 	numout((integer)1);
867 
868 	cmdout("[");
869 	numout((integer)width);
870 	numout((integer)0);
871 	numout((integer)0);
872 	numout((integer)-high);
873 	numout((integer)0);
874 	numout((integer)0);
875 	cmdout("]");
876 
877 	nlcmdout("{currentfile picstr readhexstring pop} image");
878 
879 	fseek(f, 32, SEEK_SET);
880 
881 	line = (char *) mymalloc((integer)tobyte(wide));
882 	for (i = 0; i < high; i++) {
883 		fread(line, 1, tobyte(wide), f);
884 		newline();
885 		mhexout((unsigned char *) line,(long)tobyte(wide));
886 	}
887 	free(line);
888 }
889 
890 
891 static void
mspgraph(FILE * f,char * filename,float emwidth,float emheight)892 mspgraph(FILE *f, char *filename, float emwidth, float emheight)
893 {
894 	struct wpnt_1 head;
895 	int paint_type = 0;
896 
897         /* read the header of the file and figure out what it is */
898 	fread(head.id, 1, 4, f);
899 	head.width = readhalfword(f);
900 	head.high = readhalfword(f);
901 	head.x_asp = readhalfword(f);
902 	head.y_asp = readhalfword(f);
903 	head.x_asp_prn = readhalfword(f);
904 	head.y_asp_prn = readhalfword(f);
905 	head.width_prn = readhalfword(f);
906 	head.high_prn = readhalfword(f);
907 	head.chk_sum = readinteger(f);
908 	head.chk_head = readhalfword(f);
909 
910 	if (feof(f)) {
911 		fprintf(stderr, "em:graph: Unable to Read Valid MSP Header\n");
912 		return;
913 	}
914 
915         /* check the id bytes */
916 	if (!memcmp(head.id, "DanM", 4))
917         	paint_type = WPAINT_1;
918 	if (!memcmp(head.id, "LinS", 4))
919 		paint_type = WPAINT_2;
920 
921 
922 	imagehead(filename,head.width,head.high,emwidth,emheight);
923 	switch (paint_type) {
924 		case WPAINT_1:
925                 	MSP_1_ps(f, head.width, head.high);
926 			break;
927                 case WPAINT_2:
928                 	MSP_2_ps(f, head.width, head.high);
929 			break;
930 		default:
931 			sprintf(errbuf, "em:graph: Unknown MSP File Type");
932 			specerror(errbuf);
933 	}
934 	imagetail();
935 }
936 
937 /* ------------------------------------------------------------------------ */
938 /* .BMP file structures */
939 struct rgbquad {
940 	char blue;
941 	char green;
942 	char red;
943 	char res;
944 };
945 
946 struct bitmapinfoheader {
947 	integer size;
948 	integer width;
949 	integer height;
950 	halfword planes;			/* must be set to 1 */
951 	halfword bitcount;			/* 1, 4, 8 or 24 */
952 	integer compression;
953 	integer sizeimage;
954 	integer xpelspermeter;
955 	integer ypelspermeter;
956 	integer clrused;
957 	integer clrimportant;
958 };
959 
960 #ifdef WIN32
961 #undef RGB
962 #endif
963 
964 /* constants for the compression field */
965 #define RGB 0L
966 #define RLE8 1L
967 #define RLE4 2L
968 
969 struct bitmapfileheader {
970 	char type[2];
971 	integer size;
972 	halfword reserved1;
973 	halfword reserved2;
974 	integer offbits;
975 };
976 
977 static void
rgbread(FILE * f,int w,int b,char * s)978 rgbread(FILE *f, int w, int b, char *s)
979 {
980 	int i;
981 
982 	/* set the line to white */
983 	memset(s, 0xff, ((w*b)/8)+1);
984 
985 	/* read in all the full bytes */
986 	for (i = 0; i < (w * b) / 8; i++)
987 		*s++ = fgetc(f);
988 
989 	/* read in a partly filled byte */
990 	if ((w * b) % 8) {
991 		i++;
992 		*s++ = fgetc(f);
993 	}
994 
995 	/* check that we are on a 32 bit boundary; otherwise align */
996 	while (i % 4 != 0) {
997 		fgetc(f);
998 		i++;
999 	}
1000 }
1001 
1002 unsigned rle_dx = 0;	/* delta command horizontal offset */
1003 unsigned rle_dy = 0;	/* delta command vertical offset */
1004 
1005 /* checked against output from Borland Resource Workshop */
1006 static void
rle4read(FILE * f,int w,int b,char * s)1007 rle4read(FILE *f, int w, int b, char *s)
1008 {
1009 	int i;
1010 	int limit;
1011 	int ch;
1012 	unsigned cnt;
1013 	int hi;
1014 
1015 	limit = (w*b)/8;
1016 	i = 0;
1017 	hi = TRUE;
1018 	/* set the line to white */
1019 	memset(s, 0xff, limit+1);
1020 
1021 	if (rle_dy) {
1022 	    rle_dy--;
1023 	    return;
1024 	}
1025 
1026 	if (rle_dx) {
1027 	    for (; rle_dx>1; rle_dx-=2) {
1028 		s++;
1029 		i++;
1030 	    }
1031 	    if (rle_dx)
1032 	    	hi = FALSE;
1033 	}
1034 
1035 	while (i<=limit) {
1036 	    cnt = fgetc(f);
1037 	    ch  = fgetc(f);
1038 	    if (cnt == 0) { /* special operation */
1039 		switch(ch) {
1040 		    case 0:	/* EOL */
1041 			return;	/* this is our way out */
1042 		    case 1:	/* End of Bitmap */
1043 		    	return;
1044 		    case 2:	/* Delta */  /* untested */
1045 			rle_dx = fgetc(f) + i*2 + (hi ? 1 : 0);
1046 			rle_dy = fgetc(f);
1047 			return;
1048 		    default:	/* next cnt bytes are absolute */
1049 		    	/* must be aligned on word boundary */
1050 			if (!hi)
1051 				fprintf(stderr,"em:graph: RLE4 absolute is not byte aligned\n");
1052 			for (cnt = ch; cnt>0 && i<=limit; cnt-=2) {
1053 		    	    i++;
1054 			    *s++ = fgetc(f);
1055 			}
1056 			if (ch % 4)	/* word align file */
1057 			    fgetc(f);
1058   		}
1059 	    }
1060 	    else {   /* cnt is repeat count */
1061 		if (!hi) {   /* we are about to place the low 4 bits */
1062 		    ch = ((ch>>4)&0x0f) | ((ch<<4)&0xf0); /* swap order */
1063 		    i++;
1064 		    *s = (*s & 0xf0) | (ch & 0x0f);
1065                     s++;
1066 		    hi = TRUE;
1067 		    cnt--;
1068 		}
1069 		/* we are about to place the high 4 bits */
1070 		for (; cnt>1 && i<=limit; cnt-=2) { /* place the whole bytes */
1071 		    i++;
1072 		    *s++ = ch;
1073 	        }
1074 		if (cnt) { /* place the partial byte */
1075 		    *s = (*s & 0x0f) | (ch & 0xf0);
1076 		    hi = FALSE;
1077 		}
1078 	    }
1079   	}
1080 }
1081 
1082 /* untested */
1083 static void
rle8read(FILE * f,int w,int b,char * s)1084 rle8read(FILE *f, int w, int b, char *s)
1085 {
1086 	int i;
1087 	int limit;
1088 	int ch;
1089 	unsigned cnt;
1090 
1091 	limit = (w*b)/8;
1092 	i = 0;
1093 	/* set the line to white */
1094 	memset(s, 0xff, limit+1);
1095 
1096 	if (rle_dy) {
1097 	    rle_dy--;
1098 	    return;
1099 	}
1100 
1101 	if (rle_dx) {
1102 	    for (; rle_dx > 0; rle_dx--) {
1103 		s++;
1104 		i++;
1105 	    }
1106 	}
1107 
1108 	while (i<=limit) {
1109 	    cnt = fgetc(f);
1110 	    ch  = fgetc(f);
1111 	    if (cnt == 0) { /* special operation */
1112 		switch(ch) {
1113 		    case 0:	/* EOL */
1114 			return;	/* this is our way out */
1115 		    case 1:	/* End of Bitmap */
1116 			return;
1117 		    case 2:	/* Delta */  /* untested */
1118 			rle_dx = fgetc(f) + i;
1119 			rle_dy = fgetc(f);
1120 			return;
1121 		    default:	/* next cnt bytes are absolute */
1122 			for (cnt = ch; cnt>0 && i<=limit; cnt--) {
1123 		    	    i++;
1124 			    *s++ = fgetc(f);
1125 		        }
1126 			if (ch % 2)	/* word align file */
1127 			    fgetc(f);
1128 		}
1129 	    }
1130 	    else { /* cnt is repeat count */
1131 		for (; cnt>0 && i<=limit; cnt--) {
1132 		    i++;
1133 		    *s++ = ch;
1134 		}
1135 	    }
1136 	}
1137 }
1138 
1139 static void
bmpgraph(FILE * f,char * filename,float emwidth,float emheight)1140 bmpgraph(FILE *f, char *filename, float emwidth, float emheight)
1141 {
1142 	struct bitmapfileheader bmfh;
1143 	struct bitmapinfoheader bmih;
1144 
1145 	unsigned char isblack[256];
1146 	unsigned char rr;
1147 	unsigned char gg;
1148 	unsigned char bb;
1149 	unsigned char c = 0;
1150 
1151 	char *line;
1152 	char *pshexa;
1153 
1154 	int clrtablesize;
1155 	int i;
1156 	int j;
1157 
1158 	unsigned char omask;
1159 	int oroll;
1160 
1161 	unsigned char emask = 0;
1162 	integer ewidth = 0;
1163 	int isOS2;
1164 
1165         /* read the header of the file */
1166 	fread(bmfh.type, 1, 2, f);
1167 	bmfh.size = readinteger(f);
1168 	bmfh.reserved1 = readhalfword(f);
1169 	bmfh.reserved2 = readhalfword(f);
1170 	bmfh.offbits = readinteger(f);
1171 	if (feof(f)) {
1172 		sprintf(errbuf, "em:graph: Unable to Read Valid BMP Header\n");
1173 		specerror(errbuf);
1174 		return;
1175 	}
1176 
1177 	bmih.size = readinteger(f);
1178 	if (bmih.size == 12) { /* OS2 bitmap */
1179 		isOS2 = TRUE;
1180 		bmih.width = readhalfword(f);
1181 		bmih.height = readhalfword(f);
1182 		bmih.planes = readhalfword(f);
1183 		bmih.bitcount = readhalfword(f);
1184 		/* the following don't exist in OS2 format so fill with 0's */
1185 		bmih.compression = RGB;
1186 		bmih.sizeimage = 0;
1187 		bmih.xpelspermeter = 0;
1188 		bmih.ypelspermeter = 0;
1189 		bmih.clrused = 0;
1190 		bmih.clrimportant = 0;
1191 	}
1192 	else { /* Windows bitmap */
1193 		isOS2 = FALSE;
1194 		bmih.width = readinteger(f);
1195 		bmih.height = readinteger(f);
1196 		bmih.planes = readhalfword(f);
1197 		bmih.bitcount = readhalfword(f);
1198 		bmih.compression = readinteger(f);
1199 		bmih.sizeimage = readinteger(f);
1200 		bmih.xpelspermeter = readinteger(f);
1201 		bmih.ypelspermeter = readinteger(f);
1202 		bmih.clrused = readinteger(f);
1203 		bmih.clrimportant = readinteger(f);
1204 	}
1205 
1206 	if (feof(f)) {
1207 		sprintf(errbuf, "em:graph: Unable to Read Valid BMP Info");
1208 		specerror(errbuf);
1209 		return;
1210 	}
1211 
1212 	if (memcmp(bmfh.type, "BM", 2)) {
1213 		sprintf(errbuf, "em:graph: Unknown BMP File Type");
1214 		specerror(errbuf);
1215 		return;
1216 	}
1217 
1218 	if ((bmih.compression == RLE4) && (bmih.bitcount != 4)) {
1219 		sprintf(errbuf, "em:graph: Can't do BMP RLE4 with %d bits per pixel",
1220 			bmih.bitcount);
1221 		specerror(errbuf);
1222 		return;
1223 	}
1224 
1225 	if ((bmih.compression == RLE8) && (bmih.bitcount != 8)) {
1226 		sprintf(errbuf, "em:graph: Can't do BMP RLE8 with %d bits per pixel\n",
1227 			bmih.bitcount);
1228 		specerror(errbuf);
1229 		return;
1230 	}
1231 
1232 	imagehead(filename,(int)bmih.width,(int)bmih.height,emwidth,emheight);
1233 
1234 	/* determine the size of the color table to read */
1235 	clrtablesize = 0;
1236 	if (bmih.clrused == 0) {
1237 		switch (bmih.bitcount) {
1238 			case 1:
1239 				clrtablesize = 2;
1240 				break;
1241 			case 4:
1242 				clrtablesize = 16;
1243 				break;
1244 			case 8:
1245 				clrtablesize = 256;
1246 				break;
1247 			case 24:
1248 				break;
1249 		}
1250 	}
1251         else
1252 		clrtablesize = bmih.clrused;
1253 
1254 	/* read in the color table */
1255 	for (i = 0; i < clrtablesize; i++) {
1256 		bb = fgetc(f);
1257 		gg = fgetc(f);
1258 		rr = fgetc(f);
1259 		isblack[i] = (rr < 0xff) || (gg < 0xff) || (bb < 0xff);
1260 		if (!isOS2)
1261 			(void) fgetc(f);
1262 	}
1263 
1264 	line = (char *) mymalloc((integer)((bmih.width * bmih.bitcount) / 8) + 1);
1265 	pshexa = (char *) mymalloc((integer)tobyte(bmih.width));
1266 
1267 	/* output the postscript image size preamble */
1268 	cmdout("/picstr");
1269 	numout((integer)tobyte(bmih.width));
1270 	cmdout("string def");
1271 
1272 	numout((integer)bmih.width);
1273 	numout((integer)bmih.height);
1274 	numout((integer)1);
1275 
1276 	cmdout("[");
1277 	numout((integer)bmih.width);
1278 	numout((integer)0);
1279 	numout((integer)0);
1280 	numout((integer)bmih.height);
1281 	numout((integer)0);
1282 	numout((integer)bmih.height);
1283 	cmdout("]");
1284 
1285 	nlcmdout("{currentfile picstr readhexstring pop} image");
1286 
1287 	if (bmih.bitcount == 1) {
1288 		if (bmih.width%8)
1289 			emask = (1<<(8-(bmih.width%8)))-1;	/* mask for edge of bitmap */
1290 		else
1291 			emask = 0;
1292 		ewidth = tobyte(bmih.width);
1293 	}
1294 
1295 	/* read in all the lines of the file */
1296 	for (i = 0; i < bmih.height; i++) {
1297 		memset(pshexa,0xff,tobyte(bmih.width));
1298 		switch (bmih.compression) {
1299 		    case RGB:
1300 			rgbread(f, (int) bmih.width, (int) bmih.bitcount, line);
1301 			break;
1302 		    case RLE4:
1303 			rle4read(f, (int) bmih.width, (int) bmih.bitcount, line);
1304 			break;
1305 		    case RLE8:
1306 			rle8read(f, (int) bmih.width, (int) bmih.bitcount, line);
1307 			break;
1308 		    default:
1309 			sprintf(errbuf,"em:graph: Unknown BMP compression\n");
1310 			specerror(errbuf);
1311 			return;
1312 		}
1313 
1314 		omask = 0x80;
1315 		oroll = 7;
1316 
1317 		if (bmih.bitcount == 1) {
1318 		    if (isblack[0])
1319 			for (j = 0; j < ewidth; j++)
1320 				pshexa[j] = line[j];
1321 		    else
1322 			for (j = 0; j < ewidth; j++)
1323 				pshexa[j] = ~line[j];
1324 		    pshexa[ewidth-1] |= emask;
1325 		}
1326 		else {
1327 		    for (j = 0; j < bmih.width; j++) {
1328 			switch (bmih.bitcount) {
1329 				case 4:
1330 					c = line[j>>1];
1331 					if (!(j&1))
1332 						c >>= 4;
1333 					c = isblack[ c & 0x0f ];
1334 					break;
1335 				case 8:
1336 					c = isblack[ (int)(line[j]) ];
1337 					break;
1338 				case 24:
1339 					rr = line[j*3];
1340 					gg = line[j*3+1];
1341 					bb = line[j*3+2];
1342 					c = (rr < 0xff) || (gg < 0xff) || (bb < 0xff);
1343 					break;
1344 			}
1345 			if (c)
1346 			    pshexa[j/8] &= ~omask;
1347 			else
1348 			    pshexa[j/8] |= omask;
1349 			oroll--;
1350 			omask >>= 1;
1351 			if (oroll < 0) {
1352 			    omask = 0x80;
1353 			    oroll = 7;
1354 			}
1355 		    }
1356 		}
1357 		newline();
1358 		mhexout((unsigned char *) pshexa,(long)tobyte(bmih.width));
1359 	}
1360 	imagetail();
1361 	free(pshexa);
1362 	free(line);
1363 }
1364 /* ------------------------------------------------------------------------ */
1365 
1366 #define PCX 0
1367 #define MSP 1
1368 #define BMP 2
1369 const char *extarr[]=
1370 { ".pcx", ".msp", ".bmp", NULL };
1371 
1372 static void
emgraph(char * filename,float emwidth,float emheight)1373 emgraph(char *filename, float emwidth, float emheight)
1374 {
1375 	char fname[500];
1376 	int filetype;
1377 	FILE *f;
1378 	char *env;
1379 	char id[4];
1380 	int i;
1381 
1382 	strcpy(fname, filename);
1383 
1384 	/* find the file */
1385 	f = search(figpath, fname, READBIN);
1386 	if (f == (FILE *)NULL) {
1387    	    if ( (env = getenv("DVIDRVGRAPH")) != NULL )
1388 #ifdef KPATHSEA
1389 		f = search((kpse_file_format_type)env,filename,READBIN);
1390 #else
1391 		f = search(env,filename,READBIN);
1392 #endif
1393 	}
1394 	/* if still haven't found it try adding extensions */
1395 	if (f == (FILE *)NULL) {
1396 	    i = 0;
1397 	    while (extarr[i] != NULL) {
1398 		strcpy(fname, filename);
1399 		strcat(fname, extarr[i]);
1400 		f = search(figpath, fname, READBIN);
1401 		if (f == (FILE *)NULL) {
1402 	    	    if ( (env = getenv("DVIDRVGRAPH")) != NULL )
1403 #ifdef KPATHSEA
1404 			f = search((kpse_file_format_type)env,filename,READBIN);
1405 #else
1406 			f = search(env,filename,READBIN);
1407 #endif
1408 		}
1409 		if (f != (FILE *)NULL)
1410 		    break;
1411 		i++;
1412 	    }
1413 	}
1414 
1415 	filetype = -1;
1416 	if (f != (FILE *)NULL) {
1417 	    for (i=0; i<4; i++) {
1418 		id[i] = readquarterword(f);
1419 	    }
1420 	    if ( (id[0] == 0x0a) && (id[2] == 0x01) )
1421 		filetype = PCX;
1422 	    if (!memcmp(id, "DanM", 4))
1423 		filetype = MSP;
1424 	    if (!memcmp(id, "LinS", 4))
1425 		filetype = MSP;
1426 	    if (!memcmp(id, "BM", 2))
1427 		filetype = BMP;
1428 	    fseek(f, 0L, SEEK_SET);
1429 	}
1430 
1431 	switch (filetype) {
1432 		case PCX:
1433 			pcxgraph(f, fname, emwidth, emheight);
1434 			break;
1435 		case MSP:
1436 			mspgraph(f, fname, emwidth, emheight);
1437 			break;
1438 		case BMP:
1439 			bmpgraph(f, fname, emwidth, emheight);
1440 			break;
1441 		default:
1442 			snprintf(fname, sizeof(fname),
1443                                  "em:graph: %s: File not found", filename);
1444 			error(fname);
1445 	}
1446 	if (f != (FILE *)NULL)
1447 	    close_file(f);
1448 }
1449 
1450 #else
1451 void
emspecial(char * p)1452 emspecial(char *p)
1453 {
1454 	sprintf(errbuf,"emTeX specials not compiled in this version");
1455 	specerror(errbuf);
1456 }
1457 #endif /* EMTEX */
1458