xref: /csrg-svn/old/vpr/vtools/fed/io.c (revision 11509)
1 /*	io.c	4.1	83/03/09	*/
2 /*
3  * io.c: font file I/O subroutines for fed.
4  */
5 
6 #include "fed.h"
7 
8 getglyph(c)
9 char c;
10 {
11 	register int i, j;
12 	int windno;
13 	int vertoff, horoff;
14 	char *tmp;
15 
16 	if (trace)
17 		fprintf(trace, "\n\ngetglyph(%s)\n", rdchar(c));
18 	if (disptable[c].nbytes == 0) {
19 		if (trace)
20 			fprintf(trace, "no such char: %s\n", rdchar(c));
21 		sprintf(msgbuf, "no such character: %s", rdchar(c));
22 		message(msgbuf);
23 		return;
24 	}
25 
26 	curchar = c;
27 	turnofcurs();
28 	if (cht[curchar].wherewind >= 0) {
29 		/* It's already in a window.  Don't have to do much. */
30 		if (trace)
31 			fprintf(trace, "already in %d\n", cht[curchar].wherewind);
32 		windno = cht[curchar].wherewind;
33 		/* Put a box around the current window */
34 		if (windno != curwind) {
35 			drawbox(base[curwind].r-1, base[curwind].c-1, 0, GLROW+2, GLCOL+2);
36 			drawbox(base[windno].r-1, base[windno].c-1, 1, GLROW+2, GLCOL+2);
37 		}
38 		curwind = windno;
39 		syncwind(windno);
40 		/* should center base */
41 	} else {
42 		/*
43 		 * Not on screen.  First find a suitable window,
44 		 * using round robin.
45 		 */
46 		windno = nextwind;
47 		if (trace)
48 			fprintf(trace, "chose window %d\n", windno);
49 		if (++nextwind >= NWIND)
50 			nextwind = 0;
51 #ifdef TWOWIND
52 		/*
53 		 * This is for debugging what happens when we run out
54 		 * of windows.
55 		 */
56 		if (nextwind >= 2)
57 			nextwind = 0;
58 #endif
59 
60 		/* Put a box around the current window */
61 		if (windno != curwind) {
62 			if (trace)
63 				fprintf(trace, "drawbox (%d %d)\n", base[windno].r-1, base[windno].c-1);
64 			drawbox(base[curwind].r-1, base[curwind].c-1, 0, GLROW+2, GLCOL+2);
65 			drawbox(base[windno].r-1, base[windno].c-1, 1, GLROW+2, GLCOL+2);
66 		}
67 
68 		/* Print the char at the lower left of the window */
69 		sprintf(msgbuf, "%s", rdchar(curchar));
70 		dispmsg(msgbuf, base[windno].c, base[windno].r-11, 2);
71 
72 		/* Now make room in the window */
73 		if (wind[windno].onscreen == NULL) {
74 			/* Brand new window, have to allocate space */
75 			wind[windno].onscreen = newmat(GLROW, GLCOL);
76 		} else {
77 			/* Save prev glyph for later */
78 			cht[wind[windno].used].whereat = wind[windno].val;
79 			cht[wind[windno].used].wherewind = -2;
80 			if (trace)
81 				fprintf(trace, "windno=%s, wind[windno].used=%d, cht[..].wherewind set to -2\n", rdchar(windno), wind[windno].used);
82 		}
83 		if (wind[windno].undval != NULL) {
84 			if (trace)
85 				fprintf(trace, "getglyph frees undo: %x\n", wind[windno].undval);
86 			free(wind[windno].undval);
87 		}
88 		wind[windno].undval = NULL;
89 		wind[windno].used = curchar;
90 
91 		/*
92 		 * Vertical & horizontal offsets.  Line up the baseline
93 		 * of the char at BASELINE from bottom, but center
94 		 * horizontally.
95 		 */
96 		vertoff = GLROW - BASELINE - disptable[curchar].up;
97 		/* Check to see if the glyph is being nosed off the edge. */
98 		if (vertoff < 0) {
99 			vertoff = 0;
100 		} else if (vertoff + disptable[curchar].up + disptable[curchar].down >= GLROW) {
101 			vertoff = GLROW - disptable[curchar].up - disptable[curchar].down;
102 		}
103 		horoff = (GLCOL-(disptable[curchar].left+disptable[curchar].right)) / 2;
104 		wind[windno].val = findbits(curchar, GLROW, GLCOL, horoff, vertoff, &curs_r, &curs_c);
105 		cht[curchar].rcent = curs_r;
106 		cht[curchar].ccent = curs_c;
107 		curwind = windno;
108 		cht[curchar].wherewind = windno;
109 		syncwind(windno);
110 	}
111 }
112 
113 /*
114  * writeback: write the font back to the file at the end of editing.
115  * Also have to write width table.
116  */
117 writeback()
118 {
119 	writefont(fontfile);
120 }
121 
122 /*
123  * writefont: write current font on file fname.
124  */
125 writefont(fname)
126 char *fname;
127 {
128 	register int i, j;
129 	register int c;
130 	FILE *fntout;
131 	int bytes;
132 	bitmat tmp;
133 	int nextoff = 0;
134 	int charcount, bytecount;
135 	extern char *sys_errlist[];
136 	extern int errno;
137 
138 	if (trace)
139 		fprintf(trace, "writefont(%s)\n", fname);
140 	/*
141 	 * The following unlink is important because we are about to
142 	 * do an fopen( , "w") on fname.  We still have fontdes open
143 	 * for reading.  If we don't do the unlink the fopen will truncate
144 	 * the file and subsequent reads will fail.  If we do the unlink
145 	 * the file won't go away until it is closed, so we can still
146 	 * read from the old version.
147 	 */
148 	if (strcmp(fname, fontfile)==0 && unlink(fname) < 0) {
149 		sprintf(msgbuf, "unlink %s: %s", fname, sys_errlist[errno]);
150 		error(msgbuf);
151 	}
152 
153 	fntout = fopen(fname, "w");
154 	if (fntout == NULL) {
155 		sprintf(msgbuf, "%s: %s", fname, sys_errlist[errno]);
156 		if (trace)
157 			fprintf(trace, "%s\n", msgbuf);
158 		error(msgbuf);
159 	}
160 	sprintf(msgbuf, "\"%s\"", fname);
161 	message(msgbuf);
162 	fflush(stdout);
163 
164 	fwrite(&FontHeader, sizeof FontHeader, 1, fntout);
165 	fwrite(&disptable[0], sizeof disptable, 1, fntout);
166 	charcount = 0; bytecount = fbase;
167 	for (c=0; c<256; c++)
168 		if (disptable[c].nbytes || cht[c].wherewind != -1) {
169 			if (trace)
170 				fprintf(trace, "char %s, nbytes %d, wherewind %d.. ", rdchar(c), disptable[c].nbytes, cht[c].wherewind);
171 			packmat(c, &tmp, &bytes);
172 			disptable[c].addr = nextoff;
173 			disptable[c].nbytes = bytes;
174 			if (trace)
175 				fprintf(trace, "offset %d size %d\n", nextoff, bytes);
176 			nextoff += bytes;
177 			fwrite(tmp, bytes, 1, fntout);
178 			charcount++;
179 			bytecount += bytes;
180 		}
181 	FontHeader.size = nextoff;
182 	fseek(fntout, 0L, 0);
183 	fwrite(&FontHeader, sizeof FontHeader, 1, fntout);
184 	fwrite(&disptable[0], sizeof disptable, 1, fntout);
185 
186 	/* Should fix the width tables here */
187 	fclose(fntout);
188 	sprintf(msgbuf, "%s %d glyphs, %d bytes", fname, charcount, bytecount);
189 	message(msgbuf);
190 	changes = 0;
191 }
192 
193 /*
194  * make a packed matrix of the bits for char c.
195  * return the matrix ptr in result and the size in bytes in nbytes.
196  */
197 packmat(c, result, nbytes)
198 int c;
199 bitmat *result;
200 int *nbytes;
201 {
202 	register int i, j;
203 	bitmat wp;
204 	int nb, nr, nc;
205 	int rmin, cmin, rmax, cmax;
206 	static char tmp[WINDSIZE];
207 
208 	if (cht[c].wherewind == -1) {
209 		/* It has never been read from file.  Just copy from file. */
210 		nb = disptable[c].nbytes;
211 		fseek(fontdes, (long) fbase+disptable[c].addr, 0);
212 		fread(tmp, nb, 1, fontdes);
213 	} else {
214 		if (cht[c].wherewind == -2)
215 			wp = cht[c].whereat;
216 		else
217 			wp = wind[cht[c].wherewind].val;
218 		minmax(wp, GLROW, GLCOL, &rmin, &cmin, &rmax, &cmax);
219 		nr = rmax-rmin+1; nc = cmax-cmin+1;
220 		zermat(tmp, nr, nc);
221 		for (i=rmin; i<=rmax; i++)
222 			for (j=cmin; j<=cmax; j++) {
223 				setmat(tmp, nr, nc, i-rmin, j-cmin,
224 					mat(wp, GLROW, GLCOL, i, j));
225 			}
226 		nb = ((nc + 7) >> 3) * nr;
227 		disptable[c].up = cht[c].rcent - rmin;
228 		disptable[c].down = rmax - cht[c].rcent + 1;
229 		disptable[c].left = cht[c].ccent - cmin;
230 		disptable[c].right = cmax - cht[c].ccent + 1;
231 		if (trace) {
232 			fprintf(trace, "rmax=%d, rcent=%d, rmin=%d, cmax=%d, ccent=%d, cmin=%d, ", rmax, cht[c].rcent, rmin, cmax, cht[c].ccent, cmin);
233 			fprintf(trace, "up=%d, down=%d, left=%d, right=%d\n", disptable[c].up, disptable[c].down, disptable[c].left, disptable[c].right);
234 		}
235 	}
236 	*result = tmp;
237 	*nbytes = nb;
238 	if (trace)
239 		fprintf(trace, "nbytes = %d, ", nb);
240 	return;
241 }
242 
243 /*
244  * editfont: make the file fname be the current focus of attention,
245  * including reading it into the buffer.
246  */
247 editfont(fname)
248 char *fname;
249 {
250 	register char *cp;
251 
252 	clearfont();
253 	editing = 1;
254 	truename(fname, fontfile);
255 	fontdes = fopen(fontfile, "r");
256 	readfont(fontfile, 0, 255);
257 
258 	/*
259 	 * Figure out the point size, and make a guess as to the
260 	 * appropriate width of the heavy pen.
261 	 */
262 	for (cp=fontfile; *cp && *cp!='.'; cp++)
263 		;
264 	if (*cp) {
265 		pointsize = atoi(++cp);
266 		setpen(pointsize>30?3 : pointsize>15?2 : pointsize>8?1 : 0);
267 	} else {
268 		pointsize = 0;
269 		setpen(2);
270 	}
271 }
272 
273 /*
274  * readfont: read in a font, overlaying the current font.
275  * also used to edit a font by clearing first.
276  *
277  * Conflicts are handled interactively.
278  */
279 readfont(fname, c1, c2)
280 char *fname;
281 int c1, c2;
282 {
283 	register int i;
284 	register char *cp;
285 	struct dispatch d;
286 	char choice, mode = 0;
287 	FILE *hold_fontdes;
288 	int horoff, vertoff;
289 	long ftsave;
290 
291 	hold_fontdes = fontdes;
292 	fontdes = fopen(fname, "r");
293 	if (fontdes == NULL) {
294 		sprintf(msgbuf, "%s not found", fname);
295 		fontdes = hold_fontdes;
296 		error(msgbuf);
297 	}
298 	fread(&FontHeader, sizeof FontHeader, 1, fontdes);
299 	fseek(fontdes, c1*sizeof d, 1);	/* skip over unread chars */
300 	ftsave = ftell(fontdes);
301 	for (i=c1; i<=c2; i++) {
302 		fseek(fontdes, ftsave, 0);
303 		fread(&d, sizeof d, 1, fontdes);
304 		ftsave = ftell(fontdes);
305 		/* Decide which of the two to take */
306 		if (d.nbytes == 0)
307 			continue;	/* We take the one in the buffer */
308 		if (disptable[i].nbytes > 0) {
309 			/* Conflict */
310 			switch(mode) {
311 			case 'f':
312 				/* fall through */
313 				break;
314 			case 'b':
315 				continue;
316 			default:
317 				sprintf(msgbuf, "%s <file> or <buffer>", rdchar(i));
318 				message(msgbuf);
319 				choice = inchar();
320 				switch(choice) {
321 				case 'F':
322 					mode = 'f';
323 				default:
324 				case 'f':
325 					break;
326 				case 'B':
327 					mode = 'b';
328 				case 'b':
329 					continue;
330 				}
331 			}
332 		}
333 		disptable[i] = d;	/* We take the one in the file */
334 		cht[i].nrow = d.up + d.down;
335 		cht[i].ncol = d.left + d.right;
336 		if (!editing && disptable[i].nbytes) {
337 			horoff = (GLCOL-(disptable[i].left+disptable[i].right))/2;
338 			vertoff = GLROW - BASELINE - disptable[i].up;
339 			/* Check to see if the glyph is being nosed off the edge. */
340 			if (vertoff < 0) {
341 				vertoff = 0;
342 			} else if (vertoff + disptable[curchar].up + disptable[curchar].down >= GLROW) {
343 				vertoff = GLROW - disptable[curchar].up - disptable[curchar].down;
344 			}
345 			if (cht[i].wherewind >= 0) {
346 				/* The old glyph is in a window - destroy it */
347 				wind[cht[i].wherewind].used = -1;
348 			}
349 			cht[i].wherewind = -1;
350 			cht[i].whereat = findbits(i, GLROW, GLCOL, horoff, vertoff, &cht[i].rcent, &cht[i].ccent);
351 			cht[i].wherewind = -2;
352 			if (trace)
353 				fprintf(trace, "setting cht[%d].wherewind to -2 in readfont\n", i);
354 		} else
355 			cht[i].wherewind = -1;
356 	}
357 	fbase = sizeof FontHeader + sizeof disptable;	/* ftell(fontdes) */
358 
359 	sprintf(msgbuf, "\"%s\", raster data %d bytes, width %d, height %d, xtend %d", fname, FontHeader.size, FontHeader.maxx, FontHeader.maxy, FontHeader.xtend);
360 
361 	fontdes = hold_fontdes;
362 	message(msgbuf);
363 }
364 
365 /*
366  * Figure out the true name of the font file, given that
367  * the abbreviated name is fname.  The result is placed
368  * in the provided buffer result.
369  */
370 truename(fname, result)
371 char *fname;
372 char *result;
373 {
374 	FILE *t;
375 
376 	strcpy(result, fname);
377 	if ((t = fopen(result, "r")) == NULL) {
378 		sprintf(result,"/usr/lib/vfont/%s",fname);
379 		if ((t = fopen(result, "r")) == NULL) {
380 			strcpy(result, fname);
381 			sprintf(msgbuf, "Can't find %s\n",fname);
382 			error(msgbuf);
383 		}
384 	}
385 	fclose(t);
386 }
387 
388 
389 /*
390  * clearfont: delete all characters in the current font.
391  */
392 clearfont()
393 {
394 	register int i;
395 
396 	if (fontdes)
397 		fclose(fontdes);
398 	for (i=0; i<256; i++) {
399 		cht[i].wherewind = -1;
400 		disptable[i].addr = 0;
401 		disptable[i].nbytes = 0;
402 		disptable[i].up = 0;
403 		disptable[i].down = 0;
404 		disptable[i].left = 0;
405 		disptable[i].right = 0;
406 		disptable[i].width = 0;
407 	}
408 }
409 
410 /*
411  * fileiocmd: do a file I/O command.  These all take optional file
412  * names, defaulting to the current file.
413  */
414 fileiocmd(cmd)
415 char cmd;
416 {
417 	char fname[100], truefname[100];
418 
419 	readline("file: ", fname, sizeof fname);
420 	if (fname[0] == 0 || fname[0] == ' ')
421 		strcpy(fname, fontfile);
422 	switch(cmd) {
423 	case 'E':
424 		confirm();
425 		editfont(fname);
426 		break;
427 
428 	case 'N':
429 		if (changes)
430 			writeback();
431 		editfont(fname);
432 		break;
433 
434 	case 'R':
435 		editing = 0;
436 		truename(fname, truefname);
437 		readfont(truefname, 0, 255);
438 		changes++;
439 		break;
440 
441 	case 'W':
442 		editing = 0;
443 		writefont(fname);
444 		break;
445 	}
446 	if (editing)
447 		changes = 0;
448 }
449 
450 /*
451  * readchars: read in a partial font (the P command).
452  */
453 readchars()
454 {
455 	int c1, c2;
456 	char fnamebuf[100];
457 	char truebuf[100];
458 	char buf[5];
459 
460 	message("Partial read <firstchar>");
461 	c1 = inchar();
462 	sprintf(msgbuf, "Partial read %s thru <lastchar>", rdchar(c1));
463 	message(msgbuf);
464 	c2 = inchar();
465 	strcpy(buf, rdchar(c1));
466 	sprintf(msgbuf, "Partial read %s thru %s from file: ", buf, rdchar(c2));
467 	readline(msgbuf, fnamebuf, sizeof fnamebuf);
468 	editing = 0;
469 	if (fnamebuf[0] == 0 || fnamebuf[0] == ' ')
470 		strcpy(fnamebuf, fontfile);
471 	truename(fnamebuf, truebuf);
472 	changes++;
473 	readfont(truebuf, c1, c2);
474 }
475