1*2b949d04SAndroid Build Coastguard Worker /*
2*2b949d04SAndroid Build Coastguard Worker * Copyright © 2020 Red Hat, Inc.
3*2b949d04SAndroid Build Coastguard Worker *
4*2b949d04SAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a
5*2b949d04SAndroid Build Coastguard Worker * copy of this software and associated documentation files (the "Software"),
6*2b949d04SAndroid Build Coastguard Worker * to deal in the Software without restriction, including without limitation
7*2b949d04SAndroid Build Coastguard Worker * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*2b949d04SAndroid Build Coastguard Worker * and/or sell copies of the Software, and to permit persons to whom the
9*2b949d04SAndroid Build Coastguard Worker * Software is furnished to do so, subject to the following conditions:
10*2b949d04SAndroid Build Coastguard Worker *
11*2b949d04SAndroid Build Coastguard Worker * The above copyright notice and this permission notice (including the next
12*2b949d04SAndroid Build Coastguard Worker * paragraph) shall be included in all copies or substantial portions of the
13*2b949d04SAndroid Build Coastguard Worker * Software.
14*2b949d04SAndroid Build Coastguard Worker *
15*2b949d04SAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*2b949d04SAndroid Build Coastguard Worker * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*2b949d04SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18*2b949d04SAndroid Build Coastguard Worker * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*2b949d04SAndroid Build Coastguard Worker * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*2b949d04SAndroid Build Coastguard Worker * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21*2b949d04SAndroid Build Coastguard Worker * DEALINGS IN THE SOFTWARE.
22*2b949d04SAndroid Build Coastguard Worker */
23*2b949d04SAndroid Build Coastguard Worker
24*2b949d04SAndroid Build Coastguard Worker #include "config.h"
25*2b949d04SAndroid Build Coastguard Worker
26*2b949d04SAndroid Build Coastguard Worker #include <sys/stat.h>
27*2b949d04SAndroid Build Coastguard Worker #include <fcntl.h>
28*2b949d04SAndroid Build Coastguard Worker #include <stdbool.h>
29*2b949d04SAndroid Build Coastguard Worker #include <stdlib.h>
30*2b949d04SAndroid Build Coastguard Worker #include <string.h>
31*2b949d04SAndroid Build Coastguard Worker #include <stdint.h>
32*2b949d04SAndroid Build Coastguard Worker #include <libxml/parser.h>
33*2b949d04SAndroid Build Coastguard Worker
34*2b949d04SAndroid Build Coastguard Worker #include "xkbcommon/xkbregistry.h"
35*2b949d04SAndroid Build Coastguard Worker #include "utils.h"
36*2b949d04SAndroid Build Coastguard Worker #include "util-list.h"
37*2b949d04SAndroid Build Coastguard Worker
38*2b949d04SAndroid Build Coastguard Worker struct rxkb_object;
39*2b949d04SAndroid Build Coastguard Worker
40*2b949d04SAndroid Build Coastguard Worker typedef void (*destroy_func_t)(struct rxkb_object *object);
41*2b949d04SAndroid Build Coastguard Worker
42*2b949d04SAndroid Build Coastguard Worker /**
43*2b949d04SAndroid Build Coastguard Worker * All our objects are refcounted and are linked to iterate through them.
44*2b949d04SAndroid Build Coastguard Worker * Abstract those bits away into a shared parent class so we can generate
45*2b949d04SAndroid Build Coastguard Worker * most of the functions through macros.
46*2b949d04SAndroid Build Coastguard Worker */
47*2b949d04SAndroid Build Coastguard Worker struct rxkb_object {
48*2b949d04SAndroid Build Coastguard Worker struct rxkb_object *parent;
49*2b949d04SAndroid Build Coastguard Worker uint32_t refcount;
50*2b949d04SAndroid Build Coastguard Worker struct list link;
51*2b949d04SAndroid Build Coastguard Worker destroy_func_t destroy;
52*2b949d04SAndroid Build Coastguard Worker };
53*2b949d04SAndroid Build Coastguard Worker
54*2b949d04SAndroid Build Coastguard Worker struct rxkb_iso639_code {
55*2b949d04SAndroid Build Coastguard Worker struct rxkb_object base;
56*2b949d04SAndroid Build Coastguard Worker char *code;
57*2b949d04SAndroid Build Coastguard Worker };
58*2b949d04SAndroid Build Coastguard Worker
59*2b949d04SAndroid Build Coastguard Worker struct rxkb_iso3166_code {
60*2b949d04SAndroid Build Coastguard Worker struct rxkb_object base;
61*2b949d04SAndroid Build Coastguard Worker char *code;
62*2b949d04SAndroid Build Coastguard Worker };
63*2b949d04SAndroid Build Coastguard Worker
64*2b949d04SAndroid Build Coastguard Worker enum context_state {
65*2b949d04SAndroid Build Coastguard Worker CONTEXT_NEW,
66*2b949d04SAndroid Build Coastguard Worker CONTEXT_PARSED,
67*2b949d04SAndroid Build Coastguard Worker CONTEXT_FAILED,
68*2b949d04SAndroid Build Coastguard Worker };
69*2b949d04SAndroid Build Coastguard Worker
70*2b949d04SAndroid Build Coastguard Worker struct rxkb_context {
71*2b949d04SAndroid Build Coastguard Worker struct rxkb_object base;
72*2b949d04SAndroid Build Coastguard Worker enum context_state context_state;
73*2b949d04SAndroid Build Coastguard Worker
74*2b949d04SAndroid Build Coastguard Worker bool load_extra_rules_files;
75*2b949d04SAndroid Build Coastguard Worker
76*2b949d04SAndroid Build Coastguard Worker struct list models; /* list of struct rxkb_models */
77*2b949d04SAndroid Build Coastguard Worker struct list layouts; /* list of struct rxkb_layouts */
78*2b949d04SAndroid Build Coastguard Worker struct list option_groups; /* list of struct rxkb_option_group */
79*2b949d04SAndroid Build Coastguard Worker
80*2b949d04SAndroid Build Coastguard Worker darray(char *) includes;
81*2b949d04SAndroid Build Coastguard Worker
82*2b949d04SAndroid Build Coastguard Worker
83*2b949d04SAndroid Build Coastguard Worker ATTR_PRINTF(3, 0) void (*log_fn)(struct rxkb_context *ctx,
84*2b949d04SAndroid Build Coastguard Worker enum rxkb_log_level level,
85*2b949d04SAndroid Build Coastguard Worker const char *fmt, va_list args);
86*2b949d04SAndroid Build Coastguard Worker enum rxkb_log_level log_level;
87*2b949d04SAndroid Build Coastguard Worker
88*2b949d04SAndroid Build Coastguard Worker void *userdata;
89*2b949d04SAndroid Build Coastguard Worker };
90*2b949d04SAndroid Build Coastguard Worker
91*2b949d04SAndroid Build Coastguard Worker struct rxkb_model {
92*2b949d04SAndroid Build Coastguard Worker struct rxkb_object base;
93*2b949d04SAndroid Build Coastguard Worker
94*2b949d04SAndroid Build Coastguard Worker char *name;
95*2b949d04SAndroid Build Coastguard Worker char *vendor;
96*2b949d04SAndroid Build Coastguard Worker char *description;
97*2b949d04SAndroid Build Coastguard Worker enum rxkb_popularity popularity;
98*2b949d04SAndroid Build Coastguard Worker };
99*2b949d04SAndroid Build Coastguard Worker
100*2b949d04SAndroid Build Coastguard Worker struct rxkb_layout {
101*2b949d04SAndroid Build Coastguard Worker struct rxkb_object base;
102*2b949d04SAndroid Build Coastguard Worker
103*2b949d04SAndroid Build Coastguard Worker char *name;
104*2b949d04SAndroid Build Coastguard Worker char *brief;
105*2b949d04SAndroid Build Coastguard Worker char *description;
106*2b949d04SAndroid Build Coastguard Worker char *variant;
107*2b949d04SAndroid Build Coastguard Worker enum rxkb_popularity popularity;
108*2b949d04SAndroid Build Coastguard Worker
109*2b949d04SAndroid Build Coastguard Worker struct list iso639s; /* list of struct rxkb_iso639_code */
110*2b949d04SAndroid Build Coastguard Worker struct list iso3166s; /* list of struct rxkb_iso3166_code */
111*2b949d04SAndroid Build Coastguard Worker };
112*2b949d04SAndroid Build Coastguard Worker
113*2b949d04SAndroid Build Coastguard Worker struct rxkb_option_group {
114*2b949d04SAndroid Build Coastguard Worker struct rxkb_object base;
115*2b949d04SAndroid Build Coastguard Worker
116*2b949d04SAndroid Build Coastguard Worker bool allow_multiple;
117*2b949d04SAndroid Build Coastguard Worker struct list options; /* list of struct rxkb_options */
118*2b949d04SAndroid Build Coastguard Worker char *name;
119*2b949d04SAndroid Build Coastguard Worker char *description;
120*2b949d04SAndroid Build Coastguard Worker enum rxkb_popularity popularity;
121*2b949d04SAndroid Build Coastguard Worker };
122*2b949d04SAndroid Build Coastguard Worker
123*2b949d04SAndroid Build Coastguard Worker struct rxkb_option {
124*2b949d04SAndroid Build Coastguard Worker struct rxkb_object base;
125*2b949d04SAndroid Build Coastguard Worker
126*2b949d04SAndroid Build Coastguard Worker char *name;
127*2b949d04SAndroid Build Coastguard Worker char *brief;
128*2b949d04SAndroid Build Coastguard Worker char *description;
129*2b949d04SAndroid Build Coastguard Worker enum rxkb_popularity popularity;
130*2b949d04SAndroid Build Coastguard Worker };
131*2b949d04SAndroid Build Coastguard Worker
132*2b949d04SAndroid Build Coastguard Worker static bool
133*2b949d04SAndroid Build Coastguard Worker parse(struct rxkb_context *ctx, const char *path,
134*2b949d04SAndroid Build Coastguard Worker enum rxkb_popularity popularity);
135*2b949d04SAndroid Build Coastguard Worker
136*2b949d04SAndroid Build Coastguard Worker ATTR_PRINTF(3, 4)
137*2b949d04SAndroid Build Coastguard Worker static void
rxkb_log(struct rxkb_context * ctx,enum rxkb_log_level level,const char * fmt,...)138*2b949d04SAndroid Build Coastguard Worker rxkb_log(struct rxkb_context *ctx, enum rxkb_log_level level,
139*2b949d04SAndroid Build Coastguard Worker const char *fmt, ...)
140*2b949d04SAndroid Build Coastguard Worker {
141*2b949d04SAndroid Build Coastguard Worker va_list args;
142*2b949d04SAndroid Build Coastguard Worker
143*2b949d04SAndroid Build Coastguard Worker if (ctx->log_level < level)
144*2b949d04SAndroid Build Coastguard Worker return;
145*2b949d04SAndroid Build Coastguard Worker
146*2b949d04SAndroid Build Coastguard Worker va_start(args, fmt);
147*2b949d04SAndroid Build Coastguard Worker ctx->log_fn(ctx, level, fmt, args);
148*2b949d04SAndroid Build Coastguard Worker va_end(args);
149*2b949d04SAndroid Build Coastguard Worker }
150*2b949d04SAndroid Build Coastguard Worker
151*2b949d04SAndroid Build Coastguard Worker /*
152*2b949d04SAndroid Build Coastguard Worker * The format is not part of the argument list in order to avoid the
153*2b949d04SAndroid Build Coastguard Worker * "ISO C99 requires rest arguments to be used" warning when only the
154*2b949d04SAndroid Build Coastguard Worker * format is supplied without arguments. Not supplying it would still
155*2b949d04SAndroid Build Coastguard Worker * result in an error, though.
156*2b949d04SAndroid Build Coastguard Worker */
157*2b949d04SAndroid Build Coastguard Worker #define log_dbg(ctx, ...) \
158*2b949d04SAndroid Build Coastguard Worker rxkb_log((ctx), RXKB_LOG_LEVEL_DEBUG, __VA_ARGS__)
159*2b949d04SAndroid Build Coastguard Worker #define log_info(ctx, ...) \
160*2b949d04SAndroid Build Coastguard Worker rxkb_log((ctx), RXKB_LOG_LEVEL_INFO, __VA_ARGS__)
161*2b949d04SAndroid Build Coastguard Worker #define log_warn(ctx, ...) \
162*2b949d04SAndroid Build Coastguard Worker rxkb_log((ctx), RXKB_LOG_LEVEL_WARNING, __VA_ARGS__)
163*2b949d04SAndroid Build Coastguard Worker #define log_err(ctx, ...) \
164*2b949d04SAndroid Build Coastguard Worker rxkb_log((ctx), RXKB_LOG_LEVEL_ERROR, __VA_ARGS__)
165*2b949d04SAndroid Build Coastguard Worker #define log_wsgo(ctx, ...) \
166*2b949d04SAndroid Build Coastguard Worker rxkb_log((ctx), RXKB_LOG_LEVEL_CRITICAL, __VA_ARGS__)
167*2b949d04SAndroid Build Coastguard Worker
168*2b949d04SAndroid Build Coastguard Worker
169*2b949d04SAndroid Build Coastguard Worker #define DECLARE_REF_UNREF_FOR_TYPE(type_) \
170*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT struct type_ * type_##_ref(struct type_ *object) { \
171*2b949d04SAndroid Build Coastguard Worker rxkb_object_ref(&object->base); \
172*2b949d04SAndroid Build Coastguard Worker return object; \
173*2b949d04SAndroid Build Coastguard Worker } \
174*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT struct type_ * type_##_unref(struct type_ *object) { \
175*2b949d04SAndroid Build Coastguard Worker if (!object) return NULL; \
176*2b949d04SAndroid Build Coastguard Worker return rxkb_object_unref(&object->base); \
177*2b949d04SAndroid Build Coastguard Worker }
178*2b949d04SAndroid Build Coastguard Worker
179*2b949d04SAndroid Build Coastguard Worker #define DECLARE_CREATE_FOR_TYPE(type_) \
180*2b949d04SAndroid Build Coastguard Worker static inline struct type_ * type_##_create(struct rxkb_object *parent) { \
181*2b949d04SAndroid Build Coastguard Worker struct type_ *t = calloc(1, sizeof *t); \
182*2b949d04SAndroid Build Coastguard Worker if (t) \
183*2b949d04SAndroid Build Coastguard Worker rxkb_object_init(&t->base, parent, (destroy_func_t)type_##_destroy); \
184*2b949d04SAndroid Build Coastguard Worker return t; \
185*2b949d04SAndroid Build Coastguard Worker }
186*2b949d04SAndroid Build Coastguard Worker
187*2b949d04SAndroid Build Coastguard Worker #define DECLARE_TYPED_GETTER_FOR_TYPE(type_, field_, rtype_) \
188*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT rtype_ type_##_get_##field_(struct type_ *object) { \
189*2b949d04SAndroid Build Coastguard Worker return object->field_; \
190*2b949d04SAndroid Build Coastguard Worker }
191*2b949d04SAndroid Build Coastguard Worker
192*2b949d04SAndroid Build Coastguard Worker #define DECLARE_GETTER_FOR_TYPE(type_, field_) \
193*2b949d04SAndroid Build Coastguard Worker DECLARE_TYPED_GETTER_FOR_TYPE(type_, field_, const char*)
194*2b949d04SAndroid Build Coastguard Worker
195*2b949d04SAndroid Build Coastguard Worker #define DECLARE_FIRST_NEXT_FOR_TYPE(type_, parent_type_, parent_field_) \
196*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT struct type_ * type_##_first(struct parent_type_ *parent) { \
197*2b949d04SAndroid Build Coastguard Worker struct type_ *o = NULL; \
198*2b949d04SAndroid Build Coastguard Worker if (!list_empty(&parent->parent_field_)) \
199*2b949d04SAndroid Build Coastguard Worker o = list_first_entry(&parent->parent_field_, o, base.link); \
200*2b949d04SAndroid Build Coastguard Worker return o; \
201*2b949d04SAndroid Build Coastguard Worker } \
202*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT struct type_ * \
203*2b949d04SAndroid Build Coastguard Worker type_##_next(struct type_ *o) \
204*2b949d04SAndroid Build Coastguard Worker { \
205*2b949d04SAndroid Build Coastguard Worker struct parent_type_ *parent; \
206*2b949d04SAndroid Build Coastguard Worker struct type_ *next; \
207*2b949d04SAndroid Build Coastguard Worker parent = container_of(o->base.parent, struct parent_type_, base); \
208*2b949d04SAndroid Build Coastguard Worker next = list_first_entry(&o->base.link, o, base.link); \
209*2b949d04SAndroid Build Coastguard Worker if (list_is_last(&parent->parent_field_, &o->base.link)) \
210*2b949d04SAndroid Build Coastguard Worker return NULL; \
211*2b949d04SAndroid Build Coastguard Worker return next; \
212*2b949d04SAndroid Build Coastguard Worker }
213*2b949d04SAndroid Build Coastguard Worker
214*2b949d04SAndroid Build Coastguard Worker static void
rxkb_object_init(struct rxkb_object * object,struct rxkb_object * parent,destroy_func_t destroy)215*2b949d04SAndroid Build Coastguard Worker rxkb_object_init(struct rxkb_object *object, struct rxkb_object *parent, destroy_func_t destroy)
216*2b949d04SAndroid Build Coastguard Worker {
217*2b949d04SAndroid Build Coastguard Worker object->refcount = 1;
218*2b949d04SAndroid Build Coastguard Worker object->destroy = destroy;
219*2b949d04SAndroid Build Coastguard Worker object->parent = parent;
220*2b949d04SAndroid Build Coastguard Worker list_init(&object->link);
221*2b949d04SAndroid Build Coastguard Worker }
222*2b949d04SAndroid Build Coastguard Worker
223*2b949d04SAndroid Build Coastguard Worker static void
rxkb_object_destroy(struct rxkb_object * object)224*2b949d04SAndroid Build Coastguard Worker rxkb_object_destroy(struct rxkb_object *object)
225*2b949d04SAndroid Build Coastguard Worker {
226*2b949d04SAndroid Build Coastguard Worker if (object->destroy)
227*2b949d04SAndroid Build Coastguard Worker object->destroy(object);
228*2b949d04SAndroid Build Coastguard Worker list_remove(&object->link);
229*2b949d04SAndroid Build Coastguard Worker free(object);
230*2b949d04SAndroid Build Coastguard Worker }
231*2b949d04SAndroid Build Coastguard Worker
232*2b949d04SAndroid Build Coastguard Worker static void *
rxkb_object_ref(struct rxkb_object * object)233*2b949d04SAndroid Build Coastguard Worker rxkb_object_ref(struct rxkb_object *object)
234*2b949d04SAndroid Build Coastguard Worker {
235*2b949d04SAndroid Build Coastguard Worker assert(object->refcount >= 1);
236*2b949d04SAndroid Build Coastguard Worker ++object->refcount;
237*2b949d04SAndroid Build Coastguard Worker return object;
238*2b949d04SAndroid Build Coastguard Worker }
239*2b949d04SAndroid Build Coastguard Worker
240*2b949d04SAndroid Build Coastguard Worker static void *
rxkb_object_unref(struct rxkb_object * object)241*2b949d04SAndroid Build Coastguard Worker rxkb_object_unref(struct rxkb_object *object)
242*2b949d04SAndroid Build Coastguard Worker {
243*2b949d04SAndroid Build Coastguard Worker assert(object->refcount >= 1);
244*2b949d04SAndroid Build Coastguard Worker if (--object->refcount == 0)
245*2b949d04SAndroid Build Coastguard Worker rxkb_object_destroy(object);
246*2b949d04SAndroid Build Coastguard Worker return NULL;
247*2b949d04SAndroid Build Coastguard Worker }
248*2b949d04SAndroid Build Coastguard Worker
249*2b949d04SAndroid Build Coastguard Worker static void
rxkb_iso639_code_destroy(struct rxkb_iso639_code * code)250*2b949d04SAndroid Build Coastguard Worker rxkb_iso639_code_destroy(struct rxkb_iso639_code *code)
251*2b949d04SAndroid Build Coastguard Worker {
252*2b949d04SAndroid Build Coastguard Worker free(code->code);
253*2b949d04SAndroid Build Coastguard Worker }
254*2b949d04SAndroid Build Coastguard Worker
255*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT struct rxkb_iso639_code *
rxkb_layout_get_iso639_first(struct rxkb_layout * layout)256*2b949d04SAndroid Build Coastguard Worker rxkb_layout_get_iso639_first(struct rxkb_layout *layout)
257*2b949d04SAndroid Build Coastguard Worker {
258*2b949d04SAndroid Build Coastguard Worker struct rxkb_iso639_code *code = NULL;
259*2b949d04SAndroid Build Coastguard Worker
260*2b949d04SAndroid Build Coastguard Worker if (!list_empty(&layout->iso639s))
261*2b949d04SAndroid Build Coastguard Worker code = list_first_entry(&layout->iso639s, code, base.link);
262*2b949d04SAndroid Build Coastguard Worker
263*2b949d04SAndroid Build Coastguard Worker return code;
264*2b949d04SAndroid Build Coastguard Worker }
265*2b949d04SAndroid Build Coastguard Worker
266*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT struct rxkb_iso639_code *
rxkb_iso639_code_next(struct rxkb_iso639_code * code)267*2b949d04SAndroid Build Coastguard Worker rxkb_iso639_code_next(struct rxkb_iso639_code *code)
268*2b949d04SAndroid Build Coastguard Worker {
269*2b949d04SAndroid Build Coastguard Worker struct rxkb_iso639_code *next = NULL;
270*2b949d04SAndroid Build Coastguard Worker struct rxkb_layout *layout;
271*2b949d04SAndroid Build Coastguard Worker
272*2b949d04SAndroid Build Coastguard Worker layout = container_of(code->base.parent, struct rxkb_layout, base);
273*2b949d04SAndroid Build Coastguard Worker
274*2b949d04SAndroid Build Coastguard Worker if (list_is_last(&layout->iso639s, &code->base.link))
275*2b949d04SAndroid Build Coastguard Worker return NULL;
276*2b949d04SAndroid Build Coastguard Worker
277*2b949d04SAndroid Build Coastguard Worker next = list_first_entry(&code->base.link, code, base.link);
278*2b949d04SAndroid Build Coastguard Worker
279*2b949d04SAndroid Build Coastguard Worker return next;
280*2b949d04SAndroid Build Coastguard Worker }
281*2b949d04SAndroid Build Coastguard Worker
282*2b949d04SAndroid Build Coastguard Worker DECLARE_REF_UNREF_FOR_TYPE(rxkb_iso639_code);
283*2b949d04SAndroid Build Coastguard Worker DECLARE_CREATE_FOR_TYPE(rxkb_iso639_code);
284*2b949d04SAndroid Build Coastguard Worker DECLARE_GETTER_FOR_TYPE(rxkb_iso639_code, code);
285*2b949d04SAndroid Build Coastguard Worker
286*2b949d04SAndroid Build Coastguard Worker static void
rxkb_iso3166_code_destroy(struct rxkb_iso3166_code * code)287*2b949d04SAndroid Build Coastguard Worker rxkb_iso3166_code_destroy(struct rxkb_iso3166_code *code)
288*2b949d04SAndroid Build Coastguard Worker {
289*2b949d04SAndroid Build Coastguard Worker free(code->code);
290*2b949d04SAndroid Build Coastguard Worker }
291*2b949d04SAndroid Build Coastguard Worker
292*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT struct rxkb_iso3166_code *
rxkb_layout_get_iso3166_first(struct rxkb_layout * layout)293*2b949d04SAndroid Build Coastguard Worker rxkb_layout_get_iso3166_first(struct rxkb_layout *layout)
294*2b949d04SAndroid Build Coastguard Worker {
295*2b949d04SAndroid Build Coastguard Worker struct rxkb_iso3166_code *code = NULL;
296*2b949d04SAndroid Build Coastguard Worker
297*2b949d04SAndroid Build Coastguard Worker if (!list_empty(&layout->iso3166s))
298*2b949d04SAndroid Build Coastguard Worker code = list_first_entry(&layout->iso3166s, code, base.link);
299*2b949d04SAndroid Build Coastguard Worker
300*2b949d04SAndroid Build Coastguard Worker return code;
301*2b949d04SAndroid Build Coastguard Worker }
302*2b949d04SAndroid Build Coastguard Worker
303*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT struct rxkb_iso3166_code *
rxkb_iso3166_code_next(struct rxkb_iso3166_code * code)304*2b949d04SAndroid Build Coastguard Worker rxkb_iso3166_code_next(struct rxkb_iso3166_code *code)
305*2b949d04SAndroid Build Coastguard Worker {
306*2b949d04SAndroid Build Coastguard Worker struct rxkb_iso3166_code *next = NULL;
307*2b949d04SAndroid Build Coastguard Worker struct rxkb_layout *layout;
308*2b949d04SAndroid Build Coastguard Worker
309*2b949d04SAndroid Build Coastguard Worker layout = container_of(code->base.parent, struct rxkb_layout, base);
310*2b949d04SAndroid Build Coastguard Worker
311*2b949d04SAndroid Build Coastguard Worker if (list_is_last(&layout->iso3166s, &code->base.link))
312*2b949d04SAndroid Build Coastguard Worker return NULL;
313*2b949d04SAndroid Build Coastguard Worker
314*2b949d04SAndroid Build Coastguard Worker next = list_first_entry(&code->base.link, code, base.link);
315*2b949d04SAndroid Build Coastguard Worker
316*2b949d04SAndroid Build Coastguard Worker return next;
317*2b949d04SAndroid Build Coastguard Worker }
318*2b949d04SAndroid Build Coastguard Worker
319*2b949d04SAndroid Build Coastguard Worker DECLARE_REF_UNREF_FOR_TYPE(rxkb_iso3166_code);
320*2b949d04SAndroid Build Coastguard Worker DECLARE_CREATE_FOR_TYPE(rxkb_iso3166_code);
321*2b949d04SAndroid Build Coastguard Worker DECLARE_GETTER_FOR_TYPE(rxkb_iso3166_code, code);
322*2b949d04SAndroid Build Coastguard Worker
323*2b949d04SAndroid Build Coastguard Worker static void
rxkb_option_destroy(struct rxkb_option * o)324*2b949d04SAndroid Build Coastguard Worker rxkb_option_destroy(struct rxkb_option *o)
325*2b949d04SAndroid Build Coastguard Worker {
326*2b949d04SAndroid Build Coastguard Worker free(o->name);
327*2b949d04SAndroid Build Coastguard Worker free(o->brief);
328*2b949d04SAndroid Build Coastguard Worker free(o->description);
329*2b949d04SAndroid Build Coastguard Worker }
330*2b949d04SAndroid Build Coastguard Worker
331*2b949d04SAndroid Build Coastguard Worker DECLARE_REF_UNREF_FOR_TYPE(rxkb_option);
332*2b949d04SAndroid Build Coastguard Worker DECLARE_CREATE_FOR_TYPE(rxkb_option);
333*2b949d04SAndroid Build Coastguard Worker DECLARE_GETTER_FOR_TYPE(rxkb_option, name);
334*2b949d04SAndroid Build Coastguard Worker DECLARE_GETTER_FOR_TYPE(rxkb_option, brief);
335*2b949d04SAndroid Build Coastguard Worker DECLARE_GETTER_FOR_TYPE(rxkb_option, description);
336*2b949d04SAndroid Build Coastguard Worker DECLARE_TYPED_GETTER_FOR_TYPE(rxkb_option, popularity, enum rxkb_popularity);
337*2b949d04SAndroid Build Coastguard Worker DECLARE_FIRST_NEXT_FOR_TYPE(rxkb_option, rxkb_option_group, options);
338*2b949d04SAndroid Build Coastguard Worker
339*2b949d04SAndroid Build Coastguard Worker static void
rxkb_layout_destroy(struct rxkb_layout * l)340*2b949d04SAndroid Build Coastguard Worker rxkb_layout_destroy(struct rxkb_layout *l)
341*2b949d04SAndroid Build Coastguard Worker {
342*2b949d04SAndroid Build Coastguard Worker struct rxkb_iso639_code *iso639, *tmp_639;
343*2b949d04SAndroid Build Coastguard Worker struct rxkb_iso3166_code *iso3166, *tmp_3166;
344*2b949d04SAndroid Build Coastguard Worker
345*2b949d04SAndroid Build Coastguard Worker free(l->name);
346*2b949d04SAndroid Build Coastguard Worker free(l->brief);
347*2b949d04SAndroid Build Coastguard Worker free(l->description);
348*2b949d04SAndroid Build Coastguard Worker free(l->variant);
349*2b949d04SAndroid Build Coastguard Worker
350*2b949d04SAndroid Build Coastguard Worker list_for_each_safe(iso639, tmp_639, &l->iso639s, base.link) {
351*2b949d04SAndroid Build Coastguard Worker rxkb_iso639_code_unref(iso639);
352*2b949d04SAndroid Build Coastguard Worker }
353*2b949d04SAndroid Build Coastguard Worker list_for_each_safe(iso3166, tmp_3166, &l->iso3166s, base.link) {
354*2b949d04SAndroid Build Coastguard Worker rxkb_iso3166_code_unref(iso3166);
355*2b949d04SAndroid Build Coastguard Worker }
356*2b949d04SAndroid Build Coastguard Worker }
357*2b949d04SAndroid Build Coastguard Worker
358*2b949d04SAndroid Build Coastguard Worker DECLARE_REF_UNREF_FOR_TYPE(rxkb_layout);
359*2b949d04SAndroid Build Coastguard Worker DECLARE_CREATE_FOR_TYPE(rxkb_layout);
360*2b949d04SAndroid Build Coastguard Worker DECLARE_GETTER_FOR_TYPE(rxkb_layout, name);
361*2b949d04SAndroid Build Coastguard Worker DECLARE_GETTER_FOR_TYPE(rxkb_layout, brief);
362*2b949d04SAndroid Build Coastguard Worker DECLARE_GETTER_FOR_TYPE(rxkb_layout, description);
363*2b949d04SAndroid Build Coastguard Worker DECLARE_GETTER_FOR_TYPE(rxkb_layout, variant);
364*2b949d04SAndroid Build Coastguard Worker DECLARE_TYPED_GETTER_FOR_TYPE(rxkb_layout, popularity, enum rxkb_popularity);
365*2b949d04SAndroid Build Coastguard Worker DECLARE_FIRST_NEXT_FOR_TYPE(rxkb_layout, rxkb_context, layouts);
366*2b949d04SAndroid Build Coastguard Worker
367*2b949d04SAndroid Build Coastguard Worker static void
rxkb_model_destroy(struct rxkb_model * m)368*2b949d04SAndroid Build Coastguard Worker rxkb_model_destroy(struct rxkb_model *m)
369*2b949d04SAndroid Build Coastguard Worker {
370*2b949d04SAndroid Build Coastguard Worker free(m->name);
371*2b949d04SAndroid Build Coastguard Worker free(m->vendor);
372*2b949d04SAndroid Build Coastguard Worker free(m->description);
373*2b949d04SAndroid Build Coastguard Worker }
374*2b949d04SAndroid Build Coastguard Worker
375*2b949d04SAndroid Build Coastguard Worker DECLARE_REF_UNREF_FOR_TYPE(rxkb_model);
376*2b949d04SAndroid Build Coastguard Worker DECLARE_CREATE_FOR_TYPE(rxkb_model);
377*2b949d04SAndroid Build Coastguard Worker DECLARE_GETTER_FOR_TYPE(rxkb_model, name);
378*2b949d04SAndroid Build Coastguard Worker DECLARE_GETTER_FOR_TYPE(rxkb_model, vendor);
379*2b949d04SAndroid Build Coastguard Worker DECLARE_GETTER_FOR_TYPE(rxkb_model, description);
380*2b949d04SAndroid Build Coastguard Worker DECLARE_TYPED_GETTER_FOR_TYPE(rxkb_model, popularity, enum rxkb_popularity);
381*2b949d04SAndroid Build Coastguard Worker DECLARE_FIRST_NEXT_FOR_TYPE(rxkb_model, rxkb_context, models);
382*2b949d04SAndroid Build Coastguard Worker
383*2b949d04SAndroid Build Coastguard Worker static void
rxkb_option_group_destroy(struct rxkb_option_group * og)384*2b949d04SAndroid Build Coastguard Worker rxkb_option_group_destroy(struct rxkb_option_group *og)
385*2b949d04SAndroid Build Coastguard Worker {
386*2b949d04SAndroid Build Coastguard Worker struct rxkb_option *o, *otmp;
387*2b949d04SAndroid Build Coastguard Worker
388*2b949d04SAndroid Build Coastguard Worker free(og->name);
389*2b949d04SAndroid Build Coastguard Worker free(og->description);
390*2b949d04SAndroid Build Coastguard Worker
391*2b949d04SAndroid Build Coastguard Worker list_for_each_safe(o, otmp, &og->options, base.link) {
392*2b949d04SAndroid Build Coastguard Worker rxkb_option_unref(o);
393*2b949d04SAndroid Build Coastguard Worker }
394*2b949d04SAndroid Build Coastguard Worker }
395*2b949d04SAndroid Build Coastguard Worker
396*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT bool
rxkb_option_group_allows_multiple(struct rxkb_option_group * g)397*2b949d04SAndroid Build Coastguard Worker rxkb_option_group_allows_multiple(struct rxkb_option_group *g)
398*2b949d04SAndroid Build Coastguard Worker {
399*2b949d04SAndroid Build Coastguard Worker return g->allow_multiple;
400*2b949d04SAndroid Build Coastguard Worker }
401*2b949d04SAndroid Build Coastguard Worker
402*2b949d04SAndroid Build Coastguard Worker DECLARE_REF_UNREF_FOR_TYPE(rxkb_option_group);
403*2b949d04SAndroid Build Coastguard Worker DECLARE_CREATE_FOR_TYPE(rxkb_option_group);
404*2b949d04SAndroid Build Coastguard Worker DECLARE_GETTER_FOR_TYPE(rxkb_option_group, name);
405*2b949d04SAndroid Build Coastguard Worker DECLARE_GETTER_FOR_TYPE(rxkb_option_group, description);
406*2b949d04SAndroid Build Coastguard Worker DECLARE_TYPED_GETTER_FOR_TYPE(rxkb_option_group, popularity, enum rxkb_popularity);
407*2b949d04SAndroid Build Coastguard Worker DECLARE_FIRST_NEXT_FOR_TYPE(rxkb_option_group, rxkb_context, option_groups);
408*2b949d04SAndroid Build Coastguard Worker
409*2b949d04SAndroid Build Coastguard Worker static void
rxkb_context_destroy(struct rxkb_context * ctx)410*2b949d04SAndroid Build Coastguard Worker rxkb_context_destroy(struct rxkb_context *ctx)
411*2b949d04SAndroid Build Coastguard Worker {
412*2b949d04SAndroid Build Coastguard Worker struct rxkb_model *m, *mtmp;
413*2b949d04SAndroid Build Coastguard Worker struct rxkb_layout *l, *ltmp;
414*2b949d04SAndroid Build Coastguard Worker struct rxkb_option_group *og, *ogtmp;
415*2b949d04SAndroid Build Coastguard Worker char **path;
416*2b949d04SAndroid Build Coastguard Worker
417*2b949d04SAndroid Build Coastguard Worker list_for_each_safe(m, mtmp, &ctx->models, base.link)
418*2b949d04SAndroid Build Coastguard Worker rxkb_model_unref(m);
419*2b949d04SAndroid Build Coastguard Worker assert(list_empty(&ctx->models));
420*2b949d04SAndroid Build Coastguard Worker
421*2b949d04SAndroid Build Coastguard Worker list_for_each_safe(l, ltmp, &ctx->layouts, base.link)
422*2b949d04SAndroid Build Coastguard Worker rxkb_layout_unref(l);
423*2b949d04SAndroid Build Coastguard Worker assert(list_empty(&ctx->layouts));
424*2b949d04SAndroid Build Coastguard Worker
425*2b949d04SAndroid Build Coastguard Worker list_for_each_safe(og, ogtmp, &ctx->option_groups, base.link)
426*2b949d04SAndroid Build Coastguard Worker rxkb_option_group_unref(og);
427*2b949d04SAndroid Build Coastguard Worker assert(list_empty(&ctx->option_groups));
428*2b949d04SAndroid Build Coastguard Worker
429*2b949d04SAndroid Build Coastguard Worker darray_foreach(path, ctx->includes)
430*2b949d04SAndroid Build Coastguard Worker free(*path);
431*2b949d04SAndroid Build Coastguard Worker darray_free(ctx->includes);
432*2b949d04SAndroid Build Coastguard Worker
433*2b949d04SAndroid Build Coastguard Worker assert(darray_empty(ctx->includes));
434*2b949d04SAndroid Build Coastguard Worker }
435*2b949d04SAndroid Build Coastguard Worker
436*2b949d04SAndroid Build Coastguard Worker DECLARE_REF_UNREF_FOR_TYPE(rxkb_context);
437*2b949d04SAndroid Build Coastguard Worker DECLARE_CREATE_FOR_TYPE(rxkb_context);
438*2b949d04SAndroid Build Coastguard Worker DECLARE_TYPED_GETTER_FOR_TYPE(rxkb_context, log_level, enum rxkb_log_level);
439*2b949d04SAndroid Build Coastguard Worker
440*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT void
rxkb_context_set_log_level(struct rxkb_context * ctx,enum rxkb_log_level level)441*2b949d04SAndroid Build Coastguard Worker rxkb_context_set_log_level(struct rxkb_context *ctx,
442*2b949d04SAndroid Build Coastguard Worker enum rxkb_log_level level)
443*2b949d04SAndroid Build Coastguard Worker {
444*2b949d04SAndroid Build Coastguard Worker ctx->log_level = level;
445*2b949d04SAndroid Build Coastguard Worker }
446*2b949d04SAndroid Build Coastguard Worker
447*2b949d04SAndroid Build Coastguard Worker static const char *
log_level_to_prefix(enum rxkb_log_level level)448*2b949d04SAndroid Build Coastguard Worker log_level_to_prefix(enum rxkb_log_level level)
449*2b949d04SAndroid Build Coastguard Worker {
450*2b949d04SAndroid Build Coastguard Worker switch (level) {
451*2b949d04SAndroid Build Coastguard Worker case RXKB_LOG_LEVEL_DEBUG:
452*2b949d04SAndroid Build Coastguard Worker return "xkbregistry: DEBUG: ";
453*2b949d04SAndroid Build Coastguard Worker case RXKB_LOG_LEVEL_INFO:
454*2b949d04SAndroid Build Coastguard Worker return "xkbregistry: INFO: ";
455*2b949d04SAndroid Build Coastguard Worker case RXKB_LOG_LEVEL_WARNING:
456*2b949d04SAndroid Build Coastguard Worker return "xkbregistry: WARNING: ";
457*2b949d04SAndroid Build Coastguard Worker case RXKB_LOG_LEVEL_ERROR:
458*2b949d04SAndroid Build Coastguard Worker return "xkbregistry: ERROR: ";
459*2b949d04SAndroid Build Coastguard Worker case RXKB_LOG_LEVEL_CRITICAL:
460*2b949d04SAndroid Build Coastguard Worker return "xkbregistry: CRITICAL: ";
461*2b949d04SAndroid Build Coastguard Worker default:
462*2b949d04SAndroid Build Coastguard Worker return NULL;
463*2b949d04SAndroid Build Coastguard Worker }
464*2b949d04SAndroid Build Coastguard Worker }
465*2b949d04SAndroid Build Coastguard Worker
466*2b949d04SAndroid Build Coastguard Worker ATTR_PRINTF(3, 0) static void
default_log_fn(struct rxkb_context * ctx,enum rxkb_log_level level,const char * fmt,va_list args)467*2b949d04SAndroid Build Coastguard Worker default_log_fn(struct rxkb_context *ctx, enum rxkb_log_level level,
468*2b949d04SAndroid Build Coastguard Worker const char *fmt, va_list args)
469*2b949d04SAndroid Build Coastguard Worker {
470*2b949d04SAndroid Build Coastguard Worker const char *prefix = log_level_to_prefix(level);
471*2b949d04SAndroid Build Coastguard Worker
472*2b949d04SAndroid Build Coastguard Worker if (prefix)
473*2b949d04SAndroid Build Coastguard Worker fprintf(stderr, "%s", prefix);
474*2b949d04SAndroid Build Coastguard Worker vfprintf(stderr, fmt, args);
475*2b949d04SAndroid Build Coastguard Worker }
476*2b949d04SAndroid Build Coastguard Worker
477*2b949d04SAndroid Build Coastguard Worker static enum rxkb_log_level
log_level(const char * level)478*2b949d04SAndroid Build Coastguard Worker log_level(const char *level) {
479*2b949d04SAndroid Build Coastguard Worker char *endptr;
480*2b949d04SAndroid Build Coastguard Worker enum rxkb_log_level lvl;
481*2b949d04SAndroid Build Coastguard Worker
482*2b949d04SAndroid Build Coastguard Worker errno = 0;
483*2b949d04SAndroid Build Coastguard Worker lvl = strtol(level, &endptr, 10);
484*2b949d04SAndroid Build Coastguard Worker if (errno == 0 && (endptr[0] == '\0' || is_space(endptr[0])))
485*2b949d04SAndroid Build Coastguard Worker return lvl;
486*2b949d04SAndroid Build Coastguard Worker if (istreq_prefix("crit", level))
487*2b949d04SAndroid Build Coastguard Worker return RXKB_LOG_LEVEL_CRITICAL;
488*2b949d04SAndroid Build Coastguard Worker if (istreq_prefix("err", level))
489*2b949d04SAndroid Build Coastguard Worker return RXKB_LOG_LEVEL_ERROR;
490*2b949d04SAndroid Build Coastguard Worker if (istreq_prefix("warn", level))
491*2b949d04SAndroid Build Coastguard Worker return RXKB_LOG_LEVEL_WARNING;
492*2b949d04SAndroid Build Coastguard Worker if (istreq_prefix("info", level))
493*2b949d04SAndroid Build Coastguard Worker return RXKB_LOG_LEVEL_INFO;
494*2b949d04SAndroid Build Coastguard Worker if (istreq_prefix("debug", level) || istreq_prefix("dbg", level))
495*2b949d04SAndroid Build Coastguard Worker return RXKB_LOG_LEVEL_DEBUG;
496*2b949d04SAndroid Build Coastguard Worker
497*2b949d04SAndroid Build Coastguard Worker return RXKB_LOG_LEVEL_ERROR;
498*2b949d04SAndroid Build Coastguard Worker }
499*2b949d04SAndroid Build Coastguard Worker
500*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT struct rxkb_context *
rxkb_context_new(enum rxkb_context_flags flags)501*2b949d04SAndroid Build Coastguard Worker rxkb_context_new(enum rxkb_context_flags flags)
502*2b949d04SAndroid Build Coastguard Worker {
503*2b949d04SAndroid Build Coastguard Worker struct rxkb_context *ctx = rxkb_context_create(NULL);
504*2b949d04SAndroid Build Coastguard Worker const char *env;
505*2b949d04SAndroid Build Coastguard Worker
506*2b949d04SAndroid Build Coastguard Worker if (!ctx)
507*2b949d04SAndroid Build Coastguard Worker return NULL;
508*2b949d04SAndroid Build Coastguard Worker
509*2b949d04SAndroid Build Coastguard Worker ctx->context_state = CONTEXT_NEW;
510*2b949d04SAndroid Build Coastguard Worker ctx->load_extra_rules_files = flags & RXKB_CONTEXT_LOAD_EXOTIC_RULES;
511*2b949d04SAndroid Build Coastguard Worker ctx->log_fn = default_log_fn;
512*2b949d04SAndroid Build Coastguard Worker ctx->log_level = RXKB_LOG_LEVEL_ERROR;
513*2b949d04SAndroid Build Coastguard Worker
514*2b949d04SAndroid Build Coastguard Worker /* Environment overwrites defaults. */
515*2b949d04SAndroid Build Coastguard Worker env = secure_getenv("RXKB_LOG_LEVEL");
516*2b949d04SAndroid Build Coastguard Worker if (env)
517*2b949d04SAndroid Build Coastguard Worker rxkb_context_set_log_level(ctx, log_level(env));
518*2b949d04SAndroid Build Coastguard Worker
519*2b949d04SAndroid Build Coastguard Worker list_init(&ctx->models);
520*2b949d04SAndroid Build Coastguard Worker list_init(&ctx->layouts);
521*2b949d04SAndroid Build Coastguard Worker list_init(&ctx->option_groups);
522*2b949d04SAndroid Build Coastguard Worker
523*2b949d04SAndroid Build Coastguard Worker if (!(flags & RXKB_CONTEXT_NO_DEFAULT_INCLUDES) &&
524*2b949d04SAndroid Build Coastguard Worker !rxkb_context_include_path_append_default(ctx)) {
525*2b949d04SAndroid Build Coastguard Worker rxkb_context_unref(ctx);
526*2b949d04SAndroid Build Coastguard Worker return NULL;
527*2b949d04SAndroid Build Coastguard Worker }
528*2b949d04SAndroid Build Coastguard Worker
529*2b949d04SAndroid Build Coastguard Worker return ctx;
530*2b949d04SAndroid Build Coastguard Worker }
531*2b949d04SAndroid Build Coastguard Worker
532*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT void
rxkb_context_set_log_fn(struct rxkb_context * ctx,void (* log_fn)(struct rxkb_context * ctx,enum rxkb_log_level level,const char * fmt,va_list args))533*2b949d04SAndroid Build Coastguard Worker rxkb_context_set_log_fn(struct rxkb_context *ctx,
534*2b949d04SAndroid Build Coastguard Worker void (*log_fn)(struct rxkb_context *ctx,
535*2b949d04SAndroid Build Coastguard Worker enum rxkb_log_level level,
536*2b949d04SAndroid Build Coastguard Worker const char *fmt, va_list args))
537*2b949d04SAndroid Build Coastguard Worker {
538*2b949d04SAndroid Build Coastguard Worker ctx->log_fn = (log_fn ? log_fn : default_log_fn);
539*2b949d04SAndroid Build Coastguard Worker }
540*2b949d04SAndroid Build Coastguard Worker
541*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT bool
rxkb_context_include_path_append(struct rxkb_context * ctx,const char * path)542*2b949d04SAndroid Build Coastguard Worker rxkb_context_include_path_append(struct rxkb_context *ctx, const char *path)
543*2b949d04SAndroid Build Coastguard Worker {
544*2b949d04SAndroid Build Coastguard Worker struct stat stat_buf;
545*2b949d04SAndroid Build Coastguard Worker int err;
546*2b949d04SAndroid Build Coastguard Worker char *tmp = NULL;
547*2b949d04SAndroid Build Coastguard Worker char rules[PATH_MAX];
548*2b949d04SAndroid Build Coastguard Worker
549*2b949d04SAndroid Build Coastguard Worker if (ctx->context_state != CONTEXT_NEW) {
550*2b949d04SAndroid Build Coastguard Worker log_err(ctx, "include paths can only be appended to a new context\n");
551*2b949d04SAndroid Build Coastguard Worker return false;
552*2b949d04SAndroid Build Coastguard Worker }
553*2b949d04SAndroid Build Coastguard Worker
554*2b949d04SAndroid Build Coastguard Worker tmp = strdup(path);
555*2b949d04SAndroid Build Coastguard Worker if (!tmp)
556*2b949d04SAndroid Build Coastguard Worker goto err;
557*2b949d04SAndroid Build Coastguard Worker
558*2b949d04SAndroid Build Coastguard Worker err = stat(path, &stat_buf);
559*2b949d04SAndroid Build Coastguard Worker if (err != 0)
560*2b949d04SAndroid Build Coastguard Worker goto err;
561*2b949d04SAndroid Build Coastguard Worker if (!S_ISDIR(stat_buf.st_mode))
562*2b949d04SAndroid Build Coastguard Worker goto err;
563*2b949d04SAndroid Build Coastguard Worker
564*2b949d04SAndroid Build Coastguard Worker if (!check_eaccess(path, R_OK | X_OK))
565*2b949d04SAndroid Build Coastguard Worker goto err;
566*2b949d04SAndroid Build Coastguard Worker
567*2b949d04SAndroid Build Coastguard Worker /* Pre-filter for the 99.9% case - if we can't assemble the default ruleset
568*2b949d04SAndroid Build Coastguard Worker * path, complain here instead of during parsing later. The niche cases
569*2b949d04SAndroid Build Coastguard Worker * where this is the wrong behaviour aren't worth worrying about.
570*2b949d04SAndroid Build Coastguard Worker */
571*2b949d04SAndroid Build Coastguard Worker if (!snprintf_safe(rules, sizeof(rules), "%s/rules/%s.xml",
572*2b949d04SAndroid Build Coastguard Worker path, DEFAULT_XKB_RULES))
573*2b949d04SAndroid Build Coastguard Worker goto err;
574*2b949d04SAndroid Build Coastguard Worker
575*2b949d04SAndroid Build Coastguard Worker darray_append(ctx->includes, tmp);
576*2b949d04SAndroid Build Coastguard Worker
577*2b949d04SAndroid Build Coastguard Worker return true;
578*2b949d04SAndroid Build Coastguard Worker
579*2b949d04SAndroid Build Coastguard Worker err:
580*2b949d04SAndroid Build Coastguard Worker free(tmp);
581*2b949d04SAndroid Build Coastguard Worker return false;
582*2b949d04SAndroid Build Coastguard Worker }
583*2b949d04SAndroid Build Coastguard Worker
584*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT bool
rxkb_context_include_path_append_default(struct rxkb_context * ctx)585*2b949d04SAndroid Build Coastguard Worker rxkb_context_include_path_append_default(struct rxkb_context *ctx)
586*2b949d04SAndroid Build Coastguard Worker {
587*2b949d04SAndroid Build Coastguard Worker const char *home, *xdg, *root, *extra;
588*2b949d04SAndroid Build Coastguard Worker char *user_path;
589*2b949d04SAndroid Build Coastguard Worker bool ret = false;
590*2b949d04SAndroid Build Coastguard Worker
591*2b949d04SAndroid Build Coastguard Worker if (ctx->context_state != CONTEXT_NEW) {
592*2b949d04SAndroid Build Coastguard Worker log_err(ctx, "include paths can only be appended to a new context\n");
593*2b949d04SAndroid Build Coastguard Worker return false;
594*2b949d04SAndroid Build Coastguard Worker }
595*2b949d04SAndroid Build Coastguard Worker
596*2b949d04SAndroid Build Coastguard Worker home = secure_getenv("HOME");
597*2b949d04SAndroid Build Coastguard Worker
598*2b949d04SAndroid Build Coastguard Worker xdg = secure_getenv("XDG_CONFIG_HOME");
599*2b949d04SAndroid Build Coastguard Worker if (xdg != NULL) {
600*2b949d04SAndroid Build Coastguard Worker user_path = asprintf_safe("%s/xkb", xdg);
601*2b949d04SAndroid Build Coastguard Worker if (user_path) {
602*2b949d04SAndroid Build Coastguard Worker ret |= rxkb_context_include_path_append(ctx, user_path);
603*2b949d04SAndroid Build Coastguard Worker free(user_path);
604*2b949d04SAndroid Build Coastguard Worker }
605*2b949d04SAndroid Build Coastguard Worker } else if (home != NULL) {
606*2b949d04SAndroid Build Coastguard Worker /* XDG_CONFIG_HOME fallback is $HOME/.config/ */
607*2b949d04SAndroid Build Coastguard Worker user_path = asprintf_safe("%s/.config/xkb", home);
608*2b949d04SAndroid Build Coastguard Worker if (user_path) {
609*2b949d04SAndroid Build Coastguard Worker ret |= rxkb_context_include_path_append(ctx, user_path);
610*2b949d04SAndroid Build Coastguard Worker free(user_path);
611*2b949d04SAndroid Build Coastguard Worker }
612*2b949d04SAndroid Build Coastguard Worker }
613*2b949d04SAndroid Build Coastguard Worker
614*2b949d04SAndroid Build Coastguard Worker if (home != NULL) {
615*2b949d04SAndroid Build Coastguard Worker user_path = asprintf_safe("%s/.xkb", home);
616*2b949d04SAndroid Build Coastguard Worker if (user_path) {
617*2b949d04SAndroid Build Coastguard Worker ret |= rxkb_context_include_path_append(ctx, user_path);
618*2b949d04SAndroid Build Coastguard Worker free(user_path);
619*2b949d04SAndroid Build Coastguard Worker }
620*2b949d04SAndroid Build Coastguard Worker }
621*2b949d04SAndroid Build Coastguard Worker
622*2b949d04SAndroid Build Coastguard Worker extra = secure_getenv("XKB_CONFIG_EXTRA_PATH");
623*2b949d04SAndroid Build Coastguard Worker if (extra != NULL)
624*2b949d04SAndroid Build Coastguard Worker ret |= rxkb_context_include_path_append(ctx, extra);
625*2b949d04SAndroid Build Coastguard Worker else
626*2b949d04SAndroid Build Coastguard Worker ret |= rxkb_context_include_path_append(ctx, DFLT_XKB_CONFIG_EXTRA_PATH);
627*2b949d04SAndroid Build Coastguard Worker
628*2b949d04SAndroid Build Coastguard Worker root = secure_getenv("XKB_CONFIG_ROOT");
629*2b949d04SAndroid Build Coastguard Worker if (root != NULL)
630*2b949d04SAndroid Build Coastguard Worker ret |= rxkb_context_include_path_append(ctx, root);
631*2b949d04SAndroid Build Coastguard Worker else
632*2b949d04SAndroid Build Coastguard Worker ret |= rxkb_context_include_path_append(ctx, DFLT_XKB_CONFIG_ROOT);
633*2b949d04SAndroid Build Coastguard Worker
634*2b949d04SAndroid Build Coastguard Worker return ret;
635*2b949d04SAndroid Build Coastguard Worker }
636*2b949d04SAndroid Build Coastguard Worker
637*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT bool
rxkb_context_parse_default_ruleset(struct rxkb_context * ctx)638*2b949d04SAndroid Build Coastguard Worker rxkb_context_parse_default_ruleset(struct rxkb_context *ctx)
639*2b949d04SAndroid Build Coastguard Worker {
640*2b949d04SAndroid Build Coastguard Worker return rxkb_context_parse(ctx, DEFAULT_XKB_RULES);
641*2b949d04SAndroid Build Coastguard Worker }
642*2b949d04SAndroid Build Coastguard Worker
643*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT bool
rxkb_context_parse(struct rxkb_context * ctx,const char * ruleset)644*2b949d04SAndroid Build Coastguard Worker rxkb_context_parse(struct rxkb_context *ctx, const char *ruleset)
645*2b949d04SAndroid Build Coastguard Worker {
646*2b949d04SAndroid Build Coastguard Worker char **path;
647*2b949d04SAndroid Build Coastguard Worker bool success = false;
648*2b949d04SAndroid Build Coastguard Worker
649*2b949d04SAndroid Build Coastguard Worker if (ctx->context_state != CONTEXT_NEW) {
650*2b949d04SAndroid Build Coastguard Worker log_err(ctx, "parse must only be called on a new context\n");
651*2b949d04SAndroid Build Coastguard Worker return false;
652*2b949d04SAndroid Build Coastguard Worker }
653*2b949d04SAndroid Build Coastguard Worker
654*2b949d04SAndroid Build Coastguard Worker darray_foreach_reverse(path, ctx->includes) {
655*2b949d04SAndroid Build Coastguard Worker char rules[PATH_MAX];
656*2b949d04SAndroid Build Coastguard Worker
657*2b949d04SAndroid Build Coastguard Worker if (snprintf_safe(rules, sizeof(rules), "%s/rules/%s.xml",
658*2b949d04SAndroid Build Coastguard Worker *path, ruleset)) {
659*2b949d04SAndroid Build Coastguard Worker log_dbg(ctx, "Parsing %s\n", rules);
660*2b949d04SAndroid Build Coastguard Worker if (parse(ctx, rules, RXKB_POPULARITY_STANDARD))
661*2b949d04SAndroid Build Coastguard Worker success = true;
662*2b949d04SAndroid Build Coastguard Worker }
663*2b949d04SAndroid Build Coastguard Worker
664*2b949d04SAndroid Build Coastguard Worker if (ctx->load_extra_rules_files &&
665*2b949d04SAndroid Build Coastguard Worker snprintf_safe(rules, sizeof(rules), "%s/rules/%s.extras.xml",
666*2b949d04SAndroid Build Coastguard Worker *path, ruleset)) {
667*2b949d04SAndroid Build Coastguard Worker log_dbg(ctx, "Parsing %s\n", rules);
668*2b949d04SAndroid Build Coastguard Worker if (parse(ctx, rules, RXKB_POPULARITY_EXOTIC))
669*2b949d04SAndroid Build Coastguard Worker success = true;
670*2b949d04SAndroid Build Coastguard Worker }
671*2b949d04SAndroid Build Coastguard Worker }
672*2b949d04SAndroid Build Coastguard Worker
673*2b949d04SAndroid Build Coastguard Worker ctx->context_state = success ? CONTEXT_PARSED : CONTEXT_FAILED;
674*2b949d04SAndroid Build Coastguard Worker
675*2b949d04SAndroid Build Coastguard Worker return success;
676*2b949d04SAndroid Build Coastguard Worker }
677*2b949d04SAndroid Build Coastguard Worker
678*2b949d04SAndroid Build Coastguard Worker
679*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT void
rxkb_context_set_user_data(struct rxkb_context * ctx,void * userdata)680*2b949d04SAndroid Build Coastguard Worker rxkb_context_set_user_data(struct rxkb_context *ctx, void *userdata)
681*2b949d04SAndroid Build Coastguard Worker {
682*2b949d04SAndroid Build Coastguard Worker ctx->userdata = userdata;
683*2b949d04SAndroid Build Coastguard Worker }
684*2b949d04SAndroid Build Coastguard Worker
685*2b949d04SAndroid Build Coastguard Worker XKB_EXPORT void *
rxkb_context_get_user_data(struct rxkb_context * ctx)686*2b949d04SAndroid Build Coastguard Worker rxkb_context_get_user_data(struct rxkb_context *ctx)
687*2b949d04SAndroid Build Coastguard Worker {
688*2b949d04SAndroid Build Coastguard Worker return ctx->userdata;
689*2b949d04SAndroid Build Coastguard Worker }
690*2b949d04SAndroid Build Coastguard Worker
691*2b949d04SAndroid Build Coastguard Worker static inline bool
is_node(xmlNode * node,const char * name)692*2b949d04SAndroid Build Coastguard Worker is_node(xmlNode *node, const char *name)
693*2b949d04SAndroid Build Coastguard Worker {
694*2b949d04SAndroid Build Coastguard Worker return node->type == XML_ELEMENT_NODE &&
695*2b949d04SAndroid Build Coastguard Worker xmlStrEqual(node->name, (const xmlChar*)name);
696*2b949d04SAndroid Build Coastguard Worker }
697*2b949d04SAndroid Build Coastguard Worker
698*2b949d04SAndroid Build Coastguard Worker /* return a copy of the text content from the first text node of this node */
699*2b949d04SAndroid Build Coastguard Worker static char *
extract_text(xmlNode * node)700*2b949d04SAndroid Build Coastguard Worker extract_text(xmlNode *node)
701*2b949d04SAndroid Build Coastguard Worker {
702*2b949d04SAndroid Build Coastguard Worker xmlNode *n;
703*2b949d04SAndroid Build Coastguard Worker
704*2b949d04SAndroid Build Coastguard Worker for (n = node->children; n; n = n->next) {
705*2b949d04SAndroid Build Coastguard Worker if (n->type == XML_TEXT_NODE)
706*2b949d04SAndroid Build Coastguard Worker return (char *)xmlStrdup(n->content);
707*2b949d04SAndroid Build Coastguard Worker }
708*2b949d04SAndroid Build Coastguard Worker return NULL;
709*2b949d04SAndroid Build Coastguard Worker }
710*2b949d04SAndroid Build Coastguard Worker
711*2b949d04SAndroid Build Coastguard Worker static bool
parse_config_item(struct rxkb_context * ctx,xmlNode * parent,char ** name,char ** description,char ** brief,char ** vendor)712*2b949d04SAndroid Build Coastguard Worker parse_config_item(struct rxkb_context *ctx,
713*2b949d04SAndroid Build Coastguard Worker xmlNode *parent,
714*2b949d04SAndroid Build Coastguard Worker char **name,
715*2b949d04SAndroid Build Coastguard Worker char **description,
716*2b949d04SAndroid Build Coastguard Worker char **brief,
717*2b949d04SAndroid Build Coastguard Worker char **vendor)
718*2b949d04SAndroid Build Coastguard Worker {
719*2b949d04SAndroid Build Coastguard Worker xmlNode *node = NULL;
720*2b949d04SAndroid Build Coastguard Worker xmlNode *ci = NULL;
721*2b949d04SAndroid Build Coastguard Worker
722*2b949d04SAndroid Build Coastguard Worker for (ci = parent->children; ci; ci = ci->next) {
723*2b949d04SAndroid Build Coastguard Worker if (is_node(ci, "configItem")) {
724*2b949d04SAndroid Build Coastguard Worker *name = NULL;
725*2b949d04SAndroid Build Coastguard Worker *description = NULL;
726*2b949d04SAndroid Build Coastguard Worker *brief = NULL;
727*2b949d04SAndroid Build Coastguard Worker *vendor = NULL;
728*2b949d04SAndroid Build Coastguard Worker
729*2b949d04SAndroid Build Coastguard Worker for (node = ci->children; node; node = node->next) {
730*2b949d04SAndroid Build Coastguard Worker if (is_node(node, "name"))
731*2b949d04SAndroid Build Coastguard Worker *name = extract_text(node);
732*2b949d04SAndroid Build Coastguard Worker else if (is_node(node, "description"))
733*2b949d04SAndroid Build Coastguard Worker *description = extract_text(node);
734*2b949d04SAndroid Build Coastguard Worker else if (is_node(node, "shortDescription"))
735*2b949d04SAndroid Build Coastguard Worker *brief = extract_text(node);
736*2b949d04SAndroid Build Coastguard Worker else if (is_node(node, "vendor"))
737*2b949d04SAndroid Build Coastguard Worker *vendor = extract_text(node);
738*2b949d04SAndroid Build Coastguard Worker /* Note: the DTD allows for vendor + brief but models only use
739*2b949d04SAndroid Build Coastguard Worker * vendor and everything else only uses shortDescription */
740*2b949d04SAndroid Build Coastguard Worker }
741*2b949d04SAndroid Build Coastguard Worker
742*2b949d04SAndroid Build Coastguard Worker if (!*name || !strlen(*name)) {
743*2b949d04SAndroid Build Coastguard Worker log_err(ctx, "xml:%d: missing required element 'name'\n",
744*2b949d04SAndroid Build Coastguard Worker ci->line);
745*2b949d04SAndroid Build Coastguard Worker free(*name);
746*2b949d04SAndroid Build Coastguard Worker free(*description);
747*2b949d04SAndroid Build Coastguard Worker free(*brief);
748*2b949d04SAndroid Build Coastguard Worker free(*vendor);
749*2b949d04SAndroid Build Coastguard Worker return false;
750*2b949d04SAndroid Build Coastguard Worker }
751*2b949d04SAndroid Build Coastguard Worker
752*2b949d04SAndroid Build Coastguard Worker return true; /* only one configItem allowed in the dtd */
753*2b949d04SAndroid Build Coastguard Worker }
754*2b949d04SAndroid Build Coastguard Worker }
755*2b949d04SAndroid Build Coastguard Worker
756*2b949d04SAndroid Build Coastguard Worker return false;
757*2b949d04SAndroid Build Coastguard Worker }
758*2b949d04SAndroid Build Coastguard Worker
759*2b949d04SAndroid Build Coastguard Worker static void
parse_model(struct rxkb_context * ctx,xmlNode * model,enum rxkb_popularity popularity)760*2b949d04SAndroid Build Coastguard Worker parse_model(struct rxkb_context *ctx, xmlNode *model,
761*2b949d04SAndroid Build Coastguard Worker enum rxkb_popularity popularity)
762*2b949d04SAndroid Build Coastguard Worker {
763*2b949d04SAndroid Build Coastguard Worker char *name, *description, *brief, *vendor;
764*2b949d04SAndroid Build Coastguard Worker
765*2b949d04SAndroid Build Coastguard Worker if (parse_config_item(ctx, model, &name, &description, &brief, &vendor)) {
766*2b949d04SAndroid Build Coastguard Worker struct rxkb_model *m;
767*2b949d04SAndroid Build Coastguard Worker
768*2b949d04SAndroid Build Coastguard Worker list_for_each(m, &ctx->models, base.link) {
769*2b949d04SAndroid Build Coastguard Worker if (streq(m->name, name)) {
770*2b949d04SAndroid Build Coastguard Worker free(name);
771*2b949d04SAndroid Build Coastguard Worker free(description);
772*2b949d04SAndroid Build Coastguard Worker free(brief);
773*2b949d04SAndroid Build Coastguard Worker free(vendor);
774*2b949d04SAndroid Build Coastguard Worker return;
775*2b949d04SAndroid Build Coastguard Worker }
776*2b949d04SAndroid Build Coastguard Worker }
777*2b949d04SAndroid Build Coastguard Worker
778*2b949d04SAndroid Build Coastguard Worker /* new model */
779*2b949d04SAndroid Build Coastguard Worker m = rxkb_model_create(&ctx->base);
780*2b949d04SAndroid Build Coastguard Worker m->name = name;
781*2b949d04SAndroid Build Coastguard Worker m->description = description;
782*2b949d04SAndroid Build Coastguard Worker m->vendor = vendor;
783*2b949d04SAndroid Build Coastguard Worker m->popularity = popularity;
784*2b949d04SAndroid Build Coastguard Worker list_append(&ctx->models, &m->base.link);
785*2b949d04SAndroid Build Coastguard Worker }
786*2b949d04SAndroid Build Coastguard Worker }
787*2b949d04SAndroid Build Coastguard Worker
788*2b949d04SAndroid Build Coastguard Worker static void
parse_model_list(struct rxkb_context * ctx,xmlNode * model_list,enum rxkb_popularity popularity)789*2b949d04SAndroid Build Coastguard Worker parse_model_list(struct rxkb_context *ctx, xmlNode *model_list,
790*2b949d04SAndroid Build Coastguard Worker enum rxkb_popularity popularity)
791*2b949d04SAndroid Build Coastguard Worker {
792*2b949d04SAndroid Build Coastguard Worker xmlNode *node = NULL;
793*2b949d04SAndroid Build Coastguard Worker
794*2b949d04SAndroid Build Coastguard Worker for (node = model_list->children; node; node = node->next) {
795*2b949d04SAndroid Build Coastguard Worker if (is_node(node, "model"))
796*2b949d04SAndroid Build Coastguard Worker parse_model(ctx, node, popularity);
797*2b949d04SAndroid Build Coastguard Worker }
798*2b949d04SAndroid Build Coastguard Worker }
799*2b949d04SAndroid Build Coastguard Worker
800*2b949d04SAndroid Build Coastguard Worker static void
parse_language_list(xmlNode * language_list,struct rxkb_layout * layout)801*2b949d04SAndroid Build Coastguard Worker parse_language_list(xmlNode *language_list, struct rxkb_layout *layout)
802*2b949d04SAndroid Build Coastguard Worker {
803*2b949d04SAndroid Build Coastguard Worker xmlNode *node = NULL;
804*2b949d04SAndroid Build Coastguard Worker struct rxkb_iso639_code *code;
805*2b949d04SAndroid Build Coastguard Worker
806*2b949d04SAndroid Build Coastguard Worker for (node = language_list->children; node; node = node->next) {
807*2b949d04SAndroid Build Coastguard Worker if (is_node(node, "iso639Id")) {
808*2b949d04SAndroid Build Coastguard Worker char *str = extract_text(node);
809*2b949d04SAndroid Build Coastguard Worker struct rxkb_object *parent;
810*2b949d04SAndroid Build Coastguard Worker
811*2b949d04SAndroid Build Coastguard Worker if (!str || strlen(str) != 3) {
812*2b949d04SAndroid Build Coastguard Worker free(str);
813*2b949d04SAndroid Build Coastguard Worker continue;
814*2b949d04SAndroid Build Coastguard Worker }
815*2b949d04SAndroid Build Coastguard Worker
816*2b949d04SAndroid Build Coastguard Worker parent = &layout->base;
817*2b949d04SAndroid Build Coastguard Worker code = rxkb_iso639_code_create(parent);
818*2b949d04SAndroid Build Coastguard Worker code->code = str;
819*2b949d04SAndroid Build Coastguard Worker list_append(&layout->iso639s, &code->base.link);
820*2b949d04SAndroid Build Coastguard Worker }
821*2b949d04SAndroid Build Coastguard Worker }
822*2b949d04SAndroid Build Coastguard Worker }
823*2b949d04SAndroid Build Coastguard Worker
824*2b949d04SAndroid Build Coastguard Worker static void
parse_country_list(xmlNode * country_list,struct rxkb_layout * layout)825*2b949d04SAndroid Build Coastguard Worker parse_country_list(xmlNode *country_list, struct rxkb_layout *layout)
826*2b949d04SAndroid Build Coastguard Worker {
827*2b949d04SAndroid Build Coastguard Worker xmlNode *node = NULL;
828*2b949d04SAndroid Build Coastguard Worker struct rxkb_iso3166_code *code;
829*2b949d04SAndroid Build Coastguard Worker
830*2b949d04SAndroid Build Coastguard Worker for (node = country_list->children; node; node = node->next) {
831*2b949d04SAndroid Build Coastguard Worker if (is_node(node, "iso3166Id")) {
832*2b949d04SAndroid Build Coastguard Worker char *str = extract_text(node);
833*2b949d04SAndroid Build Coastguard Worker struct rxkb_object *parent;
834*2b949d04SAndroid Build Coastguard Worker
835*2b949d04SAndroid Build Coastguard Worker if (!str || strlen(str) != 2) {
836*2b949d04SAndroid Build Coastguard Worker free(str);
837*2b949d04SAndroid Build Coastguard Worker continue;
838*2b949d04SAndroid Build Coastguard Worker }
839*2b949d04SAndroid Build Coastguard Worker
840*2b949d04SAndroid Build Coastguard Worker parent = &layout->base;
841*2b949d04SAndroid Build Coastguard Worker code = rxkb_iso3166_code_create(parent);
842*2b949d04SAndroid Build Coastguard Worker code->code = str;
843*2b949d04SAndroid Build Coastguard Worker list_append(&layout->iso3166s, &code->base.link);
844*2b949d04SAndroid Build Coastguard Worker }
845*2b949d04SAndroid Build Coastguard Worker }
846*2b949d04SAndroid Build Coastguard Worker }
847*2b949d04SAndroid Build Coastguard Worker
848*2b949d04SAndroid Build Coastguard Worker static void
parse_variant(struct rxkb_context * ctx,struct rxkb_layout * l,xmlNode * variant,enum rxkb_popularity popularity)849*2b949d04SAndroid Build Coastguard Worker parse_variant(struct rxkb_context *ctx, struct rxkb_layout *l,
850*2b949d04SAndroid Build Coastguard Worker xmlNode *variant, enum rxkb_popularity popularity)
851*2b949d04SAndroid Build Coastguard Worker {
852*2b949d04SAndroid Build Coastguard Worker xmlNode *ci;
853*2b949d04SAndroid Build Coastguard Worker char *name, *description, *brief, *vendor;
854*2b949d04SAndroid Build Coastguard Worker
855*2b949d04SAndroid Build Coastguard Worker if (parse_config_item(ctx, variant, &name, &description, &brief, &vendor)) {
856*2b949d04SAndroid Build Coastguard Worker struct rxkb_layout *v;
857*2b949d04SAndroid Build Coastguard Worker bool exists = false;
858*2b949d04SAndroid Build Coastguard Worker
859*2b949d04SAndroid Build Coastguard Worker list_for_each(v, &ctx->layouts, base.link) {
860*2b949d04SAndroid Build Coastguard Worker if (streq(v->name, name) && streq(v->name, l->name)) {
861*2b949d04SAndroid Build Coastguard Worker exists = true;
862*2b949d04SAndroid Build Coastguard Worker break;
863*2b949d04SAndroid Build Coastguard Worker }
864*2b949d04SAndroid Build Coastguard Worker }
865*2b949d04SAndroid Build Coastguard Worker
866*2b949d04SAndroid Build Coastguard Worker if (!exists) {
867*2b949d04SAndroid Build Coastguard Worker v = rxkb_layout_create(&ctx->base);
868*2b949d04SAndroid Build Coastguard Worker list_init(&v->iso639s);
869*2b949d04SAndroid Build Coastguard Worker list_init(&v->iso3166s);
870*2b949d04SAndroid Build Coastguard Worker v->name = strdup(l->name);
871*2b949d04SAndroid Build Coastguard Worker v->variant = name;
872*2b949d04SAndroid Build Coastguard Worker v->description = description;
873*2b949d04SAndroid Build Coastguard Worker // if variant omits brief, inherit from parent layout.
874*2b949d04SAndroid Build Coastguard Worker v->brief = brief == NULL ? strdup_safe(l->brief) : brief;
875*2b949d04SAndroid Build Coastguard Worker v->popularity = popularity;
876*2b949d04SAndroid Build Coastguard Worker list_append(&ctx->layouts, &v->base.link);
877*2b949d04SAndroid Build Coastguard Worker
878*2b949d04SAndroid Build Coastguard Worker for (ci = variant->children; ci; ci = ci->next) {
879*2b949d04SAndroid Build Coastguard Worker xmlNode *node;
880*2b949d04SAndroid Build Coastguard Worker
881*2b949d04SAndroid Build Coastguard Worker if (!is_node(ci, "configItem"))
882*2b949d04SAndroid Build Coastguard Worker continue;
883*2b949d04SAndroid Build Coastguard Worker
884*2b949d04SAndroid Build Coastguard Worker bool found_language_list = false;
885*2b949d04SAndroid Build Coastguard Worker bool found_country_list = false;
886*2b949d04SAndroid Build Coastguard Worker for (node = ci->children; node; node = node->next) {
887*2b949d04SAndroid Build Coastguard Worker if (is_node(node, "languageList")) {
888*2b949d04SAndroid Build Coastguard Worker parse_language_list(node, v);
889*2b949d04SAndroid Build Coastguard Worker found_language_list = true;
890*2b949d04SAndroid Build Coastguard Worker }
891*2b949d04SAndroid Build Coastguard Worker if (is_node(node, "countryList")) {
892*2b949d04SAndroid Build Coastguard Worker parse_country_list(node, v);
893*2b949d04SAndroid Build Coastguard Worker found_country_list = true;
894*2b949d04SAndroid Build Coastguard Worker }
895*2b949d04SAndroid Build Coastguard Worker }
896*2b949d04SAndroid Build Coastguard Worker if (!found_language_list) {
897*2b949d04SAndroid Build Coastguard Worker // inherit from parent layout
898*2b949d04SAndroid Build Coastguard Worker struct rxkb_iso639_code* x;
899*2b949d04SAndroid Build Coastguard Worker list_for_each(x, &l->iso639s, base.link) {
900*2b949d04SAndroid Build Coastguard Worker struct rxkb_iso639_code* code = rxkb_iso639_code_create(&v->base);
901*2b949d04SAndroid Build Coastguard Worker code->code = strdup(x->code);
902*2b949d04SAndroid Build Coastguard Worker list_append(&v->iso639s, &code->base.link);
903*2b949d04SAndroid Build Coastguard Worker }
904*2b949d04SAndroid Build Coastguard Worker }
905*2b949d04SAndroid Build Coastguard Worker if (!found_country_list) {
906*2b949d04SAndroid Build Coastguard Worker // inherit from parent layout
907*2b949d04SAndroid Build Coastguard Worker struct rxkb_iso3166_code* x;
908*2b949d04SAndroid Build Coastguard Worker list_for_each(x, &l->iso3166s, base.link) {
909*2b949d04SAndroid Build Coastguard Worker struct rxkb_iso3166_code* code = rxkb_iso3166_code_create(&v->base);
910*2b949d04SAndroid Build Coastguard Worker code->code = strdup(x->code);
911*2b949d04SAndroid Build Coastguard Worker list_append(&v->iso3166s, &code->base.link);
912*2b949d04SAndroid Build Coastguard Worker }
913*2b949d04SAndroid Build Coastguard Worker }
914*2b949d04SAndroid Build Coastguard Worker }
915*2b949d04SAndroid Build Coastguard Worker } else {
916*2b949d04SAndroid Build Coastguard Worker free(name);
917*2b949d04SAndroid Build Coastguard Worker free(description);
918*2b949d04SAndroid Build Coastguard Worker free(brief);
919*2b949d04SAndroid Build Coastguard Worker free(vendor);
920*2b949d04SAndroid Build Coastguard Worker }
921*2b949d04SAndroid Build Coastguard Worker }
922*2b949d04SAndroid Build Coastguard Worker }
923*2b949d04SAndroid Build Coastguard Worker
924*2b949d04SAndroid Build Coastguard Worker static void
parse_variant_list(struct rxkb_context * ctx,struct rxkb_layout * l,xmlNode * variant_list,enum rxkb_popularity popularity)925*2b949d04SAndroid Build Coastguard Worker parse_variant_list(struct rxkb_context *ctx, struct rxkb_layout *l,
926*2b949d04SAndroid Build Coastguard Worker xmlNode *variant_list, enum rxkb_popularity popularity)
927*2b949d04SAndroid Build Coastguard Worker {
928*2b949d04SAndroid Build Coastguard Worker xmlNode *node = NULL;
929*2b949d04SAndroid Build Coastguard Worker
930*2b949d04SAndroid Build Coastguard Worker for (node = variant_list->children; node; node = node->next) {
931*2b949d04SAndroid Build Coastguard Worker if (is_node(node, "variant"))
932*2b949d04SAndroid Build Coastguard Worker parse_variant(ctx, l, node, popularity);
933*2b949d04SAndroid Build Coastguard Worker }
934*2b949d04SAndroid Build Coastguard Worker }
935*2b949d04SAndroid Build Coastguard Worker
936*2b949d04SAndroid Build Coastguard Worker static void
parse_layout(struct rxkb_context * ctx,xmlNode * layout,enum rxkb_popularity popularity)937*2b949d04SAndroid Build Coastguard Worker parse_layout(struct rxkb_context *ctx, xmlNode *layout,
938*2b949d04SAndroid Build Coastguard Worker enum rxkb_popularity popularity)
939*2b949d04SAndroid Build Coastguard Worker {
940*2b949d04SAndroid Build Coastguard Worker char *name, *description, *brief, *vendor;
941*2b949d04SAndroid Build Coastguard Worker struct rxkb_layout *l;
942*2b949d04SAndroid Build Coastguard Worker xmlNode *node = NULL;
943*2b949d04SAndroid Build Coastguard Worker bool exists = false;
944*2b949d04SAndroid Build Coastguard Worker
945*2b949d04SAndroid Build Coastguard Worker if (!parse_config_item(ctx, layout, &name, &description, &brief, &vendor))
946*2b949d04SAndroid Build Coastguard Worker return;
947*2b949d04SAndroid Build Coastguard Worker
948*2b949d04SAndroid Build Coastguard Worker list_for_each(l, &ctx->layouts, base.link) {
949*2b949d04SAndroid Build Coastguard Worker if (streq(l->name, name) && l->variant == NULL) {
950*2b949d04SAndroid Build Coastguard Worker exists = true;
951*2b949d04SAndroid Build Coastguard Worker break;
952*2b949d04SAndroid Build Coastguard Worker }
953*2b949d04SAndroid Build Coastguard Worker }
954*2b949d04SAndroid Build Coastguard Worker
955*2b949d04SAndroid Build Coastguard Worker if (!exists) {
956*2b949d04SAndroid Build Coastguard Worker l = rxkb_layout_create(&ctx->base);
957*2b949d04SAndroid Build Coastguard Worker list_init(&l->iso639s);
958*2b949d04SAndroid Build Coastguard Worker list_init(&l->iso3166s);
959*2b949d04SAndroid Build Coastguard Worker l->name = name;
960*2b949d04SAndroid Build Coastguard Worker l->variant = NULL;
961*2b949d04SAndroid Build Coastguard Worker l->description = description;
962*2b949d04SAndroid Build Coastguard Worker l->brief = brief;
963*2b949d04SAndroid Build Coastguard Worker l->popularity = popularity;
964*2b949d04SAndroid Build Coastguard Worker list_append(&ctx->layouts, &l->base.link);
965*2b949d04SAndroid Build Coastguard Worker } else {
966*2b949d04SAndroid Build Coastguard Worker free(name);
967*2b949d04SAndroid Build Coastguard Worker free(description);
968*2b949d04SAndroid Build Coastguard Worker free(brief);
969*2b949d04SAndroid Build Coastguard Worker free(vendor);
970*2b949d04SAndroid Build Coastguard Worker }
971*2b949d04SAndroid Build Coastguard Worker
972*2b949d04SAndroid Build Coastguard Worker for (node = layout->children; node; node = node->next) {
973*2b949d04SAndroid Build Coastguard Worker if (is_node(node, "variantList")) {
974*2b949d04SAndroid Build Coastguard Worker parse_variant_list(ctx, l, node, popularity);
975*2b949d04SAndroid Build Coastguard Worker }
976*2b949d04SAndroid Build Coastguard Worker if (!exists && is_node(node, "configItem")) {
977*2b949d04SAndroid Build Coastguard Worker xmlNode *ll;
978*2b949d04SAndroid Build Coastguard Worker for (ll = node->children; ll; ll = ll->next) {
979*2b949d04SAndroid Build Coastguard Worker if (is_node(ll, "languageList"))
980*2b949d04SAndroid Build Coastguard Worker parse_language_list(ll, l);
981*2b949d04SAndroid Build Coastguard Worker if (is_node(ll, "countryList"))
982*2b949d04SAndroid Build Coastguard Worker parse_country_list(ll, l);
983*2b949d04SAndroid Build Coastguard Worker }
984*2b949d04SAndroid Build Coastguard Worker }
985*2b949d04SAndroid Build Coastguard Worker }
986*2b949d04SAndroid Build Coastguard Worker }
987*2b949d04SAndroid Build Coastguard Worker
988*2b949d04SAndroid Build Coastguard Worker static void
parse_layout_list(struct rxkb_context * ctx,xmlNode * layout_list,enum rxkb_popularity popularity)989*2b949d04SAndroid Build Coastguard Worker parse_layout_list(struct rxkb_context *ctx, xmlNode *layout_list,
990*2b949d04SAndroid Build Coastguard Worker enum rxkb_popularity popularity)
991*2b949d04SAndroid Build Coastguard Worker {
992*2b949d04SAndroid Build Coastguard Worker xmlNode *node = NULL;
993*2b949d04SAndroid Build Coastguard Worker
994*2b949d04SAndroid Build Coastguard Worker for (node = layout_list->children; node; node = node->next) {
995*2b949d04SAndroid Build Coastguard Worker if (is_node(node, "layout"))
996*2b949d04SAndroid Build Coastguard Worker parse_layout(ctx, node, popularity);
997*2b949d04SAndroid Build Coastguard Worker }
998*2b949d04SAndroid Build Coastguard Worker }
999*2b949d04SAndroid Build Coastguard Worker
1000*2b949d04SAndroid Build Coastguard Worker static void
parse_option(struct rxkb_context * ctx,struct rxkb_option_group * group,xmlNode * option,enum rxkb_popularity popularity)1001*2b949d04SAndroid Build Coastguard Worker parse_option(struct rxkb_context *ctx, struct rxkb_option_group *group,
1002*2b949d04SAndroid Build Coastguard Worker xmlNode *option, enum rxkb_popularity popularity)
1003*2b949d04SAndroid Build Coastguard Worker {
1004*2b949d04SAndroid Build Coastguard Worker char *name, *description, *brief, *vendor;
1005*2b949d04SAndroid Build Coastguard Worker
1006*2b949d04SAndroid Build Coastguard Worker if (parse_config_item(ctx, option, &name, &description, &brief, &vendor)) {
1007*2b949d04SAndroid Build Coastguard Worker struct rxkb_option *o;
1008*2b949d04SAndroid Build Coastguard Worker
1009*2b949d04SAndroid Build Coastguard Worker list_for_each(o, &group->options, base.link) {
1010*2b949d04SAndroid Build Coastguard Worker if (streq(o->name, name)) {
1011*2b949d04SAndroid Build Coastguard Worker free(name);
1012*2b949d04SAndroid Build Coastguard Worker free(description);
1013*2b949d04SAndroid Build Coastguard Worker free(brief);
1014*2b949d04SAndroid Build Coastguard Worker free(vendor);
1015*2b949d04SAndroid Build Coastguard Worker return;
1016*2b949d04SAndroid Build Coastguard Worker }
1017*2b949d04SAndroid Build Coastguard Worker }
1018*2b949d04SAndroid Build Coastguard Worker
1019*2b949d04SAndroid Build Coastguard Worker o = rxkb_option_create(&group->base);
1020*2b949d04SAndroid Build Coastguard Worker o->name = name;
1021*2b949d04SAndroid Build Coastguard Worker o->description = description;
1022*2b949d04SAndroid Build Coastguard Worker o->popularity = popularity;
1023*2b949d04SAndroid Build Coastguard Worker list_append(&group->options, &o->base.link);
1024*2b949d04SAndroid Build Coastguard Worker }
1025*2b949d04SAndroid Build Coastguard Worker }
1026*2b949d04SAndroid Build Coastguard Worker
1027*2b949d04SAndroid Build Coastguard Worker static void
parse_group(struct rxkb_context * ctx,xmlNode * group,enum rxkb_popularity popularity)1028*2b949d04SAndroid Build Coastguard Worker parse_group(struct rxkb_context *ctx, xmlNode *group,
1029*2b949d04SAndroid Build Coastguard Worker enum rxkb_popularity popularity)
1030*2b949d04SAndroid Build Coastguard Worker {
1031*2b949d04SAndroid Build Coastguard Worker char *name, *description, *brief, *vendor;
1032*2b949d04SAndroid Build Coastguard Worker struct rxkb_option_group *g;
1033*2b949d04SAndroid Build Coastguard Worker xmlNode *node = NULL;
1034*2b949d04SAndroid Build Coastguard Worker xmlChar *multiple;
1035*2b949d04SAndroid Build Coastguard Worker bool exists = false;
1036*2b949d04SAndroid Build Coastguard Worker
1037*2b949d04SAndroid Build Coastguard Worker if (!parse_config_item(ctx, group, &name, &description, &brief, &vendor))
1038*2b949d04SAndroid Build Coastguard Worker return;
1039*2b949d04SAndroid Build Coastguard Worker
1040*2b949d04SAndroid Build Coastguard Worker list_for_each(g, &ctx->option_groups, base.link) {
1041*2b949d04SAndroid Build Coastguard Worker if (streq(g->name, name)) {
1042*2b949d04SAndroid Build Coastguard Worker exists = true;
1043*2b949d04SAndroid Build Coastguard Worker break;
1044*2b949d04SAndroid Build Coastguard Worker }
1045*2b949d04SAndroid Build Coastguard Worker }
1046*2b949d04SAndroid Build Coastguard Worker
1047*2b949d04SAndroid Build Coastguard Worker if (!exists) {
1048*2b949d04SAndroid Build Coastguard Worker g = rxkb_option_group_create(&ctx->base);
1049*2b949d04SAndroid Build Coastguard Worker g->name = name;
1050*2b949d04SAndroid Build Coastguard Worker g->description = description;
1051*2b949d04SAndroid Build Coastguard Worker g->popularity = popularity;
1052*2b949d04SAndroid Build Coastguard Worker
1053*2b949d04SAndroid Build Coastguard Worker multiple = xmlGetProp(group, (const xmlChar*)"allowMultipleSelection");
1054*2b949d04SAndroid Build Coastguard Worker if (multiple && xmlStrEqual(multiple, (const xmlChar*)"true"))
1055*2b949d04SAndroid Build Coastguard Worker g->allow_multiple = true;
1056*2b949d04SAndroid Build Coastguard Worker xmlFree(multiple);
1057*2b949d04SAndroid Build Coastguard Worker
1058*2b949d04SAndroid Build Coastguard Worker list_init(&g->options);
1059*2b949d04SAndroid Build Coastguard Worker list_append(&ctx->option_groups, &g->base.link);
1060*2b949d04SAndroid Build Coastguard Worker } else {
1061*2b949d04SAndroid Build Coastguard Worker free(name);
1062*2b949d04SAndroid Build Coastguard Worker free(description);
1063*2b949d04SAndroid Build Coastguard Worker free(brief);
1064*2b949d04SAndroid Build Coastguard Worker free(vendor);
1065*2b949d04SAndroid Build Coastguard Worker }
1066*2b949d04SAndroid Build Coastguard Worker
1067*2b949d04SAndroid Build Coastguard Worker for (node = group->children; node; node = node->next) {
1068*2b949d04SAndroid Build Coastguard Worker if (is_node(node, "option"))
1069*2b949d04SAndroid Build Coastguard Worker parse_option(ctx, g, node, popularity);
1070*2b949d04SAndroid Build Coastguard Worker }
1071*2b949d04SAndroid Build Coastguard Worker }
1072*2b949d04SAndroid Build Coastguard Worker
1073*2b949d04SAndroid Build Coastguard Worker static void
parse_option_list(struct rxkb_context * ctx,xmlNode * option_list,enum rxkb_popularity popularity)1074*2b949d04SAndroid Build Coastguard Worker parse_option_list(struct rxkb_context *ctx, xmlNode *option_list,
1075*2b949d04SAndroid Build Coastguard Worker enum rxkb_popularity popularity)
1076*2b949d04SAndroid Build Coastguard Worker {
1077*2b949d04SAndroid Build Coastguard Worker xmlNode *node = NULL;
1078*2b949d04SAndroid Build Coastguard Worker
1079*2b949d04SAndroid Build Coastguard Worker for (node = option_list->children; node; node = node->next) {
1080*2b949d04SAndroid Build Coastguard Worker if (is_node(node, "group"))
1081*2b949d04SAndroid Build Coastguard Worker parse_group(ctx, node, popularity);
1082*2b949d04SAndroid Build Coastguard Worker }
1083*2b949d04SAndroid Build Coastguard Worker }
1084*2b949d04SAndroid Build Coastguard Worker
1085*2b949d04SAndroid Build Coastguard Worker static void
parse_rules_xml(struct rxkb_context * ctx,xmlNode * root,enum rxkb_popularity popularity)1086*2b949d04SAndroid Build Coastguard Worker parse_rules_xml(struct rxkb_context *ctx, xmlNode *root,
1087*2b949d04SAndroid Build Coastguard Worker enum rxkb_popularity popularity)
1088*2b949d04SAndroid Build Coastguard Worker {
1089*2b949d04SAndroid Build Coastguard Worker xmlNode *node = NULL;
1090*2b949d04SAndroid Build Coastguard Worker
1091*2b949d04SAndroid Build Coastguard Worker for (node = root->children; node; node = node->next) {
1092*2b949d04SAndroid Build Coastguard Worker if (is_node(node, "modelList"))
1093*2b949d04SAndroid Build Coastguard Worker parse_model_list(ctx, node, popularity);
1094*2b949d04SAndroid Build Coastguard Worker else if (is_node(node, "layoutList"))
1095*2b949d04SAndroid Build Coastguard Worker parse_layout_list(ctx, node, popularity);
1096*2b949d04SAndroid Build Coastguard Worker else if (is_node(node, "optionList"))
1097*2b949d04SAndroid Build Coastguard Worker parse_option_list(ctx, node, popularity);
1098*2b949d04SAndroid Build Coastguard Worker }
1099*2b949d04SAndroid Build Coastguard Worker }
1100*2b949d04SAndroid Build Coastguard Worker
1101*2b949d04SAndroid Build Coastguard Worker static void
1102*2b949d04SAndroid Build Coastguard Worker ATTR_PRINTF(2, 0)
xml_error_func(void * ctx,const char * msg,...)1103*2b949d04SAndroid Build Coastguard Worker xml_error_func(void *ctx, const char *msg, ...)
1104*2b949d04SAndroid Build Coastguard Worker {
1105*2b949d04SAndroid Build Coastguard Worker static char buf[PATH_MAX];
1106*2b949d04SAndroid Build Coastguard Worker static int slen = 0;
1107*2b949d04SAndroid Build Coastguard Worker va_list args;
1108*2b949d04SAndroid Build Coastguard Worker int rc;
1109*2b949d04SAndroid Build Coastguard Worker
1110*2b949d04SAndroid Build Coastguard Worker /* libxml2 prints IO errors from bad includes paths by
1111*2b949d04SAndroid Build Coastguard Worker * calling the error function once per word. So we get to
1112*2b949d04SAndroid Build Coastguard Worker * re-assemble the message here and print it when we get
1113*2b949d04SAndroid Build Coastguard Worker * the line break. My enthusiasm about this is indescribable.
1114*2b949d04SAndroid Build Coastguard Worker */
1115*2b949d04SAndroid Build Coastguard Worker va_start(args, msg);
1116*2b949d04SAndroid Build Coastguard Worker rc = vsnprintf(&buf[slen], sizeof(buf) - slen, msg, args);
1117*2b949d04SAndroid Build Coastguard Worker va_end(args);
1118*2b949d04SAndroid Build Coastguard Worker
1119*2b949d04SAndroid Build Coastguard Worker /* This shouldn't really happen */
1120*2b949d04SAndroid Build Coastguard Worker if (rc < 0) {
1121*2b949d04SAndroid Build Coastguard Worker log_err(ctx, "+++ out of cheese error. redo from start +++\n");
1122*2b949d04SAndroid Build Coastguard Worker slen = 0;
1123*2b949d04SAndroid Build Coastguard Worker memset(buf, 0, sizeof(buf));
1124*2b949d04SAndroid Build Coastguard Worker return;
1125*2b949d04SAndroid Build Coastguard Worker }
1126*2b949d04SAndroid Build Coastguard Worker
1127*2b949d04SAndroid Build Coastguard Worker slen += rc;
1128*2b949d04SAndroid Build Coastguard Worker if (slen >= (int)sizeof(buf)) {
1129*2b949d04SAndroid Build Coastguard Worker /* truncated, let's flush this */
1130*2b949d04SAndroid Build Coastguard Worker buf[sizeof(buf) - 1] = '\n';
1131*2b949d04SAndroid Build Coastguard Worker slen = sizeof(buf);
1132*2b949d04SAndroid Build Coastguard Worker }
1133*2b949d04SAndroid Build Coastguard Worker
1134*2b949d04SAndroid Build Coastguard Worker /* We're assuming here that the last character is \n. */
1135*2b949d04SAndroid Build Coastguard Worker if (buf[slen - 1] == '\n') {
1136*2b949d04SAndroid Build Coastguard Worker log_err(ctx, "%s", buf);
1137*2b949d04SAndroid Build Coastguard Worker memset(buf, 0, sizeof(buf));
1138*2b949d04SAndroid Build Coastguard Worker slen = 0;
1139*2b949d04SAndroid Build Coastguard Worker }
1140*2b949d04SAndroid Build Coastguard Worker }
1141*2b949d04SAndroid Build Coastguard Worker
1142*2b949d04SAndroid Build Coastguard Worker static bool
validate(struct rxkb_context * ctx,xmlDoc * doc)1143*2b949d04SAndroid Build Coastguard Worker validate(struct rxkb_context *ctx, xmlDoc *doc)
1144*2b949d04SAndroid Build Coastguard Worker {
1145*2b949d04SAndroid Build Coastguard Worker bool success = false;
1146*2b949d04SAndroid Build Coastguard Worker xmlValidCtxt *dtdvalid = NULL;
1147*2b949d04SAndroid Build Coastguard Worker xmlDtd *dtd = NULL;
1148*2b949d04SAndroid Build Coastguard Worker xmlParserInputBufferPtr buf = NULL;
1149*2b949d04SAndroid Build Coastguard Worker /* This is a modified version of the xkeyboard-config xkb.dtd. That one
1150*2b949d04SAndroid Build Coastguard Worker * requires modelList, layoutList and optionList, we
1151*2b949d04SAndroid Build Coastguard Worker * allow for any of those to be missing.
1152*2b949d04SAndroid Build Coastguard Worker */
1153*2b949d04SAndroid Build Coastguard Worker const char dtdstr[] =
1154*2b949d04SAndroid Build Coastguard Worker "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1155*2b949d04SAndroid Build Coastguard Worker "<!ELEMENT xkbConfigRegistry (modelList?, layoutList?, optionList?)>\n"
1156*2b949d04SAndroid Build Coastguard Worker "<!ATTLIST xkbConfigRegistry version CDATA \"1.1\">\n"
1157*2b949d04SAndroid Build Coastguard Worker "<!ELEMENT modelList (model*)>\n"
1158*2b949d04SAndroid Build Coastguard Worker "<!ELEMENT model (configItem)>\n"
1159*2b949d04SAndroid Build Coastguard Worker "<!ELEMENT layoutList (layout*)>\n"
1160*2b949d04SAndroid Build Coastguard Worker "<!ELEMENT layout (configItem, variantList?)>\n"
1161*2b949d04SAndroid Build Coastguard Worker "<!ELEMENT optionList (group*)>\n"
1162*2b949d04SAndroid Build Coastguard Worker "<!ELEMENT variantList (variant*)>\n"
1163*2b949d04SAndroid Build Coastguard Worker "<!ELEMENT variant (configItem)>\n"
1164*2b949d04SAndroid Build Coastguard Worker "<!ELEMENT group (configItem, option*)>\n"
1165*2b949d04SAndroid Build Coastguard Worker "<!ATTLIST group allowMultipleSelection (true|false) \"false\">\n"
1166*2b949d04SAndroid Build Coastguard Worker "<!ELEMENT option (configItem)>\n"
1167*2b949d04SAndroid Build Coastguard Worker "<!ELEMENT configItem (name, shortDescription?, description?, vendor?, countryList?, languageList?, hwList?)>\n"
1168*2b949d04SAndroid Build Coastguard Worker "<!ATTLIST configItem popularity (standard|exotic) \"standard\">\n"
1169*2b949d04SAndroid Build Coastguard Worker "<!ELEMENT name (#PCDATA)>\n"
1170*2b949d04SAndroid Build Coastguard Worker "<!ELEMENT shortDescription (#PCDATA)>\n"
1171*2b949d04SAndroid Build Coastguard Worker "<!ELEMENT description (#PCDATA)>\n"
1172*2b949d04SAndroid Build Coastguard Worker "<!ELEMENT vendor (#PCDATA)>\n"
1173*2b949d04SAndroid Build Coastguard Worker "<!ELEMENT countryList (iso3166Id+)>\n"
1174*2b949d04SAndroid Build Coastguard Worker "<!ELEMENT iso3166Id (#PCDATA)>\n"
1175*2b949d04SAndroid Build Coastguard Worker "<!ELEMENT languageList (iso639Id+)>\n"
1176*2b949d04SAndroid Build Coastguard Worker "<!ELEMENT iso639Id (#PCDATA)>\n"
1177*2b949d04SAndroid Build Coastguard Worker "<!ELEMENT hwList (hwId+)>\n"
1178*2b949d04SAndroid Build Coastguard Worker "<!ELEMENT hwId (#PCDATA)>\n";
1179*2b949d04SAndroid Build Coastguard Worker
1180*2b949d04SAndroid Build Coastguard Worker /* Note: do not use xmlParserInputBufferCreateStatic, it generates random
1181*2b949d04SAndroid Build Coastguard Worker * DTD validity errors for unknown reasons */
1182*2b949d04SAndroid Build Coastguard Worker buf = xmlParserInputBufferCreateMem(dtdstr, sizeof(dtdstr),
1183*2b949d04SAndroid Build Coastguard Worker XML_CHAR_ENCODING_UTF8);
1184*2b949d04SAndroid Build Coastguard Worker if (!buf)
1185*2b949d04SAndroid Build Coastguard Worker return false;
1186*2b949d04SAndroid Build Coastguard Worker
1187*2b949d04SAndroid Build Coastguard Worker dtd = xmlIOParseDTD(NULL, buf, XML_CHAR_ENCODING_UTF8);
1188*2b949d04SAndroid Build Coastguard Worker if (!dtd) {
1189*2b949d04SAndroid Build Coastguard Worker log_err(ctx, "Failed to load DTD\n");
1190*2b949d04SAndroid Build Coastguard Worker return false;
1191*2b949d04SAndroid Build Coastguard Worker }
1192*2b949d04SAndroid Build Coastguard Worker
1193*2b949d04SAndroid Build Coastguard Worker dtdvalid = xmlNewValidCtxt();
1194*2b949d04SAndroid Build Coastguard Worker if (xmlValidateDtd(dtdvalid, doc, dtd))
1195*2b949d04SAndroid Build Coastguard Worker success = true;
1196*2b949d04SAndroid Build Coastguard Worker
1197*2b949d04SAndroid Build Coastguard Worker if (dtd)
1198*2b949d04SAndroid Build Coastguard Worker xmlFreeDtd(dtd);
1199*2b949d04SAndroid Build Coastguard Worker if (dtdvalid)
1200*2b949d04SAndroid Build Coastguard Worker xmlFreeValidCtxt(dtdvalid);
1201*2b949d04SAndroid Build Coastguard Worker
1202*2b949d04SAndroid Build Coastguard Worker return success;
1203*2b949d04SAndroid Build Coastguard Worker }
1204*2b949d04SAndroid Build Coastguard Worker
1205*2b949d04SAndroid Build Coastguard Worker static bool
parse(struct rxkb_context * ctx,const char * path,enum rxkb_popularity popularity)1206*2b949d04SAndroid Build Coastguard Worker parse(struct rxkb_context *ctx, const char *path,
1207*2b949d04SAndroid Build Coastguard Worker enum rxkb_popularity popularity)
1208*2b949d04SAndroid Build Coastguard Worker {
1209*2b949d04SAndroid Build Coastguard Worker bool success = false;
1210*2b949d04SAndroid Build Coastguard Worker xmlDoc *doc = NULL;
1211*2b949d04SAndroid Build Coastguard Worker xmlNode *root = NULL;
1212*2b949d04SAndroid Build Coastguard Worker
1213*2b949d04SAndroid Build Coastguard Worker if (!check_eaccess(path, R_OK))
1214*2b949d04SAndroid Build Coastguard Worker return false;
1215*2b949d04SAndroid Build Coastguard Worker
1216*2b949d04SAndroid Build Coastguard Worker LIBXML_TEST_VERSION
1217*2b949d04SAndroid Build Coastguard Worker
1218*2b949d04SAndroid Build Coastguard Worker xmlSetGenericErrorFunc(ctx, xml_error_func);
1219*2b949d04SAndroid Build Coastguard Worker
1220*2b949d04SAndroid Build Coastguard Worker doc = xmlParseFile(path);
1221*2b949d04SAndroid Build Coastguard Worker if (!doc)
1222*2b949d04SAndroid Build Coastguard Worker return false;
1223*2b949d04SAndroid Build Coastguard Worker
1224*2b949d04SAndroid Build Coastguard Worker if (!validate(ctx, doc)) {
1225*2b949d04SAndroid Build Coastguard Worker log_err(ctx, "XML error: failed to validate document at %s\n", path);
1226*2b949d04SAndroid Build Coastguard Worker goto error;
1227*2b949d04SAndroid Build Coastguard Worker }
1228*2b949d04SAndroid Build Coastguard Worker
1229*2b949d04SAndroid Build Coastguard Worker root = xmlDocGetRootElement(doc);
1230*2b949d04SAndroid Build Coastguard Worker parse_rules_xml(ctx, root, popularity);
1231*2b949d04SAndroid Build Coastguard Worker
1232*2b949d04SAndroid Build Coastguard Worker success = true;
1233*2b949d04SAndroid Build Coastguard Worker error:
1234*2b949d04SAndroid Build Coastguard Worker xmlFreeDoc(doc);
1235*2b949d04SAndroid Build Coastguard Worker
1236*2b949d04SAndroid Build Coastguard Worker return success;
1237*2b949d04SAndroid Build Coastguard Worker }
1238