summaryrefslogtreecommitdiff
path: root/dviware/textool/dvistuff.c
blob: 513c08938a671696c71d879ada5fa10c05fafe2b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
/*
 * This is the DVI related part of TeXtool
 */

/*
 * This code has quite a long history.
 * The header comment from the dvi2ps driver from the TeX tape I
 * received about August 86 is shown below
 */

/*
 *
 * AUTHOR(s)
 *	 Mark Senn wrote the early versions of this program for the
 *	 BBN BitGraph.  Stephan Bechtolsheim, Bob Brown, Richard
 *	 Furuta, James Schaad and Robert Wells improved it.  Norm
 *	 Hutchinson ported the program to the Sun.  Neal Holtz ported
 *	 it to the Apollo, and from there to producing PostScript
 *	 output. Scott Jones added intelligent font substitution.
 *
 */

/*
 * This version presumably diverged from the dvi2ps line before the
 * move to Apollo and was then modified by Y. Ledru (yl@lln-cs)
 * to work with SunView.
 * A bugfix from dvi2ps to do with marking font files closed when they
 * are removed from the cache has been "bought back" into this version.
 * The font data structures have also been changed so they are
 * cross-linked so no searching has to be done except to find the
 * least used cache entry.
 * Extra tests for valid data values have been put into LoadAChar()
 * as a bogus PXL file was causing havoc by overfilling a character
 * pixrect.
 * Much other tidying up and removal of code which was no longer used
 * has also been done
 * Peter Ilieve - peter@memex.co.uk
 */

#include "defs.h"
#include "commands.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <pixrect/pixrect_hs.h>
char *index();
char *calloc();
char *rindex();
char *sprintf();
char *strcpy();

/* procedures in sunstuff */
extern void		BatchStart();
extern void		BatchEnd();
extern void		Fatal();
extern void		SetBop();
extern void		SetChar();
extern void		SetRule();
extern void		Warning();

/* procedures in pxlstuff or pkstuff */
extern void		FindFontFile();
extern void		LoadAChar();
extern void		ReadCharDefs();

/* procedures here */
float		ActualFactor();
FILE*		BINARYOPEN();
void		CloseDviFile();
int		DoConv();
void		DoPage();
Boolean DviFileChanged();
void		FindPostAmblePtr();
void		FreeFontStorage();
void		GetBytes();
int		NoSignExtend();
void		OpenDviFile();
FILE		*OpenFontFile();
int		ReadFontDef();
void		ReadPagePointers();
void		ReadPreAmble();
void		ReadPostAmble();
void		SetFntNum();
int		SignExtend();
void		SkipFontDef();
#ifdef DEBUG
void		ShowPxlCache();
void		ShowPxlFd();
#endif

/* a few global variables and data structures */
#include "globals.h"

struct pixel_list
{
	FILE *pixel_file_id;		/* file identifier */
	struct font_entry *feptr;		/* font_entry for this cache slot */
	int use_count;			  /* count of "opens" */
};

struct font_entry *fontptr;	 /* font_entry pointer */
struct font_entry *hfontptr=NULL;/* font_entry pointer to head of chain */
struct font_entry *pfontptr = NULL; /* previous font_entry pointer */
int nopen = 0;						/* number of open font files */
struct pixel_list pixel_files[MAXOPEN+1];
								/* list of open font file identifiers */
								/* slot 0 not used */

/*
 * DVI file related data structures
 */

/* pagepointers moved to globals to let sunstuff get at count_0 */

								/* two structs to hold pre and postamble */
								/* a lot of this is not used */
struct Preamble
{
	unsigned int num;
	unsigned int den;
	unsigned int mag;
} preamble;

struct Postamble
{
	long last_page_ptr;
	unsigned int num;
	unsigned int den;
	unsigned int mag;
	unsigned int maxheight;
	unsigned int maxwidth;
	unsigned short maxstack;
	unsigned short totalpages;
} postamble;

FILE *dvifp;						/* DVI file pointer */
static time_t dvimodtime;

