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