Commit 8e1fed6c68ca23d8a6f31c30e36417f4c07274b1

Ran Benita 2015-03-24T16:40:29

compose: correctly parse modifier syntax As described in: http://cgit.freedesktop.org/xorg/lib/libX11/commit/?id=ddf3b09bb262d01b56fbaade421ac85b0e60a69f Signed-off-by: Ran Benita <ran234@gmail.com>

diff --git a/src/compose/parser.c b/src/compose/parser.c
index 95f0fdd..9e936a9 100644
--- a/src/compose/parser.c
+++ b/src/compose/parser.c
@@ -113,8 +113,9 @@ cached_keysym_from_name(struct keysym_from_name_cache *cache,
  * COMMENT       ::= "#" {<any character except null or newline>}
  * LHS           ::= EVENT { EVENT }
  * EVENT         ::= [MODIFIER_LIST] "<" keysym ">"
- * MODIFIER_LIST ::= ("!" {MODIFIER} ) | "None"
- * MODIFIER      ::= ["~"] modifier_name
+ * MODIFIER_LIST ::= (["!"] {MODIFIER} ) | "None"
+ * MODIFIER      ::= ["~"] MODIFIER_NAME
+ * MODIFIER_NAME ::= ("Ctrl"|"Lock"|"Caps"|"Shift"|"Alt"|"Meta")
  * RHS           ::= ( STRING | keysym | STRING keysym )
  * STRING        ::= '"' { CHAR } '"'
  * CHAR          ::= GRAPHIC_CHAR | ESCAPED_CHAR
@@ -357,8 +358,9 @@ struct production {
     bool has_keysym;
     bool has_string;
 
-    xkb_mod_mask_t mods;
+    /* The matching is as follows: (active_mods & modmask) == mods. */
     xkb_mod_mask_t modmask;
+    xkb_mod_mask_t mods;
 };
 
 static uint32_t
@@ -456,6 +458,9 @@ add_production(struct xkb_compose_table *table, struct scanner *s,
     }
 }
 
+/* Should match resolve_modifier(). */
+#define ALL_MODS_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3))
+
 static xkb_mod_index_t
 resolve_modifier(const char *name)
 {
@@ -587,15 +592,16 @@ lhs_tok:
         }
         goto rhs;
     case TOK_IDENT:
-        if (!streq(val.string.str, "None")) {
-            scanner_err(s, "unrecognized identifier \"%s\"", val.string.str);
-            goto error;
+        if (streq(val.string.str, "None")) {
+            production.mods = 0;
+            production.modmask = ALL_MODS_MASK;
+            goto lhs_keysym;
         }
-        production.mods = 0;
-        /* XXX Should only include the mods in resolve_mods(). */
-        production.modmask = 0xff;
-        goto lhs_keysym;
+        goto lhs_mod_list_tok;
+    case TOK_TILDE:
+        goto lhs_mod_list_tok;
     case TOK_BANG:
+        production.modmask = ALL_MODS_MASK;
         goto lhs_mod_list;
     default:
         goto lhs_keysym_tok;
@@ -625,21 +631,22 @@ lhs_keysym_tok:
         goto unexpected;
     }
 
-lhs_mod_list: {
+lhs_mod_list:
+    tok = lex(s, &val);
+lhs_mod_list_tok: {
         bool tilde = false;
         xkb_mod_index_t mod;
 
-        tok = lex(s, &val);
+        if (tok != TOK_TILDE && tok != TOK_IDENT)
+            goto lhs_keysym_tok;
+
         if (tok == TOK_TILDE) {
             tilde = true;
             tok = lex(s, &val);
         }
 
-        if (tok != TOK_IDENT) {
-            if (tilde || production.modmask == 0)
-                goto unexpected;
-            goto lhs_keysym_tok;
-        }
+        if (tok != TOK_IDENT)
+            goto unexpected;
 
         mod = resolve_modifier(val.string.str);
         if (mod == XKB_MOD_INVALID) {
diff --git a/test/compose.c b/test/compose.c
index 9bbef18..d9f3629 100644
--- a/test/compose.c
+++ b/test/compose.c
@@ -434,6 +434,16 @@ test_modifier_syntax(struct xkb_context *ctx)
 
     assert(test_compose_seq_buffer(ctx,
         "None <A>          : X \n"
+        "Shift <B>         : Y \n"
+        "Ctrl <C>          : Y \n"
+        "Alt <D>           : Y \n"
+        "Caps <E>          : Y \n"
+        "Lock <F>          : Y \n"
+        "Shift Ctrl <G>    : Y \n"
+        "~Shift <H>        : Y \n"
+        "~Shift Ctrl <I>   : Y \n"
+        "Shift ~Ctrl <J>   : Y \n"
+        "Shift ~Ctrl ~Alt <K> : Y \n"
         "! Shift <B>       : Y \n"
         "! Ctrl <C>        : Y \n"
         "! Alt <D>         : Y \n"
@@ -454,7 +464,7 @@ test_modifier_syntax(struct xkb_context *ctx)
         "! None <A>        : X \n"
         "! Foo <B>         : X \n"
         "None ! Shift <C>  : X \n"
-        "! <D>             : X \n"
+        "! ! <D>           : X \n"
         "! ~ <E>           : X \n"
         "! ! <F>           : X \n"
         "! Ctrl ! Ctrl <G> : X \n"