struct stack_entry {  /* stack entry */
		int h, v, w, x, y, z;  /* what's on stack */
};
struct stack_entry stack[STACKSIZE];   /* stack */
int sp;					/* stack pointer */

						/* h and v are global */
int w;								/* current horizontal spacing */
int x;								/* current horizontal spacing */
int y;								/* current vertical spacing */
int z;								/* current vertical spacing */

/* display related stuff */

int hconv, vconv;				/* converts DVI units to pixels */

/* now to the real code */

/*-->ActualFactor*/
/**********************************************************************/
/**************************  ActualFactor  ****************************/
/**********************************************************************/

float				/* compute the actual size factor given the approximation */
ActualFactor(unmodsize)
int unmodsize;  /* actually factor * 1000 */
{
	float realsize;		/* the actual magnification factor */

	realsize = (float)unmodsize / 1000.0;
	/* a real hack to correct for rounding in some cases--rkf */
	if(unmodsize==1095) realsize = 1.095445;		/*stephalf*/
	else if(unmodsize==1315) realsize=1.314534;		/*stepihalf*/
	else if(unmodsize==2074) realsize=2.0736;		/*stepiv*/
	else if(unmodsize==2488) realsize=2.48832;  /*stepv*/
	else if(unmodsize==2986) realsize=2.985984;		/*stepiv*/
	/* the remaining magnification steps are represented with sufficient
		   accuracy already */
	return(realsize);
}


/*-->CloseDviFile*/
/**********************************************************************/
/************************** CloseDviFile  ******************************/
/**********************************************************************/

void
CloseDviFile()
{
	if (dvifp != NULL)
		fclose(dvifp);
	if (pagepointers != NULL) {
		free (pagepointers);
		pagepointers = NULL;
	}
}


/*-->DoConv*/
/**********************************************************************/
/******************************  DoConv  ******************************/
/**********************************************************************/

int
DoConv(num, den, mag, convResolution)
{
	register float conv;
	conv = ((float)num/(float)den) * 
#ifdef USEGLOBALMAG
		ActualFactor(mag) *
#endif
		((float)convResolution/254000.0);
	return((int) (1.0 / conv + 0.5));
}


/*-->DoPage*/
/**********************************************************************/
/******************************  DoPage  ******************************/
/**********************************************************************/

