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.
322 * Len was 32k, but latarcyrheb-sun32.psfu is 34377 bytes
323 * (it has largish Unicode map).
326 buffer = xmalloc_read(STDIN_FILENO, &len);
327 // xmalloc_open_zipped_read_close(filename, &len);
329 bb_perror_msg_and_die("error reading input font");
330 do_load(get_console_fd_or_die(), buffer, len);
341 setfont [-O font+umap.orig] [-o font.orig] [-om cmap.orig]
342 [-ou umap.orig] [-N] [font.new ...] [-m cmap] [-u umap] [-C console]
345 -h NN Override font height
347 Save previous font in file
349 Save previous font and Unicode map in file
351 Store console map in file
353 Save previous Unicode map in file
355 Load console map or Unicode console map from file
357 Load Unicode table describing the font from file
362 0x80 U+0410 # CYRILLIC CAPITAL LETTER A
363 0x81 U+0411 # CYRILLIC CAPITAL LETTER BE
364 0x82 U+0412 # CYRILLIC CAPITAL LETTER VE
366 Set the font for the indicated console
371 #if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP
372 static int ctoi(char *s)
374 if (s[0] == '\'' && s[1] != '\0' && s[2] == '\'' && s[3] == '\0')
377 if (s[0] == 'U' && s[1] == '+') {
383 return xstrtoul(s, 0);
387 int setfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
388 int setfont_main(int argc UNUSED_PARAM, char **argv)
393 unsigned char *buffer;
395 const char *tty_name = CURRENT_TTY;
397 opt_complementary = "=1";
398 opts = getopt32(argv, "m:C:", &mapfilename, &tty_name);
401 fd = xopen_nonblocking(tty_name);
403 if (sizeof(CONFIG_DEFAULT_SETFONT_DIR) > 1) { // if not ""
404 if (*argv[0] != '/') {
405 // goto default fonts location. don't die if doesn't exist
406 chdir(CONFIG_DEFAULT_SETFONT_DIR "/consolefonts");
411 buffer = xmalloc_open_zipped_read_close(*argv, &len);
413 bb_simple_perror_msg_and_die(*argv);
414 do_load(fd, buffer, len);
416 // load the screen map, if any
417 if (opts & 1) { // -m
418 unsigned mode = PIO_SCRNMAP;
421 if (sizeof(CONFIG_DEFAULT_SETFONT_DIR) > 1) { // if not ""
422 if (mapfilename[0] != '/') {
423 // goto default keymaps location
424 chdir(CONFIG_DEFAULT_SETFONT_DIR "/consoletrans");
428 map = xmalloc_open_zipped_read_close(mapfilename, &len);
430 bb_simple_perror_msg_and_die(mapfilename);
431 // file size is 256 or 512 bytes? -> assume binary map
432 if (len == E_TABSZ || len == 2*E_TABSZ) {
433 if (len == 2*E_TABSZ)
434 mode = PIO_UNISCRNMAP;
436 #if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP
437 // assume textual Unicode console maps:
438 // 0x00 U+0000 # NULL (NUL)
439 // 0x01 U+0001 # START OF HEADING (SOH)
440 // 0x02 U+0002 # START OF TEXT (STX)
441 // 0x03 U+0003 # END OF TEXT (ETX)
447 if (ENABLE_FEATURE_CLEAN_UP)
449 map = xmalloc(E_TABSZ * sizeof(unsigned short));
451 #define unicodes ((unsigned short *)map)
453 for (i = 0; i < E_TABSZ; i++)
454 unicodes[i] = 0xf000 + i;
456 parser = config_open(mapfilename);
457 while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL | PARSE_MIN_DIE)) {
458 // parse code/value pair
459 int a = ctoi(token[0]);
460 int b = ctoi(token[1]);
461 if (a < 0 || a >= E_TABSZ
462 || b < 0 || b > 65535
464 bb_error_msg_and_die("map format");
468 // unicode character is met?
470 mode = PIO_UNISCRNMAP;
472 if (ENABLE_FEATURE_CLEAN_UP)
473 config_close(parser);
475 if (mode != PIO_UNISCRNMAP) {
476 #define asciis ((unsigned char *)map)
477 for (i = 0; i < E_TABSZ; i++)
478 asciis[i] = unicodes[i];
483 #endif // ENABLE_FEATURE_SETFONT_TEXTUAL_MAP
486 xioctl(fd, mode, map);
488 if (ENABLE_FEATURE_CLEAN_UP)