diff options
author | Marco Gerards <metgerards@student.han.nl> | 2011-03-06 17:45:44 -0300 |
---|---|---|
committer | Diego Nieto Cid <dnietoc@gmail.com> | 2011-03-17 18:34:16 -0300 |
commit | 345f8d5ff5fe7e909e8e9aae6a7d02981263ff91 (patch) | |
tree | 273103afc843d043239e30172176be82e2105dc3 /console-client/xkb/compose.c | |
parent | bebc64a9a0f064a0e5f8a3549aa01aa9ac79a2e9 (diff) |
Add XKB parser and implementation.
* console-client/xkb/Compose: New file.
* console-client/xkb/MISSING-FEATURES: Likewise.
* console-client/xkb/README: Likewise.
* console-client/xkb/TODO: Likewise.
* console-client/xkb/compose.c: Likewise.
* console-client/xkb/default.xkb: Likewise.
* console-client/xkb/keysymdef.h: Likewise.
* console-client/xkb/ks_tables.h: Likewise.
* console-client/xkb/kstoucs.c: Likewise.
* console-client/xkb/lex.l: Likewise.
* console-client/xkb/makeconf.sh: Likewise.
* console-client/xkb/parser.y: Likewise.
* console-client/xkb/symname.c: Likewise.
* console-client/xkb/xkb-data/keymap/hurd: Likewise.
* console-client/xkb/xkb-data/symbols/hurd: Likewise.
* console-client/xkb/xkb-data/types/hurd: Likewise.
* console-client/xkb/xkb.c: Likewise.
* console-client/xkb/xkb.h: Likewise.
* console-client/xkb/xkbdata.c: Likewise.
* console-client/xkb/xkbdefaults.c: Likewise.
* console-client/xkb/xkbtimer.c: Likewise.
Diffstat (limited to 'console-client/xkb/compose.c')
-rw-r--r-- | console-client/xkb/compose.c | 422 |
1 files changed, 422 insertions, 0 deletions
diff --git a/console-client/xkb/compose.c b/console-client/xkb/compose.c new file mode 100644 index 00000000..38bcb47b --- /dev/null +++ b/console-client/xkb/compose.c @@ -0,0 +1,422 @@ +/* compose.c -- Keysym composing + + Copyright (C) 2003 Marco Gerards + + Written by Marco Gerards <metgerards@student.han.nl> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <stdio.h> +#include <stdlib.h> +#include "keysymdef.h" +#include "xkb.h" +#include <ctype.h> +#include <string.h> + +#define NoSymbol 0 + +/* Tokens that can be recognised by the scanner. */ +enum tokentype + { + UNKNOWN, + EOL, + REQKS, + SEMICOL, + STR, + PRODKS, + END + }; + +/* The current token. */ +struct token +{ + enum tokentype toktype; + char value[50]; +} tok; + +/* The linenumber of the line currently parsed, used for returning + errors and warnings. */ +static int linenum; + +/* Read a token from the file CF. */ +static void +read_token (FILE *cf) +{ + int c = fgetc (cf); + int pos = 0; + + /* Remove whitespaces. */ + while (c == ' ' || c == '\t') + c = fgetc (cf); + + /* Comment, remove until end of line and return a EOL token. */ + if (c == '#') + { + while (c != '\n') + c = fgetc (cf); + tok.toktype = EOL; + linenum++; + return; + } + + /* End of file. */ + if (c == EOF) + { + tok.toktype = END; + return; + } + + /* Semicolon. */ + if (c == ':') + { + tok.toktype = SEMICOL; + return; + } + + /* End of line. */ + if (c == '\n') + { + linenum++; + tok.toktype = EOL; + return; + } + + + /* Required keysym. */ + if (c == '<') + { + while ((c = fgetc (cf)) != '>') + tok.value[pos++] = c; + tok.value[pos] = '\0'; + tok.toktype = REQKS; + return; + } + + /* Character string. */ + if (c == '"') + { + while ((c = fgetc (cf)) != '"') + { + if (c == '\\') + c = fgetc (cf); + + tok.value[pos++] = c; + } + tok.value[pos] = '\0'; + tok.toktype = STR; + return; + } + + /* Produced keysym. */ + if (isalpha (c)) + { + tok.value[pos++] = c; + while (isgraph (c = fgetc (cf))) + tok.value[pos++] = c; + tok.value[pos] = '\0'; + tok.toktype = PRODKS; + ungetc (c, cf); + return; + } + + /* Unknown token. */ + tok.toktype = UNKNOWN; + return; +} + +/* Compose sequence. */ +struct compose +{ + struct compose *left; + struct compose *right; + symbol *expected; + symbol produced; +} *compose_tree; + + +/* Compare symbol sequence s1 to symbol sequence s1. This function + works just like the strcmp function. */ +static int +symbolscmp (symbol *s1, symbol *s2) +{ + while (*s1 && *s2 && (*s1 == *s2)) + { + s1++;s2++; + } + if (*s1 < *s2) + return -1; + if (*s1 > *s2) + return 1; + return 0; +} + +/* Compare symbol sequence s1 to symbol sequence s1, compare a maximum + of N symbols. This function works just like the strcmp function. + */ +static int +symbolsncmp (symbol *s1, symbol *s2, int n) +{ + int cnt = 0; + while (*s1 && *s2 && (*s1 == *s2)) + { + if (++cnt == n) + break; + s1++;s2++; + } + + if (*s1 < *s2) + return -1; + if (*s1 > *s2) + return 1; + return 0; +} + + +/* Add the compose sequence EXP to the binary tree, store RESULT as + the keysym produced by EXP. */ +static struct compose * +composetree_add (struct compose *tree, symbol *exp, symbol result) +{ + int cmp; + + if (tree == NULL) + { + tree = malloc (sizeof (struct compose)); + tree->expected = exp; + tree->produced = result; + tree->left = tree->right = NULL; + + return tree; + } + + cmp = symbolscmp (exp, tree->expected); + if (cmp == 0) + { + printf ("Warning: line %d: Double sequence.\n", linenum); + free (exp); + } + else if (cmp < 0) + tree->left = composetree_add (tree->left, exp, result); + else + tree->right = composetree_add (tree->right, exp, result); + return tree; +} + +/* Parse the composefile CF and put all sequences in the binary tree + COMPOSE_TREE. This function may never fail because of syntactical or + lexalical errors, generate a warning instead. */ +static error_t +parse_composefile (FILE *cf) +{ + void skip_line (void) + { + while (tok.toktype != EOL && tok.toktype != END) + read_token (cf); + } + + for (;;) + { + /* Expected keysyms. */ + symbol exp[50]; + symbol *exps; + size_t expcnt = 0; + symbol sym; + + read_token (cf); + /* Blank line. */ + if (tok.toktype == EOL) + continue; + + /* End of file, done parsing. */ + if (tok.toktype == END) + return 0; + + if (tok.toktype != REQKS) + { + printf ("Warning: line %d: Keysym expected on beginning of line.\n", + linenum); + skip_line (); + continue; + } + + /* Keysym was recognised, add it. */ + sym = XStringToKeysym (tok.value); + if (!sym) + { + printf ("Warning: line %d: Unknown keysym \"%s\".\n", linenum, + tok.value); + skip_line (); + continue; + } + exp[expcnt++] = sym; + + do + { + read_token (cf); + /* If another required keysym is recognised, add it. */ + if (tok.toktype == REQKS) + { + sym = XStringToKeysym (tok.value); + if (!sym) + { + printf ("Warning: line %d: Unknown keysym \"%s\".\n", + linenum, tok.value); + skip_line (); + continue; + } + exp[expcnt++] = sym; + } + } while (tok.toktype == REQKS); + + if (tok.toktype != SEMICOL) + { + printf ("Warning: line %d: Semicolon expected.\n", linenum); + skip_line (); + continue; + } + + read_token (cf); + /* Force token and ignore it. */ + if (tok.toktype != STR) + { + printf ("Warning: line %d: string expected.\n", linenum); + skip_line (); + continue; + } + + read_token (cf); + if (tok.toktype != PRODKS) + { + printf ("Warning: line %d: keysym expected.\n", linenum); + skip_line (); + continue; + } + sym = XStringToKeysym (tok.value); + if (!sym) + { + printf ("Warning: line %d: Unknown keysym \"%s\".\n", linenum, + tok.value); + skip_line (); + continue; + } + + read_token (cf); + if (tok.toktype != EOL && tok.toktype != END) + { + printf ("Warning: line %d: end of line or end of file expected.\n", + linenum); + skip_line (); + continue; + } + + /* Add the production rule. */ + exp[expcnt++] = 0; + exps = malloc (sizeof (symbol) * expcnt); + memcpy (exps, exp, sizeof (symbol) * expcnt); + compose_tree = composetree_add (compose_tree, exps, sym); + } + return 0; +} + +/* Read keysyms passed to this function by S until a keysym can be + composed. If the first keysym cannot start a compose sequence return + the keysym. */ +symbol +compose_symbols (symbol s) +{ + /* Current position in the compose tree. */ + static struct compose *treepos = NULL; + /* Current compose sequence. */ + static symbol syms[100]; + /* Current position in the compose sequence. */ + static int pos = 0; + int cmp; + + if (!treepos) + treepos = compose_tree; + + /* Maximum sequence length reached. Some idiot typed this many + symbols and now we throw it all away, wheee!!! */ + if (pos == 99) + { + treepos = compose_tree; + pos = 0; + } + + /* Put the keysym in the compose sequence array. */ + syms[pos++] = s; + syms[pos] = 0; + + /* Search the tree for a keysym sequence that can match the current one. */ + while (treepos) + { + cmp = symbolsncmp (syms, treepos->expected, pos); + if (cmp == 0) + { + /* The keysym sequence was partially recognised, check if it + can completely match. */ + if (!symbolscmp (syms, treepos->expected)) + { + symbol ret = treepos->produced; + treepos = compose_tree; + pos = 0; + return ret; + } + + /* The sequence was partially recognised. */ + return -1; + } + + if (cmp < 0) + treepos = treepos->left; + else + treepos = treepos->right; + } + + /* Nothing can be found. */ + treepos = compose_tree; + + /* This ks should've started a sequence but couldn't be found, + just return it. */ + if (pos == 1) + { + pos = 0; + return s; + } + + debug_printf ("Invalid\n"); + /* Invalid keysym sequence. */ + pos = 0; + return -1; +} + +/* Read a Compose file. */ +error_t +read_composefile (char *composefn) +{ + FILE *cf; + + error_t err; + cf = fopen (composefn, "r"); + if (cf == NULL) + return errno; + + err = parse_composefile (cf); + if (err) + fclose (cf); + + return err; +} |