void
DoPage(pagenumber)
int pagenumber;
{
	unsigned char command;
	int val, val2;
	int k;

#ifdef DEBUG
	if (Debug)
		fprintf(stderr,"DoPage(%d)\n", pagenumber);
#endif
	if (!(main_state & SB_INTERPRET))
		return;
	h = v = w = x = y = z = 0;		/* zero position */
	sp = 0;						/* empty stack */
	fontptr = NULL;				/* no font */
	fseek(dvifp, pagepointers[pagenumber].page_ptr, 0); /* go to correct page */
	SetBop();						/* clear canvas */
	if (Batching)
		BatchStart();
	while (main_state & SB_INTERPRET)				/* interpret DVI file */

								/* we use getc here for speed */
								/* also force a complete jump table */
		switch (command=getc(dvifp)) {

		case SETC_000: case SETC_001: case SETC_002: case SETC_003:
		case SETC_004: case SETC_005: case SETC_006: case SETC_007:
		case SETC_008: case SETC_009: case SETC_010: case SETC_011:
		case SETC_012: case SETC_013: case SETC_014: case SETC_015:
		case SETC_016: case SETC_017: case SETC_018: case SETC_019:
		case SETC_020: case SETC_021: case SETC_022: case SETC_023:
		case SETC_024: case SETC_025: case SETC_026: case SETC_027:
		case SETC_028: case SETC_029: case SETC_030: case SETC_031:
		case SETC_032: case SETC_033: case SETC_034: case SETC_035:
		case SETC_036: case SETC_037: case SETC_038: case SETC_039:
		case SETC_040: case SETC_041: case SETC_042: case SETC_043:
		case SETC_044: case SETC_045: case SETC_046: case SETC_047:
		case SETC_048: case SETC_049: case SETC_050: case SETC_051:
		case SETC_052: case SETC_053: case SETC_054: case SETC_055:
		case SETC_056: case SETC_057: case SETC_058: case SETC_059:
		case SETC_060: case SETC_061: case SETC_062: case SETC_063:
		case SETC_064: case SETC_065: case SETC_066: case SETC_067:
		case SETC_068: case SETC_069: case SETC_070: case SETC_071:
		case SETC_072: case SETC_073: case SETC_074: case SETC_075:
		case SETC_076: case SETC_077: case SETC_078: case SETC_079:
		case SETC_080: case SETC_081: case SETC_082: case SETC_083:
		case SETC_084: case SETC_085: case SETC_086: case SETC_087:
		case SETC_088: case SETC_089: case SETC_090: case SETC_091:
		case SETC_092: case SETC_093: case SETC_094: case SETC_095:
		case SETC_096: case SETC_097: case SETC_098: case SETC_099:
		case SETC_100: case SETC_101: case SETC_102: case SETC_103:
		case SETC_104: case SETC_105: case SETC_106: case SETC_107:
		case SETC_108: case SETC_109: case SETC_110: case SETC_111:
		case SETC_112: case SETC_113: case SETC_114: case SETC_115:
		case SETC_116: case SETC_117: case SETC_118: case SETC_119:
		case SETC_120: case SETC_121: case SETC_122: case SETC_123:
		case SETC_124: case SETC_125: case SETC_126: case SETC_127:
			SetChar(&(fontptr->ch[command - SETC_000]), SETCMD);
			break;

		case SET1:case SET2:case SET3:case SET4:
			val = NoSignExtend(dvifp, command-SET1+1);
			SetChar(&(fontptr->ch[val]), SETCMD);
			break;

		case SET_RULE:
			val = NoSignExtend(dvifp, 4);
			val2 = NoSignExtend(dvifp, 4);
			SetRule(val, val2, SETCMD);
			break;

		case PUT1:case PUT2:case PUT3:case PUT4:
			val = NoSignExtend(dvifp,command-PUT1+1);
			SetChar(&(fontptr->ch[val]), PUTCMD);
			break;

		case PUT_RULE:
			val = NoSignExtend(dvifp, 4);
			val2 = NoSignExtend(dvifp, 4);
			SetRule(val, val2, PUTCMD);
			break;

		case NOP:
			break;

		case BOP:
			Fatal("BOP encountered in page");
			break;

		case EOP:
			if (Batching)
				BatchEnd();
#ifdef DEBUG
			if (Debug)
				fprintf(stderr,"DoPage return after EOP found\n");
#endif
			return;

		case PUSH:
			if (sp >= STACKSIZE)
				Fatal("stack overflow");
			else {
				stack[sp].h = h;
				stack[sp].v = v;
				stack[sp].w = w;
				stack[sp].x = x;
				stack[sp].y = y;
				stack[sp].z = z;
				sp++;
			}
			break;

		case POP:
			--sp;
			if (sp < 0)
				Fatal("stack underflow");
			else {
				h = stack[sp].h;
				v = stack[sp].v;
				w = stack[sp].w;
				x = stack[sp].x;
				y = stack[sp].y;
				z = stack[sp].z;
			}
			break;

		case RIGHT1:case RIGHT2:case RIGHT3:case RIGHT4:
			val = SignExtend(dvifp,command-RIGHT1+1);
			MoveOver(val);
			break;

		case W0:
			MoveOver(w);
			break;

		case W1:case W2:case W3:case W4:
			w = SignExtend(dvifp,command-W1+1);
			MoveOver(w);
			break;

		case X0:
			MoveOver(x);
			break;

		case X1:case X2:case X3:case X4:
			x = SignExtend(dvifp,command-X1+1);
			MoveOver(x);
			break;

		case DOWN1:case DOWN2:case DOWN3:case DOWN4:
			val = SignExtend(dvifp,command-DOWN1+1);
			MoveDown(val);
			break;

		case Y0:
			MoveDown(y);
			break;

		case Y1:case Y2:case Y3:case Y4:
			y = SignExtend(dvifp,command-Y1+1);
			MoveDown(y);
			break;

		case Z0:
			MoveDown(z);
			break;

		case Z1:case Z2:case Z3:case Z4:
			z = SignExtend(dvifp,command-Z1+1);
			MoveDown(z);
			break;

		case FONT_00: case FONT_01: case FONT_02: case FONT_03:
		case FONT_04: case FONT_05: case FONT_06: case FONT_07:
		case FONT_08: case FONT_09: case FONT_10: case FONT_11:
		case FONT_12: case FONT_13: case FONT_14: case FONT_15:
		case FONT_16: case FONT_17: case FONT_18: case FONT_19:
		case FONT_20: case FONT_21: case FONT_22: case FONT_23:
		case FONT_24: case FONT_25: case FONT_26: case FONT_27:
		case FONT_28: case FONT_29: case FONT_30: case FONT_31:
		case FONT_32: case FONT_33: case FONT_34: case FONT_35:
		case FONT_36: case FONT_37: case FONT_38: case FONT_39:
		case FONT_40: case FONT_41: case FONT_42: case FONT_43:
		case FONT_44: case FONT_45: case FONT_46: case FONT_47:
		case FONT_48: case FONT_49: case FONT_50: case FONT_51:
		case FONT_52: case FONT_53: case FONT_54: case FONT_55:
		case FONT_56: case FONT_57: case FONT_58: case FONT_59:
		case FONT_60: case FONT_61: case FONT_62: case FONT_63:
			SetFntNum(command - FONT_00);
			break;

		case FNT1:case FNT2:case FNT3:case FNT4:
			SetFntNum(NoSignExtend(dvifp, command-FNT1+1));
			break;

		case XXX1:case XXX2:case XXX3:case XXX4:
			k = NoSignExtend(dvifp,command-XXX1+1);
			while (k--)
				getc(dvifp);
			break;

		case FNT_DEF1:case FNT_DEF2:case FNT_DEF3:case FNT_DEF4:
			k = NoSignExtend(dvifp, command-FNT_DEF1+1);
			SkipFontDef (k);		/* always read from postamble */
			break;

		case PRE:
			Fatal("PRE occurs within file");
			break;

		case POST:
			Fatal("POST found before EOP");
			break;

		case POST_POST:
 			Fatal("POST_POST with no preceding POST");
			break;

		case UNDEF_00: case UNDEF_01: case UNDEF_02: case UNDEF_03:
		case UNDEF_04: case UNDEF_05:
		default:
			Fatal("%d is an undefined command", command);
			break;

		}
		if (Batching)
			BatchEnd();		/* to catch cases when stop in mid page */
}


