1 /* vi: set sw=4 ts=4: */
3 * loadfont.c - Eugene Crosser & Andries Brouwer
7 * Loads the console font, and possibly the corresponding screen map(s).
8 * (Adapted for busybox by Matej Vela.)
10 * Licensed under GPLv2, see file LICENSE in this source tree.
13 //usage:#define loadfont_trivial_usage
15 //usage:#define loadfont_full_usage "\n\n"
16 //usage: "Load a console font from stdin"
17 /* //usage: "\n -C TTY Affect TTY instead of /dev/tty" */
19 //usage:#define loadfont_example_usage
20 //usage: "$ loadfont < /etc/i18n/fontname\n"
22 //usage:#define setfont_trivial_usage
23 //usage: "FONT [-m MAPFILE] [-C TTY]"
24 //usage:#define setfont_full_usage "\n\n"
25 //usage: "Load a console font\n"
27 //usage: "\n -m MAPFILE Load console screen map"
28 //usage: "\n -C TTY Affect TTY instead of /dev/tty"
30 //usage:#define setfont_example_usage
31 //usage: "$ setfont -m koi8-r /etc/i18n/fontname\n"
37 # define KDFONTOP 0x4B72
38 struct console_font_op {
39 unsigned op; /* KD_FONT_OP_* */
40 unsigned flags; /* KD_FONT_FLAG_* */
41 unsigned width, height;
43 unsigned char *data; /* font data with height fixed to 32 */
45 # define KD_FONT_OP_SET 0 /* Set font */
46 # define KD_FONT_OP_GET 1 /* Get font */
47 # define KD_FONT_OP_SET_DEFAULT 2 /* Set font to default, data points to name / NULL */
48 # define KD_FONT_OP_COPY 3 /* Copy from another console */
49 # define KD_FONT_FLAG_OLD 0x80000000 /* Invoked via old interface */
50 # define KD_FONT_FLAG_DONT_RECALC 1 /* Don't call adjust_height() */
51 /* (Used internally for PIO_FONT support) */
59 PSF1_MODEHASTAB = 0x02,
60 PSF1_MODEHASSEQ = 0x04,
62 PSF1_STARTSEQ = 0xfffe,
63 PSF1_SEPARATOR = 0xffff,
67 unsigned char magic[2]; /* Magic number */
68 unsigned char mode; /* PSF font mode */
69 unsigned char charsize; /* Character size */
72 #define psf1h(x) ((struct psf1_header*)(x))
74 #define PSF1_MAGIC_OK(x) ( \
75 (x)->magic[0] == PSF1_MAGIC0 \
76 && (x)->magic[1] == PSF1_MAGIC1 \
79 #if ENABLE_FEATURE_LOADFONT_PSF2
85 PSF2_HAS_UNICODE_TABLE = 0x01,
92 unsigned char magic[4];
94 unsigned int headersize; /* offset of bitmaps in file */
96 unsigned int length; /* number of glyphs */
97 unsigned int charsize; /* number of bytes for each character */
98 unsigned int height; /* max dimensions of glyphs */
99 unsigned int width; /* charsize = height * ((width + 7) / 8) */
102 #define psf2h(x) ((struct psf2_header*)(x))
104 #define PSF2_MAGIC_OK(x) ( \
105 (x)->magic[0] == PSF2_MAGIC0 \
106 && (x)->magic[1] == PSF2_MAGIC1 \
107 && (x)->magic[2] == PSF2_MAGIC2 \
108 && (x)->magic[3] == PSF2_MAGIC3 \
110 #endif /* ENABLE_FEATURE_LOADFONT_PSF2 */
113 static void do_loadfont(int fd, unsigned char *inbuf, int height, int width, int charsize, int fontsize)
116 int charwidth = 32 * ((width+7)/8);
119 if (height < 1 || height > 32 || width < 1 || width > 32)
120 bb_error_msg_and_die("bad character size %dx%d", height, width);
122 buf = xzalloc(charwidth * ((fontsize < 128) ? 128 : fontsize));
123 for (i = 0; i < fontsize; i++)
124 memcpy(buf + (i*charwidth), inbuf + (i*charsize), charsize);
127 struct console_font_op cfo;
128 cfo.op = KD_FONT_OP_SET;
132 cfo.charcount = fontsize;
134 xioctl(fd, KDFONTOP, &cfo);
141 * Format of the Unicode information:
143 * For each font position <uc>*<seq>*<term>
144 * where <uc> is a 2-byte little endian Unicode value (PSF1)
145 * or an UTF-8 coded value (PSF2),
146 * <seq> = <ss><uc><uc>*, <ss> = psf1 ? 0xFFFE : 0xFE,
147 * <term> = psf1 ? 0xFFFF : 0xFF.
148 * and * denotes zero or more occurrences of the preceding item.
151 * The leading <uc>* part gives Unicode symbols that are all
152 * represented by this font position. The following sequences
153 * are sequences of Unicode symbols - probably a symbol
154 * together with combining accents - also represented by
155 * this font position.
158 * At the font position for a capital A-ring glyph, we
160 * 00C5,212B,FFFE,0041,030A,FFFF
161 * Some font positions may be described by sequences only,
162 * namely when there is no precomposed Unicode value for the glyph.
164 #if !ENABLE_FEATURE_LOADFONT_PSF2
165 #define do_loadtable(fd, inbuf, tailsz, fontsize, psf2) \
166 do_loadtable(fd, inbuf, tailsz, fontsize)
168 static void do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize, int psf2)
170 #if !ENABLE_FEATURE_LOADFONT_PSF2
171 /* gcc 4.3.1 code size: */
172 # define psf2 0 /* +0 bytes */
173 // const int psf2 = 0; /* +8 bytes */
174 // enum { psf2 = 0 }; /* +13 bytes */
176 struct unimapinit advice;
177 struct unimapdesc ud;
183 maxct = tailsz; /* more than enough */
184 up = xmalloc(maxct * sizeof(*up));
186 for (glyph = 0; glyph < fontsize; glyph++) {
188 if (!psf2) { /* PSF1 */
189 unicode = (((uint16_t) inbuf[1]) << 8) + inbuf[0];
192 if (unicode == PSF1_SEPARATOR)
195 #if ENABLE_FEATURE_LOADFONT_PSF2
198 if (unicode == PSF2_SEPARATOR) {
200 } else if (unicode == PSF2_STARTSEQ) {
201 bb_error_msg_and_die("unicode sequences not implemented");
202 } else if (unicode >= 0xC0) {
204 unicode &= 0x01, maxct = 5;
205 else if (unicode >= 0xF8)
206 unicode &= 0x03, maxct = 4;
207 else if (unicode >= 0xF0)
208 unicode &= 0x07, maxct = 3;
209 else if (unicode >= 0xE0)
210 unicode &= 0x0F, maxct = 2;
212 unicode &= 0x1F, maxct = 1;
214 if (tailsz <= 0 || *inbuf < 0x80 || *inbuf > 0xBF)
215 bb_error_msg_and_die("illegal UTF-8 character");
217 unicode = (unicode << 6) + (*inbuf++ & 0x3F);
218 } while (--maxct > 0);
219 } else if (unicode >= 0x80) {
220 bb_error_msg_and_die("illegal UTF-8 character");
226 up[ct].unicode = unicode;
227 up[ct].fontpos = glyph;
232 /* Note: after PIO_UNIMAPCLR and before PIO_UNIMAP
233 this printf did not work on many kernels */
235 advice.advised_hashsize = 0;
236 advice.advised_hashstep = 0;
237 advice.advised_hashlevel = 0;
238 xioctl(fd, PIO_UNIMAPCLR, &advice);
241 xioctl(fd, PIO_UNIMAP, &ud);
245 static void do_load(int fd, unsigned char *buffer, size_t len)
252 unsigned char *font = buffer;
253 unsigned char *table;
255 if (len >= sizeof(struct psf1_header) && PSF1_MAGIC_OK(psf1h(buffer))) {
256 if (psf1h(buffer)->mode > PSF1_MAXMODE)
257 bb_error_msg_and_die("unsupported psf file mode");
258 if (psf1h(buffer)->mode & PSF1_MODE512)
260 if (psf1h(buffer)->mode & PSF1_MODEHASTAB)
262 height = charsize = psf1h(buffer)->charsize;
263 font += sizeof(struct psf1_header);
265 #if ENABLE_FEATURE_LOADFONT_PSF2
266 if (len >= sizeof(struct psf2_header) && PSF2_MAGIC_OK(psf2h(buffer))) {
267 if (psf2h(buffer)->version > PSF2_MAXVERSION)
268 bb_error_msg_and_die("unsupported psf file version");
269 fontsize = psf2h(buffer)->length;
270 if (psf2h(buffer)->flags & PSF2_HAS_UNICODE_TABLE)
272 charsize = psf2h(buffer)->charsize;
273 height = psf2h(buffer)->height;
274 width = psf2h(buffer)->width;
275 font += psf2h(buffer)->headersize;
278 #if ENABLE_FEATURE_LOADFONT_RAW
279 if (len == 9780) { /* file with three code pages? */
280 charsize = height = 16;
282 } else if ((len & 0377) == 0) { /* bare font */
283 charsize = height = len / 256;
287 bb_error_msg_and_die("input file: bad length or unsupported font type");
290 #if !defined(PIO_FONTX) || defined(__sparc__)
292 bb_error_msg_and_die("only fontsize 256 supported");
295 table = font + fontsize * charsize;
298 if (table > buffer || (!has_table && table != buffer))
299 bb_error_msg_and_die("input file: bad length");
301 do_loadfont(fd, font, height, width, charsize, fontsize);
304 do_loadtable(fd, table, buffer - table, fontsize, has_table - 1);
309 int loadfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
310 int loadfont_main(int argc UNUSED_PARAM, char **argv)
313 unsigned char *buffer;
315 // no arguments allowed!
316 opt_complementary = "=0";
320 * We used to look at the length of the input file
321 * with stat(); now that we accept compressed files,
322 * just read the entire file.
324 len = 32*1024; // can't be larger
325 buffer = xmalloc_read(STDIN_FILENO, &len);
326 // xmalloc_open_zipped_read_close(filename, &len);
328 bb_perror_msg_and_die("error reading input font");
329 do_load(get_console_fd_or_die(), buffer, len);
340 setfont [-O font+umap.orig] [-o font.orig] [-om cmap.orig]
341 [-ou umap.orig] [-N] [font.new ...] [-m cmap] [-u umap] [-C console]
344 -h NN Override font height
346 Save previous font in file
348 Save previous font and Unicode map in file
350 Store console map in file
352 Save previous Unicode map in file
354 Load console map or Unicode console map from file
356 Load Unicode table describing the font from file
361 0x80 U+0410 # CYRILLIC CAPITAL LETTER A
362 0x81 U+0411 # CYRILLIC CAPITAL LETTER BE
363 0x82 U+0412 # CYRILLIC CAPITAL LETTER VE
365 Set the font for the indicated console
370 #if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP
371 static int ctoi(char *s)
373 if (s[0] == '\'' && s[1] != '\0' && s[2] == '\'' && s[3] == '\0')
376 if (s[0] == 'U' && s[1] == '+') {
382 return xstrtoul(s, 0);
386 int setfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
387 int setfont_main(int argc UNUSED_PARAM, char **argv)
392 unsigned char *buffer;
394 const char *tty_name = CURRENT_TTY;
396 opt_complementary = "=1";
397 opts = getopt32(argv, "m:C:", &mapfilename, &tty_name);
400 fd = xopen_nonblocking(tty_name);
402 if (sizeof(CONFIG_DEFAULT_SETFONT_DIR) > 1) { // if not ""
403 if (*argv[0] != '/') {
404 // goto default fonts location. don't die if doesn't exist
405 chdir(CONFIG_DEFAULT_SETFONT_DIR "/consolefonts");
409 len = 32*1024; // can't be larger
410 buffer = xmalloc_open_zipped_read_close(*argv, &len);
412 bb_simple_perror_msg_and_die(*argv);
413 do_load(fd, buffer, len);
415 // load the screen map, if any
416 if (opts & 1) { // -m
417 unsigned mode = PIO_SCRNMAP;
420 if (sizeof(CONFIG_DEFAULT_SETFONT_DIR) > 1) { // if not ""
421 if (mapfilename[0] != '/') {
422 // goto default keymaps location
423 chdir(CONFIG_DEFAULT_SETFONT_DIR "/consoletrans");
427 map = xmalloc_open_zipped_read_close(mapfilename, &len);
429 bb_simple_perror_msg_and_die(mapfilename);
430 // file size is 256 or 512 bytes? -> assume binary map
431 if (len == E_TABSZ || len == 2*E_TABSZ) {
432 if (len == 2*E_TABSZ)
433 mode = PIO_UNISCRNMAP;
435 #if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP
436 // assume textual Unicode console maps:
437 // 0x00 U+0000 # NULL (NUL)
438 // 0x01 U+0001 # START OF HEADING (SOH)
439 // 0x02 U+0002 # START OF TEXT (STX)
440 // 0x03 U+0003 # END OF TEXT (ETX)
446 if (ENABLE_FEATURE_CLEAN_UP)
448 map = xmalloc(E_TABSZ * sizeof(unsigned short));
450 #define unicodes ((unsigned short *)map)
452 for (i = 0; i < E_TABSZ; i++)
453 unicodes[i] = 0xf000 + i;
455 parser = config_open(mapfilename);
456 while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL | PARSE_MIN_DIE)) {
457 // parse code/value pair
458 int a = ctoi(token[0]);
459 int b = ctoi(token[1]);
460 if (a < 0 || a >= E_TABSZ
461 || b < 0 || b > 65535
463 bb_error_msg_and_die("map format");
467 // unicode character is met?
469 mode = PIO_UNISCRNMAP;
471 if (ENABLE_FEATURE_CLEAN_UP)
472 config_close(parser);
474 if (mode != PIO_UNISCRNMAP) {
475 #define asciis ((unsigned char *)map)
476 for (i = 0; i < E_TABSZ; i++)
477 asciis[i] = unicodes[i];
482 #endif // ENABLE_FEATURE_SETFONT_TEXTUAL_MAP
485 xioctl(fd, mode, map);
487 if (ENABLE_FEATURE_CLEAN_UP)