7 #include <xkbcommon/xkbcommon.h>
9 static char **log_buffer
= NULL
;
10 static int log_buffer_size
= 0;
11 static bool log_alloc_success
= true;
13 static void add_log(struct xkb_context
*ctx
, enum xkb_log_level level
,
14 const char *fmt
, va_list args
)
21 if (log_buffer
== NULL
)
22 log_buffer
= malloc(sizeof(char *));
24 log_buffer
= realloc(log_buffer
, sizeof(char *) * log_buffer_size
);
26 if (log_buffer
== NULL
) {
27 perror("buffer alloc");
28 log_alloc_success
= false;
33 /* Unfortunately, vasprintf() is a GNU extension and thus not very
34 * portable, so let's first get the required buffer size using a dummy
35 * vsnprintf and afterwards allocate the returned amount of bytes.
37 * We also need to make a copy of the args, because the value of the args
38 * will be indeterminate after the return.
40 va_copy(tmpargs
, args
);
41 buflen
= vsnprintf(NULL
, 0, fmt
, tmpargs
);
44 log_buffer
[log_buffer_size
- 1] = malloc(++buflen
);
46 if (vsnprintf(log_buffer
[log_buffer_size
- 1], buflen
, fmt
, args
) == -1) {
47 perror("log line alloc");
48 log_alloc_success
= false;
53 static void print_logs(void)
55 for (int i
= 0; i
< log_buffer_size
; ++i
)
56 fprintf(stderr
, " %s", log_buffer
[i
]);
59 static void free_logs(void)
61 if (log_buffer
== NULL
)
63 for (int i
= 0; i
< log_buffer_size
; ++i
)
70 static bool try_keymap(struct xkb_context
*ctx
, struct xkb_rule_names
*rdef
)
72 struct xkb_keymap
*keymap
;
75 if ((keymap
= xkb_keymap_new_from_names(ctx
, rdef
, 0)) == NULL
)
78 xkb_keymap_unref(keymap
);
83 static void print_error(const char *name
, const char *value
,
84 const char *nixos_option
)
86 fprintf(stderr
, "\nThe value `%s' for keyboard %s is invalid.\n\n"
87 "Please check the definition in `services.xserver.%s'.\n",
88 value
, name
, nixos_option
);
89 fputs("\nDetailed XKB compiler errors:\n\n", stderr
);
94 #define TRY_KEYMAP(name, value, nixos_option) \
95 *rdef = (struct xkb_rule_names) {0}; \
98 result = try_keymap(ctx, rdef); \
99 if (!log_alloc_success) \
102 print_error(#name, value, nixos_option); \
103 exit_code = EXIT_FAILURE; \
107 int main(int argc
, char **argv
)
109 int exit_code
= EXIT_SUCCESS
;
111 struct xkb_context
*ctx
;
112 struct xkb_rule_names
*rdef
;
115 fprintf(stderr
, "Usage: %s model layout variant options\n", argv
[0]);
119 ctx
= xkb_context_new(XKB_CONTEXT_NO_ENVIRONMENT_NAMES
);
120 xkb_context_set_log_fn(ctx
, add_log
);
122 rdef
= malloc(sizeof(struct xkb_rule_names
));
124 TRY_KEYMAP(model
, argv
[1], "xkb.model");
125 TRY_KEYMAP(layout
, argv
[2], "xkb.layout");
126 TRY_KEYMAP(variant
, argv
[3], "xkb.variant");
127 TRY_KEYMAP(options
, argv
[4], "xkb.options");
130 rdef
->model
= argv
[1];
131 rdef
->layout
= argv
[2];
132 rdef
->variant
= argv
[3];
133 rdef
->options
= argv
[4];
135 result
= try_keymap(ctx
, rdef
);
136 if (!log_alloc_success
)
140 fputs("The XKB keyboard definition failed to compile:\n", stderr
);
142 exit_code
= EXIT_FAILURE
;
148 xkb_context_unref(ctx
);