/*-->DviFileChanged*/
/**********************************************************************/
/************************  DviFileChanged  ****************************/
/**********************************************************************/

Boolean
DviFileChanged()
{
		struct stat statbuf;

		if (main_state & (SB_NOFILE | SB_NODVIFILE))	/* can't do fstat */
				return (FALSE);
		fstat(fileno(dvifp), &statbuf);
		if (statbuf.st_mtime > dvimodtime) {
				dvimodtime = statbuf.st_mtime;
				return (TRUE);
		}
		else
				return (FALSE);
}


/*-->FindPostAmblePtr*/
/**********************************************************************/
/************************  FindPostAmblePtr  **************************/
/**********************************************************************/

void
FindPostAmblePtr(postambleptr)
long		*postambleptr;

/* this routine will move to the end of the file and find the start
	of the postamble */

{
	int	 i;

	fseek (dvifp, (long) 0, 2);   /* goto end of file */
	*postambleptr = ftell (dvifp) - 4;
	fseek (dvifp, *postambleptr, 0);

	while (TRUE) {
		fseek (dvifp, --(*postambleptr), 0);
		if (((i = NoSignExtend(dvifp, 1)) != 223) && (i != DVIFORMAT)) {
			Fatal ("Bad end of DVI file");
			return;
		}
		if (i == DVIFORMAT)
			break;
	}
	fseek (dvifp, (*postambleptr) - 4, 0);
	(*postambleptr) = NoSignExtend(dvifp, 4);
	fseek (dvifp, *postambleptr, 0);
}


/*-->FreeFontStorage*/
/**********************************************************************/
/****************************  FreeFontStorage  ***********************/
/**********************************************************************/

void
FreeFontStorage()
{
	register struct font_entry *tfontptr;
	register struct char_entry *tcharptr;
	register int i;

	while (hfontptr != NULL) {
		tfontptr = hfontptr->next;
								/* close open font file */
		if (hfontptr->cache_slot != NOTCACHED)
			fclose(pixel_files[hfontptr->cache_slot].pixel_file_id);
								/* free all memory pixrects for chars */
		if (hfontptr->has_been_opened == TRUE) {
			for (i = FIRSTPXLCHAR; i <= LASTPXLCHAR; i++) {
				tcharptr = &(hfontptr->ch[i]);
				if (tcharptr->where.isloaded == TRUE)
					pr_destroy(tcharptr->where.address.pixrectptr);
			}
		}
								/* free font_entry struct */
		free(hfontptr);
		hfontptr = tfontptr;
	}
	pfontptr = NULL;
	nopen = 0;						/* zero font cache count */
}


/*-->GetBytes*/
/**********************************************************************/
/*****************************  GetBytes  *****************************/
/**********************************************************************/

void
GetBytes(fp, cp, n)		/* get n bytes from file fp */
register FILE *fp;		/* file pointer */
register char *cp;		/* character pointer */
register int n;				/* number of bytes */

{
	while (n--)
		*cp++ = getc(fp);
}


/*-->NoSignExtend*/
/**********************************************************************/
/***************************  NoSignExtend  ***************************/
/**********************************************************************/

int
NoSignExtend(fp, n)		/* return n byte quantity from file fd */
register FILE *fp;		/* file pointer */
register int n;				/* number of bytes */

{
	register int x;		/* number being constructed */

	x = 0;
	while (n--) {
		x <<= 8;
		x |= getc(fp);
	}
	return(x);
}


/*-->OpenDviFile*/
/**********************************************************************/
/************************** OpenDviFile  ******************************/
/**********************************************************************/

void
OpenDviFile(dviname)
char *dviname;
{
	if (main_state & (SB_NOFILE | SB_NODVIFILE))
		return;						/* don't even try */
	if ((dvifp=BINARYOPEN(dviname,"r")) == NULL) {
		Fatal("Can't open \"%s\"", dviname);
		return;
	}
	ReadPreAmble();
#ifdef USEGLOBALMAG
	if (Mflag)
		preamble.mag = user_mag;
#endif
	ReadPostAmble();
#ifdef USEGLOBALMAG
	if (Mflag)
		postamble.mag = user_mag;
#endif
	ReadPagePointers();
	if (postamble.maxstack >= STACKSIZE) {
		Fatal ("Stack size is too small for \"%s\"", dviname);
		return;
	}
	if ((preamble.num != postamble.num) ||
		(preamble.den != postamble.den) ||
		(preamble.mag != postamble.mag)) {
		Fatal("Preamble-Postamble mismatch in \"%s\"", dviname);
		return;
	}
	totalpages = postamble.totalpages;
	hconv = DoConv(preamble.num, preamble.den, preamble.mag, RESOLUTION);
	vconv = DoConv(preamble.num, preamble.den, preamble.mag, RESOLUTION);
	dvimodtime = 0;		/* to force DviFileChanged() to set it */
	(void)DviFileChanged();
#ifdef DEBUG
	if (Debug) fprintf(stderr,"DVI file open OK, total pages = %d\n",
						totalpages);
#endif
}


