It turns out that DODMALLOC was broken when I reorganized busybox.h
[oweals/busybox.git] / console-tools / loadfont.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * loadfont.c - Eugene Crosser & Andries Brouwer
4  *
5  * Version 0.96bb
6  *
7  * Loads the console font, and possibly the corresponding screen map(s).
8  * (Adapted for busybox by Matej Vela.)
9  */
10 #include <stdio.h>
11 #include <string.h>
12 #include <fcntl.h>
13 #include <memory.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <sys/types.h>
17 #include <dirent.h>
18 #include <errno.h>
19 #include <sys/ioctl.h>
20 #include <sys/kd.h>
21 #include <endian.h>
22 #include "busybox.h"
23
24 static const int PSF_MAGIC1 = 0x36;
25 static const int PSF_MAGIC2 = 0x04;
26
27 static const int PSF_MODE512 = 0x01;
28 static const int PSF_MODEHASTAB = 0x02;
29 static const int PSF_MAXMODE = 0x03;
30 static const int PSF_SEPARATOR = 0xFFFF;
31
32 struct psf_header {
33         unsigned char magic1, magic2;   /* Magic number */
34         unsigned char mode;                     /* PSF font mode */
35         unsigned char charsize;         /* Character size */
36 };
37
38 #define PSF_MAGIC_OK(x) ((x).magic1 == PSF_MAGIC1 && (x).magic2 == PSF_MAGIC2)
39
40 static void loadnewfont(int fd);
41
42 extern int loadfont_main(int argc, char **argv)
43 {
44         int fd;
45
46         if (argc != 1)
47                 show_usage();
48
49         fd = open("/dev/tty0", O_RDWR);
50         if (fd < 0)
51                 perror_msg_and_die("Error opening /dev/tty0");
52         loadnewfont(fd);
53
54         return EXIT_SUCCESS;
55 }
56
57 static void do_loadfont(int fd, char *inbuf, int unit, int fontsize)
58 {
59         char buf[16384];
60         int i;
61
62         memset(buf, 0, sizeof(buf));
63
64         if (unit < 1 || unit > 32)
65                 error_msg_and_die("Bad character size %d", unit);
66
67         for (i = 0; i < fontsize; i++)
68                 memcpy(buf + (32 * i), inbuf + (unit * i), unit);
69
70 #if defined( PIO_FONTX ) && !defined( __sparc__ )
71         {
72                 struct consolefontdesc cfd;
73
74                 cfd.charcount = fontsize;
75                 cfd.charheight = unit;
76                 cfd.chardata = buf;
77
78                 if (ioctl(fd, PIO_FONTX, &cfd) == 0)
79                         return;                         /* success */
80                 perror_msg("PIO_FONTX ioctl error (trying PIO_FONT)");
81         }
82 #endif
83         if (ioctl(fd, PIO_FONT, buf))
84                 perror_msg_and_die("PIO_FONT ioctl error");
85 }
86
87 static void
88 do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize)
89 {
90         struct unimapinit advice;
91         struct unimapdesc ud;
92         struct unipair *up;
93         int ct = 0, maxct;
94         int glyph;
95         u_short unicode;
96
97         maxct = tailsz;                         /* more than enough */
98         up = (struct unipair *) xmalloc(maxct * sizeof(struct unipair));
99
100         for (glyph = 0; glyph < fontsize; glyph++) {
101                 while (tailsz >= 2) {
102                         unicode = (((u_short) inbuf[1]) << 8) + inbuf[0];
103                         tailsz -= 2;
104                         inbuf += 2;
105                         if (unicode == PSF_SEPARATOR)
106                                 break;
107                         up[ct].unicode = unicode;
108                         up[ct].fontpos = glyph;
109                         ct++;
110                 }
111         }
112
113         /* Note: after PIO_UNIMAPCLR and before PIO_UNIMAP
114            this printf did not work on many kernels */
115
116         advice.advised_hashsize = 0;
117         advice.advised_hashstep = 0;
118         advice.advised_hashlevel = 0;
119         if (ioctl(fd, PIO_UNIMAPCLR, &advice)) {
120 #ifdef ENOIOCTLCMD
121                 if (errno == ENOIOCTLCMD) {
122                         error_msg("It seems this kernel is older than 1.1.92");
123                         error_msg_and_die("No Unicode mapping table loaded.");
124                 } else
125 #endif
126                         perror_msg_and_die("PIO_UNIMAPCLR");
127         }
128         ud.entry_ct = ct;
129         ud.entries = up;
130         if (ioctl(fd, PIO_UNIMAP, &ud)) {
131 #if 0
132                 if (errno == ENOMEM) {
133                         /* change advice parameters */
134                 }
135 #endif
136                 perror_msg_and_die("PIO_UNIMAP");
137         }
138 }
139
140 static void loadnewfont(int fd)
141 {
142         int unit;
143         char inbuf[32768];                      /* primitive */
144         unsigned int inputlth, offset;
145
146         /*
147          * We used to look at the length of the input file
148          * with stat(); now that we accept compressed files,
149          * just read the entire file.
150          */
151         inputlth = fread(inbuf, 1, sizeof(inbuf), stdin);
152         if (ferror(stdin))
153                 perror_msg_and_die("Error reading input font");
154         /* use malloc/realloc in case of giant files;
155            maybe these do not occur: 16kB for the font,
156            and 16kB for the map leaves 32 unicode values
157            for each font position */
158         if (!feof(stdin))
159                 perror_msg_and_die("Font too large");
160
161         /* test for psf first */
162         {
163                 struct psf_header psfhdr;
164                 int fontsize;
165                 int hastable;
166                 unsigned int head0, head;
167
168                 if (inputlth < sizeof(struct psf_header))
169                         goto no_psf;
170
171                 psfhdr = *(struct psf_header *) &inbuf[0];
172
173                 if (!PSF_MAGIC_OK(psfhdr))
174                         goto no_psf;
175
176                 if (psfhdr.mode > PSF_MAXMODE)
177                         error_msg_and_die("Unsupported psf file mode");
178                 fontsize = ((psfhdr.mode & PSF_MODE512) ? 512 : 256);
179 #if !defined( PIO_FONTX ) || defined( __sparc__ )
180                 if (fontsize != 256)
181                         error_msg_and_die("Only fontsize 256 supported");
182 #endif
183                 hastable = (psfhdr.mode & PSF_MODEHASTAB);
184                 unit = psfhdr.charsize;
185                 head0 = sizeof(struct psf_header);
186
187                 head = head0 + fontsize * unit;
188                 if (head > inputlth || (!hastable && head != inputlth))
189                         error_msg_and_die("Input file: bad length");
190                 do_loadfont(fd, inbuf + head0, unit, fontsize);
191                 if (hastable)
192                         do_loadtable(fd, inbuf + head, inputlth - head, fontsize);
193                 return;
194         }
195   no_psf:
196
197         /* file with three code pages? */
198         if (inputlth == 9780) {
199                 offset = 40;
200                 unit = 16;
201         } else {
202                 /* bare font */
203                 if (inputlth & 0377)
204                         error_msg_and_die("Bad input file size");
205                 offset = 0;
206                 unit = inputlth / 256;
207         }
208         do_loadfont(fd, inbuf + offset, unit, 256);
209 }