/* * kdfontop.c - export getfont(), getfontsize() and putfont() * * Font handling differs between various kernel versions. * Hide the differences in this file. */ #include "config.h" #include #include #include /* free() */ #include #include #include "kdfontop.h" #include "nls.h" #include "version.h" #ifdef COMPAT_HEADERS #include "compat/linux-kd.h" #endif int restorefont(int fd) { if (ioctl(fd, PIO_FONTRESET, 0)) { perror("PIO_FONTRESET"); return -1; } return 0; } int font_charheight(unsigned char *buf, int count, int width) { int h, i, x; int bytewidth = (width + 7) / 8; for (h = 32; h > 0; h--) for (i = 0; i < count; i++) for (x = 0; x < bytewidth; x++) if (buf[(32 * i + h - 1) * bytewidth + x]) goto nonzero; nonzero: return h; } /* * May be called with buf==NULL if we only want info. * May be called with width==NULL and height==NULL. * Must not exit - we may have cleanup to do. */ int getfont(int fd, unsigned char *buf, int *count, int *width, int *height) { struct consolefontdesc cfd; struct console_font_op cfo; int i; /* First attempt: KDFONTOP */ cfo.op = KD_FONT_OP_GET; cfo.flags = 0; cfo.width = cfo.height = 32; cfo.charcount = *count; cfo.data = buf; i = ioctl(fd, KDFONTOP, &cfo); if (i == 0) { *count = cfo.charcount; if (height) *height = cfo.height; if (width) *width = cfo.width; return 0; } if (errno != ENOSYS && errno != EINVAL) { perror("getfont: KDFONTOP"); return -1; } /* The other methods do not support width != 8 */ if (width) *width = 8; /* Second attempt: GIO_FONTX */ cfd.charcount = *count; cfd.charheight = 0; cfd.chardata = (char *)buf; i = ioctl(fd, GIO_FONTX, &cfd); if (i == 0) { *count = cfd.charcount; if (height) *height = cfd.charheight; return 0; } if (errno != ENOSYS && errno != EINVAL) { perror("getfont: GIO_FONTX"); return -1; } /* Third attempt: GIO_FONT */ if (*count < 256) { fprintf(stderr, _("bug: getfont called with count<256\n")); return -1; } if (!buf) { fprintf(stderr, _("bug: getfont using GIO_FONT needs buf.\n")); return -1; } i = ioctl(fd, GIO_FONT, buf); if (i) { perror("getfont: GIO_FONT"); return -1; } *count = 256; if (height) *height = 0; /* undefined, at most 32 */ return 0; } int getfontsize(int fd) { int count; int i; count = 0; i = getfont(fd, NULL, &count, NULL, NULL); return (i == 0) ? count : 256; } int putfont(int fd, unsigned char *buf, int count, int width, int height) { struct consolefontdesc cfd; struct console_font_op cfo; int i; if (!width) width = 8; if (!height) height = font_charheight(buf, count, width); /* First attempt: KDFONTOP */ cfo.op = KD_FONT_OP_SET; cfo.flags = 0; cfo.width = width; cfo.height = height; cfo.charcount = count; cfo.data = buf; i = ioctl(fd, KDFONTOP, &cfo); if (i == 0) return 0; if (width != 8 || (errno != ENOSYS && errno != EINVAL)) { perror("putfont: KDFONTOP"); return -1; } /* Variation on first attempt: in case count is not 256 or 512 round up and try again. */ if (errno == EINVAL && width == 8 && count != 256 && count < 512) { int ct = ((count > 256) ? 512 : 256); unsigned char *mybuf = malloc(32 * ct); if (!mybuf) { fprintf(stderr, _("%s: out of memory\n"), progname); return -1; } memset(mybuf, 0, 32 * ct); memcpy(mybuf, buf, 32 * count); cfo.data = mybuf; cfo.charcount = ct; i = ioctl(fd, KDFONTOP, &cfo); free(mybuf); if (i == 0) return 0; } /* Second attempt: PIO_FONTX */ cfd.charcount = count; cfd.charheight = height; cfd.chardata = (char *)buf; i = ioctl(fd, PIO_FONTX, &cfd); if (i == 0) return 0; if (errno != ENOSYS && errno != EINVAL) { fprintf(stderr, "%s: putfont: %d,%dx%d:failed: %d\n", progname, count, width, height, i); perror("putfont: PIO_FONTX"); return -1; } /* Third attempt: PIO_FONT */ /* This will load precisely 256 chars, independent of count */ i = ioctl(fd, PIO_FONT, buf); if (i) { fprintf(stderr, "%s: putfont: %d,%dx%d: failed: %d\n", progname, count, width, height, i); perror("putfont: PIO_FONT"); return -1; } return 0; }