/*-->OpenFontFile*/
/**********************************************************************/
/************************** OpenFontFile  *****************************/
/**********************************************************************/

FILE *
OpenFontFile()
/***********************************************************************
	The original version of this dvi driver reopened the font file  each
	time the font changed, resulting in an enormous number of relatively
	expensive file  openings.   This version  keeps  a cache  of  up  to
	MAXOPEN open files,  so that when  a font change  is made, the  file
	pointer returned can  usually be  updated from the  cache.  When  the
	file is not found in  the cache, it must  be opened.  In this  case,
	the next empty slot  in the cache  is assigned, or  if the cache  is
	full, the least used font file is closed and its slot reassigned for
	the new file.  Identification of the least used file is based on the
	counts of the number  of times each file  has been "opened" by  this
	routine.  On return, the file pointer is always repositioned to  the
	beginning of the file.

***********************************************************************/
{
	register int i,least_used,current;
	FILE *fontfp;

#ifdef DEBUG
	if (ExtraDebug) fprintf(stderr,"Open Font file:\n");
#endif
	if (pfontptr == fontptr)
	{
	pixel_files[fontptr->cache_slot].use_count++; /* update reference count */
#ifdef DEBUG
	if (ExtraDebug) fprintf(stderr,"quick return (k = %d)\n",
		fontptr->k);
#endif
	return (pixel_files[fontptr->cache_slot].pixel_file_id);
	}

	if ((current = fontptr->cache_slot) != NOTCACHED)
								/* it is already in cache */
	{
		fontfp = pixel_files[current].pixel_file_id;
		fseek(fontfp,0,0);		/* reposition to start of file */
#ifdef DEBUG
		if (ExtraDebug) fprintf(stderr,
								"reposition font file position %d (k = %d)\n",
				current, fontptr->k);
#endif
	}
	else						/* file not in cache */
	{
		if (nopen < MAXOPEN)	/* just add it to list */
			current = ++nopen;
		else					/* list full -- find least used file, */
		{					   /* close it, and reuse slot for new file */
			least_used = 1;
			for (i = 2; i <= MAXOPEN; ++i)
				if (pixel_files[least_used].use_count >
					pixel_files[i].use_count)
					least_used = i;
			(pixel_files[least_used].feptr)->cache_slot = NOTCACHED;
								/* flag font_entry as no longer cached */
			fclose(pixel_files[least_used].pixel_file_id);
								/* close it */
#ifdef DEBUG
			if (ExtraDebug) fprintf(stderr,
								"font file %s, slot %d closed (k = %d)\n",
								(pixel_files[least_used].feptr)->name,
								least_used,
								(pixel_files[least_used].feptr)->k);
#endif
			current = least_used;
		}
		if (!fontptr->has_been_opened)
			FindFontFile(fontptr, preamble.mag);
		if (ExtraDebug)
			printf("Trying to open file %s\n", fontptr->name);
		if ((fontfp=BINARYOPEN(fontptr->name,"r")) == NULL) {
			if (ExtraDebug)
				printf("Failed to open file %s\n", fontptr->name);
			Fatal("font file %s could not be opened; %d font files are open",
				fontptr->name,nopen);
			return (NULL);
		}
#ifdef DEBUG
		if (ExtraDebug)
				fprintf(stderr,"font file %s opened, position %d, (k = %d)\n",
				fontptr->name, current, fontptr->k);
#endif
		pixel_files[current].pixel_file_id = fontfp;
		pixel_files[current].use_count = 0;
		pixel_files[current].feptr = fontptr; /* make cross links */
		fontptr->cache_slot = current;
		if (!fontptr->has_been_opened) {
			ReadCharDefs(fontptr, fontfp);
			fontptr->has_been_opened = TRUE;
		}
	}
	pfontptr = fontptr;						/* make previous = current font */
	pixel_files[current].use_count++;		/* update reference count */
	return (fontfp);
}


/*-->ReadFontDef*/
/**********************************************************************/
/****************************  ReadFontDef  ***************************/
/**********************************************************************/

