Add pancyrillic font
[platform/upstream/kbd.git] / src / loadunimap.c
1 /*
2  * loadunimap.c - aeb
3  *
4  * Version 1.09
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 <unistd.h>
14 #include <fcntl.h>
15 #include <sys/ioctl.h>
16 #include <linux/kd.h>
17 #include "paths.h"
18 #include "getfd.h"
19 #include "xmalloc.h"
20 #include "findfile.h"
21 #include "kdmapop.h"
22 #include "psffontop.h"
23 #include "loadunimap.h"
24 #include "utf8.h"
25 #include "psf.h"
26 #include "nls.h"
27
28 extern char *progname;
29 extern int force;
30
31 static const char *const unidirpath[] = { "", DATADIR "/" UNIMAPDIR "/", 0 };
32 static const char *const unisuffixes[] = { "", ".uni", ".sfm", 0 };
33
34 #ifdef MAIN
35 #include "version.h"
36 int verbose = 0;
37 int force = 0;
38 int debug = 0;
39
40 static void __attribute__ ((noreturn))
41 usage(void) {
42         fprintf(stderr,
43                 _("Usage:\n\t%s [-C console] [-o map.orig]\n"), progname);
44         exit(1);
45 }
46
47 int
48 main(int argc, char *argv[]) {
49         int fd, c;
50         char *console = NULL;
51         char *outfnam = NULL;
52         char *infnam = "def.uni";
53
54         set_progname(argv[0]);
55
56         setlocale(LC_ALL, "");
57         bindtextdomain(PACKAGE_NAME, LOCALEDIR);
58         textdomain(PACKAGE_NAME);
59
60         if (argc == 2 &&
61             (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version")))
62                 print_version_and_exit();
63
64         while ((c = getopt(argc, argv, "C:o:")) != EOF) {
65                 switch (c) {
66                 case 'C':
67                         console = optarg;
68                         break;
69                 case 'o':
70                         outfnam = optarg;
71                         break;
72                 default:
73                         usage();
74                 }
75         }
76
77         if (argc > optind+1 || (argc == optind && !outfnam))
78                 usage();
79
80         fd = getfd(console);
81
82         if (outfnam) {
83                 saveunicodemap(fd, outfnam);
84                 if (argc == optind)
85                         exit(0);
86         }
87
88         if (argc == optind+1)
89                 infnam = argv[optind];
90         loadunicodemap(fd, infnam);
91         exit(0);
92 }
93 #endif
94
95 /*
96  * Skip spaces and read U+1234 or return -1 for error.
97  * Return first non-read position in *p0 (unchanged on error).
98  */ 
99 static int
100 getunicode(char **p0) {
101         char *p = *p0;
102
103         while (*p == ' ' || *p == '\t')
104                 p++;
105 #if 0
106         /* The code below also allows one to accept 'utf8' */
107         if (*p == '\'') {
108                 int err;
109                 unsigned long u;
110                 char *p1 = p+1;
111
112                 /*
113                  * Read a single complete utf-8 character, and
114                  * expect it to be closed by a single quote.
115                  */
116                 u = from_utf8(&p1, 0, &err);
117                 if (err || *p1 != '\'')
118                         return -1;
119                 *p0 = p1+1;
120                 return u;
121         }
122 #endif
123         if (*p != 'U' || p[1] != '+' || !isxdigit(p[2]) || !isxdigit(p[3]) ||
124             !isxdigit(p[4]) || !isxdigit(p[5]) || isxdigit(p[6]))
125                 return -1;
126         *p0 = p+6;
127         return strtol(p+2,0,16);
128 }
129
130 static struct unimapdesc descr;
131
132 static struct unipair *list = 0;
133 static int listsz = 0;
134 static int listct = 0;
135
136 static void
137 addpair(int fp, int un) {
138     if (listct == listsz) {
139         listsz += 4096;
140         list = xrealloc((char *)list, listsz);
141     }
142     list[listct].fontpos = fp;
143     list[listct].unicode = un;
144     listct++;
145 }
146
147 /*
148  * Syntax accepted:
149  *      <fontpos>       <unicode> <unicode> ...
150  *      <range>         idem
151  *      <range>         <unicode>
152  *      <range>         <unicode range>
153  *
154  * where <range> ::= <fontpos>-<fontpos>
155  * and <unicode> ::= U+<h><h><h><h>
156  * and <h> ::= <hexadecimal digit>
157  */
158
159 static void
160 parseline(char *buffer, char *tblname) {
161         int fontlen = 512;
162         int i;
163         int fp0, fp1, un0, un1;
164         char *p, *p1;
165
166         p = buffer;
167
168         while (*p == ' ' || *p == '\t')
169                 p++;
170         if (!*p || *p == '#')
171                 return; /* skip comment or blank line */
172
173         fp0 = strtol(p, &p1, 0);
174         if (p1 == p) {
175                 fprintf(stderr, _("Bad input line: %s\n"), buffer);
176                 exit(EX_DATAERR);
177         }
178         p = p1;
179
180         while (*p == ' ' || *p == '\t')
181                 p++;
182         if (*p == '-') {
183                 p++;
184                 fp1 = strtol(p, &p1, 0);
185                 if (p1 == p) {
186                         fprintf(stderr, _("Bad input line: %s\n"), buffer);
187                         exit(EX_DATAERR);
188                 }
189                 p = p1;
190         } else
191                 fp1 = 0;
192
193         if ( fp0 < 0 || fp0 >= fontlen ) {
194                 fprintf(stderr,
195                         _("%s: Glyph number (0x%x) larger than font length\n"),
196                         tblname, fp0);
197                 exit(EX_DATAERR);
198         }
199         if ( fp1 && (fp1 < fp0 || fp1 >= fontlen) ) {
200                 fprintf(stderr,
201                         _("%s: Bad end of range (0x%x)\n"),
202                         tblname, fp1);
203                 exit(EX_DATAERR);
204         }
205
206         if (fp1) {
207                 /* we have a range; expect the word "idem" or a Unicode range
208                    of the same length or a single Unicode value */
209                 while (*p == ' ' || *p == '\t')
210                         p++;
211                 if (!strncmp(p, "idem", 4)) {
212                         p += 4;
213                         for (i=fp0; i<=fp1; i++)
214                                 addpair(i,i);
215                         goto lookattail;
216                 }
217
218                 un0 = getunicode(&p);
219                 while (*p == ' ' || *p == '\t')
220                         p++;
221                 if (*p != '-') {
222                         for (i=fp0; i<=fp1; i++)
223                                 addpair(i,un0);
224                         goto lookattail;
225                 }
226
227                 p++;
228                 un1 = getunicode(&p);
229                 if (un0 < 0 || un1 < 0) {
230                         fprintf(stderr,
231                                 _("%s: Bad Unicode range corresponding to "
232                                   "font position range 0x%x-0x%x\n"),
233                                 tblname, fp0, fp1);
234                         exit(EX_DATAERR);
235                 }
236                 if (un1 - un0 != fp1 - fp0) {
237                         fprintf(stderr,
238                                 _("%s: Unicode range U+%x-U+%x not of the same"
239                                   " length as font position range 0x%x-0x%x\n"),
240                                 tblname, un0, un1, fp0, fp1);
241                         exit(EX_DATAERR);
242                 }
243                 for(i=fp0; i<=fp1; i++)
244                         addpair(i,un0-fp0+i);
245
246         } else {
247                 /* no range; expect a list of unicode values
248                    for a single font position */
249
250                 while ( (un0 = getunicode(&p)) >= 0 )
251                         addpair(fp0, un0);
252         }
253  lookattail:
254         while (*p == ' ' || *p == '\t')
255                 p++;
256         if (*p && *p != '#')
257                 fprintf(stderr, _("%s: trailing junk (%s) ignored\n"),
258                         tblname, p);
259 }
260
261 void
262 loadunicodemap(int fd, char *tblname) {
263         char buffer[65536];
264         char *p;
265         lkfile_t fp;
266
267         if (lk_findfile(tblname, unidirpath, unisuffixes, &fp)) {
268                 perror(tblname);
269                 exit(EX_NOINPUT);
270         }
271
272         if (verbose)
273                 printf(_("Loading unicode map from file %s\n"), fp.pathname);
274
275         while ( fgets(buffer, sizeof(buffer), fp.fd) != NULL ) {
276                 if ( (p = strchr(buffer, '\n')) != NULL )
277                         *p = '\0';
278                 else
279                         fprintf(stderr, _("%s: %s: Warning: line too long\n"),
280                                 progname, tblname);
281
282                 parseline(buffer, tblname);
283         }
284
285         lk_fpclose(&fp);
286
287         if (listct == 0 && !force) {
288                 fprintf(stderr,
289                         _("%s: not loading empty unimap\n"
290                           "(if you insist: use option -f to override)\n"),
291                         progname);
292         } else {
293                 descr.entry_ct = listct;
294                 descr.entries = list;
295                 if (loadunimap (fd, NULL, &descr))
296                         exit(1);
297                 listct = 0;
298         }
299 }
300
301 static struct unimapdesc
302 getunicodemap(int fd) {
303   struct unimapdesc unimap_descr;
304
305   if (getunimap(fd, &unimap_descr))
306           exit(1);
307
308 #ifdef MAIN
309   fprintf(stderr, "# %d %s\n", unimap_descr.entry_ct,
310          (unimap_descr.entry_ct == 1) ? _("entry") : _("entries"));
311 #endif
312
313   return unimap_descr;
314 }
315
316 void
317 saveunicodemap(int fd, char *oufil) {
318   FILE *fpo;
319   struct unimapdesc unimap_descr;
320   struct unipair *unilist;
321   int i;
322
323   if ((fpo = fopen(oufil, "w")) == NULL) {
324       perror(oufil);
325       exit(1);
326   }
327
328   unimap_descr = getunicodemap(fd);
329   unilist = unimap_descr.entries;
330
331   for(i=0; i<unimap_descr.entry_ct; i++)
332       fprintf(fpo, "0x%02x\tU+%04x\n", unilist[i].fontpos, unilist[i].unicode);
333   fclose(fpo);
334
335   if (verbose)
336     printf(_("Saved unicode map on `%s'\n"), oufil);
337 }
338
339 void
340 appendunicodemap(int fd, FILE *fp, int fontsize, int utf8) {
341         struct unimapdesc unimap_descr;
342         struct unipair *unilist;
343         int i, j;
344
345         unimap_descr = getunicodemap(fd);
346         unilist = unimap_descr.entries;
347
348                 
349         for(i=0; i<fontsize; i++) {
350 #if 0
351                 /* More than one mapping is not a sequence! */
352                 int no = 0;
353                 for(j=0; j<unimap_descr.entry_ct; j++) 
354                         if (unilist[j].fontpos == i)
355                                 no++;
356                 if (no > 1)
357                         appendseparator(fp, 1, utf8);
358 #endif          
359                 if (debug) printf ("\nchar %03x: ", i);
360                 for(j=0; j<unimap_descr.entry_ct; j++)
361                         if (unilist[j].fontpos == i) {
362                                 if (debug)
363                                         printf ("%04x ", unilist[j].unicode);
364                                 appendunicode(fp, unilist[j].unicode, utf8);
365                         }
366                 appendseparator(fp, 0, utf8);
367         }
368
369
370         if (debug) printf ("\n");
371         if (verbose)
372                 printf(_("Appended Unicode map\n"));
373 }