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"
26 //usage: "\n -m MAPFILE Load console screen map"
27 //usage: "\n -C TTY Affect TTY instead of /dev/tty"
29 //usage:#define setfont_example_usage
30 //usage: "$ setfont -m koi8-r /etc/i18n/fontname\n"
36 # define KDFONTOP 0x4B72
37 struct console_font_op {
38 unsigned op; /* KD_FONT_OP_* */
39 unsigned flags; /* KD_FONT_FLAG_* */
40 unsigned width, height;
42 unsigned char *data; /* font data with height fixed to 32 */
44 # define KD_FONT_OP_SET 0 /* Set font */
45 # define KD_FONT_OP_GET 1 /* Get font */
46 # define KD_FONT_OP_SET_DEFAULT 2 /* Set font to default, data points to name / NULL */
47 # define KD_FONT_OP_COPY 3 /* Copy from another console */
48 # define KD_FONT_FLAG_OLD 0x80000000 /* Invoked via old interface */
49 # define KD_FONT_FLAG_DONT_RECALC 1 /* Don't call adjust_height() */
50 /* (Used internally for PIO_FONT support) */
58 PSF1_MODEHASTAB = 0x02,
59 PSF1_MODEHASSEQ = 0x04,
61 PSF1_STARTSEQ = 0xfffe,
62 PSF1_SEPARATOR = 0xffff,
66 unsigned char magic[2]; /* Magic number */
67 unsigned char mode; /* PSF font mode */
68 unsigned char charsize; /* Character size */
71 #define psf1h(x) ((struct psf1_header*)(x))
73 #define PSF1_MAGIC_OK(x) ( \
74 (x)->magic[0] == PSF1_MAGIC0 \
75 && (x)->magic[1] == PSF1_MAGIC1 \
78 #if ENABLE_FEATURE_LOADFONT_PSF2
84 PSF2_HAS_UNICODE_TABLE = 0x01,
91 unsigned char magic[4];
93 unsigned int headersize; /* offset of bitmaps in file */
95 unsigned int length; /* number of glyphs */
96 unsigned int charsize; /* number of bytes for each character */
97 unsigned int height; /* max dimensions of glyphs */
98 unsigned int width; /* charsize = height * ((width + 7) / 8) */
101 #define psf2h(x) ((struct psf2_header*)(x))
103 #define PSF2_MAGIC_OK(x) ( \
104 (x)->magic[0] == PSF2_MAGIC0 \
105 && (x)->magic[1] == PSF2_MAGIC1 \
106 && (x)->magic[2] == PSF2_MAGIC2 \
107 && (x)->magic[3] == PSF2_MAGIC3 \
109 #endif /* ENABLE_FEATURE_LOADFONT_PSF2 */
112 static void do_loadfont(int fd, unsigned char *inbuf, int height, int width, int charsize, int fontsize)
115 int charwidth = 32 * ((width+7)/8);
118 if (height < 1 || height > 32 || width < 1 || width > 32)
119 bb_error_msg_and_die("bad character size %dx%d", height, width);
121 buf = xzalloc(charwidth * ((fontsize < 128) ? 128 : fontsize));
122 for (i = 0; i < fontsize; i++)
123 memcpy(buf + (i*charwidth), inbuf + (i*charsize), charsize);
126 struct console_font_op cfo;
127 cfo.op = KD_FONT_OP_SET;
131 cfo.charcount = fontsize;
133 xioctl(fd, KDFONTOP, &cfo);
140 * Format of the Unicode information:
142 * For each font position <uc>*<seq>*<term>
143 * where <uc> is a 2-byte little endian Unicode value (PSF1)
144 * or an UTF-8 coded value (PSF2),
145 * <seq> = <ss><uc><uc>*, <ss> = psf1 ? 0xFFFE : 0xFE,
146 * <term> = psf1 ? 0xFFFF : 0xFF.
147 * and * denotes zero or more occurrences of the preceding item.
150 * The leading <uc>* part gives Unicode symbols that are all
151 * represented by this font position. The following sequences
152 * are sequences of Unicode symbols - probably a symbol
153 * together with combining accents - also represented by
154 * this font position.
157 * At the font position for a capital A-ring glyph, we
159 * 00C5,212B,FFFE,0041,030A,FFFF
160 * Some font positions may be described by sequences only,
161 * namely when there is no precomposed Unicode value for the glyph.
163 #if !ENABLE_FEATURE_LOADFONT_PSF2
164 #define do_loadtable(fd, inbuf, tailsz, fontsize, psf2) \
165 do_loadtable(fd, inbuf, tailsz, fontsize)
167 static void do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize, int psf2)
169 #if !ENABLE_FEATURE_LOADFONT_PSF2
170 /* gcc 4.3.1 code size: */
171 # define psf2 0 /* +0 bytes */
172 // const int psf2 = 0; /* +8 bytes */
173 // enum { psf2 = 0 }; /* +13 bytes */
175 struct unimapinit advice;
176 struct unimapdesc ud;
182 maxct = tailsz; /* more than enough */
183 up = xmalloc(maxct * sizeof(*up));
185 for (glyph = 0; glyph < fontsize; glyph++) {
187 if (!psf2) { /* PSF1 */
188 unicode = (((uint16_t) inbuf[1]) << 8) + inbuf[0];
191 if (unicode == PSF1_SEPARATOR)
194 #if ENABLE_FEATURE_LOADFONT_PSF2
197 if (unicode == PSF2_SEPARATOR) {
199 } else if (unicode == PSF2_STARTSEQ) {
200 bb_error_msg_and_die("unicode sequences not implemented");
201 } else if (unicode >= 0xC0) {
203 unicode &= 0x01, maxct = 5;
204 else if (unicode >= 0xF8)
205 unicode &= 0x03, maxct = 4;
206 else if (unicode >= 0xF0)
207 unicode &= 0x07, maxct = 3;
208 else if (unicode >= 0xE0)
209 unicode &= 0x0F, maxct = 2;
211 unicode &= 0x1F, maxct = 1;
213 if (tailsz <= 0 || *inbuf < 0x80 || *inbuf > 0xBF)
214 bb_error_msg_and_die("illegal UTF-8 character");
216 unicode = (unicode << 6) + (*inbuf++ & 0x3F);
217 } while (--maxct > 0);
218 } else if (unicode >= 0x80) {
219 bb_error_msg_and_die("illegal UTF-8 character");
225 up[ct].unicode = unicode;
226 up[ct].fontpos = glyph;
231 /* Note: after PIO_UNIMAPCLR and before PIO_UNIMAP
232 this printf did not work on many kernels */
234 advice.advised_hashsize = 0;
235 advice.advised_hashstep = 0;
236 advice.advised_hashlevel = 0;
237 xioctl(fd, PIO_UNIMAPCLR, &advice);
240 xioctl(fd, PIO_UNIMAP, &ud);
244 static void do_load(int fd, unsigned char *buffer, size_t len)
251 unsigned char *font = buffer;
252 unsigned char *table;
254 if (len >= sizeof(struct psf1_header) && PSF1_MAGIC_OK(psf1h(buffer))) {
255 if (psf1h(buffer)->mode > PSF1_MAXMODE)
256 bb_error_msg_and_die("unsupported psf file mode");
257 if (psf1h(buffer)->mode & PSF1_MODE512)
259 if (psf1h(buffer)->mode & PSF1_MODEHASTAB)
261 height = charsize = psf1h(buffer)->charsize;
262 font += sizeof(struct psf1_header);
264 #if ENABLE_FEATURE_LOADFONT_PSF2
265 if (len >= sizeof(struct psf2_header) && PSF2_MAGIC_OK(psf2h(buffer))) {
266 if (psf2h(buffer)->version > PSF2_MAXVERSION)
267 bb_error_msg_and_die("unsupported psf file version");
268 fontsize = psf2h(buffer)->length;
269 if (psf2h(buffer)->flags & PSF2_HAS_UNICODE_TABLE)
271 charsize = psf2h(buffer)->charsize;
272 height = psf2h(buffer)->height;
273 width = psf2h(buffer)->width;
274 font += psf2h(buffer)->headersize;
277 #if ENABLE_FEATURE_LOADFONT_RAW
278 if (len == 9780) { /* file with three code pages? */
279 charsize = height = 16;
281 } else if ((len & 0377) == 0) { /* bare font */
282 charsize = height = len / 256;
286 bb_error_msg_and_die("input file: bad length or unsupported font type");
289 #if !defined(PIO_FONTX) || defined(__sparc__)
291 bb_error_msg_and_die("only fontsize 256 supported");
294 table = font + fontsize * charsize;
297 if (table > buffer || (!has_table && table != buffer))
298 bb_error_msg_and_die("input file: bad length");
300 do_loadfont(fd, font, height, width, charsize, fontsize);
303 do_loadtable(fd, table, buffer - table, fontsize, has_table - 1);
308 int loadfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
309 int loadfont_main(int argc UNUSED_PARAM, char **argv)
312 unsigned char *buffer;
314 // no arguments allowed!
315 opt_complementary = "=0";
319 * We used to look at the length of the input file
320 * with stat(); now that we accept compressed files,
321 * just read the entire file.
323 len = 32*1024; // can't be larger
324 buffer = xmalloc_read(STDIN_FILENO, &len);
325 // xmalloc_open_zipped_read_close(filename, &len);
327 bb_perror_msg_and_die("error reading input font");
328 do_load(get_console_fd_or_die(), buffer, len);
339 setfont [-O font+umap.orig] [-o font.orig] [-om cmap.orig]
340 [-ou umap.orig] [-N] [font.new ...] [-m cmap] [-u umap] [-C console]
343 -h NN Override font height
345 Save previous font in file
347 Save previous font and Unicode map in file
349 Store console map in file
351 Save previous Unicode map in file
353 Load console map or Unicode console map from file
355 Load Unicode table describing the font from file
360 0x80 U+0410 # CYRILLIC CAPITAL LETTER A
361 0x81 U+0411 # CYRILLIC CAPITAL LETTER BE
362 0x82 U+0412 # CYRILLIC CAPITAL LETTER VE
364 Set the font for the indicated console
369 #if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP
370 static int ctoi(char *s)
372 if (s[0] == '\'' && s[1] != '\0' && s[2] == '\'' && s[3] == '\0')
375 if (s[0] == 'U' && s[1] == '+') {
381 return xstrtoul(s, 0);
385 int setfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
386 int setfont_main(int argc UNUSED_PARAM, char **argv)
391 unsigned char *buffer;
393 const char *tty_name = CURRENT_TTY;
395 opt_complementary = "=1";
396 opts = getopt32(argv, "m:C:", &mapfilename, &tty_name);
399 fd = xopen_nonblocking(tty_name);
401 if (sizeof(CONFIG_DEFAULT_SETFONT_DIR) > 1) { // if not ""
402 if (*argv[0] != '/') {
403 // goto default fonts location. don't die if doesn't exist
404 chdir(CONFIG_DEFAULT_SETFONT_DIR "/consolefonts");
408 len = 32*1024; // can't be larger
409 buffer = xmalloc_open_zipped_read_close(*argv, &len);
411 bb_simple_perror_msg_and_die(*argv);
412 do_load(fd, buffer, len);
414 // load the screen map, if any
415 if (opts & 1) { // -m
416 unsigned mode = PIO_SCRNMAP;
419 if (sizeof(CONFIG_DEFAULT_SETFONT_DIR) > 1) { // if not ""
420 if (mapfilename[0] != '/') {
421 // goto default keymaps location
422 chdir(CONFIG_DEFAULT_SETFONT_DIR "/consoletrans");
426 map = xmalloc_open_zipped_read_close(mapfilename, &len);
428 bb_simple_perror_msg_and_die(mapfilename);
429 // file size is 256 or 512 bytes? -> assume binary map
430 if (len == E_TABSZ || len == 2*E_TABSZ) {
431 if (len == 2*E_TABSZ)
432 mode = PIO_UNISCRNMAP;
434 #if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP
435 // assume textual Unicode console maps:
436 // 0x00 U+0000 # NULL (NUL)
437 // 0x01 U+0001 # START OF HEADING (SOH)
438 // 0x02 U+0002 # START OF TEXT (STX)
439 // 0x03 U+0003 # END OF TEXT (ETX)
445 if (ENABLE_FEATURE_CLEAN_UP)
447 map = xmalloc(E_TABSZ * sizeof(unsigned short));
449 #define unicodes ((unsigned short *)map)
451 for (i = 0; i < E_TABSZ; i++)
452 unicodes[i] = 0xf000 + i;
454 parser = config_open(mapfilename);
455 while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL | PARSE_MIN_DIE)) {
456 // parse code/value pair
457 int a = ctoi(token[0]);
458 int b = ctoi(token[1]);
459 if (a < 0 || a >= E_TABSZ
460 || b < 0 || b > 65535
462 bb_error_msg_and_die("map format");
466 // unicode character is met?
468 mode = PIO_UNISCRNMAP;
470 if (ENABLE_FEATURE_CLEAN_UP)
471 config_close(parser);
473 if (mode != PIO_UNISCRNMAP) {
474 #define asciis ((unsigned char *)map)
475 for (i = 0; i < E_TABSZ; i++)
476 asciis[i] = unicodes[i];
481 #endif // ENABLE_FEATURE_SETFONT_TEXTUAL_MAP
484 xioctl(fd, mode, map);
486 if (ENABLE_FEATURE_CLEAN_UP)