#include "rules.h"
#include "path.h"
-#define DFLT_LINE_SIZE 128
-
-struct input_line {
- size_t size;
- size_t offset;
- char buf[DFLT_LINE_SIZE];
- char *line;
-};
-
-static void
-input_line_init(struct input_line *line)
-{
- line->size = DFLT_LINE_SIZE;
- line->offset = 0;
- line->line = line->buf;
-}
-
-static void
-input_line_deinit(struct input_line *line)
-{
- if (line->line != line->buf)
- free(line->line);
- line->offset = 0;
- line->size = DFLT_LINE_SIZE;
- line->line = line->buf;
-}
-
-static int
-input_line_add_char(struct input_line *line, int ch)
-{
- if (line->offset >= line->size) {
- if (line->line == line->buf) {
- line->line = malloc(line->size * 2);
- memcpy(line->line, line->buf, line->size);
- }
- else {
- line->line = realloc(line->line, line->size * 2);
- }
-
- line->size *= 2;
- }
-
- line->line[line->offset++] = ch;
- return ch;
-}
-
static bool
-input_line_get(FILE *file, struct input_line *line)
+input_line_get(FILE *file, darray_char *line)
{
int ch;
bool end_of_file = false;
bool slash_pending;
bool in_comment;
- while (!end_of_file && line->offset == 0) {
+ while (!end_of_file && darray_empty(*line)) {
space_pending = slash_pending = in_comment = false;
while ((ch = getc(file)) != '\n' && ch != EOF) {
if (slash_pending) {
if (space_pending) {
- input_line_add_char(line, ' ');
+ darray_append(*line, ' ');
space_pending = false;
}
- input_line_add_char(line, '/');
+ darray_append(*line, '/');
slash_pending = false;
}
if (ch == EOF)
break;
- if (ch != '\n' && line->offset > 0)
+ if (ch != '\n' && !darray_empty(*line))
space_pending = true;
ungetc(ch, file);
}
else {
if (space_pending) {
- input_line_add_char(line, ' ');
+ darray_append(*line, ' ');
space_pending = false;
}
if (ch == '!') {
- if (line->offset != 0) {
+ if (!darray_empty(*line)) {
WARN("The '!' is legal only at start of line\n");
ACTION("Line containing '!' ignored\n");
- line->offset = 0;
+ darray_resize(*line, 0);
break;
}
}
- input_line_add_char(line, ch);
+ darray_append(*line, ch);
}
}
end_of_file = true;
}
- if (line->offset == 0 && end_of_file)
+ if (darray_empty(*line) && end_of_file)
return false;
- input_line_add_char(line, '\0');
+ darray_append(*line, '\0');
return true;
}
TYPES,
COMPAT,
GEOMETRY,
- KEYMAP,
#define COMPONENT_MASK \
((1 << KEYCODES) | (1 << SYMBOLS) | (1 << TYPES) | (1 << COMPAT) | \
- (1 << GEOMETRY) | (1 << KEYMAP))
+ (1 << GEOMETRY))
MAX_WORDS
};
[TYPES] = "types",
[COMPAT] = "compat",
[GEOMETRY] = "geometry",
- [KEYMAP] = "keymap",
-};
-
-struct var_defs {
- const char *model;
- const char *layout;
- const char *variant;
- const char *options;
};
struct multi_defs {
char *desc;
};
-struct describe_vars {
- size_t sz_desc;
- size_t num_desc;
- struct var_desc *desc;
-};
-
struct group {
int number;
char *name;
char *symbols;
char *types;
char *compat;
- char *keymap;
unsigned flags;
};
struct rules {
- struct describe_vars models;
- struct describe_vars layouts;
- struct describe_vars variants;
- struct describe_vars options;
-
- size_t sz_rules;
- size_t num_rules;
- struct rule *rules;
-
- size_t sz_groups;
- size_t num_groups;
- struct group *groups;
+ darray(struct rule) rules;
+ darray(struct group) groups;
};
/***====================================================================***/
* mapping->map[3] = {.word = SYMBOLS, .index = 0}
*/
static void
-match_mapping_line(struct input_line *line, struct mapping *mapping)
+match_mapping_line(darray_char *line, struct mapping *mapping)
{
char *tok;
- char *str = &line->line[1];
+ char *str = darray_mem(*line, 1);
unsigned present = 0, layout_ndx_present = 0, variant_ndx_present = 0;
int i, tmp;
size_t len;
return;
}
- if (((present & COMPONENT_MASK) & (1 << KEYMAP)) &&
- ((present & COMPONENT_MASK) != (1 << KEYMAP))) {
- WARN("Keymap cannot appear with other components\n");
- ACTION("Illegal mapping ignored\n");
- mapping->num_maps = 0;
- return;
- }
-
mapping->number++;
}
* ! $pcmodels = pc101 pc102 pc104 pc105
*/
static bool
-match_group_line(struct input_line *line, struct group *group)
+match_group_line(darray_char *line, struct group *group)
{
int i;
- char *name = strchr(line->line, '$');
+ char *name = strchr(darray_mem(*line, 0), '$');
char *words = strchr(name, ' ');
if (!words)
/* Match lines following a mapping (see match_mapping_line comment). */
static bool
-match_rule_line(struct input_line *line, struct mapping *mapping,
+match_rule_line(darray_char *line, struct mapping *mapping,
struct rule *rule)
{
char *str, *tok;
return false;
}
- str = line->line;
+ str = darray_mem(*line, 0);
for (nread = 0; (tok = strtok_r(str, " ", &strtok_buf)) != NULL; nread++) {
str = NULL;
}
if (nread < mapping->num_maps) {
- WARN("Too few words on a line: %s\n", line->line);
+ WARN("Too few words on a line: %s\n", darray_mem(*line, 0));
ACTION("line ignored\n");
return false;
}
rule->symbols = uDupString(names[SYMBOLS]);
rule->types = uDupString(names[TYPES]);
rule->compat = uDupString(names[COMPAT]);
- rule->keymap = uDupString(names[KEYMAP]);
rule->layout_num = rule->variant_num = 0;
for (i = 0; i < nread; i++) {
}
static bool
-match_line(struct input_line *line, struct mapping *mapping,
+match_line(darray_char *line, struct mapping *mapping,
struct rule *rule, struct group *group)
{
- if (line->line[0] != '!')
+ if (darray_item(*line, 0) != '!')
return match_rule_line(line, mapping, rule);
- if (line->line[1] == '$' || (line->line[1] == ' ' && line->line[2] == '$'))
+ if (darray_item(*line, 1) == '$' ||
+ (darray_item(*line, 1) == ' ' && darray_item(*line, 2) == '$'))
return match_group_line(line, group);
match_mapping_line(line, mapping);
}
/*
- * Expand the layout and variant of a var_defs and remove extraneous spaces.
- * If there's one layout/variant, it is kept in .layout[0]/.variant[0], else
- * is kept in [1], [2] and so on, and [0] remains empty.
- * For example, this var_defs:
+ * Expand the layout and variant of the rule_names and remove extraneous
+ * spaces. If there's one layout/variant, it is kept in
+ * .layout[0]/.variant[0], else is kept in [1], [2] and so on, and [0]
+ * remains empty. For example, this rule_names:
* .model = "pc105",
* .layout = "us,il,ru,ca"
* .variant = ",,,multix"
* .options = "grp:alts_toggle,ctrl:nocaps,compose:rwin"
*/
static bool
-make_multi_defs(struct multi_defs *mdefs, struct var_defs *defs)
+make_multi_defs(struct multi_defs *mdefs, const struct xkb_rule_names *mlvo)
{
char *p;
int i;
memset(mdefs, 0, sizeof(*mdefs));
- if (defs->model) {
- mdefs->model = defs->model;
+ if (mlvo->model) {
+ mdefs->model = mlvo->model;
}
- if (defs->options) {
- mdefs->options = strdup(defs->options);
+ if (mlvo->options) {
+ mdefs->options = strdup(mlvo->options);
if (mdefs->options == NULL)
return false;
squeeze_spaces(mdefs->options);
}
- if (defs->layout) {
- if (!strchr(defs->layout, ',')) {
- mdefs->layout[0] = defs->layout;
+ if (mlvo->layout) {
+ if (!strchr(mlvo->layout, ',')) {
+ mdefs->layout[0] = mlvo->layout;
}
else {
- p = strdup(defs->layout);
+ p = strdup(mlvo->layout);
if (p == NULL)
return false;
}
}
- if (defs->variant) {
- if (!strchr(defs->variant, ',')) {
- mdefs->variant[0] = defs->variant;
+ if (mlvo->variant) {
+ if (!strchr(mlvo->variant, ',')) {
+ mdefs->variant[0] = mlvo->variant;
}
else {
- p = strdup(defs->variant);
+ p = strdup(mlvo->variant);
if (p == NULL)
return false;
apply(rule->symbols, &kccgst->symbols);
apply(rule->types, &kccgst->types);
apply(rule->compat, &kccgst->compat);
- apply(rule->keymap, &kccgst->keymap);
}
/*
{
int i;
const char *word;
- struct group *group;
+ struct group *iter, *group = NULL;
- for (i = 0; i < rules->num_groups; i++)
- if (strcmp(rules->groups[i].name, group_name) == 0)
+ darray_foreach(iter, rules->groups) {
+ if (strcmp(iter->name, group_name) == 0) {
+ group = iter;
break;
+ }
+ }
- if (i == rules->num_groups)
+ if (!group)
return false;
- group = &rules->groups[i];
word = group->words;
for (i = 0; i < group->number; i++, word += strlen(word) + 1)
static bool
match_one_of(const char *haystack, const char *needle, char sep)
{
- const char *s = strstr(haystack, needle);
+ const char *s = haystack;
+ const size_t len = strlen(needle);
- if (s == NULL)
- return false;
-
- if (s != haystack && *s != sep)
- return false;
-
- s += strlen(needle);
- if (*s != '\0' && *s != sep)
- return false;
+ do {
+ if (strncmp(s, needle, len) == 0 && (s[len] == '\0' || s[len] == sep))
+ return true;
+ s = strchr(s, sep);
+ } while (s++);
- return true;
+ return false;
}
static int
}
if (rule->layout) {
- if (mdefs->layout[rule->layout_num] == NULL ||
- *mdefs->layout[rule->layout_num] == '\0')
+ if (mdefs->layout[rule->layout_num] == NULL)
return 0;
if (strcmp(rule->layout, "*") == 0) {
}
if (rule->variant) {
- if (mdefs->variant[rule->variant_num] == NULL ||
- *mdefs->variant[rule->variant_num] == '\0')
+ if (mdefs->variant[rule->variant_num] == NULL)
return 0;
if (strcmp(rule->variant, "*") == 0) {
static void
clear_partial_matches(struct rules *rules)
{
- int i;
+ struct rule *rule;
- for (i = 0; i < rules->num_rules; i++)
- rules->rules[i].flags &= ~RULE_FLAG_PENDING_MATCH;
+ darray_foreach(rule, rules->rules)
+ rule->flags &= ~RULE_FLAG_PENDING_MATCH;
}
static void
apply_partial_matches(struct rules *rules, struct xkb_component_names *kccgst)
{
- int i;
+ struct rule *rule;
- for (i = 0; i < rules->num_rules; i++)
- if (rules->rules[i].flags & RULE_FLAG_PENDING_MATCH)
- apply_rule(&rules->rules[i], kccgst);
+ darray_foreach(rule, rules->rules)
+ if (rule->flags & RULE_FLAG_PENDING_MATCH)
+ apply_rule(rule, kccgst);
}
static void
apply_matching_rules(struct rules *rules, struct multi_defs *mdefs,
struct xkb_component_names *kccgst, unsigned int flags)
{
- int i;
int skip = -1;
struct rule *rule;
- for (i = 0; i < rules->num_rules; i++) {
- rule = &rules->rules[i];
-
+ darray_foreach(rule, rules->rules) {
if ((rule->flags & flags) != flags)
continue;
/***====================================================================***/
static bool
-get_components(struct rules *rules, struct var_defs *defs,
+get_components(struct rules *rules, const struct xkb_rule_names *mlvo,
struct xkb_component_names *kccgst)
{
struct multi_defs mdefs;
- make_multi_defs(&mdefs, defs);
+ make_multi_defs(&mdefs, mlvo);
clear_partial_matches(rules);
kccgst->symbols = substitute_vars(kccgst->symbols, &mdefs);
kccgst->types = substitute_vars(kccgst->types, &mdefs);
kccgst->compat = substitute_vars(kccgst->compat, &mdefs);
- kccgst->keymap = substitute_vars(kccgst->keymap, &mdefs);
free_multi_defs(&mdefs);
- return (kccgst->keycodes && kccgst->symbols && kccgst->types &&
- kccgst->compat) || kccgst->keymap;
-}
-
-static struct rule *
-XkbcRF_AddRule(struct rules *rules)
-{
- if (rules->sz_rules<1) {
- rules->sz_rules= 16;
- rules->num_rules= 0;
- rules->rules = calloc(rules->sz_rules, sizeof(*rules->rules));
- }
- else if (rules->num_rules>=rules->sz_rules) {
- rules->sz_rules*= 2;
- rules->rules = realloc(rules->rules,
- rules->sz_rules * sizeof(*rules->rules));
- }
- if (!rules->rules) {
- rules->sz_rules= rules->num_rules= 0;
- return NULL;
- }
- memset(&rules->rules[rules->num_rules], 0, sizeof(*rules->rules));
- return &rules->rules[rules->num_rules++];
-}
-
-static struct group *
-XkbcRF_AddGroup(struct rules *rules)
-{
- if (rules->sz_groups<1) {
- rules->sz_groups= 16;
- rules->num_groups= 0;
- rules->groups = calloc(rules->sz_groups, sizeof(*rules->groups));
- }
- else if (rules->num_groups >= rules->sz_groups) {
- rules->sz_groups *= 2;
- rules->groups = realloc(rules->groups,
- rules->sz_groups * sizeof(*rules->groups));
- }
- if (!rules->groups) {
- rules->sz_groups= rules->num_groups= 0;
- return NULL;
- }
-
- memset(&rules->groups[rules->num_groups], 0, sizeof(*rules->groups));
- return &rules->groups[rules->num_groups++];
+ return
+ kccgst->keycodes && kccgst->symbols && kccgst->types && kccgst->compat;
}
static struct rules *
-XkbcRF_LoadRules(FILE *file)
+load_rules(FILE *file)
{
- struct input_line line;
+ darray_char line;
struct mapping mapping;
- struct rule trule, *rule;
- struct group tgroup, *group;
+ struct rule trule;
+ struct group tgroup;
struct rules *rules;
rules = calloc(1, sizeof(*rules));
if (!rules)
return NULL;
+ darray_init(rules->rules);
+ darray_growalloc(rules->rules, 16);
memset(&mapping, 0, sizeof(mapping));
memset(&tgroup, 0, sizeof(tgroup));
- input_line_init(&line);
+ darray_init(line);
+ darray_growalloc(line, 128);
while (input_line_get(file, &line)) {
if (match_line(&line, &mapping, &trule, &tgroup)) {
if (tgroup.number) {
- if ((group= XkbcRF_AddGroup(rules))!=NULL) {
- *group= tgroup;
- memset(&tgroup, 0, sizeof(tgroup));
- }
- } else {
- if ((rule= XkbcRF_AddRule(rules))!=NULL) {
- *rule= trule;
- memset(&trule, 0, sizeof(trule));
- }
- }
- }
- line.offset = 0;
- }
- input_line_deinit(&line);
- return rules;
-}
-
-static void
-XkbRF_ClearVarDescriptions(struct describe_vars *var)
-{
- int i;
+ darray_append(rules->groups, tgroup);
+ memset(&tgroup, 0, sizeof(tgroup));
+ } else {
+ darray_append(rules->rules, trule);
+ memset(&trule, 0, sizeof(trule));
+ }
+ }
- for (i=0;i<var->num_desc;i++) {
- free(var->desc[i].name);
- free(var->desc[i].desc);
- var->desc[i].name= var->desc[i].desc= NULL;
+ darray_resize(line, 0);
}
- free(var->desc);
- var->desc= NULL;
+
+ darray_free(line);
+ return rules;
}
static void
-XkbcRF_Free(struct rules *rules)
+free_rules(struct rules *rules)
{
- int i;
struct rule *rule;
struct group *group;
if (!rules)
- return;
- XkbRF_ClearVarDescriptions(&rules->models);
- XkbRF_ClearVarDescriptions(&rules->layouts);
- XkbRF_ClearVarDescriptions(&rules->variants);
- XkbRF_ClearVarDescriptions(&rules->options);
+ return;
- for (i=0, rule = rules->rules; i < rules->num_rules && rules; i++, rule++) {
+ darray_foreach(rule, rules->rules) {
free(rule->model);
free(rule->layout);
free(rule->variant);
free(rule->symbols);
free(rule->types);
free(rule->compat);
- free(rule->keymap);
}
- free(rules->rules);
+ darray_free(rules->rules);
- for (i=0, group = rules->groups; i < rules->num_groups && group; i++, group++) {
+ darray_foreach(group, rules->groups) {
free(group->name);
free(group->words);
}
- free(rules->groups);
+ darray_free(rules->groups);
free(rules);
}
const struct xkb_rule_names *rmlvo)
{
int i;
- FILE *rulesFile;
- char *rulesPath;
- struct rules *loaded;
- struct xkb_component_names *names = NULL;
- struct var_defs defs = {
- .model = rmlvo->model,
- .layout = rmlvo->layout,
- .variant = rmlvo->variant,
- .options = rmlvo->options,
- };
-
- rulesFile = XkbFindFileInPath(ctx, rmlvo->rules, XkmRulesFile,
- &rulesPath);
- if (!rulesFile) {
+ FILE *file;
+ char *path;
+ struct rules *rules;
+ struct xkb_component_names *kccgst = NULL;
+
+ file = XkbFindFileInPath(ctx, rmlvo->rules, FILE_TYPE_RULES, &path);
+ if (!file) {
ERROR("could not find \"%s\" rules in XKB path\n", rmlvo->rules);
ERROR("%d include paths searched:\n",
xkb_context_num_include_paths(ctx));
return NULL;
}
- loaded = XkbcRF_LoadRules(rulesFile);
- if (!loaded) {
- ERROR("failed to load XKB rules \"%s\"\n", rulesPath);
- goto unwind_file;
+ rules = load_rules(file);
+ if (!rules) {
+ ERROR("failed to load XKB rules \"%s\"\n", path);
+ goto err;
}
- names = calloc(1, sizeof(*names));
- if (!names) {
+ kccgst = calloc(1, sizeof(*kccgst));
+ if (!kccgst) {
ERROR("failed to allocate XKB components\n");
- goto unwind_file;
+ goto err;
}
- if (!get_components(loaded, &defs, names)) {
- free(names->keymap);
- free(names->keycodes);
- free(names->types);
- free(names->compat);
- free(names->symbols);
- free(names);
- names = NULL;
- ERROR("no components returned from XKB rules \"%s\"\n", rulesPath);
+ if (!get_components(rules, rmlvo, kccgst)) {
+ free(kccgst->keycodes);
+ free(kccgst->types);
+ free(kccgst->compat);
+ free(kccgst->symbols);
+ free(kccgst);
+ kccgst = NULL;
+ ERROR("no components returned from XKB rules \"%s\"\n", path);
+ goto err;
}
-unwind_file:
- XkbcRF_Free(loaded);
- if (rulesFile)
- fclose(rulesFile);
- free(rulesPath);
- return names;
+err:
+ free_rules(rules);
+ if (file)
+ fclose(file);
+ free(path);
+ return kccgst;
}