Added 4th row to Vietnamese on-screen keyboard as it was in older
[ukeyboard.git] / vkb_compiler_lib.c
blob2943764186224791e909bc978d189fbe04a2827f
1 /*
2 * Copyright (c) 2007-2008 Jiri Benc <jbenc@upir.cz>
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.
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.
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
18 #include <stdlib.h>
19 #include <string.h>
20 #include <setjmp.h>
21 #include "vkb_compiler.h"
23 static struct compiler_ops *cops;
24 static void *cpriv;
25 static jmp_buf cjmp;
27 #define BUF_SIZE 8192
29 /*** tokenizer ***/
31 struct tokenizer {
32 int line;
33 char *buf, *pos;
34 char *pushed;
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", "backspace", "shift", "alpha", "num", "hexa", "tele", "dead"
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_BACKSPACE, TOK_SHIFT, TOK_ALPHA, TOK_NUM, TOK_HEXA, TOK_TELE, TOK_DEAD
54 enum tok_type {
55 TT_KEYWORD, TT_NUM, TT_STRING, TT_BEGIN, TT_END, TT_EOF
58 static void tok_error(struct tokenizer *tokenizer, char *msg)
60 cops->error(cpriv, tokenizer->line, msg);
61 longjmp(cjmp, 1);
64 static void tok_warning(struct tokenizer *tokenizer, char *msg)
66 if (cops->warning(cpriv, tokenizer->line, msg))
67 longjmp(cjmp, 1);
70 static void *e_malloc(size_t size)
72 void *p = calloc(1, size);
73 if (!p) {
74 cops->error(cpriv, -1, "Out of memory");
75 longjmp(cjmp, 1);
77 return p;
80 static void set_str(char **str, char *val)
82 if (*str)
83 free(*str);
84 if (!val) {
85 *str = NULL;
86 return;
88 *str = e_malloc(strlen(val) + 1);
89 strcpy(*str, val);
92 static char *ltrim(char *buf)
94 while (buf && (*buf == ' ' || *buf == '\t' || *buf == '\n' || *buf == '\r'))
95 buf++;
96 return buf;
99 static char *find_white(char *buf)
101 while (buf && *buf && *buf != ' ' && *buf != '\t' && *buf != '\n' && *buf != '\r')
102 buf++;
103 return buf;
106 static int read_raw(struct tokenizer *tokenizer, char *dest, size_t size, int no_ltrim)
108 char *s;
109 char tmp;
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;
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';
129 *s = tmp;
130 tokenizer->pos = s;
131 return 0;
134 static void finish_read_string(struct tokenizer *tokenizer, char *dest, size_t size)
136 char *s = dest + 1;
137 char *new = dest;
138 int special = 0;
140 while (1) {
141 while (*s) {
142 if (special) {
143 *new++ = *s++;
144 special = 0;
145 continue;
147 if (*s == '\\') {
148 special = 1;
149 s++;
150 continue;
152 if (*s == '"') {
153 *new = '\0';
154 if (s[1] != '\0')
155 tok_warning(tokenizer, "Ignored extra characters after the string");
156 return;
158 *new++ = *s++;
160 if (read_raw(tokenizer, s, size - (s - dest), 1) < 0)
161 tok_error(tokenizer, "Unterminated (or too long) string");
165 static void skip_comment(struct tokenizer *tokenizer)
167 while (*tokenizer->pos)
168 tokenizer->pos++;
171 static int find_keyword(char *s)
173 int i;
174 int max = (sizeof(keywords) / sizeof(*keywords));
176 for (i = 0; i < max; i++) {
177 if (!strcmp(s, keywords[i]))
178 return i;
180 return -1;
183 static void unread_tok(struct tokenizer *tokenizer, char *tok)
185 strncpy(tokenizer->pushed, tok, BUF_SIZE - 1);
186 tokenizer->pushed[BUF_SIZE - 1] = '\0';
189 static enum tok_type read_tok(struct tokenizer *tokenizer, char *dest, size_t size, int *parsed_int)
191 int res;
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;
203 if (dest[0] == '#')
204 skip_comment(tokenizer);
205 else
206 break;
208 if ((dest[0] >= '0' && dest[0] <= '9') || dest[0] == '-') {
209 *parsed_int = atoi(dest);
210 return TT_NUM;
212 if (dest[0] == '"') {
213 finish_read_string(tokenizer, dest, size);
214 return TT_STRING;
216 if (dest[0] == '{') {
217 if (dest[1] != '\0')
218 tok_error(tokenizer, "Whitespace required after {");
219 return TT_BEGIN;
221 if (dest[0] == '}') {
222 if (dest[1] != '\0')
223 tok_error(tokenizer, "Whitespace required after }");
224 return TT_END;
226 res = find_keyword(dest);
227 if (res < 0)
228 tok_error(tokenizer, "Uknown keyword");
229 *parsed_int = res;
230 return TT_KEYWORD;
233 static void init_tokenizer(struct tokenizer *tokenizer)
235 tokenizer->pos = tokenizer->buf = e_malloc(BUF_SIZE);
236 tokenizer->pushed = e_malloc(BUF_SIZE);
239 static void close_tokenizer(struct tokenizer *tokenizer)
241 if (!tokenizer)
242 return;
243 free(tokenizer->buf);
244 free(tokenizer->pushed);
247 /*** parser structures ***/
249 struct slide_key {
250 char *name;
251 struct slide_key *next;
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;
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
274 #define KEY_TAB (0x0400 | KEY_EXTEND)
275 #define KEY_BACKSPACE (0x0800 | KEY_EXTEND)
276 #define KEY_SHIFT (0x1000 | KEY_EXTEND)
278 struct row {
279 int keys_cnt;
280 struct key *keys;
281 struct row *next;
284 struct layout {
285 int type;
286 char *name;
287 int margins[4];
288 int default_size;
289 int rows_cnt;
290 struct row *rows;
291 struct layout *sublayout;
292 struct layout *next;
295 #define LAY_LOWERCASE 0
296 #define LAY_UPPERCASE 1
297 #define LAY_LOWERCASE_NUM 2
298 #define LAY_UPPERCASE_NUM 3
299 #define LAY_SPECIAL 4
300 #define LAY_SPECIAL_LOWER 5
301 #define LAY_SPECIAL_UPPER 6
303 struct kbd {
304 int type;
305 int layouts_cnt;
306 struct layout *layouts;
307 struct kbd *next;
310 struct size {
311 int dim[5];
312 struct size *next;
315 #define KBD_NORMAL 0
316 #define KBD_THUMB 4
317 #define KBD_SPECIAL 1
319 struct global {
320 char *name;
321 char *lang;
322 char *wc;
323 int sizes_cnt;
324 struct size *sizes;
325 int kbds_cnt;
326 struct kbd *kbds;
329 static struct global *new_global(void)
331 return e_malloc(sizeof(struct global));
334 static void free_sizes(struct size *size)
336 struct size *next;
338 while (size) {
339 next = size->next;
340 free(size);
341 size = next;
345 static void free_slides(struct slide_key *sl)
347 struct slide_key *next;
349 while (sl) {
350 next = sl->next;
351 free(sl->name);
352 free(sl);
353 sl = next;
357 static void free_keys(struct key *key)
359 struct key *next;
361 while (key) {
362 next = key->next;
363 if (key->slides_cnt)
364 free_slides(key->u.slides);
365 else
366 free(key->u.name);
367 free(key);
368 key = next;
372 static void free_rows(struct row *row)
374 struct row *next;
376 while (row) {
377 next = row->next;
378 free_keys(row->keys);
379 free(row);
380 row = next;
384 static void free_layouts(struct layout *lay)
386 struct layout *next;
388 while (lay) {
389 next = lay->next;
390 free_rows(lay->rows);
391 free_layouts(lay->sublayout);
392 free(lay->name);
393 free(lay);
394 lay = next;
398 static void free_kbds(struct kbd *kbd)
400 struct kbd *next;
402 while (kbd) {
403 next = kbd->next;
404 free_layouts(kbd->layouts);
405 free(kbd);
406 kbd = next;
410 static void free_global(struct global *glob)
412 if (!glob)
413 return;
414 free_sizes(glob->sizes);
415 free_kbds(glob->kbds);
416 free(glob->name);
417 free(glob->lang);
418 free(glob->wc);
419 free(glob);
422 /*** parser ***/
424 struct parser {
425 struct tokenizer *tokenizer;
426 struct global *global;
427 int ttype;
428 char *tstr;
429 int tint;
432 static void init_parser(struct parser *parser)
434 parser->tokenizer = e_malloc(sizeof(struct tokenizer));
435 init_tokenizer(parser->tokenizer);
436 parser->tstr = e_malloc(BUF_SIZE);
437 parser->global = new_global();
440 static void close_parser(struct parser *parser)
442 if (!parser)
443 return;
444 free_global(parser->global);
445 free(parser->tstr);
446 close_tokenizer(parser->tokenizer);
447 free(parser->tokenizer);
450 #define error(parser, msg) tok_error((parser)->tokenizer, msg)
451 #define warning(parser, msg) tok_warning((parser)->tokenizer, msg)
452 #define error_end(parser) error(parser, "} expected")
454 static void get_tok(struct parser *parser)
456 parser->ttype = read_tok(parser->tokenizer, parser->tstr, BUF_SIZE, &parser->tint);
459 static void __get_raw(struct parser *parser)
461 if (read_raw(parser->tokenizer, parser->tstr, BUF_SIZE, 0) < 0)
462 error(parser, "Unexpected end of file");
465 static void push_tok(struct parser *parser)
467 unread_tok(parser->tokenizer, parser->tstr);
470 #define is_type(parser, t) ((parser)->ttype == (t))
471 #define is_keyword(parser, w) ((parser)->ttype == TT_KEYWORD && (parser)->tint == (w))
472 #define is_begin(parser) ((parser)->ttype == TT_BEGIN)
473 #define is_end(parser) ((parser)->ttype == TT_END)
474 #define is_eof(parser) ((parser)->ttype == TT_EOF)
476 static void get_tok_type(struct parser *parser, int tt)
478 get_tok(parser);
479 if (!is_type(parser, tt)) {
480 switch (tt) {
481 case TT_NUM: error(parser, "Number expected");
482 case TT_STRING: error(parser, "String expected");
483 case TT_BEGIN: error(parser, "{ expected");
484 case TT_END: error(parser, "} expected");
485 default: error(parser, "Syntax error");
490 #define get_tok_num(parser) get_tok_type(parser, TT_NUM)
491 #define get_tok_string(parser) get_tok_type(parser, TT_STRING)
492 #define get_tok_begin(parser) get_tok_type(parser, TT_BEGIN)
493 #define get_tok_end(parser) get_tok_type(parser, TT_END)
495 static void parse_sizes(struct parser *parser, struct global *glob)
497 struct size *size;
499 get_tok_num(parser);
500 if (parser->tint != glob->sizes_cnt)
501 error(parser, "size number out of order");
502 size = e_malloc(sizeof(struct size));
503 glob->sizes_cnt++;
504 if (!glob->sizes)
505 glob->sizes = size;
506 else {
507 struct size *last = glob->sizes;
508 while (last->next)
509 last = last->next;
510 last->next = size;
512 get_tok_begin(parser);
513 while (1) {
514 get_tok(parser);
515 if (is_keyword(parser, TOK_WIDTH)) {
516 get_tok_num(parser);
517 size->dim[0] = parser->tint;
518 } else if (is_keyword(parser, TOK_HEIGHT)) {
519 get_tok_num(parser);
520 size->dim[1] = parser->tint;
521 } else if (is_keyword(parser, TOK_TEXTPOS)) {
522 get_tok_num(parser);
523 size->dim[2] = parser->tint;
524 } else if (is_keyword(parser, TOK_LEFT)) {
525 get_tok_num(parser);
526 size->dim[3] = parser->tint;
527 } else if (is_keyword(parser, TOK_TOP)) {
528 get_tok_num(parser);
529 size->dim[4] = parser->tint;
530 } else if (is_end(parser)) {
531 return;
532 } else
533 error_end(parser);
537 static void parse_header(struct parser *parser, struct global *glob)
539 get_tok_begin(parser);
540 while (1) {
541 get_tok(parser);
542 if (is_keyword(parser, TOK_NAME)) {
543 get_tok_string(parser);
544 set_str(&glob->name, parser->tstr);
545 } else if (is_keyword(parser, TOK_LANG)) {
546 get_tok_string(parser);
547 set_str(&glob->lang, parser->tstr);
548 } else if (is_keyword(parser, TOK_WC)) {
549 get_tok_string(parser);
550 set_str(&glob->wc, parser->tstr);
551 } else if (is_keyword(parser, TOK_SIZE)) {
552 parse_sizes(parser, glob);
553 } else if (is_end(parser)) {
554 return;
555 } else
556 error_end(parser);
560 static void parse_slide(struct parser *parser, struct key *key)
562 while (1) {
563 get_tok(parser);
564 if (is_keyword(parser, TOK_KEY)) {
565 struct slide_key *skey = e_malloc(sizeof(struct slide_key));
567 key->slides_cnt++;
568 if (!key->u.slides)
569 key->u.slides = skey;
570 else {
571 struct slide_key *last = key->u.slides;
572 while (last->next)
573 last = last->next;
574 last->next = skey;
576 __get_raw(parser);
577 set_str(&skey->name, parser->tstr);
578 } else if (is_end(parser))
579 return;
580 else
581 error_end(parser);
585 static void parse_key(struct parser *parser, struct row *row, int type)
587 struct key *key = e_malloc(sizeof(struct key));
589 key->size = -1;
590 row->keys_cnt++;
591 if (!row->keys)
592 row->keys = key;
593 else {
594 struct key *last = row->keys;
595 while (last->next)
596 last = last->next;
597 last->next = key;
599 if (type == TOK_KEY) {
600 __get_raw(parser);
601 set_str(&key->u.name, parser->tstr);
602 } else if (type == TOK_WHITE) {
603 set_str(&key->u.name, "");
604 key->flags |= KEY_WHITE;
605 } else if (type == TOK_TAB) {
606 set_str(&key->u.name, "");
607 key->flags |= KEY_TAB;
608 } else if (type == TOK_BACKSPACE) {
609 set_str(&key->u.name, "");
610 key->flags |= KEY_BACKSPACE;
611 } else if (type == TOK_SHIFT) {
612 set_str(&key->u.name, "");
613 key->flags |= KEY_SHIFT;
615 while (1) {
616 get_tok(parser);
617 if (is_keyword(parser, TOK_ALPHA))
618 key->flags |= KEY_ALPHA;
619 else if (is_keyword(parser, TOK_NUM))
620 key->flags |= KEY_NUM;
621 else if (is_keyword(parser, TOK_HEXA))
622 key->flags |= KEY_HEXA;
623 else if (is_keyword(parser, TOK_TELE))
624 key->flags |= KEY_TELE;
625 else if (is_keyword(parser, TOK_SPECIAL))
626 key->flags |= KEY_SPECIAL;
627 else if (is_keyword(parser, TOK_DEAD))
628 key->flags |= KEY_DEAD;
629 else if (is_keyword(parser, TOK_SIZE)) {
630 get_tok_num(parser);
631 key->size = parser->tint;
632 } else if (is_begin(parser) && type == TOK_SLIDE)
633 parse_slide(parser, key);
634 else if (is_keyword(parser, TOK_KEY) ||
635 is_keyword(parser, TOK_WHITE) ||
636 is_keyword(parser, TOK_TAB) ||
637 is_keyword(parser, TOK_BACKSPACE) ||
638 is_keyword(parser, TOK_SHIFT) ||
639 is_keyword(parser, TOK_SLIDE) ||
640 is_end(parser)) {
641 push_tok(parser);
642 if (type == TOK_SLIDE && !key->slides_cnt)
643 error(parser, "{ expected");
644 return;
645 } else
646 error_end(parser);
650 static void parse_row(struct parser *parser, struct layout *lay)
652 struct row *row = e_malloc(sizeof(struct row));
654 lay->rows_cnt++;
655 if (!lay->rows)
656 lay->rows = row;
657 else {
658 struct row *last = lay->rows;
659 while (last->next)
660 last = last->next;
661 last->next = row;
663 get_tok_begin(parser);
664 while (1) {
665 get_tok(parser);
666 if (is_keyword(parser, TOK_KEY))
667 parse_key(parser, row, TOK_KEY);
668 else if (is_keyword(parser, TOK_WHITE))
669 parse_key(parser, row, TOK_WHITE);
670 else if (is_keyword(parser, TOK_TAB))
671 parse_key(parser, row, TOK_TAB);
672 else if (is_keyword(parser, TOK_BACKSPACE))
673 parse_key(parser, row, TOK_BACKSPACE);
674 else if (is_keyword(parser, TOK_SHIFT))
675 parse_key(parser, row, TOK_SHIFT);
676 else if (is_keyword(parser, TOK_SLIDE))
677 parse_key(parser, row, TOK_SLIDE);
678 else if (is_end(parser))
679 return;
680 else
681 error_end(parser);
685 static void parse_layout(struct parser *parser, struct kbd *kbd, int type)
687 struct layout *lay = e_malloc(sizeof(struct layout));
689 if (type == LAY_LOWERCASE_NUM || type == LAY_UPPERCASE_NUM) {
690 /* numeric layout is a sublayout of a normal layout */
691 struct layout *find = kbd->layouts;
692 while (find) {
693 if (find->type == type - 2) {
694 find->sublayout = lay;
695 break;
697 find = find->next;
699 if (!find) {
700 free(lay);
701 error(parser, "lowercase_num/uppercase_num has to follow lowercase/uppercase definition");
703 } else {
704 struct layout *last = kbd->layouts;
706 if (!last)
707 kbd->layouts = lay;
708 else {
709 while (last->next)
710 last = last->next;
711 last->next = lay;
713 kbd->layouts_cnt++;
714 if ((type == LAY_UPPERCASE && (!last || last->type != LAY_LOWERCASE)) ||
715 (type == LAY_SPECIAL_UPPER && (!last || last->type != LAY_SPECIAL_LOWER)))
716 error(parser, "uppercase has to follow lowercase definition");
717 if (type == LAY_SPECIAL_UPPER && last->name)
718 set_str(&lay->name, last->name);
720 lay->type = type;
721 get_tok_begin(parser);
722 while (1) {
723 get_tok(parser);
724 if (is_keyword(parser, TOK_NAME)) {
725 get_tok_string(parser);
726 if (lay->name)
727 error(parser, "name must not be specified for uppercase layout in kbd_special section");
728 set_str(&lay->name, parser->tstr);
729 } else if (is_keyword(parser, TOK_MARGIN)) {
730 int i;
731 for (i = 0; i < 4; i++) {
732 get_tok_num(parser);
733 lay->margins[i] = parser->tint;
735 } else if (is_keyword(parser, TOK_DEFAULT_SIZE)) {
736 get_tok_num(parser);
737 lay->default_size = parser->tint;
738 } else if (is_keyword(parser, TOK_ROW))
739 parse_row(parser, lay);
740 else if (is_end(parser))
741 return;
742 else
743 error_end(parser);
747 static void parse_kbd(struct parser *parser, struct global *glob, int type)
749 struct kbd *kbd = e_malloc(sizeof(struct kbd));
751 if (!glob->kbds)
752 glob->kbds = kbd;
753 else {
754 struct kbd *last = glob->kbds;
755 while (last->next)
756 last = last->next;
757 last->next = kbd;
759 glob->kbds_cnt++;
760 kbd->type = type;
761 get_tok_begin(parser);
762 while (1) {
763 get_tok(parser);
764 if (is_keyword(parser, TOK_LOWERCASE))
765 parse_layout(parser, kbd, LAY_LOWERCASE);
766 else if (is_keyword(parser, TOK_UPPERCASE))
767 parse_layout(parser, kbd, LAY_UPPERCASE);
768 else if (is_keyword(parser, TOK_SPEC_LOWERCASE)) {
769 if (type != KBD_SPECIAL)
770 error(parser, "special_lowercase allowed only in kbd_special section");
771 parse_layout(parser, kbd, LAY_SPECIAL_LOWER);
772 } else if (is_keyword(parser, TOK_SPEC_UPPERCASE)) {
773 if (type != KBD_SPECIAL)
774 error(parser, "special_uppercase allowed only in kbd_special section");
775 parse_layout(parser, kbd, LAY_SPECIAL_UPPER);
776 } else if (is_keyword(parser, TOK_LOWERCASE_NUM)) {
777 if (type != KBD_NORMAL)
778 error(parser, "lowercase_num allowed only in kbd_normal section");
779 parse_layout(parser, kbd, LAY_LOWERCASE_NUM);
780 } else if (is_keyword(parser, TOK_UPPERCASE_NUM)) {
781 if (type != KBD_NORMAL)
782 error(parser, "uppercase_num allowed only in kbd_normal section");
783 parse_layout(parser, kbd, LAY_UPPERCASE_NUM);
784 } else if (is_keyword(parser, TOK_SPECIAL)) {
785 if (type != KBD_THUMB && type != KBD_SPECIAL)
786 error(parser, "special allowed only in kbd_thumb and kbd_special sections");
787 parse_layout(parser, kbd, LAY_SPECIAL);
788 } else if (is_end(parser)) {
789 if (!kbd->layouts_cnt)
790 error(parser, "no keyboard layouts defined");
791 return;
792 } else
793 error_end(parser);
797 static void parse_global(struct parser *parser)
799 struct global *glob = parser->global;
801 while (1) {
802 get_tok(parser);
803 if (is_keyword(parser, TOK_HEADER))
804 parse_header(parser, glob);
805 else if (is_keyword(parser, TOK_KBD_NORMAL))
806 parse_kbd(parser, glob, KBD_NORMAL);
807 else if (is_keyword(parser, TOK_KBD_THUMB))
808 parse_kbd(parser, glob, KBD_THUMB);
809 else if (is_keyword(parser, TOK_KBD_SPECIAL))
810 parse_kbd(parser, glob, KBD_SPECIAL);
811 else if (is_eof(parser)) {
812 if (!glob->kbds_cnt)
813 error(parser, "no keyboards defined");
814 return;
815 } else
816 error(parser, "header, kbd_normal, kbd_thumb or kbd_special expected");
820 /*** writer ***/
822 struct writer {
823 struct global *global;
824 int start_table;
825 int *starts;
828 static void werror(struct writer *writer)
830 (void)writer;
831 longjmp(cjmp, 1);
834 static void init_writer(struct writer *writer, struct global *global)
836 writer->global = global;
837 writer->starts = e_malloc(sizeof(int) * global->kbds_cnt);
840 static void close_writer(struct writer *writer)
842 if (!writer)
843 return;
844 free(writer->starts);
847 static void writer_byte(struct writer *writer, unsigned char b)
849 if (cops->write(cpriv, &b, 1))
850 werror(writer);
853 static void writer_word(struct writer *writer, unsigned int w)
855 unsigned char a[2];
857 a[0] = w & 0xff;
858 a[1] = (w >> 8) & 0xff;
859 if (cops->write(cpriv, a, 2))
860 werror(writer);
863 static void writer_string(struct writer *writer, char *s)
865 int len;
867 if (!s)
868 len = 0;
869 else
870 len = strlen(s);
871 writer_byte(writer, len);
872 if (len) {
873 if (cops->write(cpriv, s, len))
874 werror(writer);
878 static void writer_sizes(struct writer *writer, struct size *sizes)
880 int i;
882 while (sizes) {
883 for (i = 0; i < 5; i++)
884 writer_byte(writer, sizes->dim[i]);
885 sizes = sizes->next;
889 static void writer_keys(struct writer *writer, struct key *key, int default_size)
891 struct slide_key *skey;
893 while (key) {
894 writer_byte(writer, key->slides_cnt ? 1 : 0);
895 writer_byte(writer, key->flags & 0xff);
896 if (key->flags & KEY_EXTEND)
897 writer_byte(writer, (key->flags >> 8) & 0xff);
898 if (!key->slides_cnt)
899 writer_string(writer, key->u.name);
900 else {
901 writer_byte(writer, key->slides_cnt | 0x80);
902 skey = key->u.slides;
903 while (skey) {
904 writer_string(writer, skey->name);
905 skey = skey->next;
908 writer_byte(writer, key->size >= 0 ? key->size : default_size);
909 key = key->next;
913 static void writer_sublayout(struct writer *writer, struct layout *lay)
915 int cnt;
916 struct row *tmp;
918 cnt = 0;
919 for (tmp = lay->rows; tmp; tmp = tmp->next)
920 cnt += tmp->keys_cnt;
921 writer_byte(writer, cnt);
922 writer_byte(writer, lay->rows_cnt);
923 writer_byte(writer, lay->margins[3]);
924 writer_byte(writer, lay->margins[0]);
925 writer_byte(writer, lay->margins[2]);
926 writer_byte(writer, lay->margins[1]);
927 for (tmp = lay->rows; tmp; tmp = tmp->next)
928 writer_byte(writer, tmp->keys_cnt);
929 for (tmp = lay->rows; tmp; tmp = tmp->next)
930 writer_keys(writer, tmp->keys, lay->default_size);
933 static void writer_layouts(struct writer *writer, struct layout *lay, int idx)
935 int type, other;
937 switch (lay->type) {
938 case LAY_LOWERCASE:
939 type = 0;
940 break;
941 case LAY_UPPERCASE:
942 type = 1;
943 break;
944 default:
945 type = 2;
946 break;
948 switch (lay->type) {
949 case LAY_LOWERCASE:
950 case LAY_SPECIAL_LOWER:
951 other = idx + 1;
952 break;
953 case LAY_UPPERCASE:
954 case LAY_SPECIAL_UPPER:
955 other = idx - 1;
956 break;
957 default:
958 other = 0xff;
959 break;
961 writer_byte(writer, type);
962 writer_byte(writer, other);
963 writer_string(writer, lay->name);
964 writer_byte(writer, lay->sublayout ? 2 : 1);
965 writer_sublayout(writer, lay);
966 if (lay->sublayout)
967 writer_sublayout(writer, lay->sublayout);
970 static void writer_kbd(struct writer *writer, struct kbd *kbd)
972 struct layout *lay;
973 int i;
975 writer_byte(writer, kbd->type);
976 writer_byte(writer, kbd->layouts_cnt);
977 writer_byte(writer, 0);
978 writer_byte(writer, kbd->layouts->default_size); /* use the default size of the first layout */
979 for (lay = kbd->layouts, i = 0; lay; lay = lay->next, i++)
980 writer_layouts(writer, lay, i);
983 static void writer_global(struct writer *writer)
985 struct global *glob = writer->global;
986 struct kbd *kbd;
987 int i;
989 writer_byte(writer, 1); /* version */
990 writer_byte(writer, glob->kbds_cnt);
991 writer_string(writer, glob->name);
992 writer_string(writer, glob->lang);
993 writer_string(writer, glob->wc);
994 writer_byte(writer, 2); /* always use the default screen modes */
995 writer_byte(writer, 0);
996 writer_byte(writer, 1);
997 writer_byte(writer, glob->sizes_cnt);
998 writer_sizes(writer, glob->sizes);
999 writer->start_table = cops->tell(cpriv);
1000 for (i = 0; i < glob->kbds_cnt; i++)
1001 writer_word(writer, 0);
1002 for (i = 0; i < 20; i++)
1003 writer_byte(writer, 0);
1004 for (kbd = glob->kbds, i = 0; kbd; kbd = kbd->next, i++) {
1005 writer->starts[i] = cops->tell(cpriv);
1006 writer_kbd(writer, kbd);
1008 cops->seek(cpriv, writer->start_table);
1009 for (i = 0; i < glob->kbds_cnt; i++)
1010 writer_word(writer, writer->starts[i]);
1013 /*** main ***/
1015 int compile(struct compiler_ops *ops, void *priv)
1017 struct parser *parser = NULL;
1018 struct writer *writer = NULL;
1019 int res;
1021 cops = ops;
1022 cpriv = priv;
1024 res = setjmp(cjmp);
1025 if (!res) {
1026 parser = e_malloc(sizeof(struct parser));
1027 writer = e_malloc(sizeof(struct writer));
1028 init_parser(parser);
1029 parse_global(parser);
1030 init_writer(writer, parser->global);
1031 writer_global(writer);
1032 if (cops->return_lang)
1033 cops->return_lang(cpriv, parser->global->lang);
1035 close_writer(writer);
1036 close_parser(parser);
1037 free(writer);
1038 free(parser);
1039 return res ? -1 : 0;