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