enlightenment/src/modules/xkbswitch/e_mod_parse.c

334 lines
7.8 KiB
C

#include "e.h"
#include "e_mod_parse.h"
Eina_List *layouts = NULL;
Eina_List *models = NULL;
Eina_List *optgroups = NULL;
static const char *rules_file = NULL;
void
find_rules(void)
{
int i = 0;
const char *lstfiles[] = {
"/usr/share/X11/xkb/rules/xorg.lst",
"/usr/share/X11/xkb/rules/xfree86.lst",
"/usr/local/share/X11/xkb/rules/xorg.lst",
"/usr/local/share/X11/xkb/rules/xfree86.lst",
"/usr/X11R6/lib/X11/xkb/rules/xorg.lst",
"/usr/X11R6/lib/X11/xkb/rules/xfree86.lst",
"/usr/local/X11R6/lib/X11/xkb/rules/xorg.lst",
"/usr/local/X11R6/lib/X11/xkb/rules/xfree86.lst",
NULL
};
for (; lstfiles[i]; i++)
{
FILE *f = fopen(lstfiles[i], "r");
if (f)
{
fclose(f);
rules_file = lstfiles[i];
break;
}
}
}
int
parse_rules(void)
{
char buf[4096];
E_XKB_Model *model = NULL;
E_XKB_Layout *layout = NULL;
E_XKB_Option *option = NULL;
E_XKB_Variant *variant = NULL;
E_XKB_Option_Group *group = NULL;
FILE *f;
if (!rules_file) return 0;
layouts = NULL;
models = NULL;
f = fopen(rules_file, "r");
if (!f) return 0;
/* move on to next line, the first one is useless */
if (!fgets(buf, sizeof(buf), f)) goto err;
/* let X decide on this one, also serves as
* "fallback on global" for layout combinations
*/
model = E_NEW(E_XKB_Model, 1);
model->name = eina_stringshare_add("default");
model->description = eina_stringshare_add("Automatic");
models = eina_list_append(models, model);
/* read models here */
for (;;)
{
if (fgets(buf, sizeof(buf), f))
{
char *n;
char *p;
char *tmp;
n = strchr(buf, '\n');
if (n) *n = '\0';
/* means end of section */
if (!buf[0]) break;
/* get rid of initial 2 spaces here */
p = buf + 2;
tmp = strdup(p);
model = E_NEW(E_XKB_Model, 1);
model->name = eina_stringshare_add(strtok(tmp, " "));
free(tmp);
p += strlen(model->name);
while (p[0] == ' ') ++p;
model->description = eina_stringshare_add(p);
models = eina_list_append(models, model);
}
else
break;
}
/* move on again */
if (!fgets(buf, sizeof(buf), f)) goto err;
/* read layouts here */
for (;;)
{
if (fgets(buf, sizeof(buf), f))
{
char *n;
char *p;
char *tmp;
n = strchr(buf, '\n');
if (n) *n = '\0';
if (!buf[0]) break;
p = buf + 2;
tmp = strdup(p);
layout = E_NEW(E_XKB_Layout, 1);
layout->name = eina_stringshare_add(strtok(tmp, " "));
free(tmp);
p += strlen(layout->name);
while (p[0] == ' ') ++p;
variant = E_NEW(E_XKB_Variant, 1);
variant->name = eina_stringshare_add("basic");
variant->description = eina_stringshare_add("Default layout variant");
layout->description = eina_stringshare_add(p);
layout->variants = eina_list_append(layout->variants, variant);
layouts = eina_list_append(layouts, layout);
}
else
break;
}
/* move on again */
if (!fgets(buf, sizeof(buf), f)) goto err;
/* read variants here */
for (;;)
{
if (fgets(buf, sizeof(buf), f))
{
char *n;
char *p;
char *tmp;
char *tok;
n = strchr(buf, '\n');
if (n) *n = '\0';
if (!buf[0]) break;
p = buf + 2;
tmp = strdup(p);
variant = E_NEW(E_XKB_Variant, 1);
variant->name = eina_stringshare_add(strtok(tmp, " "));
tok = strtok(NULL, " ");
*strchr(tok, ':') = '\0';
layout = eina_list_search_unsorted(layouts, layout_sort_by_name_cb, tok);
layout->variants = eina_list_append(layout->variants, variant);
p += strlen(variant->name);
while (p[0] == ' ') ++p;
p += strlen(tok);
p += 2;
free(tmp);
variant->description = eina_stringshare_add(p);
}
else
break;
}
/* move on again */
if (!fgets(buf, sizeof(buf), f)) goto err;
/* read options here */
for (;;)
{
if (fgets(buf, sizeof(buf), f))
{
char *n;
char *p;
char *tmp;
char *name;
n = strchr(buf, '\n');
if (n) *n = '\0';
if (!buf[0]) break;
p = buf + 2;
tmp = strdup(p);
name = strtok(tmp, " ");
p += strlen(name);
while (p[0] == ' ') ++p;
/* skip "grp" options for switching kbd layouts */
//if (strncmp(name, "grp", 3))
{
if (!strchr(name, ':'))
{
group = E_NEW(E_XKB_Option_Group, 1);
/* A hack to get it to parse right if
* the group name contains a space
*/
if (strstr(p, " "))
{
p = strstr(p, " ");
while (p[0] == ' ') ++p;
}
group->description = eina_stringshare_add(p);
optgroups = eina_list_append(optgroups, group);
}
else if (group)
{
option = E_NEW(E_XKB_Option, 1);
option->name = eina_stringshare_add(name);
option->description = eina_stringshare_add(p);
group->options = eina_list_append(group->options,
option);
}
}
free(tmp);
}
else
break;
}
err:
fclose(f);
/* Sort layouts */
layouts =
eina_list_sort(layouts, eina_list_count(layouts), layout_sort_cb);
return 1;
}
void
clear_rules(void)
{
E_XKB_Option_Group *og;
E_XKB_Variant *v;
E_XKB_Option *o;
E_XKB_Layout *la;
E_XKB_Model *m;
EINA_LIST_FREE(layouts, la)
{
eina_stringshare_del(la->name);
eina_stringshare_del(la->description);
EINA_LIST_FREE(la->variants, v)
{
eina_stringshare_del(v->name);
eina_stringshare_del(v->description);
E_FREE(v);
}
E_FREE(la);
}
EINA_LIST_FREE(models, m)
{
eina_stringshare_del(m->name);
eina_stringshare_del(m->description);
E_FREE(m);
}
EINA_LIST_FREE(optgroups, og)
{
eina_stringshare_del(og->description);
EINA_LIST_FREE(og->options, o)
{
eina_stringshare_del(o->name);
eina_stringshare_del(o->description);
E_FREE(o);
}
E_FREE(og);
}
optgroups = NULL;
layouts = NULL;
models = NULL;
}
int
layout_sort_cb(const void *data1, const void *data2)
{
const E_XKB_Layout *l1, *l2;
if (!(l1 = data1)) return 1;
if (!l1->name) return 1;
if (!(l2 = data2)) return -1;
if (!l2->name) return -1;
return strcmp(l1->name, l2->name);
}
int
layout_sort_by_name_cb(const void *data1, const void *data2)
{
const E_XKB_Layout *l1 = NULL;
const char *l2 = NULL;
if (!(l1 = data1)) return 1;
if (!l1->name) return 1;
if (!(l2 = data2)) return -1;
return strcmp(l1->name, l2);
}