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.)
14 #define KDFONTOP 0x4B72
15 struct console_font_op {
16 unsigned op; /* KD_FONT_OP_* */
17 unsigned flags; /* KD_FONT_FLAG_* */
18 unsigned width, height;
20 unsigned char *data; /* font data with height fixed to 32 */
23 #define KD_FONT_OP_SET 0 /* Set font */
24 #define KD_FONT_OP_GET 1 /* Get font */
25 #define KD_FONT_OP_SET_DEFAULT 2 /* Set font to default,
26 data points to name / NULL */
27 #define KD_FONT_OP_COPY 3 /* Copy from another console */
29 #define KD_FONT_FLAG_OLD 0x80000000 /* Invoked via old interface */
30 #define KD_FONT_FLAG_DONT_RECALC 1 /* Don't call adjust_height() */
31 /* (Used internally for PIO_FONT support) */
40 PSF_MODEHASTAB = 0x02,
42 PSF_SEPARATOR = 0xffff
46 unsigned char magic1, magic2; /* Magic number */
47 unsigned char mode; /* PSF font mode */
48 unsigned char charsize; /* Character size */
51 #define PSF_MAGIC_OK(x) ((x)->magic1 == PSF_MAGIC1 && (x)->magic2 == PSF_MAGIC2)
53 static void do_loadfont(int fd, unsigned char *inbuf, int unit, int fontsize)
58 if (unit < 1 || unit > 32)
59 bb_error_msg_and_die("bad character size %d", unit);
61 buf = xzalloc(16 * 1024);
62 for (i = 0; i < fontsize; i++)
63 memcpy(buf + (32 * i), inbuf + (unit * i), unit);
66 struct console_font_op cfo;
68 cfo.op = KD_FONT_OP_SET;
72 cfo.charcount = fontsize;
73 cfo.data = (void*)buf;
75 if (!ioctl_or_perror(fd, KDFONTOP, &cfo, "KDFONTOP ioctl failed (will try PIO_FONTX)"))
76 goto ret; /* success */
78 xioctl(fd, KDFONTOP, &cfo);
83 /* These ones do not honour -C tty (they set font on current tty regardless) */
84 #if defined(PIO_FONTX) && !defined(__sparc__)
86 struct consolefontdesc cfd;
88 cfd.charcount = fontsize;
89 cfd.charheight = unit;
92 if (!ioctl_or_perror(fd, PIO_FONTX, &cfd, "PIO_FONTX ioctl failed (will try PIO_FONT)"))
93 goto ret; /* success */
96 xioctl(fd, PIO_FONT, buf);
102 static void do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize)
104 struct unimapinit advice;
105 struct unimapdesc ud;
111 maxct = tailsz; /* more than enough */
112 up = xmalloc(maxct * sizeof(struct unipair));
114 for (glyph = 0; glyph < fontsize; glyph++) {
115 while (tailsz >= 2) {
116 unicode = (((uint16_t) inbuf[1]) << 8) + inbuf[0];
119 if (unicode == PSF_SEPARATOR)
121 up[ct].unicode = unicode;
122 up[ct].fontpos = glyph;
127 /* Note: after PIO_UNIMAPCLR and before PIO_UNIMAP
128 this printf did not work on many kernels */
130 advice.advised_hashsize = 0;
131 advice.advised_hashstep = 0;
132 advice.advised_hashlevel = 0;
133 xioctl(fd, PIO_UNIMAPCLR, &advice);
136 xioctl(fd, PIO_UNIMAP, &ud);
139 static void do_load(int fd, struct psf_header *psfhdr, size_t len)
144 unsigned head0, head = head;
146 /* test for psf first */
147 if (len >= sizeof(struct psf_header) && PSF_MAGIC_OK(psfhdr)) {
148 if (psfhdr->mode > PSF_MAXMODE)
149 bb_error_msg_and_die("unsupported psf file mode");
150 fontsize = ((psfhdr->mode & PSF_MODE512) ? 512 : 256);
151 #if !defined(PIO_FONTX) || defined(__sparc__)
153 bb_error_msg_and_die("only fontsize 256 supported");
155 hastable = (psfhdr->mode & PSF_MODEHASTAB);
156 unit = psfhdr->charsize;
157 head0 = sizeof(struct psf_header);
159 head = head0 + fontsize * unit;
160 if (head > len || (!hastable && head != len))
161 bb_error_msg_and_die("input file: bad length");
163 /* file with three code pages? */
170 bb_error_msg_and_die("input file: bad length");
178 do_loadfont(fd, (unsigned char *)psfhdr + head0, unit, fontsize);
180 do_loadtable(fd, (unsigned char *)psfhdr + head, len - head, fontsize);
184 int loadfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
185 int loadfont_main(int argc UNUSED_PARAM, char **argv)
188 struct psf_header *psfhdr;
190 // no arguments allowed!
191 opt_complementary = "=0";
195 * We used to look at the length of the input file
196 * with stat(); now that we accept compressed files,
197 * just read the entire file.
199 len = 32*1024; // can't be larger
200 psfhdr = xmalloc_read(STDIN_FILENO, &len);
201 // xmalloc_open_zipped_read_close(filename, &len);
203 bb_perror_msg_and_die("error reading input font");
204 do_load(get_console_fd_or_die(), psfhdr, len);
215 setfont [-O font+umap.orig] [-o font.orig] [-om cmap.orig]
216 [-ou umap.orig] [-N] [font.new ...] [-m cmap] [-u umap] [-C console]
219 -h NN Override font height
221 Save previous font in file
223 Save previous font and Unicode map in file
225 Store console map in file
227 Save previous Unicode map in file
229 Load console map or Unicode console map from file
231 Load Unicode table describing the font from file
236 0x80 U+0410 # CYRILLIC CAPITAL LETTER A
237 0x81 U+0411 # CYRILLIC CAPITAL LETTER BE
238 0x82 U+0412 # CYRILLIC CAPITAL LETTER VE
240 Set the font for the indicated console
245 #if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP
246 static int ctoi(char *s)
248 if (s[0] == '\'' && s[1] != '\0' && s[2] == '\'' && s[3] == '\0')
251 if (s[0] == 'U' && s[1] == '+') {
257 return xstrtoul(s, 0);
261 int setfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
262 int setfont_main(int argc UNUSED_PARAM, char **argv)
267 struct psf_header *psfhdr;
269 const char *tty_name = CURRENT_TTY;
271 opt_complementary = "=1";
272 opts = getopt32(argv, "m:C:", &mapfilename, &tty_name);
275 fd = xopen(tty_name, O_NONBLOCK);
277 if (sizeof(CONFIG_DEFAULT_SETFONT_DIR) > 1) { // if not ""
278 if (*argv[0] != '/') {
279 // goto default fonts location. don't die if doesn't exist
280 chdir(CONFIG_DEFAULT_SETFONT_DIR "/consolefonts");
284 len = 32*1024; // can't be larger
285 psfhdr = xmalloc_open_zipped_read_close(*argv, &len);
287 bb_simple_perror_msg_and_die(*argv);
288 do_load(fd, psfhdr, len);
290 // load the screen map, if any
291 if (opts & 1) { // -m
292 unsigned mode = PIO_SCRNMAP;
295 if (sizeof(CONFIG_DEFAULT_SETFONT_DIR) > 1) { // if not ""
296 if (mapfilename[0] != '/') {
297 // goto default keymaps location
298 chdir(CONFIG_DEFAULT_SETFONT_DIR "/consoletrans");
302 map = xmalloc_open_zipped_read_close(mapfilename, &len);
304 bb_simple_perror_msg_and_die(mapfilename);
305 // file size is 256 or 512 bytes? -> assume binary map
306 if (len == E_TABSZ || len == 2*E_TABSZ) {
307 if (len == 2*E_TABSZ)
308 mode = PIO_UNISCRNMAP;
310 #if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP
311 // assume textual Unicode console maps:
312 // 0x00 U+0000 # NULL (NUL)
313 // 0x01 U+0001 # START OF HEADING (SOH)
314 // 0x02 U+0002 # START OF TEXT (STX)
315 // 0x03 U+0003 # END OF TEXT (ETX)
321 if (ENABLE_FEATURE_CLEAN_UP)
323 map = xmalloc(E_TABSZ * sizeof(unsigned short));
325 #define unicodes ((unsigned short *)map)
327 for (i = 0; i < E_TABSZ; i++)
328 unicodes[i] = 0xf000 + i;
330 parser = config_open(mapfilename);
331 while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL | PARSE_MIN_DIE)) {
332 // parse code/value pair
333 int a = ctoi(token[0]);
334 int b = ctoi(token[1]);
335 if (a < 0 || a >= E_TABSZ
336 || b < 0 || b > 65535
338 bb_error_msg_and_die("map format");
342 // unicode character is met?
344 mode = PIO_UNISCRNMAP;
346 if (ENABLE_FEATURE_CLEAN_UP)
347 config_close(parser);
349 if (mode != PIO_UNISCRNMAP) {
350 #define asciis ((unsigned char *)map)
351 for (i = 0; i < E_TABSZ; i++)
352 asciis[i] = unicodes[i];
357 #endif // ENABLE_FEATURE_SETFONT_TEXTUAL_MAP
360 xioctl(fd, mode, map);
362 if (ENABLE_FEATURE_CLEAN_UP)