doc: move some file comments into txt files in doc/
[platform/upstream/libxkbcommon.git] / src / xkbcomp / keycodes.c
1 /************************************************************
2  * Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3  *
4  * Permission to use, copy, modify, and distribute this
5  * software and its documentation for any purpose and without
6  * fee is hereby granted, provided that the above copyright
7  * notice appear in all copies and that both that copyright
8  * notice and this permission notice appear in supporting
9  * documentation, and that the name of Silicon Graphics not be
10  * used in advertising or publicity pertaining to distribution
11  * of the software without specific prior written permission.
12  * Silicon Graphics makes no representation about the suitability
13  * of this software for any purpose. It is provided "as is"
14  * without any express or implied warranty.
15  *
16  * SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18  * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19  * GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23  * THE USE OR PERFORMANCE OF THIS SOFTWARE.
24  *
25  ********************************************************/
26
27 #include "xkbcomp-priv.h"
28 #include "text.h"
29 #include "expr.h"
30 #include "include.h"
31
32 typedef struct {
33     enum merge_mode merge;
34
35     xkb_atom_t alias;
36     xkb_atom_t real;
37 } AliasInfo;
38
39 typedef struct {
40     enum merge_mode merge;
41
42     xkb_atom_t name;
43 } LedNameInfo;
44
45 typedef struct {
46     char *name;
47     int errorCount;
48
49     xkb_keycode_t min_key_code;
50     xkb_keycode_t max_key_code;
51     darray(xkb_atom_t) key_names;
52     darray(LedNameInfo) led_names;
53     darray(AliasInfo) aliases;
54
55     struct xkb_context *ctx;
56 } KeyNamesInfo;
57
58 /***====================================================================***/
59
60 static void
61 InitAliasInfo(AliasInfo *info, enum merge_mode merge,
62               xkb_atom_t alias, xkb_atom_t real)
63 {
64     memset(info, 0, sizeof(*info));
65     info->merge = merge;
66     info->alias = alias;
67     info->real = real;
68 }
69
70 static LedNameInfo *
71 FindLedByName(KeyNamesInfo *info, xkb_atom_t name,
72               xkb_led_index_t *idx_out)
73 {
74     LedNameInfo *ledi;
75     xkb_led_index_t idx;
76
77     darray_enumerate(idx, ledi, info->led_names) {
78         if (ledi->name == name) {
79             *idx_out = idx;
80             return ledi;
81         }
82     }
83
84     return NULL;
85 }
86
87 static bool
88 AddLedName(KeyNamesInfo *info, enum merge_mode merge, bool same_file,
89            LedNameInfo *new, xkb_led_index_t new_idx)
90 {
91     xkb_led_index_t old_idx;
92     LedNameInfo *old;
93     const int verbosity = xkb_context_get_log_verbosity(info->ctx);
94     const bool report = (same_file && verbosity > 0) || verbosity > 9;
95     const bool replace = (merge == MERGE_REPLACE || merge == MERGE_OVERRIDE);
96
97     /* LED with the same name already exists. */
98     old = FindLedByName(info, new->name, &old_idx);
99     if (old) {
100         if (old_idx == new_idx) {
101             log_warn(info->ctx,
102                      "Multiple indicators named \"%s\"; "
103                      "Identical definitions ignored\n",
104                      xkb_atom_text(info->ctx, new->name));
105             return true;
106         }
107
108         if (report) {
109             xkb_led_index_t use = (replace ? new_idx + 1 : old_idx + 1);
110             xkb_led_index_t ignore = (replace ? old_idx + 1 : new_idx + 1);
111             log_warn(info->ctx,
112                      "Multiple indicators named %s; Using %d, ignoring %d\n",
113                      xkb_atom_text(info->ctx, new->name), use, ignore);
114         }
115
116         if (replace)
117             *old = *new;
118
119         return true;
120     }
121
122     if (new_idx >= darray_size(info->led_names))
123         darray_resize0(info->led_names, new_idx + 1);
124
125     /* LED with the same index already exists. */
126     old = &darray_item(info->led_names, new_idx);
127     if (old->name != XKB_ATOM_NONE) {
128         if (report) {
129             const xkb_atom_t use = (replace ? new->name : old->name);
130             const xkb_atom_t ignore = (replace ? old->name : new->name);
131             log_warn(info->ctx, "Multiple names for indicator %d; "
132                      "Using %s, ignoring %s\n", new_idx + 1,
133                      xkb_atom_text(info->ctx, use),
134                      xkb_atom_text(info->ctx, ignore));
135         }
136
137         if (replace)
138             *old = *new;
139
140         return true;
141     }
142
143     darray_item(info->led_names, new_idx) = *new;
144     return true;
145 }
146
147 static void
148 ClearKeyNamesInfo(KeyNamesInfo *info)
149 {
150     free(info->name);
151     darray_free(info->key_names);
152     darray_free(info->aliases);
153     darray_free(info->led_names);
154 }
155
156 static void
157 InitKeyNamesInfo(KeyNamesInfo *info, struct xkb_context *ctx)
158 {
159     memset(info, 0, sizeof(*info));
160     info->ctx = ctx;
161     info->min_key_code = XKB_KEYCODE_INVALID;
162 #if XKB_KEYCODE_INVALID < XKB_KEYCODE_MAX
163 #error "Hey, you can't be changing stuff like that."
164 #endif
165 }
166
167 static xkb_keycode_t
168 FindKeyByName(KeyNamesInfo *info, xkb_atom_t name)
169 {
170     xkb_keycode_t i;
171
172     for (i = info->min_key_code; i <= info->max_key_code; i++)
173         if (darray_item(info->key_names, i) == name)
174             return i;
175
176     return XKB_KEYCODE_INVALID;
177 }
178
179 static bool
180 AddKeyName(KeyNamesInfo *info, xkb_keycode_t kc, xkb_atom_t name,
181            enum merge_mode merge, bool same_file, bool report)
182 {
183     xkb_atom_t old_name;
184     xkb_keycode_t old_kc;
185     const int verbosity = xkb_context_get_log_verbosity(info->ctx);
186
187     report = report && ((same_file && verbosity > 0) || verbosity > 7);
188
189     if (kc >= darray_size(info->key_names))
190         darray_resize0(info->key_names, kc + 1);
191
192     info->min_key_code = MIN(info->min_key_code, kc);
193     info->max_key_code = MAX(info->max_key_code, kc);
194
195     /* There's already a key with this keycode. */
196     old_name = darray_item(info->key_names, kc);
197     if (old_name != XKB_ATOM_NONE) {
198         const char *lname = KeyNameText(info->ctx, old_name);
199         const char *kname = KeyNameText(info->ctx, name);
200
201         if (old_name == name) {
202             if (report)
203                 log_warn(info->ctx,
204                          "Multiple identical key name definitions; "
205                          "Later occurrences of \"%s = %d\" ignored\n",
206                          lname, kc);
207             return true;
208         }
209         else if (merge == MERGE_AUGMENT) {
210             if (report)
211                 log_warn(info->ctx,
212                          "Multiple names for keycode %d; "
213                          "Using %s, ignoring %s\n", kc, lname, kname);
214             return true;
215         }
216         else {
217             if (report)
218                 log_warn(info->ctx,
219                          "Multiple names for keycode %d; "
220                          "Using %s, ignoring %s\n", kc, kname, lname);
221             darray_item(info->key_names, kc) = XKB_ATOM_NONE;
222         }
223     }
224
225     /* There's already a key with this name. */
226     old_kc = FindKeyByName(info, name);
227     if (old_kc != XKB_KEYCODE_INVALID && old_kc != kc) {
228         const char *kname = KeyNameText(info->ctx, name);
229
230         if (merge == MERGE_OVERRIDE) {
231             darray_item(info->key_names, old_kc) = XKB_ATOM_NONE;
232             if (report)
233                 log_warn(info->ctx,
234                          "Key name %s assigned to multiple keys; "
235                          "Using %d, ignoring %d\n", kname, kc, old_kc);
236         }
237         else {
238             if (report)
239                 log_vrb(info->ctx, 3,
240                         "Key name %s assigned to multiple keys; "
241                         "Using %d, ignoring %d\n", kname, old_kc, kc);
242             return true;
243         }
244     }
245
246     darray_item(info->key_names, kc) = name;
247     return true;
248 }
249
250 /***====================================================================***/
251
252 static int
253 HandleAliasDef(KeyNamesInfo *info, KeyAliasDef *def, enum merge_mode merge);
254
255 static void
256 MergeIncludedKeycodes(KeyNamesInfo *into, KeyNamesInfo *from,
257                       enum merge_mode merge)
258 {
259     if (from->errorCount > 0) {
260         into->errorCount += from->errorCount;
261         return;
262     }
263
264     if (into->name == NULL) {
265         into->name = from->name;
266         from->name = NULL;
267     }
268
269     /* Merge key names. */
270     if (darray_empty(into->key_names)) {
271         into->key_names = from->key_names;
272         darray_init(from->key_names);
273         into->min_key_code = from->min_key_code;
274         into->max_key_code = from->max_key_code;
275     }
276     else {
277         if (darray_size(into->key_names) < darray_size(from->key_names))
278             darray_resize0(into->key_names, darray_size(from->key_names));
279
280         for (unsigned i = from->min_key_code; i <= from->max_key_code; i++) {
281             xkb_atom_t name = darray_item(from->key_names, i);
282             if (name == XKB_ATOM_NONE)
283                 continue;
284
285             if (!AddKeyName(into, i, name, merge, true, false))
286                 into->errorCount++;
287         }
288     }
289
290     /* Merge key aliases. */
291     if (darray_empty(into->aliases)) {
292         into->aliases = from->aliases;
293         darray_init(from->aliases);
294     }
295     else {
296         AliasInfo *alias;
297
298         darray_foreach(alias, from->aliases) {
299             KeyAliasDef def;
300
301             def.merge = (merge == MERGE_DEFAULT ? alias->merge : merge);
302             def.alias = alias->alias;
303             def.real = alias->real;
304
305             if (!HandleAliasDef(into, &def, def.merge))
306                 into->errorCount++;
307         }
308     }
309
310     /* Merge LED names. */
311     if (darray_empty(into->led_names)) {
312         into->led_names = from->led_names;
313         darray_init(from->led_names);
314     }
315     else {
316         xkb_led_index_t idx;
317         LedNameInfo *ledi;
318
319         darray_enumerate(idx, ledi, from->led_names) {
320             if (ledi->name == XKB_ATOM_NONE)
321                 continue;
322
323             ledi->merge = (merge == MERGE_DEFAULT ? ledi->merge : merge);
324             if (!AddLedName(into, ledi->merge, false, ledi, idx))
325                 into->errorCount++;
326         }
327     }
328 }
329
330 static void
331 HandleKeycodesFile(KeyNamesInfo *info, XkbFile *file, enum merge_mode merge);
332
333 static bool
334 HandleIncludeKeycodes(KeyNamesInfo *info, IncludeStmt *include)
335 {
336     KeyNamesInfo included;
337
338     InitKeyNamesInfo(&included, info->ctx);
339     included.name = include->stmt;
340     include->stmt = NULL;
341
342     for (IncludeStmt *stmt = include; stmt; stmt = stmt->next_incl) {
343         KeyNamesInfo next_incl;
344         XkbFile *file;
345
346         file = ProcessIncludeFile(info->ctx, stmt, FILE_TYPE_KEYCODES);
347         if (!file) {
348             info->errorCount += 10;
349             ClearKeyNamesInfo(&included);
350             return false;
351         }
352
353         InitKeyNamesInfo(&next_incl, info->ctx);
354
355         HandleKeycodesFile(&next_incl, file, MERGE_OVERRIDE);
356
357         MergeIncludedKeycodes(&included, &next_incl, stmt->merge);
358
359         ClearKeyNamesInfo(&next_incl);
360         FreeXkbFile(file);
361     }
362
363     MergeIncludedKeycodes(info, &included, include->merge);
364     ClearKeyNamesInfo(&included);
365
366     return (info->errorCount == 0);
367 }
368
369 static bool
370 HandleKeycodeDef(KeyNamesInfo *info, KeycodeDef *stmt, enum merge_mode merge)
371 {
372     if (stmt->merge != MERGE_DEFAULT) {
373         if (stmt->merge == MERGE_REPLACE)
374             merge = MERGE_OVERRIDE;
375         else
376             merge = stmt->merge;
377     }
378
379     if (stmt->value < 0 || stmt->value > XKB_KEYCODE_MAX) {
380         log_err(info->ctx,
381                 "Illegal keycode %lld: must be between 0..%u; "
382                 "Key ignored\n", (long long) stmt->value, XKB_KEYCODE_MAX);
383         return false;
384     }
385
386     return AddKeyName(info, stmt->value, stmt->name, merge, false, true);
387 }
388
389 static int
390 HandleAliasDef(KeyNamesInfo *info, KeyAliasDef *def, enum merge_mode merge)
391 {
392     AliasInfo *old, new;
393
394     darray_foreach(old, info->aliases) {
395         if (old->alias == def->alias) {
396             if (def->real == old->real) {
397                 log_vrb(info->ctx, 1,
398                         "Alias of %s for %s declared more than once; "
399                         "First definition ignored\n",
400                         KeyNameText(info->ctx, def->alias),
401                         KeyNameText(info->ctx, def->real));
402             }
403             else {
404                 xkb_atom_t use, ignore;
405
406                 use = (merge == MERGE_AUGMENT ? old->real : def->real);
407                 ignore = (merge == MERGE_AUGMENT ? def->real : old->real);
408
409                 log_warn(info->ctx,
410                          "Multiple definitions for alias %s; "
411                          "Using %s, ignoring %s\n",
412                          KeyNameText(info->ctx, old->alias),
413                          KeyNameText(info->ctx, use),
414                          KeyNameText(info->ctx, ignore));
415
416                 old->real = use;
417             }
418
419             old->merge = merge;
420             return true;
421         }
422     }
423
424     InitAliasInfo(&new, merge, def->alias, def->real);
425     darray_append(info->aliases, new);
426     return true;
427 }
428
429 static int
430 HandleKeyNameVar(KeyNamesInfo *info, VarDef *stmt)
431 {
432     const char *elem, *field;
433     ExprDef *arrayNdx;
434
435     if (!ExprResolveLhs(info->ctx, stmt->name, &elem, &field, &arrayNdx))
436         return false;
437
438     if (elem) {
439         log_err(info->ctx, "Unknown element %s encountered; "
440                 "Default for field %s ignored\n", elem, field);
441         return false;
442     }
443
444     if (!istreq(field, "minimum") && !istreq(field, "maximum")) {
445         log_err(info->ctx, "Unknown field encountered; "
446                 "Assignment to field %s ignored\n", field);
447         return false;
448     }
449
450     /* We ignore explicit min/max statements, we always use computed. */
451     return true;
452 }
453
454 static int
455 HandleLedNameDef(KeyNamesInfo *info, LedNameDef *def,
456                  enum merge_mode merge)
457 {
458     LedNameInfo ledi;
459     xkb_atom_t name;
460
461     if (def->ndx < 1 || def->ndx > XKB_MAX_LEDS) {
462         info->errorCount++;
463         log_err(info->ctx,
464                 "Illegal indicator index (%d) specified; must be between 1 .. %d; "
465                 "Ignored\n", def->ndx, XKB_MAX_LEDS);
466         return false;
467     }
468
469     if (!ExprResolveString(info->ctx, def->name, &name)) {
470         char buf[20];
471         snprintf(buf, sizeof(buf), "%d", def->ndx);
472         info->errorCount++;
473         return ReportBadType(info->ctx, "indicator", "name", buf, "string");
474     }
475
476     ledi.merge = merge;
477     ledi.name = name;
478     return AddLedName(info, merge, true, &ledi, def->ndx - 1);
479 }
480
481 static void
482 HandleKeycodesFile(KeyNamesInfo *info, XkbFile *file, enum merge_mode merge)
483 {
484     bool ok;
485
486     free(info->name);
487     info->name = strdup_safe(file->name);
488
489     for (ParseCommon *stmt = file->defs; stmt; stmt = stmt->next) {
490         switch (stmt->type) {
491         case STMT_INCLUDE:
492             ok = HandleIncludeKeycodes(info, (IncludeStmt *) stmt);
493             break;
494         case STMT_KEYCODE:
495             ok = HandleKeycodeDef(info, (KeycodeDef *) stmt, merge);
496             break;
497         case STMT_ALIAS:
498             ok = HandleAliasDef(info, (KeyAliasDef *) stmt, merge);
499             break;
500         case STMT_VAR:
501             ok = HandleKeyNameVar(info, (VarDef *) stmt);
502             break;
503         case STMT_LED_NAME:
504             ok = HandleLedNameDef(info, (LedNameDef *) stmt, merge);
505             break;
506         default:
507             log_err(info->ctx,
508                     "Keycode files may define key and indicator names only; "
509                     "Ignoring %s\n", stmt_type_to_string(stmt->type));
510             ok = false;
511             break;
512         }
513
514         if (!ok)
515             info->errorCount++;
516
517         if (info->errorCount > 10) {
518             log_err(info->ctx, "Abandoning keycodes file \"%s\"\n",
519                     file->topName);
520             break;
521         }
522     }
523 }
524
525 /***====================================================================***/
526
527 static bool
528 CopyKeyNamesToKeymap(struct xkb_keymap *keymap, KeyNamesInfo *info)
529 {
530     xkb_keycode_t kc;
531     xkb_led_index_t idx;
532     LedNameInfo *ledi;
533     AliasInfo *alias;
534     unsigned i;
535
536     keymap->keycodes_section_name = strdup_safe(info->name);
537     XkbEscapeMapName(keymap->keycodes_section_name);
538
539     if (info->min_key_code != XKB_KEYCODE_INVALID) {
540         keymap->min_key_code = info->min_key_code;
541         keymap->max_key_code = info->max_key_code;
542     }
543     else {
544         /*
545          * If the keymap has no keys, let's just use the safest pair
546          * we know.
547          */
548         keymap->min_key_code = 8;
549         keymap->max_key_code = 255;
550     }
551
552     keymap->keys = calloc(keymap->max_key_code + 1, sizeof(*keymap->keys));
553     for (kc = keymap->min_key_code; kc <= keymap->max_key_code; kc++)
554         keymap->keys[kc].keycode = kc;
555
556     /* Copy key names. */
557     for (kc = info->min_key_code; kc <= info->max_key_code; kc++)
558         keymap->keys[kc].name = darray_item(info->key_names, kc);
559
560     /*
561      * Do some sanity checking on the aliases. We can't do it before
562      * because keys and their aliases may be added out-of-order.
563      */
564     keymap->num_key_aliases = 0;
565     darray_foreach(alias, info->aliases) {
566         /* Check that ->real is a key. */
567         if (!XkbKeyByName(keymap, alias->real, false)) {
568             log_vrb(info->ctx, 5,
569                     "Attempt to alias %s to non-existent key %s; Ignored\n",
570                     KeyNameText(info->ctx, alias->alias),
571                     KeyNameText(info->ctx, alias->real));
572             alias->real = XKB_ATOM_NONE;
573             continue;
574         }
575
576         /* Check that ->alias is not a key. */
577         if (XkbKeyByName(keymap, alias->alias, false)) {
578             log_vrb(info->ctx, 5,
579                     "Attempt to create alias with the name of a real key; "
580                     "Alias \"%s = %s\" ignored\n",
581                     KeyNameText(info->ctx, alias->alias),
582                     KeyNameText(info->ctx, alias->real));
583             alias->real = XKB_ATOM_NONE;
584             continue;
585         }
586
587         keymap->num_key_aliases++;
588     }
589
590     /* Copy key aliases. */
591     keymap->key_aliases = calloc(keymap->num_key_aliases,
592                                  sizeof(*keymap->key_aliases));
593     i = 0;
594     darray_foreach(alias, info->aliases) {
595         if (alias->real != XKB_ATOM_NONE) {
596             keymap->key_aliases[i].alias = alias->alias;
597             keymap->key_aliases[i].real = alias->real;
598             i++;
599         }
600     }
601
602     /* Copy LED names. */
603     darray_resize0(keymap->leds, darray_size(info->led_names));
604     darray_enumerate(idx, ledi, info->led_names)
605         if (ledi->name != XKB_ATOM_NONE)
606             darray_item(keymap->leds, idx).name = ledi->name;
607
608     return true;
609 }
610
611 /***====================================================================***/
612
613 bool
614 CompileKeycodes(XkbFile *file, struct xkb_keymap *keymap,
615                 enum merge_mode merge)
616 {
617     KeyNamesInfo info;
618
619     InitKeyNamesInfo(&info, keymap->ctx);
620
621     HandleKeycodesFile(&info, file, merge);
622     if (info.errorCount != 0)
623         goto err_info;
624
625     if (!CopyKeyNamesToKeymap(keymap, &info))
626         goto err_info;
627
628     ClearKeyNamesInfo(&info);
629     return true;
630
631 err_info:
632     ClearKeyNamesInfo(&info);
633     return false;
634 }