Removed ukeyboard. Package splited to slovak-l10n and posix-locales-sksk
[slovak-l10n] / ukeyboard / vkb_compiler_lib.c
diff --git a/ukeyboard/vkb_compiler_lib.c b/ukeyboard/vkb_compiler_lib.c
deleted file mode 100644 (file)
index c072e50..0000000
+++ /dev/null
@@ -1,1026 +0,0 @@
-/*
- *  Copyright (c) 2007-2008 Jiri Benc <jbenc@upir.cz>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <setjmp.h>
-#include "vkb_compiler.h"
-
-static struct compiler_ops *cops;
-static void *cpriv;
-static jmp_buf cjmp;
-
-#define BUF_SIZE       8192
-
-/*** tokenizer ***/
-
-struct tokenizer {
-       int line;
-       char *buf, *pos;
-       char *pushed;
-};
-
-static char keywords[][32] = {
-       "header", "name", "lang", "wc", "size", "width", "height",
-       "textpos", "left", "top", "kbd_normal", "kbd_thumb", "kbd_special",
-       "lowercase", "lowercase_num", "uppercase", "uppercase_num",
-       "special_lowercase", "special_uppercase",
-       "special", "margin", "default_size", "row", "key", "slide",
-       "white", "tab", "alpha", "num", "hexa", "tele", "dead"
-};
-enum keywords_const {
-       TOK_HEADER, TOK_NAME, TOK_LANG, TOK_WC, TOK_SIZE, TOK_WIDTH, TOK_HEIGHT,
-       TOK_TEXTPOS, TOK_LEFT, TOK_TOP, TOK_KBD_NORMAL, TOK_KBD_THUMB, TOK_KBD_SPECIAL,
-       TOK_LOWERCASE, TOK_LOWERCASE_NUM, TOK_UPPERCASE, TOK_UPPERCASE_NUM,
-       TOK_SPEC_LOWERCASE, TOK_SPEC_UPPERCASE,
-       TOK_SPECIAL, TOK_MARGIN, TOK_DEFAULT_SIZE, TOK_ROW, TOK_KEY, TOK_SLIDE,
-       TOK_WHITE, TOK_TAB, TOK_ALPHA, TOK_NUM, TOK_HEXA, TOK_TELE, TOK_DEAD
-};
-
-enum tok_type {
-       TT_KEYWORD, TT_NUM, TT_STRING, TT_BEGIN, TT_END, TT_EOF
-};
-
-static void tok_error(struct tokenizer *tokenizer, char *msg)
-{
-       cops->error(cpriv, tokenizer->line, msg);
-       longjmp(cjmp, 1);
-}
-
-static void tok_warning(struct tokenizer *tokenizer, char *msg)
-{
-       if (cops->warning(cpriv, tokenizer->line, msg))
-               longjmp(cjmp, 1);
-}
-
-static void *e_malloc(size_t size)
-{
-       void *p = calloc(1, size);
-       if (!p) {
-               cops->error(cpriv, -1, "Out of memory");
-               longjmp(cjmp, 1);
-       }
-       return p;
-}
-
-static void set_str(char **str, char *val)
-{
-       if (*str)
-               free(*str);
-       if (!val) {
-               *str = NULL;
-               return;
-       }
-       *str = e_malloc(strlen(val) + 1);
-       strcpy(*str, val);
-}
-
-static char *ltrim(char *buf)
-{
-       while (buf && (*buf == ' ' || *buf == '\t' || *buf == '\n' || *buf == '\r'))
-               buf++;
-       return buf;
-}
-
-static char *find_white(char *buf)
-{
-       while (buf && *buf && *buf != ' ' && *buf != '\t' && *buf != '\n' && *buf != '\r')
-               buf++;
-       return buf;
-}
-
-static int read_raw(struct tokenizer *tokenizer, char *dest, size_t size, int no_ltrim)
-{
-       char *s;
-       char tmp;
-
-       while (1) {
-               if (!no_ltrim)
-                       tokenizer->pos = ltrim(tokenizer->pos);
-               if (!*tokenizer->pos) {
-                       tokenizer->line++;
-                       tokenizer->pos = tokenizer->buf;
-                       if (cops->get_line(cpriv, tokenizer->buf, BUF_SIZE))
-                               return -1;
-               } else
-                       break;
-       }
-       s = find_white(tokenizer->pos + 1);
-       tmp = *s;
-       *s = '\0';
-       if (size) {
-               strncpy(dest, tokenizer->pos, size - 1);
-               dest[size - 1] = '\0';
-       }
-       *s = tmp;
-       tokenizer->pos = s;
-       return 0;
-}
-
-static void finish_read_string(struct tokenizer *tokenizer, char *dest, size_t size)
-{
-       char *s = dest + 1;
-       char *new = dest;
-       int special = 0;
-
-       while (1) {
-               while (*s) {
-                       if (special) {
-                               *new++ = *s++;
-                               special = 0;
-                               continue;
-                       }
-                       if (*s == '\\') {
-                               special = 1;
-                               s++;
-                               continue;
-                       }
-                       if (*s == '"') {
-                               *new = '\0';
-                               if (s[1] != '\0')
-                                       tok_warning(tokenizer, "Ignored extra characters after the string");
-                               return;
-                       }
-                       *new++ = *s++;
-               }
-               if (read_raw(tokenizer, s, size - (s - dest), 1) < 0)
-                       tok_error(tokenizer, "Unterminated (or too long) string");
-       }
-}
-
-static void skip_comment(struct tokenizer *tokenizer)
-{
-       while (*tokenizer->pos)
-               tokenizer->pos++;
-}
-
-static int find_keyword(char *s)
-{
-       int i;
-       int max = (sizeof(keywords) / sizeof(*keywords));
-
-       for (i = 0; i < max; i++) {
-               if (!strcmp(s, keywords[i]))
-                       return i;
-       }
-       return -1;
-}
-
-static void unread_tok(struct tokenizer *tokenizer, char *tok)
-{
-       strncpy(tokenizer->pushed, tok, BUF_SIZE - 1);
-       tokenizer->pushed[BUF_SIZE - 1] = '\0';
-}
-
-static enum tok_type read_tok(struct tokenizer *tokenizer, char *dest, size_t size, int *parsed_int)
-{
-       int res;
-
-       while (1) {
-               if (*tokenizer->pushed) {
-                       strncpy(dest, tokenizer->pushed, size - 1);
-                       dest[size - 1] = '\0';
-                       *tokenizer->pushed = '\0';
-               } else {
-                       res = read_raw(tokenizer, dest, size, 0);
-                       if (res < 0)
-                               return TT_EOF;
-               }
-               if (dest[0] == '#')
-                       skip_comment(tokenizer);
-               else
-                       break;
-       }
-       if ((dest[0] >= '0' && dest[0] <= '9') || dest[0] == '-') {
-               *parsed_int = atoi(dest);
-               return TT_NUM;
-       }
-       if (dest[0] == '"') {
-               finish_read_string(tokenizer, dest, size);
-               return TT_STRING;
-       }
-       if (dest[0] == '{') {
-               if (dest[1] != '\0')
-                       tok_error(tokenizer, "Whitespace required after {");
-               return TT_BEGIN;
-       }
-       if (dest[0] == '}') {
-               if (dest[1] != '\0')
-                       tok_error(tokenizer, "Whitespace required after }");
-               return TT_END;
-       }
-       res = find_keyword(dest);
-       if (res < 0)
-               tok_error(tokenizer, "Uknown keyword");
-       *parsed_int = res;
-       return TT_KEYWORD;
-}
-
-static void init_tokenizer(struct tokenizer *tokenizer)
-{
-       tokenizer->pos = tokenizer->buf = e_malloc(BUF_SIZE);
-       tokenizer->pushed = e_malloc(BUF_SIZE);
-}
-
-static void close_tokenizer(struct tokenizer *tokenizer)
-{
-       if (!tokenizer)
-               return;
-       free(tokenizer->buf);
-       free(tokenizer->pushed);
-}
-
-/*** parser structures ***/
-
-struct slide_key {
-       char *name;
-       struct slide_key *next;
-};
-
-struct key {
-       int slides_cnt;
-       union {
-               char *name;
-               struct slide_key *slides;
-       } u;
-       int size;
-       int flags;
-       struct key *next;
-};
-
-#define KEY_ALPHA      0x01
-#define KEY_NUM                0x02
-#define KEY_HEXA       0x04
-#define KEY_TELE       0x08
-#define KEY_SPECIAL    0x10
-#define KEY_DEAD       0x20
-#define KEY_WHITE      0x40
-#define KEY_EXTEND     0x80
-
-#define KEY_TAB                (0x0400 | KEY_EXTEND)
-
-struct row {
-       int keys_cnt;
-       struct key *keys;
-       struct row *next;
-};
-
-struct layout {
-       int type;
-       char *name;
-       int margins[4];
-       int default_size;
-       int rows_cnt;
-       struct row *rows;
-       struct layout *sublayout;
-       struct layout *next;
-};
-
-#define LAY_LOWERCASE          0
-#define LAY_UPPERCASE          1
-#define LAY_LOWERCASE_NUM      2
-#define LAY_UPPERCASE_NUM      3
-#define LAY_SPECIAL            4
-#define LAY_SPECIAL_LOWER      5
-#define LAY_SPECIAL_UPPER      6
-
-struct kbd {
-       int type;
-       int layouts_cnt;
-       struct layout *layouts;
-       struct kbd *next;
-};
-
-struct size {
-       int dim[5];
-       struct size *next;
-};
-
-#define KBD_NORMAL             0
-#define KBD_THUMB              4
-#define KBD_SPECIAL            1
-
-struct global {
-       char *name;
-       char *lang;
-       char *wc;
-       int sizes_cnt;
-       struct size *sizes;
-       int kbds_cnt;
-       struct kbd *kbds;
-};
-
-static struct global *new_global(void)
-{
-       return e_malloc(sizeof(struct global));
-}
-
-static void free_sizes(struct size *size)
-{
-       struct size *next;
-
-       while (size) {
-               next = size->next;
-               free(size);
-               size = next;
-       }
-}
-
-static void free_slides(struct slide_key *sl)
-{
-       struct slide_key *next;
-
-       while (sl) {
-               next = sl->next;
-               free(sl->name);
-               free(sl);
-               sl = next;
-       }
-}
-
-static void free_keys(struct key *key)
-{
-       struct key *next;
-
-       while (key) {
-               next = key->next;
-               if (key->slides_cnt)
-                       free_slides(key->u.slides);
-               else
-                       free(key->u.name);
-               free(key);
-               key = next;
-       }
-}
-
-static void free_rows(struct row *row)
-{
-       struct row *next;
-
-       while (row) {
-               next = row->next;
-               free_keys(row->keys);
-               free(row);
-               row = next;
-       }
-}
-
-static void free_layouts(struct layout *lay)
-{
-       struct layout *next;
-
-       while (lay) {
-               next = lay->next;
-               free_rows(lay->rows);
-               free_layouts(lay->sublayout);
-               free(lay->name);
-               free(lay);
-               lay = next;
-       }
-}
-
-static void free_kbds(struct kbd *kbd)
-{
-       struct kbd *next;
-
-       while (kbd) {
-               next = kbd->next;
-               free_layouts(kbd->layouts);
-               free(kbd);
-               kbd = next;
-       }
-}
-
-static void free_global(struct global *glob)
-{
-       if (!glob)
-               return;
-       free_sizes(glob->sizes);
-       free_kbds(glob->kbds);
-       free(glob->name);
-       free(glob->lang);
-       free(glob->wc);
-       free(glob);
-}
-
-/*** parser ***/
-
-struct parser {
-       struct tokenizer *tokenizer;
-       struct global *global;
-       int ttype;
-       char *tstr;
-       int tint;
-};
-
-static void init_parser(struct parser *parser)
-{
-       parser->tokenizer = e_malloc(sizeof(struct tokenizer));
-       init_tokenizer(parser->tokenizer);
-       parser->tstr = e_malloc(BUF_SIZE);
-       parser->global = new_global();
-}
-
-static void close_parser(struct parser *parser)
-{
-       if (!parser)
-               return;
-       free_global(parser->global);
-       free(parser->tstr);
-       close_tokenizer(parser->tokenizer);
-       free(parser->tokenizer);
-}
-
-#define error(parser, msg)     tok_error((parser)->tokenizer, msg)
-#define warning(parser, msg)   tok_warning((parser)->tokenizer, msg)
-#define error_end(parser)      error(parser, "} expected")
-
-static void get_tok(struct parser *parser)
-{
-       parser->ttype = read_tok(parser->tokenizer, parser->tstr, BUF_SIZE, &parser->tint);
-}
-
-static void __get_raw(struct parser *parser)
-{
-       if (read_raw(parser->tokenizer, parser->tstr, BUF_SIZE, 0) < 0)
-               error(parser, "Unexpected end of file");
-}
-
-static void push_tok(struct parser *parser)
-{
-       unread_tok(parser->tokenizer, parser->tstr);
-}
-
-#define is_type(parser, t)     ((parser)->ttype == (t))
-#define is_keyword(parser, w)  ((parser)->ttype == TT_KEYWORD && (parser)->tint == (w))
-#define is_begin(parser)       ((parser)->ttype == TT_BEGIN)
-#define is_end(parser)         ((parser)->ttype == TT_END)
-#define is_eof(parser)         ((parser)->ttype == TT_EOF)
-
-static void get_tok_type(struct parser *parser, int tt)
-{
-       get_tok(parser);
-       if (!is_type(parser, tt)) {
-               switch (tt) {
-               case TT_NUM: error(parser, "Number expected");
-               case TT_STRING: error(parser, "String expected");
-               case TT_BEGIN: error(parser, "{ expected");
-               case TT_END: error(parser, "} expected");
-               default: error(parser, "Syntax error");
-               }
-       }
-}
-
-#define get_tok_num(parser)    get_tok_type(parser, TT_NUM)
-#define get_tok_string(parser) get_tok_type(parser, TT_STRING)
-#define get_tok_begin(parser)  get_tok_type(parser, TT_BEGIN)
-#define get_tok_end(parser)    get_tok_type(parser, TT_END)
-
-static void parse_sizes(struct parser *parser, struct global *glob)
-{
-       struct size *size;
-
-       get_tok_num(parser);
-       if (parser->tint != glob->sizes_cnt)
-               error(parser, "size number out of order");
-       size = e_malloc(sizeof(struct size));
-       glob->sizes_cnt++;
-       if (!glob->sizes)
-               glob->sizes = size;
-       else {
-               struct size *last = glob->sizes;
-               while (last->next)
-                       last = last->next;
-               last->next = size;
-       }
-       get_tok_begin(parser);
-       while (1) {
-               get_tok(parser);
-               if (is_keyword(parser, TOK_WIDTH)) {
-                       get_tok_num(parser);
-                       size->dim[0] = parser->tint;
-               } else if (is_keyword(parser, TOK_HEIGHT)) {
-                       get_tok_num(parser);
-                       size->dim[1] = parser->tint;
-               } else if (is_keyword(parser, TOK_TEXTPOS)) {
-                       get_tok_num(parser);
-                       size->dim[2] = parser->tint;
-               } else if (is_keyword(parser, TOK_LEFT)) {
-                       get_tok_num(parser);
-                       size->dim[3] = parser->tint;
-               } else if (is_keyword(parser, TOK_TOP)) {
-                       get_tok_num(parser);
-                       size->dim[4] = parser->tint;
-               } else if (is_end(parser)) {
-                       return;
-               } else
-                       error_end(parser);
-       }
-}
-
-static void parse_header(struct parser *parser, struct global *glob)
-{
-       get_tok_begin(parser);
-       while (1) {
-               get_tok(parser);
-               if (is_keyword(parser, TOK_NAME)) {
-                       get_tok_string(parser);
-                       set_str(&glob->name, parser->tstr);
-               } else if (is_keyword(parser, TOK_LANG)) {
-                       get_tok_string(parser);
-                       set_str(&glob->lang, parser->tstr);
-               } else if (is_keyword(parser, TOK_WC)) {
-                       get_tok_string(parser);
-                       set_str(&glob->wc, parser->tstr);
-               } else if (is_keyword(parser, TOK_SIZE)) {
-                       parse_sizes(parser, glob);
-               } else if (is_end(parser)) {
-                       return;
-               } else
-                       error_end(parser);
-       }
-}
-
-static void parse_slide(struct parser *parser, struct key *key)
-{
-       while (1) {
-               get_tok(parser);
-               if (is_keyword(parser, TOK_KEY)) {
-                       struct slide_key *skey = e_malloc(sizeof(struct slide_key));
-
-                       key->slides_cnt++;
-                       if (!key->u.slides)
-                               key->u.slides = skey;
-                       else {
-                               struct slide_key *last = key->u.slides;
-                               while (last->next)
-                                       last = last->next;
-                               last->next = skey;
-                       }
-                       __get_raw(parser);
-                       set_str(&skey->name, parser->tstr);
-               } else if (is_end(parser))
-                       return;
-               else
-                       error_end(parser);
-       }
-}
-
-static void parse_key(struct parser *parser, struct row *row, int type)
-{
-       struct key *key = e_malloc(sizeof(struct key));
-
-       key->size = -1;
-       row->keys_cnt++;
-       if (!row->keys)
-               row->keys = key;
-       else {
-               struct key *last = row->keys;
-               while (last->next)
-                       last = last->next;
-               last->next = key;
-       }
-       if (type == TOK_KEY) {
-               __get_raw(parser);
-               set_str(&key->u.name, parser->tstr);
-       } else if (type == TOK_WHITE) {
-               set_str(&key->u.name, "");
-               key->flags |= KEY_WHITE;
-       } else if (type == TOK_TAB) {
-               set_str(&key->u.name, "");
-               key->flags |= KEY_TAB;
-       }
-       while (1) {
-               get_tok(parser);
-               if (is_keyword(parser, TOK_ALPHA))
-                       key->flags |= KEY_ALPHA;
-               else if (is_keyword(parser, TOK_NUM))
-                       key->flags |= KEY_NUM;
-               else if (is_keyword(parser, TOK_HEXA))
-                       key->flags |= KEY_HEXA;
-               else if (is_keyword(parser, TOK_TELE))
-                       key->flags |= KEY_TELE;
-               else if (is_keyword(parser, TOK_SPECIAL))
-                       key->flags |= KEY_SPECIAL;
-               else if (is_keyword(parser, TOK_DEAD))
-                       key->flags |= KEY_DEAD;
-               else if (is_keyword(parser, TOK_SIZE)) {
-                       get_tok_num(parser);
-                       key->size = parser->tint;
-               } else if (is_begin(parser) && type == TOK_SLIDE)
-                       parse_slide(parser, key);
-               else if (is_keyword(parser, TOK_KEY) ||
-                          is_keyword(parser, TOK_WHITE) ||
-                          is_keyword(parser, TOK_TAB) ||
-                          is_keyword(parser, TOK_SLIDE) ||
-                          is_end(parser)) {
-                       push_tok(parser);
-                       if (type == TOK_SLIDE && !key->slides_cnt)
-                               error(parser, "{ expected");
-                       return;
-               } else
-                       error_end(parser);
-       }
-}
-
-static void parse_row(struct parser *parser, struct layout *lay)
-{
-       struct row *row = e_malloc(sizeof(struct row));
-
-       lay->rows_cnt++;
-       if (!lay->rows)
-               lay->rows = row;
-       else {
-               struct row *last = lay->rows;
-               while (last->next)
-                       last = last->next;
-               last->next = row;
-       }
-       get_tok_begin(parser);
-       while (1) {
-               get_tok(parser);
-               if (is_keyword(parser, TOK_KEY))
-                       parse_key(parser, row, TOK_KEY);
-               else if (is_keyword(parser, TOK_WHITE))
-                       parse_key(parser, row, TOK_WHITE);
-               else if (is_keyword(parser, TOK_TAB))
-                       parse_key(parser, row, TOK_TAB);
-               else if (is_keyword(parser, TOK_SLIDE))
-                       parse_key(parser, row, TOK_SLIDE);
-               else if (is_end(parser))
-                       return;
-               else
-                       error_end(parser);
-       }
-}
-
-static void parse_layout(struct parser *parser, struct kbd *kbd, int type)
-{
-       struct layout *lay = e_malloc(sizeof(struct layout));
-
-       if (type == LAY_LOWERCASE_NUM || type == LAY_UPPERCASE_NUM) {
-               /* numeric layout is a sublayout of a normal layout */
-               struct layout *find = kbd->layouts;
-               while (find) {
-                       if (find->type == type - 2) {
-                               find->sublayout = lay;
-                               break;
-                       }
-                       find = find->next;
-               }
-               if (!find) {
-                       free(lay);
-                       error(parser, "lowercase_num/uppercase_num has to follow lowercase/uppercase definition");
-               }
-       } else {
-               struct layout *last = kbd->layouts;
-
-               if (!last)
-                       kbd->layouts = lay;
-               else {
-                       while (last->next)
-                               last = last->next;
-                       last->next = lay;
-               }
-               kbd->layouts_cnt++;
-               if ((type == LAY_UPPERCASE && (!last || last->type != LAY_LOWERCASE)) ||
-                   (type == LAY_SPECIAL_UPPER && (!last || last->type != LAY_SPECIAL_LOWER)))
-                       error(parser, "uppercase has to follow lowercase definition");
-               if (type == LAY_SPECIAL_UPPER && last->name)
-                       set_str(&lay->name, last->name);
-       }
-       lay->type = type;
-       get_tok_begin(parser);
-       while (1) {
-               get_tok(parser);
-               if (is_keyword(parser, TOK_NAME)) {
-                       get_tok_string(parser);
-                       if (lay->name)
-                               error(parser, "name must not be specified for uppercase layout in kbd_special section");
-                       set_str(&lay->name, parser->tstr);
-               } else if (is_keyword(parser, TOK_MARGIN)) {
-                       int i;
-                       for (i = 0; i < 4; i++) {
-                               get_tok_num(parser);
-                               lay->margins[i] = parser->tint;
-                       }
-               } else if (is_keyword(parser, TOK_DEFAULT_SIZE)) {
-                       get_tok_num(parser);
-                       lay->default_size = parser->tint;
-               } else if (is_keyword(parser, TOK_ROW))
-                       parse_row(parser, lay);
-               else if (is_end(parser))
-                       return;
-               else
-                       error_end(parser);
-       }
-}
-
-static void parse_kbd(struct parser *parser, struct global *glob, int type)
-{
-       struct kbd *kbd = e_malloc(sizeof(struct kbd));
-
-       if (!glob->kbds)
-               glob->kbds = kbd;
-       else {
-               struct kbd *last = glob->kbds;
-               while (last->next)
-                       last = last->next;
-               last->next = kbd;
-       }
-       glob->kbds_cnt++;
-       kbd->type = type;
-       get_tok_begin(parser);
-       while (1) {
-               get_tok(parser);
-               if (is_keyword(parser, TOK_LOWERCASE))
-                       parse_layout(parser, kbd, LAY_LOWERCASE);
-               else if (is_keyword(parser, TOK_UPPERCASE))
-                       parse_layout(parser, kbd, LAY_UPPERCASE);
-               else if (is_keyword(parser, TOK_SPEC_LOWERCASE)) {
-                       if (type != KBD_SPECIAL)
-                               error(parser, "special_lowercase allowed only in kbd_special section");
-                       parse_layout(parser, kbd, LAY_SPECIAL_LOWER);
-               } else if (is_keyword(parser, TOK_SPEC_UPPERCASE)) {
-                       if (type != KBD_SPECIAL)
-                               error(parser, "special_uppercase allowed only in kbd_special section");
-                       parse_layout(parser, kbd, LAY_SPECIAL_UPPER);
-               } else if (is_keyword(parser, TOK_LOWERCASE_NUM)) {
-                       if (type != KBD_NORMAL)
-                               error(parser, "lowercase_num allowed only in kbd_normal section");
-                       parse_layout(parser, kbd, LAY_LOWERCASE_NUM);
-               } else if (is_keyword(parser, TOK_UPPERCASE_NUM)) {
-                       if (type != KBD_NORMAL)
-                               error(parser, "uppercase_num allowed only in kbd_normal section");
-                       parse_layout(parser, kbd, LAY_UPPERCASE_NUM);
-               } else if (is_keyword(parser, TOK_SPECIAL)) {
-                       if (type != KBD_THUMB && type != KBD_SPECIAL)
-                               error(parser, "special allowed only in kbd_thumb and kbd_special sections");
-                       parse_layout(parser, kbd, LAY_SPECIAL);
-               } else if (is_end(parser)) {
-                       if (!kbd->layouts_cnt)
-                               error(parser, "no keyboard layouts defined");
-                       return;
-               } else
-                       error_end(parser);
-       }
-}
-
-static void parse_global(struct parser *parser)
-{
-       struct global *glob = parser->global;
-
-       while (1) {
-               get_tok(parser);
-               if (is_keyword(parser, TOK_HEADER))
-                       parse_header(parser, glob);
-               else if (is_keyword(parser, TOK_KBD_NORMAL))
-                       parse_kbd(parser, glob, KBD_NORMAL);
-               else if (is_keyword(parser, TOK_KBD_THUMB))
-                       parse_kbd(parser, glob, KBD_THUMB);
-               else if (is_keyword(parser, TOK_KBD_SPECIAL))
-                       parse_kbd(parser, glob, KBD_SPECIAL);
-               else if (is_eof(parser)) {
-                       if (!glob->kbds_cnt)
-                               error(parser, "no keyboards defined");
-                       return;
-               } else
-                       error(parser, "header, kbd_normal, kbd_thumb or kbd_special expected");
-       }
-}
-
-/*** writer ***/
-
-struct writer {
-       struct global *global;
-       int start_table;
-       int *starts;
-};
-
-static void werror(struct writer *writer)
-{
-       (void)writer;
-       longjmp(cjmp, 1);
-}
-
-static void init_writer(struct writer *writer, struct global *global)
-{
-       writer->global = global;
-       writer->starts = e_malloc(sizeof(int) * global->kbds_cnt);
-}
-
-static void close_writer(struct writer *writer)
-{
-       if (!writer)
-               return;
-       free(writer->starts);
-}
-
-static void writer_byte(struct writer *writer, unsigned char b)
-{
-       if (cops->write(cpriv, &b, 1))
-               werror(writer);
-}
-
-static void writer_word(struct writer *writer, unsigned int w)
-{
-       unsigned char a[2];
-
-       a[0] = w & 0xff;
-       a[1] = (w >> 8) & 0xff;
-       if (cops->write(cpriv, a, 2))
-               werror(writer);
-}
-
-static void writer_string(struct writer *writer, char *s)
-{
-       int len;
-
-       if (!s)
-               len = 0;
-       else
-               len = strlen(s);
-       writer_byte(writer, len);
-       if (len) {
-               if (cops->write(cpriv, s, len))
-                       werror(writer);
-       }
-}
-
-static void writer_sizes(struct writer *writer, struct size *sizes)
-{
-       int i;
-
-       while (sizes) {
-               for (i = 0; i < 5; i++)
-                       writer_byte(writer, sizes->dim[i]);
-               sizes = sizes->next;
-       }
-}
-
-static void writer_keys(struct writer *writer, struct key *key, int default_size)
-{
-       struct slide_key *skey;
-
-       while (key) {
-               writer_byte(writer, key->slides_cnt ? 1 : 0);
-               writer_byte(writer, key->flags & 0xff);
-               if (key->flags & KEY_EXTEND)
-                       writer_byte(writer, (key->flags >> 8) & 0xff);
-               if (!key->slides_cnt)
-                       writer_string(writer, key->u.name);
-               else {
-                       writer_byte(writer, key->slides_cnt | 0x80);
-                       skey = key->u.slides;
-                       while (skey) {
-                               writer_string(writer, skey->name);
-                               skey = skey->next;
-                       }
-               }
-               writer_byte(writer, key->size >= 0 ? key->size : default_size);
-               key = key->next;
-       }
-}
-
-static void writer_sublayout(struct writer *writer, struct layout *lay)
-{
-       int cnt;
-       struct row *tmp;
-
-       cnt = 0;
-       for (tmp = lay->rows; tmp; tmp = tmp->next)
-               cnt += tmp->keys_cnt;
-       writer_byte(writer, cnt);
-       writer_byte(writer, lay->rows_cnt);
-       writer_byte(writer, lay->margins[3]);
-       writer_byte(writer, lay->margins[0]);
-       writer_byte(writer, lay->margins[2]);
-       writer_byte(writer, lay->margins[1]);
-       for (tmp = lay->rows; tmp; tmp = tmp->next)
-               writer_byte(writer, tmp->keys_cnt);
-       for (tmp = lay->rows; tmp; tmp = tmp->next)
-               writer_keys(writer, tmp->keys, lay->default_size);
-}
-
-static void writer_layouts(struct writer *writer, struct layout *lay, int idx)
-{
-       int type, other;
-
-       switch (lay->type) {
-       case LAY_LOWERCASE:
-               type = 0;
-               break;
-       case LAY_UPPERCASE:
-               type = 1;
-               break;
-       default:
-               type = 2;
-               break;
-       }
-       switch (lay->type) {
-       case LAY_LOWERCASE:
-       case LAY_SPECIAL_LOWER:
-               other = idx + 1;
-               break;
-       case LAY_UPPERCASE:
-       case LAY_SPECIAL_UPPER:
-               other = idx - 1;
-               break;
-       default:
-               other = 0xff;
-               break;
-       }
-       writer_byte(writer, type);
-       writer_byte(writer, other);
-       writer_string(writer, lay->name);
-       writer_byte(writer, lay->sublayout ? 2 : 1);
-       writer_sublayout(writer, lay);
-       if (lay->sublayout)
-               writer_sublayout(writer, lay->sublayout);
-}
-
-static void writer_kbd(struct writer *writer, struct kbd *kbd)
-{
-       struct layout *lay;
-       int i;
-
-       writer_byte(writer, kbd->type);
-       writer_byte(writer, kbd->layouts_cnt);
-       writer_byte(writer, 0);
-       writer_byte(writer, kbd->layouts->default_size);        /* use the default size of the first layout */
-       for (lay = kbd->layouts, i = 0; lay; lay = lay->next, i++)
-               writer_layouts(writer, lay, i);
-}
-
-static void writer_global(struct writer *writer)
-{
-       struct global *glob = writer->global;
-       struct kbd *kbd;
-       int i;
-
-       writer_byte(writer, 1);         /* version */
-       writer_byte(writer, glob->kbds_cnt);
-       writer_string(writer, glob->name);
-       writer_string(writer, glob->lang);
-       writer_string(writer, glob->wc);
-       writer_byte(writer, 2);         /* always use the default screen modes */
-       writer_byte(writer, 0);
-       writer_byte(writer, 1);
-       writer_byte(writer, glob->sizes_cnt);
-       writer_sizes(writer, glob->sizes);
-       writer->start_table = cops->tell(cpriv);
-       for (i = 0; i < glob->kbds_cnt; i++)
-               writer_word(writer, 0);
-       for (i = 0; i < 20; i++)
-               writer_byte(writer, 0);
-       for (kbd = glob->kbds, i = 0; kbd; kbd = kbd->next, i++) {
-               writer->starts[i] = cops->tell(cpriv);
-               writer_kbd(writer, kbd);
-       }
-       cops->seek(cpriv, writer->start_table);
-       for (i = 0; i < glob->kbds_cnt; i++)
-               writer_word(writer, writer->starts[i]);
-}
-
-/*** main ***/
-
-int compile(struct compiler_ops *ops, void *priv)
-{
-       struct parser *parser = NULL;
-       struct writer *writer = NULL;
-       int res;
-
-       cops = ops;
-       cpriv = priv;
-
-       res = setjmp(cjmp);
-       if (!res) {
-               parser = e_malloc(sizeof(struct parser));
-               writer = e_malloc(sizeof(struct writer));
-               init_parser(parser);
-               parse_global(parser);
-               init_writer(writer, parser->global);
-               writer_global(writer);
-               if (cops->return_lang)
-                       cops->return_lang(cpriv, parser->global->lang);
-       }
-       close_writer(writer);
-       close_parser(parser);
-       free(writer);
-       free(parser);
-       return res ? -1 : 0;
-}