summaryrefslogtreecommitdiff
path: root/dviware/beebe/src/openfont.h
blob: ff785609dd266a64d790b5a7a3c9b4f490d2900b (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
/* -*-C-*- openfont.h */
/*-->openfont*/
/**********************************************************************/
/****************************** openfont ******************************/
/**********************************************************************/

void
openfont(fontname)
char *fontname;

/***********************************************************************
    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, fontfp, 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.

    If the first open attempt  fails, an attempt will  be made to use  a
    substitute font, then neighboring magnifications (with the same font
    name), or substitutes for them.
***********************************************************************/

{
    register INT16 i,j,k;	/* loop indices */
    INT16 current;
    INT16 least_used;
    INT16 maxopen = MAXOPEN;

#if    OS_VAXVMS
    long *jpi;
#endif

    struct font_entry *tfontptr;
    char subfont[MAXFNAME];
    int submag;
    char* filelist[MAXFORMATS];	/* pointers to templist[][] */
    char templist[MAXFORMATS][MAXFNAME];

#if    VIRTUAL_FONTS
    struct stat statbuf;		/* so fstat() can get file size */
    char *p;
#endif

    if ((pfontptr != (struct font_entry *)NULL) && (pfontptr == fontptr))
	return;			/* we need not have been called */

    for (j = 0; j < MAXFORMATS; ++j)	/* initialize fontlist pointers */
	filelist[j] = &templist[j][0];

#if    IBM_PC_MICROSOFT
    /* This code required rewriting to get around a fatal compiler
    assertion error occasioned by the code in the #else part */
    for (current = 1; current <= nopen; ++current)
    {
    	FILE* pfp;

	pfp = font_files[current].font_id;
	if (pfp == fontptr->font_file_id)
	    break;
    }
#else
    for (current = 1;
	(current <= nopen) &&
	    (font_files[current].font_id != fontptr->font_file_id);
	++current)
	;			/* try to find file in open list */
#endif

    if (current <= nopen)	/* file already open, lookup its id */
	fontfp = font_files[current].font_id;
    else
    {
	/***************************************************************
	The file was  not in list  of open  files.  If the  list is  not
	full, add it to  the list; otherwise  close the least-used  file
	and remove it from the font_entry containing it.  Finally,  open
	the file, or its closest  neighbor in the magnification  family.
	A warning is issued  if no file can  be opened.  The caller  can
	then proceed with zero font metrics if desired.
	***************************************************************/

#if    OS_VAXVMS
        /***************************************************************
	VAX VMS has many user quotas, one of which is the maximum number
	of files  that can be open, which  need have no relation  to the
	number  that C  permits.  If  we do  not determine the  limit at
	run-time, the drivers may attempt to open too many files, and in
	such a case, will fail.   There  are two relevant  quotas, FILLM
	(open file limit), and  FILCNT (remaining open file quota).   We
	use the latter,  and leave  one available file  for a   possible
	error log.
	***************************************************************/

	jpi = (long*)getjpi(JPI$_FILCNT);
	if (jpi == (long*)NULL)
	    maxopen = MAXOPEN;		/* should never happen */
	else
	    maxopen = nopen - 1 + *jpi;
	maxopen = MIN(maxopen,MAXOPEN);	/* we have arrays of size MAXFONT */
					/* so do not exceed that limit */
#endif /* OS_VAXVMS */

	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 (font_files[least_used].use_count >
		    font_files[i].use_count)
		    least_used = i;

	    fontfp = font_files[least_used].font_id;
	    tfontptr = hfontptr;
	    while (tfontptr != (struct font_entry*)NULL)
	    {			/* remove file pointer from its font_entry */
		if (tfontptr->font_file_id == fontfp)
		{
		    tfontptr->font_file_id = (FILE*)NULL;
		    break;
		}
		tfontptr = tfontptr->next;
	    }

#if    VIRTUAL_FONTS
	    if (virt_font && (fontfp != (FILE*)NULL))
	        (void)virtfree(fontfp);
#endif

	    (void)fclose(fontfp);
	    fontfp = (FILE*)NULL;
	    current = least_used;
	}
	(void)actfact(fontptr->font_mag);	/* Get global mag_index */

	fontfp = (FILE*)NULL;

	/***************************************************************
	Try the requested font, then any substitute font, then for  each
	neighboring magnification  from  nearest to  furthest,  try  the
	requested font, and then any substitute font.
	***************************************************************/

	for (k = 0; (fontfp == (FILE*)NULL) && (k < MAGTABSIZE); ++k)
	{				/* loop over mag family */
	    for (i = -k; (fontfp == (FILE*)NULL) && (i <= k); i += MAX(1,k+k))
	    {				/* try smaller, then larger */
		if (IN(0,mag_index+i,MAGTABSIZE-1))
		{
		    (void)fontfile(filelist, ((fontptr->a==0)?fontpath:""),
			fontname, (int)MAGSIZE(mag_table[mag_index+i]));
		    for (j = 0; (j < MAXFORMATS) && *filelist[j]; ++j)
		    {
			fontfp = FOPEN(filelist[j],RB_OPEN);
			DEBUG_OPEN(fontfp,filelist[j],RB_OPEN);
			if (fontfp != (FILE *)NULL)
			{
			    strcpy(fontptr->name,filelist[j]);
			    break;
			}
		    }
		    if ((k > 0) && (fontfp != (FILE*)NULL))
		    {
			(void)sprintf(message,
			    "Font file [%s [mag %d]] could not be opened.\n\
---using nearest neighbor [%s [mag %d]] instead.",
			    fontname,(int)MAGSIZE(mag_table[mag_index]),
			    fontptr->name,
			    (int)MAGSIZE(mag_table[mag_index+i]));
			(void)warning(message);
		    }

		    if ((fontfp == (FILE*)NULL) && fontsub(subfont,&submag,
			fontname,(int)MAGSIZE(mag_table[mag_index+i])))
		    {
			(void)fontfile(filelist,((fontptr->a==0)?fontpath:""),
			    subfont,(submag ? submag :
			    (int)MAGSIZE(mag_table[mag_index+i])));
			for (j = 0; (j < MAXFORMATS) && *filelist[j]; ++j)
			{
			    fontfp = FOPEN(filelist[j],RB_OPEN);
			    DEBUG_OPEN(fontfp,filelist[j],RB_OPEN);
			    if (fontfp != (FILE *)NULL)
			    {
				strcpy(fontptr->name,filelist[j]);
				break;
			    }
			}

			if (fontfp != (FILE*)NULL)
			{
			    (void)sprintf(message,
				"Substituting font file [%s [mag %d]] \
by [%s [mag %d]]",
				fontname,(int)MAGSIZE(mag_table[mag_index]),
				fontptr->name,
				(int)MAGSIZE(mag_table[mag_index+i]));
			    (void)warning(message);
			}
		    }
		}
	    } /* end for (i) -- loop over smaller and larger neighbors  */
	} /* end for (k) -- loop over mag family */

	if (fontfp == (FILE*)NULL)
	{
	    --nopen;			/* don't count this failed open */
	    (void)sprintf(message,"Font file [%s [mag %d]] could not be \
opened; %d font files are open\n\
Proceeding with zero size characters for this font",
		fontname,(int)MAGSIZE(mag_table[mag_index]),nopen);
	    (void)warning(message);
	}

	font_files[current].font_id = fontfp;
	font_files[current].use_count = 0;

#if    VIRTUAL_FONTS
	/*
	****************************************************************
	This code  is implementation-dependent.   On many  C  compilers,
	FILE points to a struct of the form

	struct	_iobuf {
		char	*_ptr;	// pointer to next available char
		int	_cnt;	// number of chars left in buffer
		char	*_base;	// pointer to start of buffer
		int	_flag;	// assorted flags
		int	_file;	// file number handle
		}

	To implement virtual fonts,  we save the  pointers in a  private
	global array, get the file size from fstat(), malloc() a  buffer
	for it, read the entire file in, and replace the pointers in the
	FILE variable with ones  for  the  new buffer.  Just before  the
	file is  closed, the space is  freed  and the   old pointers are
	restored.   Although many C implementations use  malloc() to get
	the buffer  space  in the  first place, which  would  make  this
	saving unnecessary, not all do; see  the implementation given in
	Kernighan and Ritchie "The C Programming Language", p. 168.

	In  implementing   this   code   on   any   new   machine,   the
	implementations of fread(), read(), fseek(), and rewind() should
	be checked to  choose the  most efficient one  (e.g. one  system
	call for entire file  read, and no  double buffering), and  make
	sure that  fseek() and  rewind()  do not  unnecessarily  discard
	input buffer  contents.  fseek()  and  rewind() are  defined  in
	terms of macros FSEEK() and REWIND() in machdefs.h to facilitate
	replacement.
	****************************************************************
	*/
	if (virt_font)
	{
	    virt_save[fileno(fontfp)].base = (char *)NULL;
	    (void)fstat(fileno(fontfp),&statbuf);	/* get file size */
	    p = (char *)MALLOC((int)statbuf.st_size);	/* get file buffer */
	    if (p != (char *)NULL)
	    {
		if (READ(fileno(fontfp),p,(int)statbuf.st_size)
		     == (int)statbuf.st_size)
		{			/* read successful */
		    virt_save[fileno(fontfp)].ptr = FILE_PTR(fontfp);
		    virt_save[fileno(fontfp)].cnt = FILE_CNT(fontfp);
		    virt_save[fileno(fontfp)].base = FILE_BASE(fontfp);
		    FILE_PTR(fontfp) = p;
		    FILE_BASE(fontfp) = p;
		    FILE_CNT(fontfp) = (int)statbuf.st_size;
		}
		else			/* failure */
		{
		    (void)REWIND(fontfp);
		    (void)free(p);	/* free dynamic buffer */
		}
	    }
	    if (DBGOPT(DBG_FONT_CACHE))
	    {
	        (void)fprintf(stderr,"\nopenfont(): Font file %d [%s] ",
			(int)fileno(fontfp),fontptr->name);
	        if (p == (char *)NULL)
		    (void)fprintf(stderr,
			"cannot callocate buffer for entire file\n");
		else
		    (void)fprintf(stderr,
			"buffer length 0x%x\told buffer at 0x%lx\t\
new buffer at 0x%lx\n",
			(int)statbuf.st_size,
			(long)virt_save[fileno(fontfp)].base,
			(long)FILE_BASE(fontfp));
	    }
	}
#endif

    } /* end if (file is in open list) */

    pfontptr = fontptr;			/* make previous = current font */
    fontptr->font_file_id = fontfp;	/* set file identifier */
    font_files[current].use_count++;	/* update reference count */
}

#if    VIRTUAL_FONTS
void
virtfree(fp)				/* free buffer space before close */
FILE *fp;
{
    if (virt_font && (fp != (FILE*)NULL) &&
	(virt_save[fileno(fp)].base != (char *)NULL))
    {
	(void)fflush(fp);
	(void)free(FILE_BASE(fp));
	FILE_PTR(fp) = virt_save[fileno(fp)].ptr;
	FILE_CNT(fp) = virt_save[fileno(fp)].cnt;
	FILE_BASE(fp) = virt_save[fileno(fp)].base;
	virt_save[fileno(fp)].base = (char *)NULL;
    }
}
#endif