From 143939ba67633739a09acdeae7147019523c19d5 Mon Sep 17 00:00:00 2001 From: Packit Date: Sep 29 2020 11:28:28 +0000 Subject: Apply patch kbd-2.0.4-covscan-fixes.patch patch_name: kbd-2.0.4-covscan-fixes.patch present_in_specfile: true --- diff --git a/src/kdmapop.c b/src/kdmapop.c index f9b72ae..a3d9969 100644 --- a/src/kdmapop.c +++ b/src/kdmapop.c @@ -154,6 +154,7 @@ int getunimap(int fd, struct unimapdesc *ud0) } if (ioctl(fd, GIO_UNIMAP, &ud)) { perror("GIO_UNIMAP"); + free(ud.entries); return -1; } if (ct != ud.entry_ct) diff --git a/src/kdmapop.c.covscan-fixes b/src/kdmapop.c.covscan-fixes new file mode 100644 index 0000000..f9b72ae --- /dev/null +++ b/src/kdmapop.c.covscan-fixes @@ -0,0 +1,207 @@ +/* + * kdmapop.c - export getscrnmap(), loadscrnmap(), + * loaduniscrnmap(), loadunimap() + * + * Hide the ioctl use in this file. + */ +#include "config.h" + +#include +#include +#include +#include +#include +#include "kdmapop.h" +#include "nls.h" +#include "version.h" + +/* + * Linux pre-0.96 defined GIO_SCRNMAP, PIO_SCRNMAP: + typedef char scrnmap_t; + #define E_TABSZ 256 + #define GIO_SCRNMAP 0x4B40 + #define PIO_SCRNMAP 0x4B41 + * and Linux 0.99.14y first implemented them. + * Usage: + scrnmap_t map[E_TABSZ]; + ioctl(fd,GIO_SCRNMAP,map); + ioctl(fd,PIO_SCRNMAP,map); + * to read or write the kernel translation table that is + * applied to user application output before displaying. + * + * Before 1.3.1, the character set was completely undetermined, + * and if the font was in an order different from the character + * set in use, the user screen map was used to map application + * codes to font indices. (To be more precise: there were four + * translation tables, and this ioctl would get/set the fourth + * table, while the other three tables are built-in and constant.) + */ +int getscrnmap(int fd, char *map) +{ + if (ioctl(fd, GIO_SCRNMAP, map)) { + perror("GIO_SCRNMAP"); + return -1; + } + return 0; +} + +int loadscrnmap(int fd, char *map) +{ + if (ioctl(fd, PIO_SCRNMAP, map)) { + perror("PIO_SCRNMAP"); + return -1; + } + return 0; +} + +/* + * Linux 1.3.1 introduces GIO_UNISCRNMAP, PIO_UNISCRNMAP: + #define GIO_UNISCRNMAP 0x4B69 + #define PIO_UNISCRNMAP 0x4B6A + * Usage: + unsigned short umap[E_TABSZ]; + ioctl(fd,GIO_UNISCRNMAP,umap); + ioctl(fd,PIO_UNISCRNMAP,umap); + * to read or write the kernel translation table that is + * applied to user application output before displaying. + * (When the console is not in utf8 mode.) + * + * The idea is that the umap values are 16-bit unicode (ucs2) + * values, and that the fonts will have an index giving the + * unicode value for each glyph, so that the kernel can match up + * application codes to font positions. + #define UNI_DIRECT_BASE 0xF000 + #define UNI_DIRECT_MASK 0x01FF + * For compatibility, and for fonts without table, the unicode + * values 0xF000+n, 0 <= n <= 0x01FF, acts as direct font indices. + * In the new scheme, the old PIO_SCRNMAP fills the kernel umap + * table with such direct-to-font values. + */ + +int getuniscrnmap(int fd, unsigned short *map) +{ + if (ioctl(fd, GIO_UNISCRNMAP, map)) { + perror("GIO_UNISCRNMAP"); + return -1; + } + return 0; +} + +int loaduniscrnmap(int fd, unsigned short *map) +{ + if (ioctl(fd, PIO_UNISCRNMAP, map)) { + perror("PIO_UNISCRNMAP"); + return -1; + } + return 0; +} + +/* + * Linux 1.1.63 introduces GIO_UNIMAP, PIO_UNIMAP, PIO_UNIMAPCLR: + #define GIO_UNIMAP 0x4B66 + #define PIO_UNIMAP 0x4B67 + #define PIO_UNIMAPCLR 0x4B68 + * And Linux 1.1.92 implements them. + * Usage: + struct unimapinit { + unsigned short advised_hashsize; + unsigned short advised_hashstep; + unsigned short advised_hashlevel; + } ui; + ioctl(fd, PIO_UNIMAPCLR, &ui); + * to clear the unimap table and advise about the kind of + * hash setup appropriate to what one is going to load + * (with 0 for "don't care"). + struct unipair { + unsigned short unicode; + unsigned short fontpos; + }; + struct unimapdesc { + unsigned short entry_ct; + struct unipair *entries; + } ud; + ioctl(fd, PIO_UNIMAP, &ud); + ioctl(fd, GIO_UNIMAP, &ud); + * to add the indicated pairs to the kernel unimap table + * or to read the kernel unimap table, where in the latter case + * ud.entry_ct indicated the room available. + * + * In Linux 1.3.28 the hash table was replaced by a 3-level + * paged table, so the contents of a struct unimapinit are + * no longer meaningful. + * + * Linux 2.6.1 makes GIO_UNIMAP, PIO_UNIMAP, PIO_UNIMAPCLR per-vt + * so that fd no longer is random. + */ +int getunimap(int fd, struct unimapdesc *ud0) +{ + struct unimapdesc ud; + int ct; + + ud.entry_ct = 0; + ud.entries = 0; + if (ioctl(fd, GIO_UNIMAP, &ud)) { + if (errno != ENOMEM || ud.entry_ct == 0) { + perror("GIO_UNIMAP(0)"); + return -1; + } + ct = ud.entry_ct; + ud.entries = (struct unipair *) + malloc(ct * sizeof(struct unipair)); + if (ud.entries == NULL) { + fprintf(stderr, _("%s: out of memory\n"), progname); + return -1; + } + if (ioctl(fd, GIO_UNIMAP, &ud)) { + perror("GIO_UNIMAP"); + return -1; + } + if (ct != ud.entry_ct) + fprintf(stderr, + _("strange... ct changed from %d to %d\n"), + ct, ud.entry_ct); + /* someone could change the unimap between our + first and second ioctl, so the above errors + are not impossible */ + } + *ud0 = ud; + return 0; +} + +int loadunimap(int fd, struct unimapinit *ui, struct unimapdesc *ud) +{ + struct unimapinit advice; + + if (ui) + advice = *ui; + else { + advice.advised_hashsize = 0; + advice.advised_hashstep = 0; + advice.advised_hashlevel = 0; + } +again: + if (ioctl(fd, PIO_UNIMAPCLR, &advice)) { +#ifdef ENOIOCTLCMD + if (errno == ENOIOCTLCMD) { + fprintf(stderr, + _("It seems this kernel is older than 1.1.92\n" + "No Unicode mapping table loaded.\n")); + } else +#endif + perror("PIO_UNIMAPCLR"); + return -1; + } + if (ud == NULL) + return 0; + + if (ioctl(fd, PIO_UNIMAP, ud)) { + if (errno == ENOMEM && advice.advised_hashlevel < 100) { + advice.advised_hashlevel++; + goto again; + } + perror("PIO_UNIMAP"); + return -1; + } + + return 0; +} diff --git a/src/libkeymap/common.c b/src/libkeymap/common.c index cfe8507..dfb15c0 100644 --- a/src/libkeymap/common.c +++ b/src/libkeymap/common.c @@ -246,5 +246,8 @@ int lk_free(struct lk_ctx *ctx) ctx->key_line = NULL; } + free(ctx); + ctx = NULL; + return 0; } diff --git a/src/libkeymap/common.c.covscan-fixes b/src/libkeymap/common.c.covscan-fixes new file mode 100644 index 0000000..cfe8507 --- /dev/null +++ b/src/libkeymap/common.c.covscan-fixes @@ -0,0 +1,250 @@ +#include "config.h" + +#include +#include +#include + +#include "keymap.h" + +#include "kbd.h" +#include "nls.h" +#include "contextP.h" + +void __attribute__((format(printf, 6, 7))) +lk_log(struct lk_ctx *ctx, int priority, + const char *file, int line, const char *fn, + const char *fmt, ...) +{ + va_list args; + if (ctx->log_fn == NULL) + return; + va_start(args, fmt); + ctx->log_fn(ctx->log_data, priority, file, line, fn, fmt, args); + va_end(args); +} + +#ifndef DEBUG +#define log_unused __attribute__((unused)) +#else +#define log_unused +#endif + +static void __attribute__((format(printf, 6, 0))) +log_file(void *data, + int priority log_unused, + const char *file log_unused, + const int line log_unused, + const char *fn log_unused, + const char *format, va_list args) +{ + FILE *fp = data; +#ifdef DEBUG + char buf[16]; + const char *priname; + + switch (priority) { + case LOG_EMERG: + priname = "EMERGENCY"; + break; + case LOG_ALERT: + priname = "ALERT"; + break; + case LOG_CRIT: + priname = "CRITICAL"; + break; + case LOG_ERR: + priname = "ERROR"; + break; + case LOG_WARNING: + priname = "WARNING"; + break; + case LOG_NOTICE: + priname = "NOTICE"; + break; + case LOG_INFO: + priname = "INFO"; + break; + case LOG_DEBUG: + priname = "DEBUG"; + break; + default: + snprintf(buf, sizeof(buf), "L:%d", priority); + priname = buf; + } + fprintf(fp, "libkeymap: %s %s:%d %s: ", priname, file, line, fn); +#endif + vfprintf(fp, format, args); + fprintf(fp, "\n"); +} + +#undef log_unused + +int lk_set_log_fn(struct lk_ctx *ctx, + void (*log_fn)(void *data, int priority, + const char *file, int line, const char *fn, + const char *format, va_list args), + const void *data) +{ + if (!ctx) + return -1; + + ctx->log_fn = log_fn; + ctx->log_data = (void *)data; + + return 0; +} + +int lk_get_log_priority(struct lk_ctx *ctx) +{ + if (!ctx) + return -1; + + return ctx->log_priority; +} + +int lk_set_log_priority(struct lk_ctx *ctx, int priority) +{ + if (!ctx) + return -1; + + ctx->log_priority = priority; + return 0; +} + +lk_flags +lk_get_parser_flags(struct lk_ctx *ctx) +{ + if (!ctx) + return -1; + + return ctx->flags; +} + +int lk_set_parser_flags(struct lk_ctx *ctx, lk_flags flags) +{ + if (!ctx) + return -1; + + ctx->flags = flags; + return 0; +} + +static int +init_array(struct lk_ctx *ctx, struct lk_array **arr, size_t size) +{ + int rc; + void *ptr; + + ptr = malloc(sizeof(struct lk_array)); + if (!ptr) { + ERR(ctx, _("out of memory")); + return -1; + } + + rc = lk_array_init(ptr, size, 0); + if (rc < 0) { + ERR(ctx, _("unable to initialize array: %s"), strerror(rc)); + return -1; + } + + *arr = ptr; + + return 0; +} + +struct lk_ctx * +lk_init(void) +{ + struct lk_ctx *ctx; + + ctx = malloc(sizeof(struct lk_ctx)); + if (!ctx) + return NULL; + + memset(ctx, 0, sizeof(struct lk_ctx)); + + lk_set_log_fn(ctx, log_file, stderr); + lk_set_log_priority(ctx, LOG_ERR); + + if (init_array(ctx, &ctx->keymap, sizeof(void *)) < 0 || + init_array(ctx, &ctx->func_table, sizeof(void *)) < 0 || + init_array(ctx, &ctx->accent_table, sizeof(void *)) < 0 || + init_array(ctx, &ctx->key_constant, sizeof(char)) < 0 || + init_array(ctx, &ctx->key_line, sizeof(int)) < 0) { + lk_free(ctx); + return NULL; + } + + return ctx; +} + +int lk_free(struct lk_ctx *ctx) +{ + unsigned int i; //, j; + + if (!ctx) + return -1; + + if (ctx->keymap) { + for (i = 0; i < ctx->keymap->total; i++) { + struct lk_array *map; + + map = lk_array_get_ptr(ctx->keymap, i); + if (!map) + continue; + + lk_array_free(map); + free(map); + } + lk_array_free(ctx->keymap); + free(ctx->keymap); + + ctx->keymap = NULL; + } + + if (ctx->func_table) { + for (i = 0; i < ctx->func_table->total; i++) { + char *ptr; + + ptr = lk_array_get_ptr(ctx->func_table, i); + if (!ptr) + continue; + + free(ptr); + } + lk_array_free(ctx->func_table); + free(ctx->func_table); + + ctx->func_table = NULL; + } + + if (ctx->accent_table) { + for (i = 0; i < ctx->accent_table->total; i++) { + struct lk_array *ptr; + + ptr = lk_array_get_ptr(ctx->accent_table, i); + if (!ptr) + continue; + + free(ptr); + } + lk_array_free(ctx->accent_table); + free(ctx->accent_table); + + ctx->accent_table = NULL; + } + + if (ctx->key_constant) { + lk_array_free(ctx->key_constant); + free(ctx->key_constant); + ctx->key_constant = NULL; + } + + if (ctx->key_line) { + lk_array_free(ctx->key_line); + free(ctx->key_line); + ctx->key_line = NULL; + } + + return 0; +} diff --git a/src/setfont.c b/src/setfont.c index d5a577d..e1a16c4 100644 --- a/src/setfont.c +++ b/src/setfont.c @@ -327,6 +327,8 @@ do_loadfont(int fd, char *inbuf, int width, int height, int hwunit, if (putfont(fd, buf, fontsize, width, hwunit)) exit(EX_OSERR); + + free(buf); } static void diff --git a/src/setfont.c.covscan-fixes b/src/setfont.c.covscan-fixes new file mode 100644 index 0000000..d5a577d --- /dev/null +++ b/src/setfont.c.covscan-fixes @@ -0,0 +1,758 @@ +/* + * setfont.c - Eugene Crosser & Andries Brouwer + * + * Version 1.05 + * + * Loads the console font, and possibly the corresponding screen map(s). + * We accept two kind of screen maps, one [-m] giving the correspondence + * between some arbitrary 8-bit character set currently in use and the + * font positions, and the second [-u] giving the correspondence between + * font positions and Unicode values. + */ +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "paths.h" +#include "getfd.h" +#include "findfile.h" +#include "loadunimap.h" +#include "psf.h" +#include "psffontop.h" +#include "kdfontop.h" +#include "kdmapop.h" +#include "xmalloc.h" +#include "nls.h" +#include "version.h" +#include "kbd_error.h" + +static int position_codepage(int iunit); +static void saveoldfont(int fd, char *ofil); +static void saveoldfontplusunicodemap(int fd, char *Ofil); +static void loadnewfont(int fd, char *ifil, + int iunit, int hwunit, int no_m, int no_u); +static void loadnewfonts(int fd, char **ifiles, int ifilct, + int iunit, int hwunit, int no_m, int no_u); +extern void saveoldmap(int fd, char *omfil); +extern void loadnewmap(int fd, char *mfil); +extern void activatemap(int fd); +extern void disactivatemap(int fd); + +int verbose = 0; +int force = 0; +int debug = 0; + +/* search for the font in these directories (with trailing /) */ +const char *const fontdirpath[] = { "", DATADIR "/" FONTDIR "/", 0 }; +const char *const fontsuffixes[] = { "", ".psfu", ".psf", ".cp", ".fnt", 0 }; +/* hide partial fonts a bit - loading a single one is a bad idea */ +const char *const partfontdirpath[] = { "", DATADIR "/" FONTDIR "/" PARTIALDIR "/", 0 }; +const char *const partfontsuffixes[] = { "", 0 }; + +static inline int +findfont(char *fnam, lkfile_t *fp) +{ + return lk_findfile(fnam, fontdirpath, fontsuffixes, fp); +} + +static inline int +findpartialfont(char *fnam, lkfile_t *fp) +{ + return lk_findfile(fnam, partfontdirpath, partfontsuffixes, fp); +} + +static void __attribute__((noreturn)) +usage(void) +{ + fprintf(stderr, _( + "Usage: setfont [write-options] [-] [newfont..] [-m consolemap] [-u unicodemap]\n" + " write-options (take place before file loading):\n" + " -o Write current font to \n" + " -O Write current font and unicode map to \n" + " -om Write current consolemap to \n" + " -ou Write current unicodemap to \n" + "If no newfont and no -[o|O|om|ou|m|u] option is given,\n" + "a default font is loaded:\n" + " setfont Load font \"default[.gz]\"\n" + " setfont - Load font \"default8x[.gz]\"\n" + "The - option selects a font from a codepage that contains three fonts:\n" + " setfont -{8|14|16} codepage.cp[.gz] Load 8x font from codepage.cp\n" + "Explicitly (with -m or -u) or implicitly (in the fontfile) given mappings\n" + "will be loaded and, in the case of consolemaps, activated.\n" + " -h (no space) Override font height.\n" + " -m Load console screen map.\n" + " -u Load font unicode map.\n" + " -m none Suppress loading and activation of a screen map.\n" + " -u none Suppress loading of a unicode map.\n" + " -v Be verbose.\n" + " -C Indicate console device to be used.\n" + " -V Print version and exit.\n" + "Files are loaded from the current directory or %s/*/.\n"), + DATADIR); + exit(EX_USAGE); +} + +#define MAXIFILES 256 + +int main(int argc, char *argv[]) +{ + char *ifiles[MAXIFILES]; + char *mfil, *ufil, *Ofil, *ofil, *omfil, *oufil, *console; + int ifilct = 0, fd, i, iunit, hwunit, no_m, no_u; + int restore = 0; + + set_progname(argv[0]); + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE_NAME, LOCALEDIR); + textdomain(PACKAGE_NAME); + + ifiles[0] = mfil = ufil = Ofil = ofil = omfil = oufil = NULL; + iunit = hwunit = 0; + no_m = no_u = 0; + console = NULL; + + /* + * No getopt() here because of the -om etc options. + */ + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-V")) { + print_version_and_exit(); + } else if (!strcmp(argv[i], "-v")) { + verbose++; + } else if (!strcmp(argv[i], "-R")) { + restore = 1; + } else if (!strcmp(argv[i], "-C")) { + if (++i == argc || console) + usage(); + console = argv[i]; + } else if (!strcmp(argv[i], "-O")) { + if (++i == argc || Ofil) + usage(); + Ofil = argv[i]; + } else if (!strcmp(argv[i], "-o")) { + if (++i == argc || ofil) + usage(); + ofil = argv[i]; + } else if (!strcmp(argv[i], "-om")) { + if (++i == argc || omfil) + usage(); + omfil = argv[i]; + } else if (!strcmp(argv[i], "-ou")) { + if (++i == argc || oufil) + usage(); + oufil = argv[i]; + } else if (!strcmp(argv[i], "-m")) { + if (++i == argc || mfil) + usage(); + if (!strcmp(argv[i], "none")) + no_m = 1; + else + mfil = argv[i]; + } else if (!strcmp(argv[i], "-u")) { + if (++i == argc || ufil) + usage(); + if (!strcmp(argv[i], "none")) + no_u = 1; + else + ufil = argv[i]; + } else if (!strcmp(argv[i], "-f")) { + force = 1; + } else if (!strncmp(argv[i], "-h", 2)) { + hwunit = atoi(argv[i] + 2); + if (hwunit <= 0 || hwunit > 32) + usage(); + } else if (argv[i][0] == '-') { + iunit = atoi(argv[i] + 1); + if (iunit <= 0 || iunit > 32) + usage(); + } else { + if (ifilct == MAXIFILES) { + fprintf(stderr, _("setfont: too many input files\n")); + exit(EX_USAGE); + } + ifiles[ifilct++] = argv[i]; + } + } + + if (ifilct && restore) { + fprintf(stderr, _("setfont: cannot both restore from character ROM" + " and from file. Font unchanged.\n")); + exit(EX_USAGE); + } + + if ((fd = getfd(console)) < 0) + kbd_error(EXIT_FAILURE, 0, _("Couldn't get a file descriptor referring to the console")); + + int kd_mode = -1; + if (!ioctl(fd, KDGETMODE, &kd_mode) && (kd_mode == KD_GRAPHICS)) { + /* + * PIO_FONT will fail on a console which is in foreground and in KD_GRAPHICS mode. + * 2005-03-03, jw@suse.de. + */ + if (verbose) + printf("setfont: graphics console %s skipped\n", console ? console : ""); + close(fd); + return 0; + } + + if (!ifilct && !mfil && !ufil && + !Ofil && !ofil && !omfil && !oufil && !restore) + /* reset to some default */ + ifiles[ifilct++] = ""; + + if (Ofil) + saveoldfontplusunicodemap(fd, Ofil); + + if (ofil) + saveoldfont(fd, ofil); + + if (omfil) + saveoldmap(fd, omfil); + + if (oufil) + saveunicodemap(fd, oufil); + + if (mfil) { + loadnewmap(fd, mfil); + activatemap(fd); + no_m = 1; + } + + if (ufil) + no_u = 1; + + if (restore) + restorefont(fd); + + if (ifilct) + loadnewfonts(fd, ifiles, ifilct, iunit, hwunit, no_m, no_u); + + if (ufil) + loadunicodemap(fd, ufil); + + return 0; +} + +/* + * 0 - do not test, 1 - test and warn, 2 - test and wipe, 3 - refuse + */ +static int erase_mode = 1; + +static void +do_loadfont(int fd, char *inbuf, int width, int height, int hwunit, + int fontsize, char *filename) +{ + unsigned char *buf; + int i, buflen; + int bytewidth = (width + 7) / 8; + int charsize = height * bytewidth; + int kcharsize = 32 * bytewidth; + int bad_video_erase_char = 0; + + if (height < 1 || height > 32) { + fprintf(stderr, _("Bad character height %d\n"), height); + exit(EX_DATAERR); + } + if (width < 1 || width > 32) { + fprintf(stderr, _("Bad character width %d\n"), width); + exit(EX_DATAERR); + } + + if (!hwunit) + hwunit = height; + + buflen = kcharsize * ((fontsize < 128) ? 128 : fontsize); + buf = xmalloc(buflen); + memset(buf, 0, buflen); + + for (i = 0; i < fontsize; i++) + memcpy(buf + (i * kcharsize), inbuf + (i * charsize), charsize); + + /* + * Due to a kernel bug, font position 32 is used + * to erase the screen, regardless of maps loaded. + * So, usually this font position should be blank. + */ + if (erase_mode) { + for (i = 0; i < kcharsize; i++) + if (buf[32 * kcharsize + i]) + bad_video_erase_char = 1; + if (bad_video_erase_char) { + fprintf(stderr, + _("%s: font position 32 is nonblank\n"), + progname); + switch (erase_mode) { + case 3: + exit(EX_DATAERR); + case 2: + for (i = 0; i < kcharsize; i++) + buf[32 * kcharsize + i] = 0; + fprintf(stderr, _("%s: wiped it\n"), progname); + break; + case 1: + fprintf(stderr, + _("%s: background will look funny\n"), + progname); + } + fflush(stderr); + sleep(2); + } + } + + if (verbose) { + if (height == hwunit && filename) + printf(_("Loading %d-char %dx%d font from file %s\n"), + fontsize, width, height, filename); + else if (height == hwunit) + printf(_("Loading %d-char %dx%d font\n"), + fontsize, width, height); + else if (filename) + printf(_("Loading %d-char %dx%d (%d) font from file %s\n"), + fontsize, width, height, hwunit, filename); + else + printf(_("Loading %d-char %dx%d (%d) font\n"), + fontsize, width, height, hwunit); + } + + if (putfont(fd, buf, fontsize, width, hwunit)) + exit(EX_OSERR); +} + +static void +do_loadtable(int fd, struct unicode_list *uclistheads, int fontsize) +{ + struct unimapdesc ud; + struct unipair *up; + int i, ct = 0, maxct; + struct unicode_list *ul; + struct unicode_seq *us; + + maxct = 0; + for (i = 0; i < fontsize; i++) { + ul = uclistheads[i].next; + while (ul) { + us = ul->seq; + if (us && !us->next) + maxct++; + ul = ul->next; + } + } + up = xmalloc(maxct * sizeof(struct unipair)); + for (i = 0; i < fontsize; i++) { + ul = uclistheads[i].next; + if (debug) + printf("char %03x:", i); + while (ul) { + us = ul->seq; + if (us && !us->next) { + up[ct].unicode = us->uc; + up[ct].fontpos = i; + ct++; + if (debug) + printf(" %04x", us->uc); + } else if (debug) { + printf(" seq: <"); + while (us) { + printf(" %04x", us->uc); + us = us->next; + } + printf(" >"); + } + ul = ul->next; + if (debug) + printf(","); + } + if (debug) + printf("\n"); + } + if (ct != maxct) { + char *u = _("%s: bug in do_loadtable\n"); + fprintf(stderr, u, progname); + exit(EX_SOFTWARE); + } + + if (verbose) + printf(_("Loading Unicode mapping table...\n")); + + ud.entry_ct = ct; + ud.entries = up; + if (loadunimap(fd, NULL, &ud)) + exit(EX_OSERR); +} + +static void +loadnewfonts(int fd, char **ifiles, int ifilct, + int iunit, int hwunit, int no_m, int no_u) +{ + char *ifil, *inbuf, *fontbuf, *bigfontbuf; + int inputlth, fontbuflth, fontsize, height, width, bytewidth; + int bigfontbuflth, bigfontsize, bigheight, bigwidth; + struct unicode_list *uclistheads; + int i; + lkfile_t fp; + + if (ifilct == 1) { + loadnewfont(fd, ifiles[0], iunit, hwunit, no_m, no_u); + return; + } + + /* several fonts that must be merged */ + /* We just concatenate the bitmaps - only allow psf fonts */ + bigfontbuf = NULL; + bigfontbuflth = 0; + bigfontsize = 0; + uclistheads = NULL; + bigheight = 0; + bigwidth = 0; + + for (i = 0; i < ifilct; i++) { + ifil = ifiles[i]; + if (findfont(ifil, &fp) && findpartialfont(ifil, &fp)) { + fprintf(stderr, _("Cannot open font file %s\n"), ifil); + exit(EX_NOINPUT); + } + + inbuf = fontbuf = NULL; + inputlth = fontbuflth = 0; + fontsize = 0; + + if (readpsffont(fp.fd, &inbuf, &inputlth, &fontbuf, &fontbuflth, + &width, &fontsize, bigfontsize, + no_u ? NULL : &uclistheads)) { + fprintf(stderr, _("When loading several fonts, all " + "must be psf fonts - %s isn't\n"), + fp.pathname); + lk_fpclose(&fp); + exit(EX_DATAERR); + } + lk_fpclose(&fp); // avoid zombies, jw@suse.de (#88501) + bytewidth = (width + 7) / 8; + height = fontbuflth / (bytewidth * fontsize); + if (verbose) + printf(_("Read %d-char %dx%d font from file %s\n"), + fontsize, width, height, fp.pathname); + + if (bigheight == 0) + bigheight = height; + else if (bigheight != height) { + fprintf(stderr, _("When loading several fonts, all " + "must have the same height\n")); + exit(EX_DATAERR); + } + if (bigwidth == 0) + bigwidth = width; + else if (bigwidth != width) { + fprintf(stderr, _("When loading several fonts, all " + "must have the same width\n")); + exit(EX_DATAERR); + } + + bigfontsize += fontsize; + bigfontbuflth += fontbuflth; + bigfontbuf = xrealloc(bigfontbuf, bigfontbuflth); + memcpy(bigfontbuf + bigfontbuflth - fontbuflth, + fontbuf, fontbuflth); + } + do_loadfont(fd, bigfontbuf, bigwidth, bigheight, hwunit, + bigfontsize, NULL); + free(bigfontbuf); + + if (uclistheads && !no_u) + do_loadtable(fd, uclistheads, bigfontsize); +} + +static void +loadnewfont(int fd, char *ifil, int iunit, int hwunit, int no_m, int no_u) +{ + lkfile_t fp; + char defname[20]; + int height, width, bytewidth, def = 0; + char *inbuf, *fontbuf; + int inputlth, fontbuflth, fontsize, offset; + struct unicode_list *uclistheads; + + if (!*ifil) { + /* try to find some default file */ + + def = 1; /* maybe also load default unimap */ + + if (iunit < 0 || iunit > 32) + iunit = 0; + if (iunit == 0) { + if (findfont(ifil = "default", &fp) && + findfont(ifil = "default8x16", &fp) && + findfont(ifil = "default8x14", &fp) && + findfont(ifil = "default8x8", &fp)) { + fprintf(stderr, _("Cannot find default font\n")); + exit(EX_NOINPUT); + } + } else { + sprintf(defname, "default8x%d", iunit); + if (findfont(ifil = defname, &fp) && + findfont(ifil = "default", &fp)) { + fprintf(stderr, _("Cannot find %s font\n"), ifil); + exit(EX_NOINPUT); + } + } + } else { + if (findfont(ifil, &fp)) { + fprintf(stderr, _("Cannot open font file %s\n"), ifil); + exit(EX_NOINPUT); + } + } + + if (verbose > 1) + printf(_("Reading font file %s\n"), ifil); + + inbuf = fontbuf = NULL; + inputlth = fontbuflth = fontsize = 0; + width = 8; + uclistheads = NULL; + if (readpsffont(fp.fd, &inbuf, &inputlth, &fontbuf, &fontbuflth, + &width, &fontsize, 0, + no_u ? NULL : &uclistheads) == 0) { + lk_fpclose(&fp); + /* we've got a psf font */ + bytewidth = (width + 7) / 8; + height = fontbuflth / (bytewidth * fontsize); + + do_loadfont(fd, fontbuf, width, height, hwunit, + fontsize, fp.pathname); + if (uclistheads && !no_u) + do_loadtable(fd, uclistheads, fontsize); +#if 1 + if (!uclistheads && !no_u && def) + loadunicodemap(fd, "def.uni"); +#endif + return; + } + lk_fpclose(&fp); // avoid zombies, jw@suse.de (#88501) + + /* instructions to combine fonts? */ + { + char *combineheader = "# combine partial fonts\n"; + int chlth = strlen(combineheader); + char *p, *q; + if (inputlth >= chlth && !strncmp(inbuf, combineheader, chlth)) { + char *ifiles[MAXIFILES]; + int ifilct = 0; + q = inbuf + chlth; + while (q < inbuf + inputlth) { + p = q; + while (q < inbuf + inputlth && *q != '\n') + q++; + if (q == inbuf + inputlth) { + fprintf(stderr, + _("No final newline in combine file\n")); + exit(EX_DATAERR); + } + *q++ = 0; + if (ifilct == MAXIFILES) { + fprintf(stderr, + _("Too many files to combine\n")); + exit(EX_DATAERR); + } + ifiles[ifilct++] = p; + } + /* recursive call */ + loadnewfonts(fd, ifiles, ifilct, iunit, hwunit, no_m, no_u); + return; + } + } + + /* file with three code pages? */ + if (inputlth == 9780) { + offset = position_codepage(iunit); + height = iunit; + fontsize = 256; + width = 8; + } else if (inputlth == 32768) { + /* restorefont -w writes a SVGA font to file + restorefont -r restores it + These fonts have size 32768, for two 512-char fonts. + In fact, when BROKEN_GRAPHICS_PROGRAMS is defined, + and it always is, there is no default font that is saved, + so probably the second half is always garbage. */ + fprintf(stderr, _("Hmm - a font from restorefont? " + "Using the first half.\n")); + inputlth = 16384; /* ignore rest */ + fontsize = 512; + offset = 0; + width = 8; + height = 32; + if (!hwunit) + hwunit = 16; + } else { + int rem = (inputlth % 256); + if (rem == 0 || rem == 40) { + /* 0: bare code page bitmap */ + /* 40: preceded by .cp header */ + /* we might check some header details */ + offset = rem; + } else { + fprintf(stderr, _("Bad input file size\n")); + exit(EX_DATAERR); + } + fontsize = 256; + width = 8; + height = inputlth / 256; + } + do_loadfont(fd, inbuf + offset, width, height, hwunit, fontsize, + fp.pathname); +} + +static int +position_codepage(int iunit) +{ + int offset; + + /* code page: first 40 bytes, then 8x16 font, + then 6 bytes, then 8x14 font, + then 6 bytes, then 8x8 font */ + + if (!iunit) { + fprintf(stderr, + _("This file contains 3 fonts: 8x8, 8x14 and 8x16." + " Please indicate\n" + "using an option -8 or -14 or -16 " + "which one you want loaded.\n")); + exit(EX_USAGE); + } + switch (iunit) { + case 8: + offset = 7732; + break; + case 14: + offset = 4142; + break; + case 16: + offset = 40; + break; + default: + fprintf(stderr, _("You asked for font size %d, " + "but only 8, 14, 16 are possible here.\n"), + iunit); + exit(EX_USAGE); + } + return offset; +} + +static void +do_saveoldfont(int fd, char *ofil, FILE *fpo, int unimap_follows, + int *count, int *utf8) +{ + +/* this is the max font size the kernel is willing to handle */ +#define MAXFONTSIZE 65536 + unsigned char buf[MAXFONTSIZE]; + + int i, ct, width, height, bytewidth, charsize, kcharsize; + + ct = sizeof(buf) / (32 * 32 / 8); /* max size 32x32, 8 bits/byte */ + if (getfont(fd, buf, &ct, &width, &height)) + exit(EX_OSERR); + + /* save as efficiently as possible */ + bytewidth = (width + 7) / 8; + height = font_charheight(buf, ct, width); + charsize = height * bytewidth; + kcharsize = 32 * bytewidth; + +/* Do we need a psf header? */ +/* Yes if ct==512 - otherwise we cannot distinguish + a 512-char 8x8 and a 256-char 8x16 font. */ +#define ALWAYS_PSF_HEADER 1 + + if (ct != 256 || width != 8 || unimap_follows || ALWAYS_PSF_HEADER) { + int psftype = 1; + int flags = 0; + + if (unimap_follows) + flags |= WPSFH_HASTAB; + writepsffontheader(fpo, width, height, ct, &psftype, flags); + if (utf8) + *utf8 = (psftype == 2); + } + + if (height == 0) { + fprintf(stderr, _("Found nothing to save\n")); + } else { + for (i = 0; i < ct; i++) { + if (fwrite(buf + (i * kcharsize), charsize, 1, fpo) != 1) { + fprintf(stderr, _("Cannot write font file")); + exit(EX_IOERR); + } + } + if (verbose) { + printf(_("Saved %d-char %dx%d font file on %s\n"), + ct, width, height, ofil); + } + } + + if (count) + *count = ct; +} + +static void +saveoldfont(int fd, char *ofil) +{ + FILE *fpo; + + if ((fpo = fopen(ofil, "w")) == NULL) { + perror(ofil); + exit(EX_CANTCREAT); + } + do_saveoldfont(fd, ofil, fpo, 0, NULL, NULL); + fclose(fpo); +} + +static void +saveoldfontplusunicodemap(int fd, char *Ofil) +{ + FILE *fpo; + int ct; + int utf8 = 0; + + if ((fpo = fopen(Ofil, "w")) == NULL) { + perror(Ofil); + exit(EX_CANTCREAT); + } + ct = 0; + do_saveoldfont(fd, Ofil, fpo, 1, &ct, &utf8); + appendunicodemap(fd, fpo, ct, utf8); + fclose(fpo); +} + +/* Only on the current console? On all allocated consoles? */ +/* A newly allocated console has NORM_MAP by default - + probably it should copy the default from the current console? + But what if we want a new one because the current one is messed up? */ +/* For the moment: only the current console, only the G0 set */ + +static void +send_escseq(int fd, char *seq, int n) +{ + if (write(fd, seq, n) != n) /* maybe fd is read-only */ + printf("%s", seq); +} + +void activatemap(int fd) +{ + send_escseq(fd, "\033(K", 3); +} + +void disactivatemap(int fd) +{ + send_escseq(fd, "\033(B", 3); +}