📄 pf.c
字号:
#ifdef sccs#ifndef lintstatic char sccsid[] = "@(#)pf.c 1.1 92/07/30 SMI from pf.c 1.20 87/12/18";#endif#endif/* * Copyright 1986-1989 Sun Microsystems, Inc. *//* * Pixfont open/close: pf_open(), pf_open_private(), pf_close() */#include <vfont.h>#include <stdio.h>#include <strings.h>#include <sys/types.h>#include <pixrect/pixrect.h>#include <pixrect/pixfont.h>#include <pixrect/memvar.h>#include <pixrect/pr_impl_util.h>#ifndef MP_FONT /* in case we have the wrong memvar.h */#define MP_FONT 32 /* Pixrect is a part of a Pixfont */#endif#ifndef NO_SHARED_LIB_FONTS#include <errno.h>#include <fcntl.h>#include <sys/mman.h>#include <link.h>extern int errno;extern struct link_dynamic _DYNAMIC;extern int getpagesize();extern char *getenv();#endifextern char *calloc(), *malloc();extern Pixfont *pf_resident(), *pf_bltindef();static Pixfont *pf_load_vfont();#ifndef NO_SHARED_LIB_FONTS/* Following added to allow a master program (e.g. sunview) * to change allocation for fonts to force them into particular VM addresses * so that slave programs (e.g. shelltool) can try to share the same fonts. * This only works if both master and slave are linked against the same set * of shared libraries with the same initial stack sizes (the common case), * but mem_ops fields exist to allow this condition to be checked. * _use_vm has the following meanings (assuming pf_linked_dynamic() is * true, otherwise we have to use private fonts): * 0: slave, try to get font from vm * 1: master, try to put font into vm * 2: either, vm did not work, don't try it any longer. */static int _use_vm; static int vm_fd; /* Only valid while master loading fonts */static char *next_free, *end_of_vm_blk;typedef struct pixrectops Pr_ops;#define PF_VM_VERSION 1#define MAX_FONT_COUNT 4typedef struct pf_vm_header { int version; /* Should be PF_VM_VERSION */ caddr_t mapped_at; /* Assigned VM addr. */ int size_of_vm_blk; /* In bytes, including header */ Pr_ops *mem_ops; /* Must match or don't share */ Pr_ops mem_ops_procs; /* fonts as VM layout bad */ int font_count; /* No. of valid fonts */ Pixfont *fonts[MAX_FONT_COUNT]; char font_names[MAX_FONT_COUNT][1024]; int vm_blk[1]; /* Lie: actually much bigger */} *Pf_vm_header;static Pf_vm_header vm_header;#define VM_FONT_FILE "/usr/tmp/vm_fonts-"#endif/* shared font list */static struct font_use { struct font_use *next; char *name; Pixfont *pf; int count; int resident;} Fonts[1];/* public functions */#ifndef NO_SHARED_LIB_FONTSintpf_linked_dynamic(){ return (&_DYNAMIC != (struct link_dynamic *)0);}intpf_use_vm(use_vm) int use_vm;{ int result = _use_vm; /* Make sure that we actually got built with shared libraries */ if (pf_linked_dynamic()) { if (_use_vm == 1 && use_vm == 0 && vm_fd > 0) { /* * Turning off vm => close backing file. * Change permissions to make it read only for others. * (We still retain write access.) */ if (fchmod(vm_fd, 0444) < 0) { perror("fchmod"); } close(vm_fd); vm_fd = 0; } _use_vm = use_vm ? 1 : 0; } return result;}#endifPixfont *pf_open(fontname) char *fontname;{ register struct font_use *use, *prev; register char *basename;#ifndef NO_SHARED_LIB_FONTS int from_vm;#endif if (fontname == 0) return pf_default(); if (basename = rindex(fontname, '/')) basename++; else basename = fontname; /* look for the font in the shared font list */ for (prev = Fonts; use = prev->next; prev = use) if (strcmp(use->name, basename) == 0) { /* found it */ use->count++; return use->pf; } /* didn't find it, add it to the end of the list */ if (use = (struct font_use *) malloc((unsigned) (sizeof *use + strlen(basename) + 1))) { use->next = 0; (void) strcpy(use->name = (char *) (use + 1), basename); use->count = 1; use->resident = 0; if (use->pf = pf_resident(basename)) use->resident = 1; else {#ifndef NO_SHARED_LIB_FONTS use->pf = pf_load_vfont(fontname, &from_vm); use->resident = from_vm;#else use->pf = pf_load_vfont(fontname);#endif } if (use->pf) { prev->next = use; return use->pf; } else (void) free((char *) use); } return 0;}Pixfont *pf_open_private(fontname) char *fontname;{#ifndef NO_SHARED_LIB_FONTS /* Set allocator to calloc() to force private copy of font. */ int save_use_vm = _use_vm; int from_vm;#endif Pixfont *result; /* * We don't know the name of the default font, and * there is no code to copy it, so we punt. */ if (fontname == 0) return 0;#ifndef NO_SHARED_LIB_FONTS _use_vm = 2; result = pf_load_vfont(fontname, &from_vm); _use_vm = save_use_vm;#else result = pf_load_vfont(fontname);#endif return result;}pf_close(pf) Pixfont *pf;{ register struct font_use *use, *prev; if (pf == 0 || pf == pf_bltindef()) return 0; /* look for a font in the shared font list */ for (prev = Fonts; use = prev->next; prev = use) { if (use->pf == pf) { /* found it */ if (--use->count <= 0) { if (!use->resident) free((char *) pf); prev->next = use->next; (void) free((char *) use); } return 0; } } /* didn't find font, must be private */ free((char *) pf); return 0;}/* implementation */#ifndef NO_SHARED_LIB_FONTS/* Following routine computes the file name of the vm backing storage. * It will try to use the information in the WINDOW_PARENT environment * variable to generate names unique for a desktop, so that users with * multiple monitors can run multiple sunviews without getting collisions. */static voidpf_vm_font_file(buf) char *buf;/* Caller must provide a buf that is at least 1024 chars long. */{ char *window_parent = getenv("WINDOW_PARENT"); strcpy(buf, VM_FONT_FILE); if (window_parent != NULL && window_parent[0] != '\0') { strcat(buf, &window_parent[strlen(window_parent)-2]); }}static char *pf_alloc_vm(to_alloc) int to_alloc;/* Caller must have rounded to_alloc to page boundary, and should only * call if pf_linked_dynamic() is true. */{ register struct link_map *lmp; int retried = 0; char vm_file_name[1024]; caddr_t mappedat; /* * Map in the file and set its length long enough to hold * the mapped region. */ pf_vm_font_file(vm_file_name);Open: if ((vm_fd = open(vm_file_name, O_RDWR | O_CREAT | O_TRUNC, 0644)) < 0) { if (errno == EACCES && !retried) { /* Assume left over from prior master and remove. */ if (unlink(vm_file_name) == 0) { retried = 1; goto Open; } } perror("open"); goto Error_return; } if (ftruncate(vm_fd, to_alloc) < 0) { perror("ftruncate"); goto Error_return; } mappedat = mmap(0, to_alloc, PROT_WRITE | PROT_READ, MAP_SHARED, vm_fd, (off_t) 0); if (mappedat == (caddr_t) -1) { perror("mmap"); goto Error_return; } return(mappedat);Error_return: if (vm_fd) { close(vm_fd); vm_fd = 0; } return(0);}static Pf_vm_headerpf_map_vm()/* Caller should only call if pf_linked_dynamic() is true. */{ struct pf_vm_header vm_header; register int fd, len, page_size; char mincore_status, vm_file_name[1024]; register caddr_t mapped_at; /* * Get a handle on the file to be mapped in, and read the header. */ pf_vm_font_file(vm_file_name); if ((fd = open(vm_file_name, O_RDONLY)) < 0) { if (errno != ENOENT) { perror("open"); } goto Error_return; } len = read(fd, &vm_header, sizeof(vm_header)); if (len != sizeof(vm_header)) { perror("read"); goto Error_return; } page_size = getpagesize(); if (vm_header.version != PF_VM_VERSION || ((int)(vm_header.mapped_at) % page_size) != 0 || vm_header.size_of_vm_blk > 1024000) { /* Header looks bad: punt. */ goto Error_return; } /* * Check to see if all of specified block is unmapped. * If so, attempt to map file at the specified address. */ for (len = vm_header.size_of_vm_blk, mapped_at = vm_header.mapped_at; len > 0; len -= page_size, mapped_at += page_size) { if (mincore(mapped_at, page_size, &mincore_status) != -1 || errno != ENOMEM) { /* Block of memory is partially mapped: punt. */ goto Error_return; } } mapped_at = mmap(vm_header.mapped_at, vm_header.size_of_vm_blk, PROT_READ, MAP_SHARED | MAP_FIXED, fd, (off_t) 0); if (mapped_at == (caddr_t) -1) { perror("mmap"); goto Error_return; } close(fd); /* fd not needed after mmap completes. */ return (Pf_vm_header)mapped_at;Error_return: if (fd >= 0) { close(fd); } return (Pf_vm_header)0;}static Pixfont *pf_alloc_font(fontname, size, from_vm) register char *fontname; register int *from_vm;{ register Pixfont *pf; register int to_alloc; register int page_size; if (!pf_linked_dynamic() || (_use_vm != 1)) { goto No_vm; } /* Defining fonts (master) : place in VM */ if (next_free == (char *)0) { /* Allocate in pages, and guess a little high in case * the first font is a small font and to allow some * room for the vm_header itself. */ page_size = getpagesize(); to_alloc = (2+MAX_FONT_COUNT) * size; to_alloc = ((to_alloc+page_size-1)/page_size) * page_size; next_free = pf_alloc_vm(to_alloc); if (next_free == (char *)0) { _use_vm = 0; goto No_vm; } end_of_vm_blk = next_free + to_alloc; vm_header = (Pf_vm_header)next_free; vm_header->version = PF_VM_VERSION; vm_header->mapped_at = (caddr_t)vm_header; vm_header->size_of_vm_blk = to_alloc; vm_header->mem_ops = &mem_ops; bcopy((char *)&mem_ops, (char *)&(vm_header->mem_ops_procs), sizeof(mem_ops)); vm_header->font_count = 0; next_free = (char *)vm_header->vm_blk; } if (vm_header->font_count == MAX_FONT_COUNT || next_free+size >= end_of_vm_blk) { goto No_vm; } pf = (Pixfont *)next_free; *from_vm = 1; /* Always align to next int boundary */ next_free += ((size+sizeof(int)-1)/sizeof(int)) * sizeof(int); /* Remember this font */ strcpy(vm_header->font_names[vm_header->font_count], fontname); vm_header->fonts[vm_header->font_count] = pf; vm_header->font_count++; return pf;No_vm: *from_vm = 0; pf = (Pixfont *)calloc(1, size); return pf;}#endifstatic Pixfont *#ifndef NO_SHARED_LIB_FONTSpf_load_vfont(fontname, from_vm) char *fontname; int *from_vm;#elsepf_load_vfont(fontname) char *fontname;#endif{ FILE *fontf; struct header hd; int defx, defy; register struct dispatch *d; register unsigned nfont, nimage; register Pixfont *pf = 0; struct dispatch disp[NUM_DISPATCH];#ifndef NO_SHARED_LIB_FONTS int i; /* Try looking in VM iff a slave. */ if (pf_linked_dynamic() && (_use_vm == 0)) { if (vm_header == (Pf_vm_header)0) { vm_header = pf_map_vm(); if (vm_header == (Pf_vm_header)0 || vm_header->mem_ops != &mem_ops || bcmp((char *)&mem_ops, (char *)&(vm_header->mem_ops_procs), sizeof(mem_ops)) != 0 ) { _use_vm = 2; goto No_vm; } } for (i = 0; i < vm_header->font_count; i++) { if (0 == strcmp(fontname, vm_header->font_names[i])) { pf = vm_header->fonts[i]; *from_vm = 1; return pf; } } }No_vm:#endif if (!(fontf = fopen(fontname, "r"))) return pf; if (fread((char *) &hd, sizeof hd, 1, fontf) != 1 || fread((char *) disp, sizeof disp, 1, fontf) != 1 || hd.magic != VFONT_MAGIC) goto bad; /* * Set default sizes. The default width of the font is taken to be * the width of a lower-case a, if there is one. The default * interline spacing is taken to be 3/2 the height of an * upper-case A above the baseline. */ if (disp['a'].nbytes && disp['a'].width > 0 && disp['A'].nbytes && disp['A'].up > 0) { defx = disp['a'].width; defy = disp['A'].up * 3 >> 1; } else { defx = hd.maxx; defy = hd.maxy + hd.xtend; } if (defx <= 0 || defy <= 0) goto bad; /* compute total font and image size */ nfont = sizeof (struct pixfont); nimage = 0; for (d = disp; d < &disp[NUM_DISPATCH]; d++) if (d->nbytes) { register int w, h; if ((w = d->left + d->right) <= 0 || (h = d->up + d->down) <= 0) { d->nbytes = 0; continue; } nfont += sizeof (struct pixrect) + sizeof (struct mpr_data); w = w <= 16 ? 2 : w + 31 >> 5 << 2; /* may need extra space to preserve 32 bit alignment */ if (w > 2 && nimage & 2) nimage += 2; nimage += pr_product(w, h); } /* allocate space for pixfont, pixrects, and images */ nimage += nfont;#ifndef NO_SHARED_LIB_FONTS pf = pf_alloc_font(fontname, nimage, from_vm); if ((pf == (Pixfont *)0) || (*from_vm && (_use_vm == 0))) { goto bad; /* bit of a misnomer */ } else {#else if (pf = (Pixfont *) calloc(1, nimage)) {#endif pf->pf_defaultsize.x = defx; pf->pf_defaultsize.y = defy; /* construct pixfont */ if (pf_build(fontf, disp, &pf->pf_char[0], (caddr_t) (pf + 1), PTR_ADD(pf, nfont))) { free((char *) pf); pf = 0; } }bad: (void) fclose(fontf); return pf;}staticpf_build(fontf, disp, pc, data, image) FILE *fontf; register struct dispatch *disp; struct pixchar *pc; caddr_t data; char *image;{ int nchar; register unsigned short addr = 0; /* hack to recycle registers */ register caddr_t Aptr, Bptr;#define Apc ((struct pixchar *) Aptr)#define Bpr ((Pixrect *) Bptr)#define Aprd ((struct mpr_data *) Aptr)#define Bimage ((char *) Bptr)#define Afile ((FILE *) Aptr) for (nchar = NUM_DISPATCH; --nchar >= 0; disp++, pc++) if (disp->nbytes) { register int w, h, pad; /* create pixchar */ Aptr = (caddr_t) pc; w = disp->left; Apc->pc_home.x = -w; w += disp->right; h = disp->up; Apc->pc_home.y = -h; h += disp->down; Apc->pc_adv.x = disp->width; Apc->pc_adv.y = 0; /* create pixrect */ Bptr = (caddr_t) data; Apc->pc_pr = Bpr; Bpr->pr_ops = &mem_ops; Bpr->pr_size.x = w; Bpr->pr_size.y = h; Bpr->pr_depth = 1; /* create pixrect data */ Aptr = (caddr_t) (Bpr + 1); Bpr->pr_data = (caddr_t) Aprd; w = (w + 7) >> 3; pad = w <= 2 ? 2 : w + 3 & ~3; Aprd->md_linebytes = pad; Bptr = (caddr_t) image; if (pad > 2 && (int) Bptr & 2) Bptr += 2; Aprd->md_image = (short *) Bimage; Aprd->md_flags = w <= 2 ? MP_FONT : 0; data = (caddr_t) (Aprd + 1); Aptr = (caddr_t) fontf; if (addr != disp->addr) { (void) fseek(Afile, (long) (sizeof (struct header) + sizeof (struct dispatch) * NUM_DISPATCH + disp->addr), 0); addr = disp->addr; }#ifdef MUTANT /* check for mutant short-padded vfont */ if (w & 1 && pr_product(w + 1, h) == disp->nbytes) w++;#endif MUTANT pad -= w; while (--h >= 0) { PR_LOOPP(w - 1, *Bimage = getc(Afile); Bptr++); Bptr += pad; addr += w; } image = Bptr; } return ferror(Afile) || feof(Afile);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -