Add pancyrillic font
[platform/upstream/kbd.git] / src / kdfontop.c
1 /*
2  * kdfontop.c - export getfont(), getfontsize() and putfont()
3  *
4  * Font handling differs between various kernel versions.
5  * Hide the differences in this file.
6  */
7 #include <stdio.h>
8 #include <errno.h>
9 #include <stdlib.h>             /* free() */
10 #include <unistd.h>             /* usleep() */
11 #include <sys/ioctl.h>
12 #include <linux/kd.h>
13 #include "kdfontop.h"
14 #include "nls.h"
15 #include "version.h"
16
17 #ifdef COMPAT_HEADERS
18 #include "compat/linux-kd.h"
19 #endif
20
21 int
22 restorefont(int fd) {
23         if (ioctl(fd, PIO_FONTRESET, 0)) {
24                 perror("PIO_FONTRESET");
25                 return -1;
26         }
27         return 0;
28 }
29
30 int
31 font_charheight(unsigned char *buf, int count, int width) {
32         int h, i, x;
33         int bytewidth = (width+7)/8;
34
35         for (h = 32; h > 0; h--)
36                 for (i = 0; i < count; i++)
37                         for (x = 0; x < bytewidth; x++)
38                                 if (buf[(32*i+h-1)*bytewidth+x])
39                                         goto nonzero;
40  nonzero:
41         return h;
42 }
43
44 /*
45  * May be called with buf==NULL if we only want info.
46  * May be called with width==NULL and height==NULL.
47  * Must not exit - we may have cleanup to do.
48  */
49 int
50 getfont(int fd, unsigned char *buf, int *count, int *width, int *height) {
51         struct consolefontdesc cfd;
52         struct console_font_op cfo;
53         int i;
54
55         /* First attempt: KDFONTOP */
56         cfo.op = KD_FONT_OP_GET;
57         cfo.flags = 0;
58         cfo.width = cfo.height = 32;
59         cfo.charcount = *count;
60         cfo.data = buf;
61         i = ioctl(fd, KDFONTOP, &cfo);
62         if (i == 0) {
63                 *count = cfo.charcount;
64                 if (height)
65                         *height = cfo.height;
66                 if (width)
67                         *width = cfo.width;
68                 return 0;
69         }
70         if (errno != ENOSYS && errno != EINVAL) {
71                 perror("getfont: KDFONTOP");
72                 return -1;
73         }
74
75         /* The other methods do not support width != 8 */
76         if (width) *width = 8;
77         /* Second attempt: GIO_FONTX */
78         cfd.charcount = *count;
79         cfd.charheight = 0;
80         cfd.chardata = (char *)buf;
81         i = ioctl(fd, GIO_FONTX, &cfd);
82         if (i == 0) {
83                 *count = cfd.charcount;
84                 if (height)
85                         *height = cfd.charheight;
86                 return 0;
87         }
88         if (errno != ENOSYS && errno != EINVAL) {
89                 perror("getfont: GIO_FONTX");
90                 return -1;
91         }
92
93         /* Third attempt: GIO_FONT */
94         if (*count < 256) {
95                 fprintf(stderr, _("bug: getfont called with count<256\n"));
96                 return -1;
97         }
98         if (!buf) {
99             fprintf(stderr, _("bug: getfont using GIO_FONT needs buf.\n"));
100             return -1;
101         }
102         i = ioctl(fd, GIO_FONT, buf);
103         if (i) {
104                 perror("getfont: GIO_FONT");
105                 return -1;
106         }
107         *count = 256;
108         if (height)
109                 *height = 0;    /* undefined, at most 32 */
110         return 0;
111 }
112
113 int
114 getfontsize(int fd) {
115         int count;
116         int i;
117
118         count = 0;
119         i = getfont(fd, NULL, &count, NULL, NULL);
120         return (i == 0) ? count : 256;
121 }
122
123 int
124 putfont(int fd, unsigned char *buf, int count, int width, int height) {
125         struct consolefontdesc cfd;
126         struct console_font_op cfo;
127         int i;
128
129         if (!width)
130                 width = 8;
131         if (!height)
132                 height = font_charheight(buf, count, width);
133
134         /* First attempt: KDFONTOP */
135         cfo.op = KD_FONT_OP_SET;
136         cfo.flags = 0;
137         cfo.width = width;
138         cfo.height = height;
139         cfo.charcount = count;
140         cfo.data = buf;
141         i = ioctl(fd, KDFONTOP, &cfo);
142         if (i == 0)
143                 return 0;
144         if (width != 8 || (errno != ENOSYS && errno != EINVAL)) {
145                 perror("putfont: KDFONTOP");
146                 return -1;
147         }
148
149         /* Variation on first attempt: in case count is not 256 or 512
150            round up and try again. */
151         if (errno == EINVAL && width == 8 && count != 256 && count < 512) {
152                 int ct = ((count > 256) ? 512 : 256);
153                 unsigned char *mybuf = malloc(32 * ct);
154
155                 if (!mybuf) {
156                         fprintf(stderr, _("%s: out of memory\n"), progname);
157                         return -1;
158                 }
159                 memset(mybuf, 0, 32 * ct);
160                 memcpy(mybuf, buf, 32 * count);
161                 cfo.data = mybuf;
162                 cfo.charcount = ct;
163                 i = ioctl(fd, KDFONTOP, &cfo);
164                 free(mybuf);
165                 if (i == 0)
166                         return 0;
167         }
168
169         /* Second attempt: PIO_FONTX */
170         cfd.charcount = count;
171         cfd.charheight = height;
172         cfd.chardata = (char *)buf;
173         i = ioctl(fd, PIO_FONTX, &cfd);
174         if (i == 0)
175                 return 0;
176         if (errno != ENOSYS && errno != EINVAL) {
177                 fprintf(stderr, "%s: putfont: %d,%dx%d:failed: %d\n", progname, count, width, height, i);
178                 perror("putfont: PIO_FONTX");
179                 return -1;
180         }
181
182         /* Third attempt: PIO_FONT */
183         /* This will load precisely 256 chars, independent of count */
184         int loop = 0;
185
186         /* we allow ourselves to hang here for ca 5 seconds, xdm may be playing tricks on us. */
187         while ((loop++ < 20) && (i = ioctl(fd, PIO_FONT, buf)))
188           {
189             if (loop <= 1)
190               fprintf(stderr, "putfont: PIO_FONT trying ...\n");
191             else
192               fprintf(stderr, ".");
193             usleep(250000);
194           }
195         fprintf(stderr, "\n");
196
197         if (i) {
198                 fprintf(stderr, "%s: putfont: %d,%dx%d:  failed: %d\n", progname, count, width, height, i);
199                 perror("putfont: PIO_FONT");
200                 return -1;
201         }
202         return 0;
203 }