c072e50df8cbba31eed296d7d896908824a297b2
[slovak-l10n] / ukeyboard / vkb_compiler_lib.c
1 /*
2  *  Copyright (c) 2007-2008 Jiri Benc <jbenc@upir.cz>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License version 2 as
6  *  published by the Free Software Foundation.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program; if not, write to the Free Software
15  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
16  */
17
18 #include <stdlib.h>
19 #include <string.h>
20 #include <setjmp.h>
21 #include "vkb_compiler.h"
22
23 static struct compiler_ops *cops;
24 static void *cpriv;
25 static jmp_buf cjmp;
26
27 #define BUF_SIZE        8192
28
29 /*** tokenizer ***/
30
31 struct tokenizer {
32         int line;
33         char *buf, *pos;
34         char *pushed;
35 };
36
37 static char keywords[][32] = {
38         "header", "name", "lang", "wc", "size", "width", "height",
39         "textpos", "left", "top", "kbd_normal", "kbd_thumb", "kbd_special",
40         "lowercase", "lowercase_num", "uppercase", "uppercase_num",
41         "special_lowercase", "special_uppercase",
42         "special", "margin", "default_size", "row", "key", "slide",
43         "white", "tab", "alpha", "num", "hexa", "tele", "dead"
44 };
45 enum keywords_const {
46         TOK_HEADER, TOK_NAME, TOK_LANG, TOK_WC, TOK_SIZE, TOK_WIDTH, TOK_HEIGHT,
47         TOK_TEXTPOS, TOK_LEFT, TOK_TOP, TOK_KBD_NORMAL, TOK_KBD_THUMB, TOK_KBD_SPECIAL,
48         TOK_LOWERCASE, TOK_LOWERCASE_NUM, TOK_UPPERCASE, TOK_UPPERCASE_NUM,
49         TOK_SPEC_LOWERCASE, TOK_SPEC_UPPERCASE,
50         TOK_SPECIAL, TOK_MARGIN, TOK_DEFAULT_SIZE, TOK_ROW, TOK_KEY, TOK_SLIDE,
51         TOK_WHITE, TOK_TAB, TOK_ALPHA, TOK_NUM, TOK_HEXA, TOK_TELE, TOK_DEAD
52 };
53
54 enum tok_type {
55         TT_KEYWORD, TT_NUM, TT_STRING, TT_BEGIN, TT_END, TT_EOF
56 };
57
58 static void tok_error(struct tokenizer *tokenizer, char *msg)
59 {
60         cops->error(cpriv, tokenizer->line, msg);
61         longjmp(cjmp, 1);
62 }
63
64 static void tok_warning(struct tokenizer *tokenizer, char *msg)
65 {
66         if (cops->warning(cpriv, tokenizer->line, msg))
67                 longjmp(cjmp, 1);
68 }
69
70 static void *e_malloc(size_t size)
71 {
72         void *p = calloc(1, size);
73         if (!p) {
74                 cops->error(cpriv, -1, "Out of memory");
75                 longjmp(cjmp, 1);
76         }
77         return p;
78 }
79
80 static void set_str(char **str, char *val)
81 {
82         if (*str)
83                 free(*str);
84         if (!val) {
85                 *str = NULL;
86                 return;
87         }
88         *str = e_malloc(strlen(val) + 1);
89         strcpy(*str, val);
90 }
91
92 static char *ltrim(char *buf)
93 {
94         while (buf && (*buf == ' ' || *buf == '\t' || *buf == '\n' || *buf == '\r'))
95                 buf++;
96         return buf;
97 }
98
99 static char *find_white(char *buf)
100 {
101         while (buf && *buf && *buf != ' ' && *buf != '\t' && *buf != '\n' && *buf != '\r')
102                 buf++;
103         return buf;
104 }
105
106 static int read_raw(struct tokenizer *tokenizer, char *dest, size_t size, int no_ltrim)
107 {
108         char *s;
109         char tmp;
110
111         while (1) {
112                 if (!no_ltrim)
113                         tokenizer->pos = ltrim(tokenizer->pos);
114                 if (!*tokenizer->pos) {
115                         tokenizer->line++;
116                         tokenizer->pos = tokenizer->buf;
117                         if (cops->get_line(cpriv, tokenizer->buf, BUF_SIZE))
118                                 return -1;
119                 } else
120                         break;
121         }
122         s = find_white(tokenizer->pos + 1);
123         tmp = *s;
124         *s = '\0';
125         if (size) {
126                 strncpy(dest, tokenizer->pos, size - 1);
127                 dest[size - 1] = '\0';
128         }
129         *s = tmp;
130         tokenizer->pos = s;
131         return 0;
132 }
133
134 static void finish_read_string(struct tokenizer *tokenizer, char *dest, size_t size)
135 {
136         char *s = dest + 1;
137         char *new = dest;
138         int special = 0;
139
140         while (1) {
141                 while (*s) {
142                         if (special) {
143                                 *new++ = *s++;
144                                 special = 0;
145                                 continue;
146                         }
147                         if (*s == '\\') {
148                                 special = 1;
149                                 s++;
150                                 continue;
151                         }
152                         if (*s == '"') {
153                                 *new = '\0';
154                                 if (s[1] != '\0')
155                                         tok_warning(tokenizer, "Ignored extra characters after the string");
156                                 return;
157                         }
158                         *new++ = *s++;
159                 }
160                 if (read_raw(tokenizer, s, size - (s - dest), 1) < 0)
161                         tok_error(tokenizer, "Unterminated (or too long) string");
162         }
163 }
164
165 static void skip_comment(struct tokenizer *tokenizer)
166 {
167         while (*tokenizer->pos)
168                 tokenizer->pos++;
169 }
170
171 static int find_keyword(char *s)
172 {
173         int i;
174         int max = (sizeof(keywords) / sizeof(*keywords));
175
176         for (i = 0; i < max; i++) {
177                 if (!strcmp(s, keywords[i]))
178                         return i;
179         }
180         return -1;
181 }
182
183 static void unread_tok(struct tokenizer *tokenizer, char *tok)
184 {
185         strncpy(tokenizer->pushed, tok, BUF_SIZE - 1);
186         tokenizer->pushed[BUF_SIZE - 1] = '\0';
187 }
188
189 static enum tok_type read_tok(struct tokenizer *tokenizer, char *dest, size_t size, int *parsed_int)
190 {
191         int res;
192
193         while (1) {
194                 if (*tokenizer->pushed) {
195                         strncpy(dest, tokenizer->pushed, size - 1);
196                         dest[size - 1] = '\0';
197                         *tokenizer->pushed = '\0';
198                 } else {
199                         res = read_raw(tokenizer, dest, size, 0);
200                         if (res < 0)
201                                 return TT_EOF;
202                 }
203                 if (dest[0] == '#')
204                         skip_comment(tokenizer);
205                 else
206                         break;
207         }
208         if ((dest[0] >= '0' && dest[0] <= '9') || dest[0] == '-') {
209                 *parsed_int = atoi(dest);
210                 return TT_NUM;
211         }
212         if (dest[0] == '"') {
213                 finish_read_string(tokenizer, dest, size);
214                 return TT_STRING;
215         }
216         if (dest[0] == '{') {
217                 if (dest[1] != '\0')
218                         tok_error(tokenizer, "Whitespace required after {");
219                 return TT_BEGIN;
220         }
221         if (dest[0] == '}') {
222                 if (dest[1] != '\0')
223                         tok_error(tokenizer, "Whitespace required after }");
224                 return TT_END;
225         }
226         res = find_keyword(dest);
227         if (res < 0)
228                 tok_error(tokenizer, "Uknown keyword");
229         *parsed_int = res;
230         return TT_KEYWORD;
231 }
232
233 static void init_tokenizer(struct tokenizer *tokenizer)
234 {
235         tokenizer->pos = tokenizer->buf = e_malloc(BUF_SIZE);
236         tokenizer->pushed = e_malloc(BUF_SIZE);
237 }
238
239 static void close_tokenizer(struct tokenizer *tokenizer)
240 {
241         if (!tokenizer)
242                 return;
243         free(tokenizer->buf);
244         free(tokenizer->pushed);
245 }
246
247 /*** parser structures ***/
248
249 struct slide_key {
250         char *name;
251         struct slide_key *next;
252 };
253
254 struct key {
255         int slides_cnt;
256         union {
257                 char *name;
258                 struct slide_key *slides;
259         } u;
260         int size;
261         int flags;
262         struct key *next;
263 };
264
265 #define KEY_ALPHA       0x01
266 #define KEY_NUM         0x02
267 #define KEY_HEXA        0x04
268 #define KEY_TELE        0x08
269 #define KEY_SPECIAL     0x10
270 #define KEY_DEAD        0x20
271 #define KEY_WHITE       0x40
272 #define KEY_EXTEND      0x80
273
274 #define KEY_TAB         (0x0400 | KEY_EXTEND)
275
276 struct row {
277         int keys_cnt;
278         struct key *keys;
279         struct row *next;
280 };
281
282 struct layout {
283         int type;
284         char *name;
285         int margins[4];
286         int default_size;
287         int rows_cnt;
288         struct row *rows;
289         struct layout *sublayout;
290         struct layout *next;
291 };
292
293 #define LAY_LOWERCASE           0
294 #define LAY_UPPERCASE           1
295 #define LAY_LOWERCASE_NUM       2
296 #define LAY_UPPERCASE_NUM       3
297 #define LAY_SPECIAL             4
298 #define LAY_SPECIAL_LOWER       5
299 #define LAY_SPECIAL_UPPER       6
300
301 struct kbd {
302         int type;
303         int layouts_cnt;
304         struct layout *layouts;
305         struct kbd *next;
306 };
307
308 struct size {
309         int dim[5];
310         struct size *next;
311 };
312
313 #define KBD_NORMAL              0
314 #define KBD_THUMB               4
315 #define KBD_SPECIAL             1
316
317 struct global {
318         char *name;
319         char *lang;
320         char *wc;
321         int sizes_cnt;
322         struct size *sizes;
323         int kbds_cnt;
324         struct kbd *kbds;
325 };
326
327 static struct global *new_global(void)
328 {
329         return e_malloc(sizeof(struct global));
330 }
331
332 static void free_sizes(struct size *size)
333 {
334         struct size *next;
335
336         while (size) {
337                 next = size->next;
338                 free(size);
339                 size = next;
340         }
341 }
342
343 static void free_slides(struct slide_key *sl)
344 {
345         struct slide_key *next;
346
347         while (sl) {
348                 next = sl->next;
349                 free(sl->name);
350                 free(sl);
351                 sl = next;
352         }
353 }
354
355 static void free_keys(struct key *key)
356 {
357         struct key *next;
358
359         while (key) {
360                 next = key->next;
361                 if (key->slides_cnt)
362                         free_slides(key->u.slides);
363                 else
364                         free(key->u.name);
365                 free(key);
366                 key = next;
367         }
368 }
369
370 static void free_rows(struct row *row)
371 {
372         struct row *next;
373
374         while (row) {
375                 next = row->next;
376                 free_keys(row->keys);
377                 free(row);
378                 row = next;
379         }
380 }
381
382 static void free_layouts(struct layout *lay)
383 {
384         struct layout *next;
385
386         while (lay) {
387                 next = lay->next;
388                 free_rows(lay->rows);
389                 free_layouts(lay->sublayout);
390                 free(lay->name);
391                 free(lay);
392                 lay = next;
393         }
394 }
395
396 static void free_kbds(struct kbd *kbd)
397 {
398         struct kbd *next;
399
400         while (kbd) {
401                 next = kbd->next;
402                 free_layouts(kbd->layouts);
403                 free(kbd);
404                 kbd = next;
405         }
406 }
407
408 static void free_global(struct global *glob)
409 {
410         if (!glob)
411                 return;
412         free_sizes(glob->sizes);
413         free_kbds(glob->kbds);
414         free(glob->name);
415         free(glob->lang);
416         free(glob->wc);
417         free(glob);
418 }
419
420 /*** parser ***/
421
422 struct parser {
423         struct tokenizer *tokenizer;
424         struct global *global;
425         int ttype;
426         char *tstr;
427         int tint;
428 };
429
430 static void init_parser(struct parser *parser)
431 {
432         parser->tokenizer = e_malloc(sizeof(struct tokenizer));
433         init_tokenizer(parser->tokenizer);
434         parser->tstr = e_malloc(BUF_SIZE);
435         parser->global = new_global();
436 }
437
438 static void close_parser(struct parser *parser)
439 {
440         if (!parser)
441                 return;
442         free_global(parser->global);
443         free(parser->tstr);
444         close_tokenizer(parser->tokenizer);
445         free(parser->tokenizer);
446 }
447
448 #define error(parser, msg)      tok_error((parser)->tokenizer, msg)
449 #define warning(parser, msg)    tok_warning((parser)->tokenizer, msg)
450 #define error_end(parser)       error(parser, "} expected")
451
452 static void get_tok(struct parser *parser)
453 {
454         parser->ttype = read_tok(parser->tokenizer, parser->tstr, BUF_SIZE, &parser->tint);
455 }
456
457 static void __get_raw(struct parser *parser)
458 {
459         if (read_raw(parser->tokenizer, parser->tstr, BUF_SIZE, 0) < 0)
460                 error(parser, "Unexpected end of file");
461 }
462
463 static void push_tok(struct parser *parser)
464 {
465         unread_tok(parser->tokenizer, parser->tstr);
466 }
467
468 #define is_type(parser, t)      ((parser)->ttype == (t))
469 #define is_keyword(parser, w)   ((parser)->ttype == TT_KEYWORD && (parser)->tint == (w))
470 #define is_begin(parser)        ((parser)->ttype == TT_BEGIN)
471 #define is_end(parser)          ((parser)->ttype == TT_END)
472 #define is_eof(parser)          ((parser)->ttype == TT_EOF)
473
474 static void get_tok_type(struct parser *parser, int tt)
475 {
476         get_tok(parser);
477         if (!is_type(parser, tt)) {
478                 switch (tt) {
479                 case TT_NUM: error(parser, "Number expected");
480                 case TT_STRING: error(parser, "String expected");
481                 case TT_BEGIN: error(parser, "{ expected");
482                 case TT_END: error(parser, "} expected");
483                 default: error(parser, "Syntax error");
484                 }
485         }
486 }
487
488 #define get_tok_num(parser)     get_tok_type(parser, TT_NUM)
489 #define get_tok_string(parser)  get_tok_type(parser, TT_STRING)
490 #define get_tok_begin(parser)   get_tok_type(parser, TT_BEGIN)
491 #define get_tok_end(parser)     get_tok_type(parser, TT_END)
492
493 static void parse_sizes(struct parser *parser, struct global *glob)
494 {
495         struct size *size;
496
497         get_tok_num(parser);
498         if (parser->tint != glob->sizes_cnt)
499                 error(parser, "size number out of order");
500         size = e_malloc(sizeof(struct size));
501         glob->sizes_cnt++;
502         if (!glob->sizes)
503                 glob->sizes = size;
504         else {
505                 struct size *last = glob->sizes;
506                 while (last->next)
507                         last = last->next;
508                 last->next = size;
509         }
510         get_tok_begin(parser);
511         while (1) {
512                 get_tok(parser);
513                 if (is_keyword(parser, TOK_WIDTH)) {
514                         get_tok_num(parser);
515                         size->dim[0] = parser->tint;
516                 } else if (is_keyword(parser, TOK_HEIGHT)) {
517                         get_tok_num(parser);
518                         size->dim[1] = parser->tint;
519                 } else if (is_keyword(parser, TOK_TEXTPOS)) {
520                         get_tok_num(parser);
521                         size->dim[2] = parser->tint;
522                 } else if (is_keyword(parser, TOK_LEFT)) {
523                         get_tok_num(parser);
524                         size->dim[3] = parser->tint;
525                 } else if (is_keyword(parser, TOK_TOP)) {
526                         get_tok_num(parser);
527                         size->dim[4] = parser->tint;
528                 } else if (is_end(parser)) {
529                         return;
530                 } else
531                         error_end(parser);
532         }
533 }
534
535 static void parse_header(struct parser *parser, struct global *glob)
536 {
537         get_tok_begin(parser);
538         while (1) {
539                 get_tok(parser);
540                 if (is_keyword(parser, TOK_NAME)) {
541                         get_tok_string(parser);
542                         set_str(&glob->name, parser->tstr);
543                 } else if (is_keyword(parser, TOK_LANG)) {
544                         get_tok_string(parser);
545                         set_str(&glob->lang, parser->tstr);
546                 } else if (is_keyword(parser, TOK_WC)) {
547                         get_tok_string(parser);
548                         set_str(&glob->wc, parser->tstr);
549                 } else if (is_keyword(parser, TOK_SIZE)) {
550                         parse_sizes(parser, glob);
551                 } else if (is_end(parser)) {
552                         return;
553                 } else
554                         error_end(parser);
555         }
556 }
557
558 static void parse_slide(struct parser *parser, struct key *key)
559 {
560         while (1) {
561                 get_tok(parser);
562                 if (is_keyword(parser, TOK_KEY)) {
563                         struct slide_key *skey = e_malloc(sizeof(struct slide_key));
564
565                         key->slides_cnt++;
566                         if (!key->u.slides)
567                                 key->u.slides = skey;
568                         else {
569                                 struct slide_key *last = key->u.slides;
570                                 while (last->next)
571                                         last = last->next;
572                                 last->next = skey;
573                         }
574                         __get_raw(parser);
575                         set_str(&skey->name, parser->tstr);
576                 } else if (is_end(parser))
577                         return;
578                 else
579                         error_end(parser);
580         }
581 }
582
583 static void parse_key(struct parser *parser, struct row *row, int type)
584 {
585         struct key *key = e_malloc(sizeof(struct key));
586
587         key->size = -1;
588         row->keys_cnt++;
589         if (!row->keys)
590                 row->keys = key;
591         else {
592                 struct key *last = row->keys;
593                 while (last->next)
594                         last = last->next;
595                 last->next = key;
596         }
597         if (type == TOK_KEY) {
598                 __get_raw(parser);
599                 set_str(&key->u.name, parser->tstr);
600         } else if (type == TOK_WHITE) {
601                 set_str(&key->u.name, "");
602                 key->flags |= KEY_WHITE;
603         } else if (type == TOK_TAB) {
604                 set_str(&key->u.name, "");
605                 key->flags |= KEY_TAB;
606         }
607         while (1) {
608                 get_tok(parser);
609                 if (is_keyword(parser, TOK_ALPHA))
610                         key->flags |= KEY_ALPHA;
611                 else if (is_keyword(parser, TOK_NUM))
612                         key->flags |= KEY_NUM;
613                 else if (is_keyword(parser, TOK_HEXA))
614                         key->flags |= KEY_HEXA;
615                 else if (is_keyword(parser, TOK_TELE))
616                         key->flags |= KEY_TELE;
617                 else if (is_keyword(parser, TOK_SPECIAL))
618                         key->flags |= KEY_SPECIAL;
619                 else if (is_keyword(parser, TOK_DEAD))
620                         key->flags |= KEY_DEAD;
621                 else if (is_keyword(parser, TOK_SIZE)) {
622                         get_tok_num(parser);
623                         key->size = parser->tint;
624                 } else if (is_begin(parser) && type == TOK_SLIDE)
625                         parse_slide(parser, key);
626                 else if (is_keyword(parser, TOK_KEY) ||
627                            is_keyword(parser, TOK_WHITE) ||
628                            is_keyword(parser, TOK_TAB) ||
629                            is_keyword(parser, TOK_SLIDE) ||
630                            is_end(parser)) {
631                         push_tok(parser);
632                         if (type == TOK_SLIDE && !key->slides_cnt)
633                                 error(parser, "{ expected");
634                         return;
635                 } else
636                         error_end(parser);
637         }
638 }
639
640 static void parse_row(struct parser *parser, struct layout *lay)
641 {
642         struct row *row = e_malloc(sizeof(struct row));
643
644         lay->rows_cnt++;
645         if (!lay->rows)
646                 lay->rows = row;
647         else {
648                 struct row *last = lay->rows;
649                 while (last->next)
650                         last = last->next;
651                 last->next = row;
652         }
653         get_tok_begin(parser);
654         while (1) {
655                 get_tok(parser);
656                 if (is_keyword(parser, TOK_KEY))
657                         parse_key(parser, row, TOK_KEY);
658                 else if (is_keyword(parser, TOK_WHITE))
659                         parse_key(parser, row, TOK_WHITE);
660                 else if (is_keyword(parser, TOK_TAB))
661                         parse_key(parser, row, TOK_TAB);
662                 else if (is_keyword(parser, TOK_SLIDE))
663                         parse_key(parser, row, TOK_SLIDE);
664                 else if (is_end(parser))
665                         return;
666                 else
667                         error_end(parser);
668         }
669 }
670
671 static void parse_layout(struct parser *parser, struct kbd *kbd, int type)
672 {
673         struct layout *lay = e_malloc(sizeof(struct layout));
674
675         if (type == LAY_LOWERCASE_NUM || type == LAY_UPPERCASE_NUM) {
676                 /* numeric layout is a sublayout of a normal layout */
677                 struct layout *find = kbd->layouts;
678                 while (find) {
679                         if (find->type == type - 2) {
680                                 find->sublayout = lay;
681                                 break;
682                         }
683                         find = find->next;
684                 }
685                 if (!find) {
686                         free(lay);
687                         error(parser, "lowercase_num/uppercase_num has to follow lowercase/uppercase definition");
688                 }
689         } else {
690                 struct layout *last = kbd->layouts;
691
692                 if (!last)
693                         kbd->layouts = lay;
694                 else {
695                         while (last->next)
696                                 last = last->next;
697                         last->next = lay;
698                 }
699                 kbd->layouts_cnt++;
700                 if ((type == LAY_UPPERCASE && (!last || last->type != LAY_LOWERCASE)) ||
701                     (type == LAY_SPECIAL_UPPER && (!last || last->type != LAY_SPECIAL_LOWER)))
702                         error(parser, "uppercase has to follow lowercase definition");
703                 if (type == LAY_SPECIAL_UPPER && last->name)
704                         set_str(&lay->name, last->name);
705         }
706         lay->type = type;
707         get_tok_begin(parser);
708         while (1) {
709                 get_tok(parser);
710                 if (is_keyword(parser, TOK_NAME)) {
711                         get_tok_string(parser);
712                         if (lay->name)
713                                 error(parser, "name must not be specified for uppercase layout in kbd_special section");
714                         set_str(&lay->name, parser->tstr);
715                 } else if (is_keyword(parser, TOK_MARGIN)) {
716                         int i;
717                         for (i = 0; i < 4; i++) {
718                                 get_tok_num(parser);
719                                 lay->margins[i] = parser->tint;
720                         }
721                 } else if (is_keyword(parser, TOK_DEFAULT_SIZE)) {
722                         get_tok_num(parser);
723                         lay->default_size = parser->tint;
724                 } else if (is_keyword(parser, TOK_ROW))
725                         parse_row(parser, lay);
726                 else if (is_end(parser))
727                         return;
728                 else
729                         error_end(parser);
730         }
731 }
732
733 static void parse_kbd(struct parser *parser, struct global *glob, int type)
734 {
735         struct kbd *kbd = e_malloc(sizeof(struct kbd));
736
737         if (!glob->kbds)
738                 glob->kbds = kbd;
739         else {
740                 struct kbd *last = glob->kbds;
741                 while (last->next)
742                         last = last->next;
743                 last->next = kbd;
744         }
745         glob->kbds_cnt++;
746         kbd->type = type;
747         get_tok_begin(parser);
748         while (1) {
749                 get_tok(parser);
750                 if (is_keyword(parser, TOK_LOWERCASE))
751                         parse_layout(parser, kbd, LAY_LOWERCASE);
752                 else if (is_keyword(parser, TOK_UPPERCASE))
753                         parse_layout(parser, kbd, LAY_UPPERCASE);
754                 else if (is_keyword(parser, TOK_SPEC_LOWERCASE)) {
755                         if (type != KBD_SPECIAL)
756                                 error(parser, "special_lowercase allowed only in kbd_special section");
757                         parse_layout(parser, kbd, LAY_SPECIAL_LOWER);
758                 } else if (is_keyword(parser, TOK_SPEC_UPPERCASE)) {
759                         if (type != KBD_SPECIAL)
760                                 error(parser, "special_uppercase allowed only in kbd_special section");
761                         parse_layout(parser, kbd, LAY_SPECIAL_UPPER);
762                 } else if (is_keyword(parser, TOK_LOWERCASE_NUM)) {
763                         if (type != KBD_NORMAL)
764                                 error(parser, "lowercase_num allowed only in kbd_normal section");
765                         parse_layout(parser, kbd, LAY_LOWERCASE_NUM);
766                 } else if (is_keyword(parser, TOK_UPPERCASE_NUM)) {
767                         if (type != KBD_NORMAL)
768                                 error(parser, "uppercase_num allowed only in kbd_normal section");
769                         parse_layout(parser, kbd, LAY_UPPERCASE_NUM);
770                 } else if (is_keyword(parser, TOK_SPECIAL)) {
771                         if (type != KBD_THUMB && type != KBD_SPECIAL)
772                                 error(parser, "special allowed only in kbd_thumb and kbd_special sections");
773                         parse_layout(parser, kbd, LAY_SPECIAL);
774                 } else if (is_end(parser)) {
775                         if (!kbd->layouts_cnt)
776                                 error(parser, "no keyboard layouts defined");
777                         return;
778                 } else
779                         error_end(parser);
780         }
781 }
782
783 static void parse_global(struct parser *parser)
784 {
785         struct global *glob = parser->global;
786
787         while (1) {
788                 get_tok(parser);
789                 if (is_keyword(parser, TOK_HEADER))
790                         parse_header(parser, glob);
791                 else if (is_keyword(parser, TOK_KBD_NORMAL))
792                         parse_kbd(parser, glob, KBD_NORMAL);
793                 else if (is_keyword(parser, TOK_KBD_THUMB))
794                         parse_kbd(parser, glob, KBD_THUMB);
795                 else if (is_keyword(parser, TOK_KBD_SPECIAL))
796                         parse_kbd(parser, glob, KBD_SPECIAL);
797                 else if (is_eof(parser)) {
798                         if (!glob->kbds_cnt)
799                                 error(parser, "no keyboards defined");
800                         return;
801                 } else
802                         error(parser, "header, kbd_normal, kbd_thumb or kbd_special expected");
803         }
804 }
805
806 /*** writer ***/
807
808 struct writer {
809         struct global *global;
810         int start_table;
811         int *starts;
812 };
813
814 static void werror(struct writer *writer)
815 {
816         (void)writer;
817         longjmp(cjmp, 1);
818 }
819
820 static void init_writer(struct writer *writer, struct global *global)
821 {
822         writer->global = global;
823         writer->starts = e_malloc(sizeof(int) * global->kbds_cnt);
824 }
825
826 static void close_writer(struct writer *writer)
827 {
828         if (!writer)
829                 return;
830         free(writer->starts);
831 }
832
833 static void writer_byte(struct writer *writer, unsigned char b)
834 {
835         if (cops->write(cpriv, &b, 1))
836                 werror(writer);
837 }
838
839 static void writer_word(struct writer *writer, unsigned int w)
840 {
841         unsigned char a[2];
842
843         a[0] = w & 0xff;
844         a[1] = (w >> 8) & 0xff;
845         if (cops->write(cpriv, a, 2))
846                 werror(writer);
847 }
848
849 static void writer_string(struct writer *writer, char *s)
850 {
851         int len;
852
853         if (!s)
854                 len = 0;
855         else
856                 len = strlen(s);
857         writer_byte(writer, len);
858         if (len) {
859                 if (cops->write(cpriv, s, len))
860                         werror(writer);
861         }
862 }
863
864 static void writer_sizes(struct writer *writer, struct size *sizes)
865 {
866         int i;
867
868         while (sizes) {
869                 for (i = 0; i < 5; i++)
870                         writer_byte(writer, sizes->dim[i]);
871                 sizes = sizes->next;
872         }
873 }
874
875 static void writer_keys(struct writer *writer, struct key *key, int default_size)
876 {
877         struct slide_key *skey;
878
879         while (key) {
880                 writer_byte(writer, key->slides_cnt ? 1 : 0);
881                 writer_byte(writer, key->flags & 0xff);
882                 if (key->flags & KEY_EXTEND)
883                         writer_byte(writer, (key->flags >> 8) & 0xff);
884                 if (!key->slides_cnt)
885                         writer_string(writer, key->u.name);
886                 else {
887                         writer_byte(writer, key->slides_cnt | 0x80);
888                         skey = key->u.slides;
889                         while (skey) {
890                                 writer_string(writer, skey->name);
891                                 skey = skey->next;
892                         }
893                 }
894                 writer_byte(writer, key->size >= 0 ? key->size : default_size);
895                 key = key->next;
896         }
897 }
898
899 static void writer_sublayout(struct writer *writer, struct layout *lay)
900 {
901         int cnt;
902         struct row *tmp;
903
904         cnt = 0;
905         for (tmp = lay->rows; tmp; tmp = tmp->next)
906                 cnt += tmp->keys_cnt;
907         writer_byte(writer, cnt);
908         writer_byte(writer, lay->rows_cnt);
909         writer_byte(writer, lay->margins[3]);
910         writer_byte(writer, lay->margins[0]);
911         writer_byte(writer, lay->margins[2]);
912         writer_byte(writer, lay->margins[1]);
913         for (tmp = lay->rows; tmp; tmp = tmp->next)
914                 writer_byte(writer, tmp->keys_cnt);
915         for (tmp = lay->rows; tmp; tmp = tmp->next)
916                 writer_keys(writer, tmp->keys, lay->default_size);
917 }
918
919 static void writer_layouts(struct writer *writer, struct layout *lay, int idx)
920 {
921         int type, other;
922
923         switch (lay->type) {
924         case LAY_LOWERCASE:
925                 type = 0;
926                 break;
927         case LAY_UPPERCASE:
928                 type = 1;
929                 break;
930         default:
931                 type = 2;
932                 break;
933         }
934         switch (lay->type) {
935         case LAY_LOWERCASE:
936         case LAY_SPECIAL_LOWER:
937                 other = idx + 1;
938                 break;
939         case LAY_UPPERCASE:
940         case LAY_SPECIAL_UPPER:
941                 other = idx - 1;
942                 break;
943         default:
944                 other = 0xff;
945                 break;
946         }
947         writer_byte(writer, type);
948         writer_byte(writer, other);
949         writer_string(writer, lay->name);
950         writer_byte(writer, lay->sublayout ? 2 : 1);
951         writer_sublayout(writer, lay);
952         if (lay->sublayout)
953                 writer_sublayout(writer, lay->sublayout);
954 }
955
956 static void writer_kbd(struct writer *writer, struct kbd *kbd)
957 {
958         struct layout *lay;
959         int i;
960
961         writer_byte(writer, kbd->type);
962         writer_byte(writer, kbd->layouts_cnt);
963         writer_byte(writer, 0);
964         writer_byte(writer, kbd->layouts->default_size);        /* use the default size of the first layout */
965         for (lay = kbd->layouts, i = 0; lay; lay = lay->next, i++)
966                 writer_layouts(writer, lay, i);
967 }
968
969 static void writer_global(struct writer *writer)
970 {
971         struct global *glob = writer->global;
972         struct kbd *kbd;
973         int i;
974
975         writer_byte(writer, 1);         /* version */
976         writer_byte(writer, glob->kbds_cnt);
977         writer_string(writer, glob->name);
978         writer_string(writer, glob->lang);
979         writer_string(writer, glob->wc);
980         writer_byte(writer, 2);         /* always use the default screen modes */
981         writer_byte(writer, 0);
982         writer_byte(writer, 1);
983         writer_byte(writer, glob->sizes_cnt);
984         writer_sizes(writer, glob->sizes);
985         writer->start_table = cops->tell(cpriv);
986         for (i = 0; i < glob->kbds_cnt; i++)
987                 writer_word(writer, 0);
988         for (i = 0; i < 20; i++)
989                 writer_byte(writer, 0);
990         for (kbd = glob->kbds, i = 0; kbd; kbd = kbd->next, i++) {
991                 writer->starts[i] = cops->tell(cpriv);
992                 writer_kbd(writer, kbd);
993         }
994         cops->seek(cpriv, writer->start_table);
995         for (i = 0; i < glob->kbds_cnt; i++)
996                 writer_word(writer, writer->starts[i]);
997 }
998
999 /*** main ***/
1000
1001 int compile(struct compiler_ops *ops, void *priv)
1002 {
1003         struct parser *parser = NULL;
1004         struct writer *writer = NULL;
1005         int res;
1006
1007         cops = ops;
1008         cpriv = priv;
1009
1010         res = setjmp(cjmp);
1011         if (!res) {
1012                 parser = e_malloc(sizeof(struct parser));
1013                 writer = e_malloc(sizeof(struct writer));
1014                 init_parser(parser);
1015                 parse_global(parser);
1016                 init_writer(writer, parser->global);
1017                 writer_global(writer);
1018                 if (cops->return_lang)
1019                         cops->return_lang(cpriv, parser->global->lang);
1020         }
1021         close_writer(writer);
1022         close_parser(parser);
1023         free(writer);
1024         free(parser);
1025         return res ? -1 : 0;
1026 }