4 * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files
8 * (the "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 * Implementation of the configuration parsers.
40 #include <xkbcommon/xkbcommon.h>
45 #define LOG_SUBSYSTEM "config"
52 struct conf_option *opts;
57 int conf_ctx_new(struct conf_ctx **out, const struct conf_option *opts,
58 size_t onum, void *mem)
63 if (!out || !opts || !onum)
66 size = sizeof(*ctx) + onum * sizeof(*opts);
69 log_error("cannot allocate memory for config context");
73 ctx->opts = (void*)((char*)ctx + sizeof(*ctx));
76 memcpy(ctx->opts, opts, onum * sizeof(*opts));
84 void conf_ctx_free(struct conf_ctx *ctx)
93 void conf_ctx_reset(struct conf_ctx *ctx)
100 for (i = 0; i < ctx->onum; ++i) {
101 if (ctx->opts[i].type->free)
102 ctx->opts[i].type->free(&ctx->opts[i]);
103 ctx->opts[i].flags = 0;
104 if (ctx->opts[i].type->set_default)
105 ctx->opts[i].type->set_default(&ctx->opts[i]);
109 void *conf_ctx_get_mem(struct conf_ctx *ctx)
118 * Copy all entries from \src into \ctx
119 * This calls the "copy" callback for each option inside of \ctx with the
120 * corresponding option inside of \src if both have the same type. If the types
121 * do not match, nothing is done.
123 int conf_ctx_parse_ctx(struct conf_ctx *ctx, const struct conf_ctx *src)
126 struct conf_option *d, *s;
132 for (i = 0; i < ctx->onum && i < src->onum; ++i) {
136 if (d->type != s->type)
138 if (d->flags & CONF_LOCKED)
141 if (s->flags & CONF_LOCKED)
142 d->flags |= CONF_LOCKED;
145 ret = d->type->copy(d, s);
161 * Parse command line arguments
162 * This temporarily allocates the short_options and long_options arrays so we
163 * can use the getopt_long() library call. It locks all arguments after they
164 * have been set so command-line options will always overwrite config-options.
166 int conf_ctx_parse_argv(struct conf_ctx *ctx, int argc, char **argv)
169 struct option *long_options;
171 struct conf_option *o;
178 short_options = malloc(sizeof(char) * (ctx->onum + 1) * 2);
179 if (!short_options) {
180 log_error("out of memory to parse cmd-line arguments (%d): %m",
185 long_options = malloc(sizeof(struct option) * ctx->onum * 2);
187 log_error("out of memory to parse cmd-line arguments (%d): %m",
194 short_options[pos++] = ':';
196 for (i = 0; i < ctx->onum; ++i) {
197 if (ctx->opts[i].short_name) {
198 short_options[pos++] = ctx->opts[i].short_name;
199 if (ctx->opts[i].type->flags & CONF_HAS_ARG)
200 short_options[pos++] = ':';
203 if (ctx->opts[i].long_name) {
204 /* skip the "no-" prefix */
205 opt->name = &ctx->opts[i].long_name[3];
206 opt->has_arg = !!(ctx->opts[i].type->flags &
209 opt->val = 100000 + i;
212 /* boolean args are also added with "no-" prefix */
213 if (!(ctx->opts[i].type->flags & CONF_HAS_ARG)) {
214 opt->name = ctx->opts[i].long_name;
217 opt->val = 200000 + i;
222 short_options[pos++] = 0;
226 c = getopt_long(argc, argv, short_options,
230 } else if (c == ':') {
231 fprintf(stderr, "Missing argument for: %s\n",
234 } else if (c == '?') {
235 if (optopt && optopt < 100000)
236 fprintf(stderr, "Unknown argument: -%c\n",
239 fprintf(stderr, "Unknown argument: %s\n",
242 fprintf(stderr, "Option takes no arg: %s\n",
245 } else if (c < 100000) {
246 for (i = 0; i < ctx->onum; ++i) {
249 if (o->short_name != c)
252 if (o->type->parse) {
253 ret = o->type->parse(o, true, optarg);
258 o->flags |= CONF_LOCKED;
259 o->flags |= CONF_DONE;
262 } else if (c < 200000) {
266 if (o->type->parse) {
267 ret = o->type->parse(o, true, optarg);
272 o->flags |= CONF_LOCKED;
273 o->flags |= CONF_DONE;
278 if (o->type->parse) {
279 ret = o->type->parse(o, false, NULL);
284 o->flags |= CONF_LOCKED;
285 o->flags |= CONF_DONE;
292 /* Perform aftercheck:
293 * All arguments that provide an aftercheck will be passed the remaining
294 * arguments in order. If they return a negative error code, it is
295 * interpreted as fatal error and returned to the caller. A positive
296 * error code is interpreted as the amount of remaining arguments that
297 * have been consumed by this aftercheck. 0 means nothing has been
299 * The next argument's aftercheck will only get the now remaning
300 * arguments passed in. If not all arguments are consumed, then this
301 * function will report an error to the caller. */
302 for (i = 0; i < ctx->onum; ++i) {
305 ret = o->aftercheck(o, argc, argv, optind);
313 fprintf(stderr, "Unparsed remaining args starting with: %s\n",
321 static int parse_kv_pair(struct conf_option *opts, size_t len,
322 const char *key, const char *value)
327 struct conf_option *opt;
329 for (i = 0; i < len; ++i) {
334 if (!strcmp(key, opt->long_name))
336 else if (!strcmp(key, &opt->long_name[3]))
341 /* ignore if already set by command-line arguments */
342 if (opt->flags & CONF_LOCKED)
346 ret = opt->file(opt, set, value);
349 opt->flags |= CONF_DONE;
353 if (opt->type->flags & CONF_HAS_ARG && !value) {
354 log_error("config option '%s' requires an argument",
357 } else if (!(opt->type->flags & CONF_HAS_ARG) && value) {
358 log_error("config option '%s' does not take arguments",
363 if (opt->type->parse) {
364 ret = opt->type->parse(opt, set, value);
369 opt->flags |= CONF_DONE;
373 log_error("unknown config option '%s'", key);
377 static void strip_spaces(char **buf)
381 while (**buf == ' ' || **buf == '\r' || **buf == '\t')
393 while (*tail == ' ' || *tail == '\r' || *tail == '\t')
397 static int parse_line(struct conf_option *opts, size_t olen,
398 char **buf, size_t *size)
425 } else if (*line == '\n') {
428 } else if (*line == '#') {
431 } else if (*line != '=') {
452 } else if (*line == '\n') {
455 } else if (*line == '#') {
477 strip_spaces(&value);
479 ret = parse_kv_pair(opts, olen, key, value);
495 static int parse_buffer(struct conf_option *opts, size_t len,
496 char *buf, size_t size)
499 struct conf_option *o;
502 while (!ret && size > 0)
503 ret = parse_line(opts, len, &buf, &size);
508 for (i = 0; i < len; ++i) {
511 ret = o->aftercheck(o, 0, NULL, 0);
520 /* chunk size when reading config files */
521 #define CONF_BUFSIZE 4096
523 /* This reads the file at \path in memory and parses it as if it was given as
524 * command line options. */
525 static int conf_parse_file(struct conf_option *opts, size_t len,
532 if (!opts || !len || !path)
535 if (access(path, F_OK))
538 if (access(path, R_OK)) {
539 log_error("read access to config file %s denied", path);
543 log_info("reading config file %s", path);
544 fd = open(path, O_RDONLY | O_CLOEXEC | O_NOCTTY);
546 log_error("cannot open %s (%d): %m", path, errno);
555 if (size - pos < CONF_BUFSIZE) {
556 tmp = realloc(buf, size + CONF_BUFSIZE + 1);
558 log_error("cannot allocate enough memory to parse config file %s (%d): %m",
564 size += CONF_BUFSIZE;
567 ret = read(fd, &buf[pos], CONF_BUFSIZE);
569 log_error("cannot read from config file %s (%d): %m",
578 ret = parse_buffer(opts, len, buf, pos);
586 int conf_ctx_parse_file(struct conf_ctx *ctx, const char *format, ...)
595 va_start(list, format);
596 ret = vasprintf(&path, format, list);
600 log_error("cannot allocate memory for config-file path");
604 ret = conf_parse_file(ctx->opts, ctx->onum, path);
611 * Each option that can be parsed must be a specific config-type. A config-type
612 * is used to parse, free and reset the value. It must implement the following
614 * set_default: This should link opt->mem to opt->def and must not fail. It is
615 * called during initialization and reset.
616 * free: This should free any allocated memory and reset the option to the
617 * initial state. It must not fail.
618 * parse: This should parse a command-line option. Return 0 on success.
619 * copy: Copy data from source into destination. Return 0 on success.
621 * The backing memory is zeroed on reset so a config-type must be able to handle
622 * this as "not set". Also, the "free" callback should reset it to zero (which
623 * is the initial state).
626 /* Miscellaneous helper */
628 static void conf_free_value(struct conf_option *opt)
630 if (*(void**)opt->mem) {
631 if (*(void**)opt->mem != opt->def)
632 free(*(void**)opt->mem);
633 *(void**)opt->mem = NULL;
639 static void conf_default_bool(struct conf_option *opt)
641 *(bool*)opt->mem = (bool)opt->def;
644 static void conf_free_bool(struct conf_option *opt)
646 *(bool*)opt->mem = false;
649 static int conf_parse_bool(struct conf_option *opt, bool on, const char *arg)
651 *(bool*)opt->mem = on;
655 static int conf_copy_bool(struct conf_option *opt,
656 const struct conf_option *src)
658 *(bool*)opt->mem = *(bool*)src->mem;
662 const struct conf_type conf_bool = {
664 .set_default = conf_default_bool,
665 .free = conf_free_bool,
666 .parse = conf_parse_bool,
667 .copy = conf_copy_bool,
672 static int conf_parse_int(struct conf_option *opt, bool on, const char *arg)
674 *(int*)opt->mem = atoi(arg);
678 static void conf_free_int(struct conf_option *opt)
683 static void conf_default_int(struct conf_option *opt)
685 *(int*)opt->mem = (int)(unsigned long)opt->def;
688 static int conf_copy_int(struct conf_option *opt,
689 const struct conf_option *src)
691 *(int*)opt->mem = *(int*)src->mem;
695 const struct conf_type conf_int = {
696 .flags = CONF_HAS_ARG,
697 .set_default = conf_default_int,
698 .free = conf_free_int,
699 .parse = conf_parse_int,
700 .copy = conf_copy_int,
703 /* Unsigned Int Option */
705 static void conf_default_uint(struct conf_option *opt)
707 *(unsigned int*)opt->mem = (unsigned int)(unsigned long)opt->def;
710 static void conf_free_uint(struct conf_option *opt)
712 *(unsigned int*)opt->mem = 0;
715 static int conf_parse_uint(struct conf_option *opt, bool on, const char *arg)
717 *(unsigned int*)opt->mem = atoi(arg);
721 static int conf_copy_uint(struct conf_option *opt,
722 const struct conf_option *src)
724 *(unsigned int*)opt->mem = *(unsigned int*)src->mem;
728 const struct conf_type conf_uint = {
729 .flags = CONF_HAS_ARG,
730 .set_default = conf_default_uint,
731 .free = conf_free_uint,
732 .parse = conf_parse_uint,
733 .copy = conf_copy_uint,
738 static void conf_default_string(struct conf_option *opt)
740 opt->type->free(opt);
741 *(void**)opt->mem = opt->def;
744 static int conf_parse_string(struct conf_option *opt, bool on, const char *arg)
746 char *val = strdup(arg);
750 opt->type->free(opt);
751 *(void**)opt->mem = val;
755 static int conf_copy_string(struct conf_option *opt,
756 const struct conf_option *src)
760 if (!*(void**)src->mem) {
763 val = strdup(*(void**)src->mem);
768 opt->type->free(opt);
769 *(void**)opt->mem = val;
773 const struct conf_type conf_string = {
774 .flags = CONF_HAS_ARG,
775 .set_default = conf_default_string,
776 .free = conf_free_value,
777 .parse = conf_parse_string,
778 .copy = conf_copy_string,
781 /* Stringlist Option */
783 static void conf_default_string_list(struct conf_option *opt)
785 opt->type->free(opt);
786 *(void**)opt->mem = opt->def;
789 static int conf_parse_string_list(struct conf_option *opt, bool on,
795 ret = shl_split_string(arg, &list, NULL, ',', true);
799 opt->type->free(opt);
800 *(char***)opt->mem = list;
804 static int conf_copy_string_list(struct conf_option *opt,
805 const struct conf_option *src)
810 if (!(void***)src->mem) {
813 ret = shl_dup_array(&t, *(char***)src->mem);
818 opt->type->free(opt);
819 *(char***)opt->mem = t;
823 const struct conf_type conf_string_list = {
824 .flags = CONF_HAS_ARG,
825 .set_default = conf_default_string_list,
826 .free = conf_free_value,
827 .parse = conf_parse_string_list,
828 .copy = conf_copy_string_list,
833 static void conf_default_grab(struct conf_option *opt)
835 opt->type->free(opt);
836 *(void**)opt->mem = opt->def;
839 static void conf_free_grab(struct conf_option *opt)
841 struct conf_grab *grab;
844 grab = *(void**)opt->mem;
845 *(void**)opt->mem = NULL;
847 if (!grab || grab == opt->def)
850 for (i = 0; i < grab->num; ++i)
851 free(grab->keysyms[i]);
854 free(grab->num_syms);
859 static int parse_single_grab(char *arg, unsigned int *mods,
860 uint32_t *keysym, bool allow_mods)
862 char *tmp, *start, *end;
875 while (*tmp && *tmp != '>')
879 log_error("missing '>' near '%s'", start);
885 if (!strcasecmp(start, "shift")) {
886 *mods |= SHL_SHIFT_MASK;
887 } else if (!strcasecmp(start, "lock")) {
888 *mods |= SHL_LOCK_MASK;
889 } else if (!strcasecmp(start, "control") ||
890 !strcasecmp(start, "ctrl")) {
891 *mods |= SHL_CONTROL_MASK;
892 } else if (!strcasecmp(start, "alt")) {
893 *mods |= SHL_ALT_MASK;
894 } else if (!strcasecmp(start, "logo")) {
895 *mods |= SHL_LOGO_MASK;
897 log_error("invalid modifier '%s'", start);
908 while (*tmp && *tmp != ' ')
922 *keysym = xkb_keysym_from_name(start, 0);
924 *keysym = xkb_keysym_from_name(start,
925 XKB_KEYSYM_CASE_INSENSITIVE);
927 log_error("invalid key '%s'", start);
931 xkb_keysym_get_name(*keysym, buf, sizeof(buf));
932 log_warning("invalid keysym '%s', did you mean '%s'? (keysyms are case-sensitive)",
940 static int conf_parse_grab(struct conf_option *opt, bool on, const char *arg)
943 unsigned int list_num, key_num, i, j, k, l;
945 struct conf_grab *grab;
947 ret = shl_split_string(arg, &list, &list_num, ',', false);
951 grab = malloc(sizeof(*grab));
956 memset(grab, 0, sizeof(*grab));
959 grab->mods = malloc(sizeof(*grab->mods) * list_num);
964 memset(grab->mods, 0, sizeof(*grab->mods) * list_num);
966 grab->num_syms = malloc(sizeof(*grab->num_syms) * list_num);
967 if (!grab->num_syms) {
971 memset(grab->num_syms, 0, sizeof(*grab->num_syms) * list_num);
973 grab->keysyms = malloc(sizeof(*grab->keysyms) * list_num);
974 if (!grab->keysyms) {
978 memset(grab->keysyms, 0, sizeof(*grab->keysyms) * list_num);
982 for (i = 0; i < list_num; ++i) {
983 ret = shl_split_string(list[i], &keys, &key_num, '+', false);
991 grab->keysyms[l] = malloc(sizeof(*grab->keysyms[l]) * key_num);
992 if (!grab->keysyms[l]) {
999 for (j = 0; j < key_num; ++j) {
1000 ret = parse_single_grab(keys[j], &grab->mods[l],
1001 &grab->keysyms[l][k],
1004 log_error("cannot parse grab '%s' in '%s'",
1015 grab->num_syms[l] = k;
1021 opt->type->free(opt);
1022 *(void**)opt->mem = grab;
1026 for (i = 0; i < list_num; ++i)
1027 free(grab->keysyms[i]);
1029 free(grab->keysyms);
1030 free(grab->num_syms);
1038 static int conf_copy_grab(struct conf_option *opt,
1039 const struct conf_option *src)
1041 struct conf_grab *grab, *s;
1045 s = *(void**)src->mem;
1048 opt->type->free(opt);
1049 *(void**)opt->mem = NULL;
1053 grab = malloc(sizeof(*grab));
1056 memset(grab, 0, sizeof(*grab));
1060 grab->mods = malloc(sizeof(*grab->mods) * grab->num);
1065 memcpy(grab->mods, s->mods, sizeof(*grab->mods) * grab->num);
1067 grab->num_syms = malloc(sizeof(*grab->num_syms) * grab->num);
1068 if (!grab->num_syms) {
1072 memcpy(grab->num_syms, s->num_syms,
1073 sizeof(*grab->num_syms) * grab->num);
1075 grab->keysyms = malloc(sizeof(*grab->keysyms) * grab->num);
1076 if (!grab->keysyms) {
1080 memset(grab->keysyms, 0, sizeof(*grab->keysyms) * grab->num);
1083 for (i = 0; i < grab->num; ++i) {
1084 grab->keysyms[i] = malloc(sizeof(*s->keysyms[i]) *
1086 if (!grab->keysyms[i]) {
1090 memcpy(grab->keysyms[i], s->keysyms[i],
1091 sizeof(*s->keysyms[i]) * s->num_syms[i]);
1094 opt->type->free(opt);
1095 *(void**)opt->mem = grab;
1099 for (i = 0; i < grab->num; ++i)
1100 free(grab->keysyms[i]);
1102 free(grab->keysyms);
1103 free(grab->num_syms);
1109 const struct conf_type conf_grab = {
1110 .flags = CONF_HAS_ARG,
1111 .set_default = conf_default_grab,
1112 .free = conf_free_grab,
1113 .parse = conf_parse_grab,
1114 .copy = conf_copy_grab,