2377b38703e6146cfe72eeeeb79f4756fb07b321
[platform/upstream/kbd.git] / src / loadunimap.c
1 /*
2  * loadunimap.c - aeb
3  *
4  * Version 0.97
5  */
6
7 #include <errno.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <sysexits.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <fcntl.h>
14 #include <linux/kd.h>
15 #include <sys/ioctl.h>
16 #include "paths.h"
17 #include "psf.h"
18 #include "nls.h"
19
20 /* the three exported functions */
21 void saveunicodemap(int fd, char *oufil);       /* save humanly readable */
22 void loadunicodemap(int fd, char *ufil);
23 void appendunicodemap(int fd, FILE *fp, int ct);/* append in psf style */
24
25 extern char *malloc(), *realloc();
26 extern char *progname;
27 extern int getfd(void);
28 extern int force;
29
30 static char *unidirpath[] = { "", DATADIR "/" TRANSDIR "/", 0 };
31 static char *unisuffixes[] = { "", ".uni", 0 };
32
33 #ifdef MAIN
34 int verbose = 0;
35 int force = 0;
36 char *progname;
37
38 int
39 main(int argc, char *argv[]) {
40         int fd;
41
42         progname = argv[0];
43
44         setlocale(LC_ALL, "");
45         bindtextdomain(PACKAGE, LOCALEDIR);
46         textdomain(PACKAGE);
47
48         fd = getfd();
49
50         if (argc >= 3 && !strcmp(argv[1], "-o")) {
51             saveunicodemap(fd, argv[2]);
52             argc -= 2;
53             argv += 2;
54             if (argc == 1)
55               exit(0);
56         }
57                 
58         if (argc > 2) {
59                 fprintf(stderr, _("usage: %s [-o map.orig] map-file\n"),
60                         progname);
61                 exit(1);
62         }
63
64         loadunicodemap(fd, (argc > 1) ? argv[1] : "def.uni");
65         exit(0);
66 }
67 #endif
68
69 /*
70  * Skip spaces and read U+1234 or return -1 for error.
71  * Return first non-read position in *p0 (unchanged on error).
72  */ 
73 int getunicode(char **p0) {
74   char *p = *p0;
75
76   while (*p == ' ' || *p == '\t')
77     p++;
78   if (*p != 'U' || p[1] != '+' || !isxdigit(p[2]) || !isxdigit(p[3]) ||
79       !isxdigit(p[4]) || !isxdigit(p[5]) || isxdigit(p[6]))
80     return -1;
81   *p0 = p+6;
82   return strtol(p+2,0,16);
83 }
84
85 struct unimapinit advice;
86
87 struct unimapdesc descr;
88
89 struct unipair *list = 0;
90 int listsz = 0;
91 int listct = 0;
92 int fd;
93
94 void outlist() {
95     advice.advised_hashsize = 0;
96     advice.advised_hashstep = 0;
97     advice.advised_hashlevel = 1;
98   again:
99     if(ioctl(fd, PIO_UNIMAPCLR, &advice)) {
100         perror("PIO_UNIMAPCLR");
101         exit(1);
102     }
103     descr.entry_ct = listct;
104     descr.entries = list;
105     if(ioctl(fd, PIO_UNIMAP, &descr)) {
106         if (errno == ENOMEM && advice.advised_hashlevel < 100) {
107             advice.advised_hashlevel++;
108 #ifdef MAIN
109             printf(_("trying hashlevel %d\n"), advice.advised_hashlevel);
110 #endif
111             goto again;
112         }
113         perror("PIO_UNIMAP");
114         exit(1);
115     }
116     listct = 0;
117 }
118
119 void addpair(int fp, int un) {
120     if (listct == listsz) {
121         listsz += 4096;
122         list = realloc((char *)list, listsz);
123         if (!list) {
124             fprintf(stderr, _("%s: out of memory\n"), progname);
125             exit(1);
126         }
127     }
128     list[listct].fontpos = fp;
129     list[listct].unicode = un;
130     listct++;
131 }
132
133 void
134 loadunicodemap(int fd, char *tblname) {
135     FILE *mapf;
136     char buffer[65536];
137     int fontlen = 512;
138     int i;
139     int fp0, fp1, un0, un1;
140     char *p, *p1;
141
142     mapf = findfile(tblname, unidirpath, unisuffixes);
143     if ( !mapf ) {
144         perror(tblname);
145         exit(EX_NOINPUT);
146     }
147
148     if (verbose)
149       printf(_("Loading unicode map from file %s\n"), pathname);
150
151     while ( fgets(buffer, sizeof(buffer), mapf) != NULL ) {
152         if ( (p = strchr(buffer, '\n')) != NULL )
153           *p = '\0';
154         else
155           fprintf(stderr, _("%s: %s: Warning: line too long\n"), progname, tblname);
156
157         p = buffer;
158
159 /*
160  * Syntax accepted:
161  *      <fontpos>       <unicode> <unicode> ...
162  *      <range>         idem
163  *      <range>         <unicode range>
164  *
165  * where <range> ::= <fontpos>-<fontpos>
166  * and <unicode> ::= U+<h><h><h><h>
167  * and <h> ::= <hexadecimal digit>
168  */
169
170         while (*p == ' ' || *p == '\t')
171           p++;
172         if (!*p || *p == '#')
173           continue;     /* skip comment or blank line */
174
175         fp0 = strtol(p, &p1, 0);
176         if (p1 == p) {
177             fprintf(stderr, _("Bad input line: %s\n"), buffer);
178             exit(EX_DATAERR);
179         }
180         p = p1;
181
182         while (*p == ' ' || *p == '\t')
183           p++;
184         if (*p == '-') {
185             p++;
186             fp1 = strtol(p, &p1, 0);
187             if (p1 == p) {
188                 fprintf(stderr, _("Bad input line: %s\n"), buffer);
189                 exit(EX_DATAERR);
190             }
191             p = p1;
192         }
193         else
194           fp1 = 0;
195
196         if ( fp0 < 0 || fp0 >= fontlen ) {
197             fprintf(stderr,
198                     _("%s: Glyph number (0x%x) larger than font length\n"),
199                     tblname, fp0);
200             exit(EX_DATAERR);
201         }
202         if ( fp1 && (fp1 < fp0 || fp1 >= fontlen) ) {
203             fprintf(stderr,
204                     _("%s: Bad end of range (0x%x)\n"),
205                     tblname, fp1);
206             exit(EX_DATAERR);
207         }
208
209         if (fp1) {
210             /* we have a range; expect the word "idem" or a Unicode range
211                of the same length */
212             while (*p == ' ' || *p == '\t')
213               p++;
214             if (!strncmp(p, "idem", 4)) {
215                 for (i=fp0; i<=fp1; i++)
216                   addpair(i,i);
217                 p += 4;
218             } else {
219                 un0 = getunicode(&p);
220                 while (*p == ' ' || *p == '\t')
221                   p++;
222                 if (*p != '-') {
223                     fprintf(stderr,
224                             _("%s: Corresponding to a range of font positions, "
225                             "there should be a Unicode range\n"),
226                             tblname);
227                     exit(EX_DATAERR);
228                 }
229                 p++;
230                 un1 = getunicode(&p);
231                 if (un0 < 0 || un1 < 0) {
232                     fprintf(stderr,
233                             _("%s: Bad Unicode range corresponding to "
234                             "font position range 0x%x-0x%x\n"),
235                             tblname, fp0, fp1);
236                     exit(EX_DATAERR);
237                 }
238                 if (un1 - un0 != fp1 - fp0) {
239                     fprintf(stderr,
240                             _("%s: Unicode range U+%x-U+%x not of the same"
241                               " length as font position range 0x%x-0x%x\n"),
242                             tblname, un0, un1, fp0, fp1);
243                     exit(EX_DATAERR);
244                 }
245                 for(i=fp0; i<=fp1; i++)
246                   addpair(i,un0-fp0+i);
247             }
248         } else {
249             /* no range; expect a list of unicode values
250                for a single font position */
251
252             while ( (un0 = getunicode(&p)) >= 0 )
253               addpair(fp0, un0);
254         }
255         while (*p == ' ' || *p == '\t')
256           p++;
257         if (*p && *p != '#')
258           fprintf(stderr, _("%s: trailing junk (%s) ignored\n"), tblname, p);
259     }
260
261     fpclose(mapf);
262
263     if (listct == 0 && !force)
264       fprintf(stderr, _("%s: not loading empty unimap\n"
265                       "(if you insist: use option -f to override)\n"),
266               progname);
267     else
268       outlist();
269 }
270
271 static struct unimapdesc
272 getunicodemap(int fd) {
273   struct unimapdesc descr;
274
275   descr.entry_ct = 0;
276   descr.entries = 0;
277   if(ioctl(fd, GIO_UNIMAP, (unsigned long) &descr)) {
278       if(errno != ENOMEM || descr.entry_ct == 0) {
279           perror("GIO_UNIMAP");
280           exit(1);
281       }
282       descr.entries = (struct unipair *)
283         malloc(descr.entry_ct * sizeof(struct unipair));
284       if (descr.entries == NULL) {
285           fprintf(stderr, _("%s: out of memory?\n"), progname);
286           exit(1);
287       }
288       if(ioctl(fd, GIO_UNIMAP, (unsigned long) &descr)) {
289           perror("GIO_UNIMAP(2)");
290           exit(1);
291       }
292   }
293 #ifdef MAIN
294   fprintf(stderr, "# %d %s\n", descr.entry_ct,
295          (descr.entry_ct == 1) ? _("entry") : _("entries"));
296 #endif
297
298   return descr;
299 }
300
301 void
302 saveunicodemap(int fd, char *oufil) {
303   FILE *fpo;
304   struct unimapdesc descr;
305   struct unipair *list;
306   int i;
307
308   if ((fpo = fopen(oufil, "w")) == NULL) {
309       perror(oufil);
310       exit(1);
311   }
312
313   descr = getunicodemap(fd);
314   list = descr.entries;
315
316   for(i=0; i<descr.entry_ct; i++)
317       fprintf(fpo, "0x%02x\tU+%04x\n", list[i].fontpos, list[i].unicode);
318   fclose(fpo);
319
320   if (verbose)
321     printf(_("Saved unicode map on `%s'\n"), oufil);
322 }
323
324 static void
325 appendunsignedshort(FILE *fp, unsigned short u) {
326   unsigned char unicodepair[2];
327
328   unicodepair[0] = (u & 0xff);
329   unicodepair[1] = ((u >> 8) & 0xff);
330   if (fwrite(unicodepair, sizeof(unicodepair), 1, fp) != 1) {
331     perror("appendunimap");
332     exit(1);
333   }
334 }
335
336 void
337 appendunicodemap(int fd, FILE *fp, int fontsize) {
338   struct unimapdesc descr;
339   struct unipair *list;
340   int i, j;
341
342   descr = getunicodemap(fd);
343   list = descr.entries;
344
345   for(i=0; i<fontsize; i++) {
346     for(j=0; j<descr.entry_ct; j++)
347       if (list[j].fontpos == i)
348         appendunsignedshort(fp, list[j].unicode);
349     appendunsignedshort(fp, PSF_SEPARATOR);
350   }
351
352   if (verbose)
353      printf(_("Appended Unicode map\n"));
354 }