1/************************************************************
2Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3
4Permission to use, copy, modify, and distribute this
5software and its documentation for any purpose and without
6fee is hereby granted, provided that the above copyright
7notice appear in all copies and that both that copyright
8notice and this permission notice appear in supporting
9documentation, and that the name of Silicon Graphics not be
10used in advertising or publicity pertaining to distribution
11of the software without specific prior written permission.
12Silicon Graphics makes no representation about the suitability
13of this software for any purpose. It is provided "as is"
14without any express or implied warranty.
15
16SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25********************************************************/
26
27#ifdef HAVE_DIX_CONFIG_H
28#include <dix-config.h>
29#endif
30
31#include <stdio.h>
32#include <X11/X.h>
33#include <X11/Xproto.h>
34#include "misc.h"
35#include "inputstr.h"
36#include <xkbsrv.h>
37#include "xkbgeom.h"
38#include <os.h>
39#include <string.h>
40
41/***===================================================================***/
42
43 /*ARGSUSED*/ Status
44XkbAllocCompatMap(XkbDescPtr xkb, unsigned which, unsigned nSI)
45{
46    XkbCompatMapPtr compat;
47    XkbSymInterpretRec *prev_interpret;
48
49    if (!xkb)
50        return BadMatch;
51    if (xkb->compat) {
52        if (xkb->compat->size_si >= nSI)
53            return Success;
54        compat = xkb->compat;
55        compat->size_si = nSI;
56        if (compat->sym_interpret == NULL)
57            compat->num_si = 0;
58        prev_interpret = compat->sym_interpret;
59        compat->sym_interpret = reallocarray(compat->sym_interpret,
60                                             nSI, sizeof(XkbSymInterpretRec));
61        if (compat->sym_interpret == NULL) {
62            free(prev_interpret);
63            compat->size_si = compat->num_si = 0;
64            return BadAlloc;
65        }
66        if (compat->num_si != 0) {
67            memset(&compat->sym_interpret[compat->num_si], 0,
68                   (compat->size_si -
69                    compat->num_si) * sizeof(XkbSymInterpretRec));
70        }
71        return Success;
72    }
73    compat = calloc(1, sizeof(XkbCompatMapRec));
74    if (compat == NULL)
75        return BadAlloc;
76    if (nSI > 0) {
77        compat->sym_interpret = calloc(nSI, sizeof(XkbSymInterpretRec));
78        if (!compat->sym_interpret) {
79            free(compat);
80            return BadAlloc;
81        }
82    }
83    compat->size_si = nSI;
84    compat->num_si = 0;
85    memset((char *) &compat->groups[0], 0,
86           XkbNumKbdGroups * sizeof(XkbModsRec));
87    xkb->compat = compat;
88    return Success;
89}
90
91void
92XkbFreeCompatMap(XkbDescPtr xkb, unsigned which, Bool freeMap)
93{
94    register XkbCompatMapPtr compat;
95
96    if ((xkb == NULL) || (xkb->compat == NULL))
97        return;
98    compat = xkb->compat;
99    if (freeMap)
100        which = XkbAllCompatMask;
101    if (which & XkbGroupCompatMask)
102        memset((char *) &compat->groups[0], 0,
103               XkbNumKbdGroups * sizeof(XkbModsRec));
104    if (which & XkbSymInterpMask) {
105        if ((compat->sym_interpret) && (compat->size_si > 0))
106            free(compat->sym_interpret);
107        compat->size_si = compat->num_si = 0;
108        compat->sym_interpret = NULL;
109    }
110    if (freeMap) {
111        free(compat);
112        xkb->compat = NULL;
113    }
114    return;
115}
116
117/***===================================================================***/
118
119Status
120XkbAllocNames(XkbDescPtr xkb, unsigned which, int nTotalRG, int nTotalAliases)
121{
122    XkbNamesPtr names;
123
124    if (xkb == NULL)
125        return BadMatch;
126    if (xkb->names == NULL) {
127        xkb->names = calloc(1, sizeof(XkbNamesRec));
128        if (xkb->names == NULL)
129            return BadAlloc;
130    }
131    names = xkb->names;
132    if ((which & XkbKTLevelNamesMask) && (xkb->map != NULL) &&
133        (xkb->map->types != NULL)) {
134        register int i;
135        XkbKeyTypePtr type;
136
137        type = xkb->map->types;
138        for (i = 0; i < xkb->map->num_types; i++, type++) {
139            if (type->level_names == NULL) {
140                type->level_names = calloc(type->num_levels, sizeof(Atom));
141                if (type->level_names == NULL)
142                    return BadAlloc;
143            }
144        }
145    }
146    if ((which & XkbKeyNamesMask) && (names->keys == NULL)) {
147        if ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
148            (!XkbIsLegalKeycode(xkb->max_key_code)) ||
149            (xkb->max_key_code < xkb->min_key_code))
150            return BadValue;
151        names->keys = calloc((xkb->max_key_code + 1), sizeof(XkbKeyNameRec));
152        if (names->keys == NULL)
153            return BadAlloc;
154    }
155    if ((which & XkbKeyAliasesMask) && (nTotalAliases > 0)) {
156        if (names->key_aliases == NULL) {
157            names->key_aliases = calloc(nTotalAliases, sizeof(XkbKeyAliasRec));
158        }
159        else if (nTotalAliases > names->num_key_aliases) {
160            XkbKeyAliasRec *prev_aliases = names->key_aliases;
161
162            names->key_aliases = reallocarray(names->key_aliases,
163                                              nTotalAliases,
164                                              sizeof(XkbKeyAliasRec));
165            if (names->key_aliases != NULL) {
166                memset(&names->key_aliases[names->num_key_aliases], 0,
167                       (nTotalAliases -
168                        names->num_key_aliases) * sizeof(XkbKeyAliasRec));
169            }
170            else {
171                free(prev_aliases);
172            }
173        }
174        if (names->key_aliases == NULL) {
175            names->num_key_aliases = 0;
176            return BadAlloc;
177        }
178        names->num_key_aliases = nTotalAliases;
179    }
180    if ((which & XkbRGNamesMask) && (nTotalRG > 0)) {
181        if (names->radio_groups == NULL) {
182            names->radio_groups = calloc(nTotalRG, sizeof(Atom));
183        }
184        else if (nTotalRG > names->num_rg) {
185            Atom *prev_radio_groups = names->radio_groups;
186
187            names->radio_groups = reallocarray(names->radio_groups,
188                                               nTotalRG, sizeof(Atom));
189            if (names->radio_groups != NULL) {
190                memset(&names->radio_groups[names->num_rg], 0,
191                       (nTotalRG - names->num_rg) * sizeof(Atom));
192            }
193            else {
194                free(prev_radio_groups);
195            }
196        }
197        if (names->radio_groups == NULL) {
198            names->num_rg = 0;
199            return BadAlloc;
200        }
201        names->num_rg = nTotalRG;
202    }
203    return Success;
204}
205
206void
207XkbFreeNames(XkbDescPtr xkb, unsigned which, Bool freeMap)
208{
209    XkbNamesPtr names;
210
211    if ((xkb == NULL) || (xkb->names == NULL))
212        return;
213    names = xkb->names;
214    if (freeMap)
215        which = XkbAllNamesMask;
216    if (which & XkbKTLevelNamesMask) {
217        XkbClientMapPtr map = xkb->map;
218
219        if ((map != NULL) && (map->types != NULL)) {
220            register int i;
221            register XkbKeyTypePtr type;
222
223            type = map->types;
224            for (i = 0; i < map->num_types; i++, type++) {
225                free(type->level_names);
226                type->level_names = NULL;
227            }
228        }
229    }
230    if ((which & XkbKeyNamesMask) && (names->keys != NULL)) {
231        free(names->keys);
232        names->keys = NULL;
233        names->num_keys = 0;
234    }
235    if ((which & XkbKeyAliasesMask) && (names->key_aliases)) {
236        free(names->key_aliases);
237        names->key_aliases = NULL;
238        names->num_key_aliases = 0;
239    }
240    if ((which & XkbRGNamesMask) && (names->radio_groups)) {
241        free(names->radio_groups);
242        names->radio_groups = NULL;
243        names->num_rg = 0;
244    }
245    if (freeMap) {
246        free(names);
247        xkb->names = NULL;
248    }
249    return;
250}
251
252/***===================================================================***/
253
254 /*ARGSUSED*/ Status
255XkbAllocControls(XkbDescPtr xkb, unsigned which)
256{
257    if (xkb == NULL)
258        return BadMatch;
259
260    if (xkb->ctrls == NULL) {
261        xkb->ctrls = calloc(1, sizeof(XkbControlsRec));
262        if (!xkb->ctrls)
263            return BadAlloc;
264    }
265    return Success;
266}
267
268 /*ARGSUSED*/ static void
269XkbFreeControls(XkbDescPtr xkb, unsigned which, Bool freeMap)
270{
271    if (freeMap && (xkb != NULL) && (xkb->ctrls != NULL)) {
272        free(xkb->ctrls);
273        xkb->ctrls = NULL;
274    }
275    return;
276}
277
278/***===================================================================***/
279
280Status
281XkbAllocIndicatorMaps(XkbDescPtr xkb)
282{
283    if (xkb == NULL)
284        return BadMatch;
285    if (xkb->indicators == NULL) {
286        xkb->indicators = calloc(1, sizeof(XkbIndicatorRec));
287        if (!xkb->indicators)
288            return BadAlloc;
289    }
290    return Success;
291}
292
293static void
294XkbFreeIndicatorMaps(XkbDescPtr xkb)
295{
296    if ((xkb != NULL) && (xkb->indicators != NULL)) {
297        free(xkb->indicators);
298        xkb->indicators = NULL;
299    }
300    return;
301}
302
303/***====================================================================***/
304
305XkbDescRec *
306XkbAllocKeyboard(void)
307{
308    XkbDescRec *xkb;
309
310    xkb = calloc(1, sizeof(XkbDescRec));
311    if (xkb)
312        xkb->device_spec = XkbUseCoreKbd;
313    return xkb;
314}
315
316void
317XkbFreeKeyboard(XkbDescPtr xkb, unsigned which, Bool freeAll)
318{
319    if (xkb == NULL)
320        return;
321    if (freeAll)
322        which = XkbAllComponentsMask;
323    if (which & XkbClientMapMask)
324        XkbFreeClientMap(xkb, XkbAllClientInfoMask, TRUE);
325    if (which & XkbServerMapMask)
326        XkbFreeServerMap(xkb, XkbAllServerInfoMask, TRUE);
327    if (which & XkbCompatMapMask)
328        XkbFreeCompatMap(xkb, XkbAllCompatMask, TRUE);
329    if (which & XkbIndicatorMapMask)
330        XkbFreeIndicatorMaps(xkb);
331    if (which & XkbNamesMask)
332        XkbFreeNames(xkb, XkbAllNamesMask, TRUE);
333    if ((which & XkbGeometryMask) && (xkb->geom != NULL)) {
334        XkbFreeGeometry(xkb->geom, XkbGeomAllMask, TRUE);
335        /* PERHAPS BONGHITS etc */
336        xkb->geom = NULL;
337    }
338    if (which & XkbControlsMask)
339        XkbFreeControls(xkb, XkbAllControlsMask, TRUE);
340    if (freeAll)
341        free(xkb);
342    return;
343}
344
345/***====================================================================***/
346
347void
348XkbFreeComponentNames(XkbComponentNamesPtr names, Bool freeNames)
349{
350    if (names) {
351        free(names->keycodes);
352        free(names->types);
353        free(names->compat);
354        free(names->symbols);
355        free(names->geometry);
356        memset(names, 0, sizeof(XkbComponentNamesRec));
357    }
358    if (freeNames)
359        free(names);
360}
361