int
ReadFontDef(k)
int k;
{
	register struct font_entry *tfontptr; /* temporary font_entry pointer */

	if ((tfontptr = NEW(1, struct font_entry)) == NULL) {
		Fatal("can't malloc space for font_entry");
		return;
	}
	tfontptr->next = hfontptr;
	fontptr = hfontptr = tfontptr;

	tfontptr->k = k;
	tfontptr->c = NoSignExtend(dvifp, 4); /* checksum */
	tfontptr->s = NoSignExtend(dvifp, 4); /* space size */
	tfontptr->d = NoSignExtend(dvifp, 4); /* design size */
	tfontptr->a = NoSignExtend(dvifp, 1); /* area length for font name */
	tfontptr->l = NoSignExtend(dvifp, 1); /* device length */
	GetBytes(dvifp, tfontptr->n, tfontptr->a+tfontptr->l);
	tfontptr->n[tfontptr->a+tfontptr->l] = '\0';
	tfontptr->cache_slot = NOTCACHED;
	tfontptr->has_been_opened = FALSE;
	if (PreLoad || BigPreLoad)
		(void)OpenFontFile();
}


/*-->ReadPagePointers*/
/**********************************************************************/
/**************************  ReadPagePointers  ************************/
/**********************************************************************/

void
ReadPagePointers()
{
	long temp_ptr;
	int index;
	int k;

	if (main_state & (SB_NOFILE | SB_NODVIFILE))
		return;
#ifdef DEBUG
	if (Debug) fprintf (stderr, "now reading page pointers\n");
#endif
	pagepointers = NEW(postamble.totalpages ,struct page_entry);
	if (pagepointers == NULL) {
		Fatal("can't malloc space for page pointers");
		return;
	}
	index = postamble.totalpages;
	temp_ptr = postamble.last_page_ptr;
	while (--index >= 0) {
		fseek(dvifp, temp_ptr, 0);
		if(NoSignExtend(dvifp, 1) != BOP) {
			Fatal("Couldn't find BOP");
			return;
		}
		pagepointers[index].count_0 = NoSignExtend(dvifp, 4);
		k = 36;
		while (k--)
			getc(dvifp);
		pagepointers[index].page_ptr = temp_ptr+45;
		temp_ptr = (long)NoSignExtend(dvifp, 4);
	}
}


/*-->ReadPreAmble*/
/**********************************************************************/
/**************************  ReadPreAmble  ****************************/
/**********************************************************************/

void
ReadPreAmble()
{
	int k;

	if (main_state & (SB_NOFILE | SB_NODVIFILE))
		return;
	if (NoSignExtend(dvifp, 2) != ((PRE << 8) | DVIFORMAT)) {
	  Fatal("This doesn't look like a DVI file, it doesn't start with PRE, %d",
				DVIFORMAT);
		return;
	}
	preamble.num = NoSignExtend(dvifp, 4);
	preamble.den = NoSignExtend(dvifp, 4);
	preamble.mag = NoSignExtend(dvifp, 4);
	k = NoSignExtend(dvifp, 1);
	while (k--)
		getc(dvifp);
}


/*-->ReadPostAmble*/
/**********************************************************************/
/**************************  ReadPostAmble  ***************************/
/**********************************************************************/

