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
getglyph(c)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 */
writeback()120 writeback()
121 {
122 writefont(fontfile);
123 }
124
125 /*
126 * writefont: write current font on file fname.
127 */
writefont(fname)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 */
packmat(c,result,nbytes)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 */
editfont(fname)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 */
readfont(fname,c1,c2)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 */
truename(fname,result)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 */
clearfont()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 */
fileiocmd(cmd)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 */
readchars()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