1: #ifndef lint 2: static char sccsid[] = "@(#)io.c 4.2 (Berkeley) 8/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: }