void
ReadPostAmble()
{
	long postambleptr;
	int command;
	Boolean foundPOST_POST;

	if (main_state & (SB_NOFILE | SB_NODVIFILE))
		return;
	FindPostAmblePtr (&postambleptr);
	if (NoSignExtend(dvifp, 1) != POST) {
		Fatal ("POST missing at head of postamble");
		return;
	}
#ifdef DEBUG
	if (Debug) fprintf (stderr, "got POST command\n");
#endif
	postamble.last_page_ptr = NoSignExtend(dvifp, 4);
	postamble.num = NoSignExtend(dvifp, 4);
	postamble.den = NoSignExtend(dvifp, 4);
	postamble.mag = NoSignExtend(dvifp, 4);
	postamble.maxheight = NoSignExtend(dvifp, 4);
	postamble.maxheight = NoSignExtend(dvifp, 4);
	postamble.maxstack = NoSignExtend(dvifp, 2);
	postamble.totalpages = NoSignExtend(dvifp, 2);

#ifdef DEBUG
	if (Debug) fprintf (stderr, "now reading font defs\n");
#endif
	foundPOST_POST = FALSE;
	while (!foundPOST_POST) {
		switch (command = NoSignExtend(dvifp, 1)) {
		case FNT_DEF1:
		case FNT_DEF2:
		case FNT_DEF3:
		case FNT_DEF4:
			ReadFontDef(NoSignExtend(dvifp, command-FNT_DEF1+1));
			break;
		case NOP:
			break;
		case POST_POST:
			foundPOST_POST = TRUE;
#ifdef DEBUG
			if (Debug) fprintf (stderr, "got POST_POST command\n");
#endif
			break;
		default:
			Fatal ("Bad command in postamble font defs");
			return;
		}
	}
}


/*-->SetFntNum*/
/**********************************************************************/
/****************************  SetFntNum  *****************************/
/**********************************************************************/

void
SetFntNum(k)
int k;

/*
 * This sets the global fontptr from the DVI font number k.
 * This font is then used for all subsequent characters until the next
 * SetFntNum
 */

{
	fontptr = hfontptr;
	while ((fontptr!=NULL) && (fontptr->k!=k))
		fontptr = fontptr->next;
	if (fontptr == NULL)
		Fatal("font %d undefined", k);
}


/*-->SignExtend*/
/**********************************************************************/
/****************************  SignExtend  ****************************/
/**********************************************************************/

int
SignExtend(fp, n)   /* return n byte quantity from file fd */
register FILE *fp;  /* file pointer */
register int n;	 /* number of bytes */

{
	int n1;		 /* number of bytes */
	register int x; /* number being constructed */

	x = getc(fp);   /* get first (high-order) byte */
	if ((x & 0x80) != 0)		/* it is negative */
		x |= 0xFFFFFF00;		/* fill upper bits with ones */
	n1 = n--;
	while (n--)  {
		x <<= 8;
		x |= getc(fp);
	}
	return(x);
}


/*-->SkipFontDef*/
/**********************************************************************/
/****************************  SkipFontDef  ***************************/
/**********************************************************************/

void
SkipFontDef()
{
	short n;

	n = 12;				/* for c, s and d params */
	while (n--)
		getc(dvifp);
	n = getc(dvifp);		/* a param */
	n += getc(dvifp);		/* l param, form a+l */
	while (n--)
		getc(dvifp);		/* throw away name */
}


#ifdef DEBUG
/*-->ShowPxlFd*/
/**********************************************************************/
/****************************  ShowPxlCache  **************************/
/**********************************************************************/

void
ShowPxlCache()
{
	short i;

	fprintf(stderr, "Font file cache contents:\n");
	for(i=1; i<=nopen; i++) {
		fprintf(stderr,"Slot %d: Name %s.%dpxl: Use count %d\n",
				i,
				(pixel_files[i].feptr)->n,
				(pixel_files[i].feptr)->font_mag,
				pixel_files[i].use_count);
	}
}


/*-->ShowPxlFd*/
/**********************************************************************/
/****************************  ShowPxlFd  *****************************/
/**********************************************************************/

void
ShowPxlFd()
{
	short i;

	if (dvifp)
		fprintf(stderr,"\ndvi file		%d\n\n", fileno(dvifp));
	fprintf(stderr,"number of pxl files open = %d\n", nopen);
	for (i=1; i<=nopen; i++)
		if ((pixel_files[i].feptr)->cache_slot != NOTCACHED)
			fprintf(stderr,"pixel_files[%d]: fd %d, name %s\n",
						i,
						fileno(pixel_files[i].pixel_file_id),
						(pixel_files[i].feptr)->n);
}
#endif