2 * setfont.c - Eugene Crosser & Andries Brouwer
6 * Loads the console font, and possibly the corresponding screen map(s).
7 * We accept two kind of screen maps, one [-m] giving the correspondence
8 * between some arbitrary 8-bit character set currently in use and the
9 * font positions, and the second [-u] giving the correspondence between
10 * font positions and Unicode values.
19 #include <sys/types.h>
21 #include <sys/ioctl.h>
28 #include "loadunimap.h"
30 #include "psffontop.h"
37 static int position_codepage(int iunit);
38 static void saveoldfont(int fd, char *ofil);
39 static void saveoldfontplusunicodemap(int fd, char *Ofil);
40 static void loadnewfont(int fd, char *ifil,
41 int iunit, int hwunit, int no_m, int no_u);
42 static void loadnewfonts(int fd, char **ifiles, int ifilct,
43 int iunit, int hwunit, int no_m, int no_u);
44 extern void saveoldmap(int fd, char *omfil);
45 extern void loadnewmap(int fd, char *mfil);
46 extern void activatemap(int fd);
47 extern void disactivatemap(int fd);
53 /* search for the font in these directories (with trailing /) */
54 const char *const fontdirpath[] = { "", DATADIR "/" FONTDIR "/", 0 };
55 const char *const fontsuffixes[] = { "", ".psfu", ".psf", ".cp", ".fnt", 0 };
56 /* hide partial fonts a bit - loading a single one is a bad idea */
57 const char *const partfontdirpath[] = { "", DATADIR "/" FONTDIR "/" PARTIALDIR "/", 0 };
58 const char *const partfontsuffixes[] = { "", 0 };
61 findfont(char *fnam, lkfile_t *fp) {
62 return lk_findfile(fnam, fontdirpath, fontsuffixes, fp);
66 findpartialfont(char *fnam, lkfile_t *fp) {
67 return lk_findfile(fnam, partfontdirpath, partfontsuffixes, fp);
70 static void __attribute__ ((noreturn))
74 "Usage: setfont [write-options] [-<N>] [newfont..] [-m consolemap] [-u unicodemap]\n"
75 " write-options (take place before file loading):\n"
76 " -o <filename> Write current font to <filename>\n"
77 " -O <filename> Write current font and unicode map to <filename>\n"
78 " -om <filename> Write current consolemap to <filename>\n"
79 " -ou <filename> Write current unicodemap to <filename>\n"
80 "If no newfont and no -[o|O|om|ou|m|u] option is given,\n"
81 "a default font is loaded:\n"
82 " setfont Load font \"default[.gz]\"\n"
83 " setfont -<N> Load font \"default8x<N>[.gz]\"\n"
84 "The -<N> option selects a font from a codepage that contains three fonts:\n"
85 " setfont -{8|14|16} codepage.cp[.gz] Load 8x<N> font from codepage.cp\n"
86 "Explicitly (with -m or -u) or implicitly (in the fontfile) given mappings\n"
87 "will be loaded and, in the case of consolemaps, activated.\n"
88 " -h<N> (no space) Override font height.\n"
89 " -m <fn> Load console screen map.\n"
90 " -u <fn> Load font unicode map.\n"
91 " -m none Suppress loading and activation of a screen map.\n"
92 " -u none Suppress loading of a unicode map.\n"
94 " -C <cons> Indicate console device to be used.\n"
95 " -V Print version and exit.\n"
96 "Files are loaded from the current directory or %s/*/.\n"
101 #define MAXIFILES 256
104 main(int argc, char *argv[]) {
105 char *ifiles[MAXIFILES];
106 char *mfil, *ufil, *Ofil, *ofil, *omfil, *oufil, *console;
107 int ifilct = 0, fd, i, iunit, hwunit, no_m, no_u;
110 set_progname(argv[0]);
112 setlocale(LC_ALL, "");
113 bindtextdomain(PACKAGE_NAME, LOCALEDIR);
114 textdomain(PACKAGE_NAME);
116 ifiles[0] = mfil = ufil = Ofil = ofil = omfil = oufil = NULL;
122 * No getopt() here because of the -om etc options.
124 for (i = 1; i < argc; i++) {
125 if (!strcmp(argv[i], "-V")) {
126 print_version_and_exit();
127 } else if (!strcmp(argv[i], "-v")) {
129 } else if (!strcmp(argv[i], "-R")) {
131 } else if (!strcmp(argv[i], "-C")) {
132 if (++i == argc || console)
135 } else if (!strcmp(argv[i], "-O")) {
136 if (++i == argc || Ofil)
139 } else if (!strcmp(argv[i], "-o")) {
140 if (++i == argc || ofil)
143 } else if (!strcmp(argv[i], "-om")) {
144 if (++i == argc || omfil)
147 } else if (!strcmp(argv[i], "-ou")) {
148 if (++i == argc || oufil)
151 } else if (!strcmp(argv[i], "-m")) {
152 if (++i == argc || mfil)
154 if (!strcmp(argv[i], "none"))
158 } else if (!strcmp(argv[i], "-u")) {
159 if (++i == argc || ufil)
161 if (!strcmp(argv[i], "none"))
165 } else if (!strcmp(argv[i], "-f")) {
167 } else if (!strncmp(argv[i], "-h", 2)) {
168 hwunit = atoi(argv[i]+2);
169 if (hwunit <= 0 || hwunit > 32)
171 } else if (argv[i][0] == '-') {
172 iunit = atoi(argv[i]+1);
173 if(iunit <= 0 || iunit > 32)
176 if (ifilct == MAXIFILES) {
177 fprintf(stderr, _("setfont: too many input files\n"));
180 ifiles[ifilct++] = argv[i];
184 if (ifilct && restore) {
185 fprintf(stderr, _("setfont: cannot both restore from character ROM"
186 " and from file. Font unchanged.\n"));
193 if (!ioctl(fd, KDGETMODE, &kd_mode) && (kd_mode == KD_GRAPHICS))
196 * PIO_FONT will fail on a console which is in foreground and in KD_GRAPHICS mode.
197 * 2005-03-03, jw@suse.de.
200 printf("setfont: graphics console %s skipped\n", console?console:"");
205 if (!ifilct && !mfil && !ufil &&
206 !Ofil && !ofil && !omfil && !oufil && !restore)
207 /* reset to some default */
208 ifiles[ifilct++] = "";
211 saveoldfontplusunicodemap(fd, Ofil);
214 saveoldfont(fd, ofil);
217 saveoldmap(fd, omfil);
220 saveunicodemap(fd, oufil);
223 loadnewmap(fd, mfil);
235 loadnewfonts(fd, ifiles, ifilct, iunit, hwunit, no_m, no_u);
238 loadunicodemap(fd, ufil);
244 * 0 - do not test, 1 - test and warn, 2 - test and wipe, 3 - refuse
246 static int erase_mode = 1;
249 do_loadfont(int fd, char *inbuf, int width, int height, int hwunit,
250 int fontsize, char *filename) {
253 int bytewidth = (width+7)/8;
254 int charsize = height * bytewidth;
255 int kcharsize = 32 * bytewidth;
256 int bad_video_erase_char = 0;
258 if (height < 1 || height > 32) {
259 fprintf(stderr, _("Bad character height %d\n"), height);
262 if (width < 1 || width > 32) {
263 fprintf(stderr, _("Bad character width %d\n"), width);
270 buflen = kcharsize * ((fontsize < 128) ? 128 : fontsize);
271 buf = xmalloc(buflen);
272 memset(buf,0,buflen);
274 for (i = 0; i < fontsize; i++)
275 memcpy(buf+(i*kcharsize), inbuf+(i*charsize), charsize);
278 * Due to a kernel bug, font position 32 is used
279 * to erase the screen, regardless of maps loaded.
280 * So, usually this font position should be blank.
283 for (i = 0; i < kcharsize; i++)
284 if (buf[32*kcharsize+i])
285 bad_video_erase_char = 1;
286 if (bad_video_erase_char) {
288 _("%s: font position 32 is nonblank\n"),
294 for (i = 0; i < kcharsize; i++)
295 buf[32*kcharsize+i] = 0;
296 fprintf(stderr, _("%s: wiped it\n"), progname);
300 _("%s: background will look funny\n"),
309 if (height == hwunit && filename)
310 printf(_("Loading %d-char %dx%d font from file %s\n"),
311 fontsize, width, height, filename);
312 else if (height == hwunit)
313 printf(_("Loading %d-char %dx%d font\n"),
314 fontsize, width, height);
316 printf(_("Loading %d-char %dx%d (%d) font from file %s\n"),
317 fontsize, width, height, hwunit, filename);
319 printf(_("Loading %d-char %dx%d (%d) font\n"),
320 fontsize, width, height, hwunit);
323 if (putfont(fd, buf, fontsize, width, hwunit))
328 do_loadtable(int fd, struct unicode_list *uclistheads, int fontsize) {
329 struct unimapdesc ud;
331 int i, ct = 0, maxct;
332 struct unicode_list *ul;
333 struct unicode_seq *us;
336 for (i = 0; i < fontsize; i++) {
337 ul = uclistheads[i].next;
340 if (us && ! us->next)
345 up = xmalloc(maxct * sizeof(struct unipair));
346 for (i = 0; i < fontsize; i++) {
347 ul = uclistheads[i].next;
348 if (debug) printf ("char %03x:", i);
351 if (us && ! us->next) {
352 up[ct].unicode = us->uc;
355 if (debug) printf (" %04x", us->uc);
361 printf (" %04x", us->uc);
367 if (debug) printf (",");
369 if (debug) printf ("\n");
372 char *u = _("%s: bug in do_loadtable\n");
373 fprintf(stderr, u, progname);
378 printf(_("Loading Unicode mapping table...\n"));
382 if (loadunimap(fd, NULL, &ud))
387 loadnewfonts(int fd, char **ifiles, int ifilct,
388 int iunit, int hwunit, int no_m, int no_u)
390 char *ifil, *inbuf, *fontbuf, *bigfontbuf;
391 int inputlth, fontbuflth, fontsize, height, width, bytewidth;
392 int bigfontbuflth, bigfontsize, bigheight, bigwidth;
393 struct unicode_list *uclistheads;
398 loadnewfont(fd, ifiles[0], iunit, hwunit, no_m, no_u);
402 /* several fonts that must be merged */
403 /* We just concatenate the bitmaps - only allow psf fonts */
411 for (i=0; i<ifilct; i++) {
413 if (findfont(ifil, &fp) && findpartialfont(ifil, &fp)) {
414 fprintf(stderr, _("Cannot open font file %s\n"), ifil);
418 inbuf = fontbuf = NULL;
419 inputlth = fontbuflth = 0;
422 if(readpsffont(fp.fd, &inbuf, &inputlth, &fontbuf, &fontbuflth,
423 &width, &fontsize, bigfontsize,
424 no_u ? NULL : &uclistheads)) {
425 fprintf(stderr, _("When loading several fonts, all "
426 "must be psf fonts - %s isn't\n"),
431 lk_fpclose(&fp); // avoid zombies, jw@suse.de (#88501)
432 bytewidth = (width+7) / 8;
433 height = fontbuflth / (bytewidth * fontsize);
435 printf(_("Read %d-char %dx%d font from file %s\n"),
436 fontsize, width, height, fp.pathname);
440 else if (bigheight != height) {
441 fprintf(stderr, _("When loading several fonts, all "
442 "must have the same height\n"));
447 else if (bigwidth != width) {
448 fprintf(stderr, _("When loading several fonts, all "
449 "must have the same width\n"));
453 bigfontsize += fontsize;
454 bigfontbuflth += fontbuflth;
455 bigfontbuf = xrealloc(bigfontbuf, bigfontbuflth);
456 memcpy(bigfontbuf+bigfontbuflth-fontbuflth,
457 fontbuf, fontbuflth);
459 do_loadfont(fd, bigfontbuf, bigwidth, bigheight, hwunit,
462 if (uclistheads && !no_u)
463 do_loadtable(fd, uclistheads, bigfontsize);
467 loadnewfont(int fd, char *ifil, int iunit, int hwunit, int no_m, int no_u)
471 int height, width, bytewidth, def = 0;
472 char *inbuf, *fontbuf;
473 int inputlth, fontbuflth, fontsize, offset;
474 struct unicode_list *uclistheads;
477 /* try to find some default file */
479 def = 1; /* maybe also load default unimap */
481 if (iunit < 0 || iunit > 32)
484 if (findfont(ifil = "default", &fp) &&
485 findfont(ifil = "default8x16", &fp) &&
486 findfont(ifil = "default8x14", &fp) &&
487 findfont(ifil = "default8x8", &fp)) {
488 fprintf(stderr, _("Cannot find default font\n"));
492 sprintf(defname, "default8x%d", iunit);
493 if (findfont(ifil = defname, &fp) &&
494 findfont(ifil = "default", &fp)) {
495 fprintf(stderr, _("Cannot find %s font\n"), ifil);
500 if (findfont(ifil, &fp)) {
501 fprintf(stderr, _("Cannot open font file %s\n"), ifil);
507 printf(_("Reading font file %s\n"), ifil);
509 inbuf = fontbuf = NULL;
510 inputlth = fontbuflth = fontsize = 0;
513 if(readpsffont(fp.fd, &inbuf, &inputlth, &fontbuf, &fontbuflth,
514 &width, &fontsize, 0,
515 no_u ? NULL : &uclistheads) == 0) {
517 /* we've got a psf font */
518 bytewidth = (width+7) / 8;
519 height = fontbuflth / (bytewidth * fontsize);
521 do_loadfont(fd, fontbuf, width, height, hwunit,
522 fontsize, fp.pathname);
523 if (uclistheads && !no_u)
524 do_loadtable(fd, uclistheads, fontsize);
526 if (!uclistheads && !no_u && def)
527 loadunicodemap(fd, "def.uni");
531 lk_fpclose(&fp); // avoid zombies, jw@suse.de (#88501)
533 /* instructions to combine fonts? */
534 { char *combineheader = "# combine partial fonts\n";
535 int chlth = strlen(combineheader);
537 if (inputlth >= chlth && !strncmp(inbuf, combineheader, chlth)) {
538 char *ifiles[MAXIFILES];
541 while(q < inbuf + inputlth) {
543 while (q < inbuf+inputlth && *q != '\n')
545 if (q == inbuf+inputlth) {
547 _("No final newline in combine file\n"));
551 if (ifilct == MAXIFILES) {
553 _("Too many files to combine\n"));
556 ifiles[ifilct++] = p;
559 loadnewfonts(fd, ifiles, ifilct, iunit, hwunit, no_m, no_u);
564 /* file with three code pages? */
565 if (inputlth == 9780) {
566 offset = position_codepage(iunit);
570 } else if (inputlth == 32768) {
571 /* restorefont -w writes a SVGA font to file
572 restorefont -r restores it
573 These fonts have size 32768, for two 512-char fonts.
574 In fact, when BROKEN_GRAPHICS_PROGRAMS is defined,
575 and it always is, there is no default font that is saved,
576 so probably the second half is always garbage. */
577 fprintf(stderr, _("Hmm - a font from restorefont? "
578 "Using the first half.\n"));
579 inputlth = 16384; /* ignore rest */
587 int rem = (inputlth % 256);
588 if (rem == 0 || rem == 40) {
589 /* 0: bare code page bitmap */
590 /* 40: preceded by .cp header */
591 /* we might check some header details */
594 fprintf(stderr, _("Bad input file size\n"));
599 height = inputlth/256;
601 do_loadfont(fd, inbuf+offset, width, height, hwunit, fontsize,
606 position_codepage(int iunit) {
609 /* code page: first 40 bytes, then 8x16 font,
610 then 6 bytes, then 8x14 font,
611 then 6 bytes, then 8x8 font */
615 _("This file contains 3 fonts: 8x8, 8x14 and 8x16."
617 "using an option -8 or -14 or -16 "
618 "which one you want loaded.\n"));
623 offset = 7732; break;
625 offset = 4142; break;
629 fprintf(stderr, _("You asked for font size %d, "
630 "but only 8, 14, 16 are possible here.\n"),
638 do_saveoldfont(int fd, char *ofil, FILE *fpo, int unimap_follows,
639 int *count, int *utf8) {
641 /* this is the max font size the kernel is willing to handle */
642 #define MAXFONTSIZE 65536
643 unsigned char buf[MAXFONTSIZE];
645 int i, ct, width, height, bytewidth, charsize, kcharsize;
647 ct = sizeof(buf)/(32*32/8); /* max size 32x32, 8 bits/byte */
648 if (getfont(fd, buf, &ct, &width, &height))
651 /* save as efficiently as possible */
652 bytewidth = (width + 7) / 8;
653 height = font_charheight(buf, ct, width);
654 charsize = height * bytewidth;
655 kcharsize = 32 * bytewidth;
657 /* Do we need a psf header? */
658 /* Yes if ct==512 - otherwise we cannot distinguish
659 a 512-char 8x8 and a 256-char 8x16 font. */
660 #define ALWAYS_PSF_HEADER 1
662 if (ct != 256 || width != 8 || unimap_follows || ALWAYS_PSF_HEADER) {
667 flags |= WPSFH_HASTAB;
668 writepsffontheader (fpo, width, height, ct, &psftype, flags);
670 *utf8 = (psftype == 2);
674 fprintf(stderr, _("Found nothing to save\n"));
676 for (i = 0; i < ct; i++) {
677 if (fwrite(buf+(i*kcharsize), charsize, 1, fpo) != 1) {
678 fprintf(stderr, _("Cannot write font file"));
683 printf(_("Saved %d-char %dx%d font file on %s\n"),
684 ct, width, height, ofil);
693 saveoldfont(int fd, char *ofil) {
696 if((fpo = fopen(ofil, "w")) == NULL) {
700 do_saveoldfont(fd, ofil, fpo, 0, NULL, NULL);
705 saveoldfontplusunicodemap(int fd, char *Ofil) {
710 if((fpo = fopen(Ofil, "w")) == NULL) {
715 do_saveoldfont(fd, Ofil, fpo, 1, &ct, &utf8);
716 appendunicodemap(fd, fpo, ct, utf8);
720 /* Only on the current console? On all allocated consoles? */
721 /* A newly allocated console has NORM_MAP by default -
722 probably it should copy the default from the current console?
723 But what if we want a new one because the current one is messed up? */
724 /* For the moment: only the current console, only the G0 set */
727 send_escseq(int fd, char *seq, int n) {
728 if (write(fd, seq, n) != n) /* maybe fd is read-only */
733 activatemap(int fd) {
734 send_escseq(fd, "\033(K", 3);
738 disactivatemap(int fd) {
739 send_escseq(fd, "\033(B", 3);