Define our own None atom value
[platform/upstream/libxkbcommon.git] / src / xkbcomp / alias.c
1 /************************************************************
2  Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
3
4  Permission to use, copy, modify, and distribute this
5  software and its documentation for any purpose and without
6  fee is hereby granted, provided that the above copyright
7  notice appear in all copies and that both that copyright
8  notice and this permission notice appear in supporting
9  documentation, and that the name of Silicon Graphics not be
10  used in advertising or publicity pertaining to distribution
11  of the software without specific prior written permission.
12  Silicon Graphics makes no representation about the suitability
13  of this software for any purpose. It is provided "as is"
14  without any express or implied warranty.
15
16  SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17  SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18  AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19  GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20  DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21  DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22  OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23  THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25  ********************************************************/
26
27 #include "xkbcomp.h"
28 #include "xkballoc.h"
29 #include "xkbmisc.h"
30 #include "misc.h"
31 #include "alias.h"
32 #include "keycodes.h"
33
34 static void
35 HandleCollision(AliasInfo * old, AliasInfo * new)
36 {
37     if (strncmp(new->real, old->real, XkbKeyNameLength) == 0)
38     {
39         if (((new->def.fileID == old->def.fileID) && (warningLevel > 0)) ||
40             (warningLevel > 9))
41         {
42             WARN("Alias of %s for %s declared more than once\n",
43                   XkbcKeyNameText(new->alias), XkbcKeyNameText(new->real));
44             ACTION("First definition ignored\n");
45         }
46     }
47     else
48     {
49         char *use, *ignore;
50         if (new->def.merge == MergeAugment)
51         {
52             use = old->real;
53             ignore = new->real;
54         }
55         else
56         {
57             use = new->real;
58             ignore = old->real;
59         }
60         if (((old->def.fileID == new->def.fileID) && (warningLevel > 0)) ||
61             (warningLevel > 9))
62         {
63             WARN("Multiple definitions for alias %s\n",
64                   XkbcKeyNameText(old->alias));
65             ACTION("Using %s, ignoring %s\n",
66                     XkbcKeyNameText(use), XkbcKeyNameText(ignore));
67         }
68         if (use != old->real)
69             memcpy(old->real, use, XkbKeyNameLength);
70     }
71     old->def.fileID = new->def.fileID;
72     old->def.merge = new->def.merge;
73 }
74
75 static void
76 InitAliasInfo(AliasInfo * info,
77               unsigned merge, unsigned file_id, char *alias, char *real)
78 {
79     memset(info, 0, sizeof(AliasInfo));
80     info->def.merge = merge;
81     info->def.fileID = file_id;
82     strncpy(info->alias, alias, XkbKeyNameLength);
83     strncpy(info->real, real, XkbKeyNameLength);
84 }
85
86 int
87 HandleAliasDef(KeyAliasDef * def,
88                unsigned merge, unsigned file_id, AliasInfo ** info_in)
89 {
90     AliasInfo *info;
91
92     for (info = *info_in; info != NULL; info = (AliasInfo *) info->def.next)
93     {
94         if (strncmp(info->alias, def->alias, XkbKeyNameLength) == 0)
95         {
96             AliasInfo new;
97             InitAliasInfo(&new, merge, file_id, def->alias, def->real);
98             HandleCollision(info, &new);
99             return True;
100         }
101     }
102     info = uTypedCalloc(1, AliasInfo);
103     if (info == NULL)
104     {
105         WSGO("Allocation failure in HandleAliasDef\n");
106         return False;
107     }
108     info->def.fileID = file_id;
109     info->def.merge = merge;
110     info->def.next = (CommonInfo *) * info_in;
111     memcpy(info->alias, def->alias, XkbKeyNameLength);
112     memcpy(info->real, def->real, XkbKeyNameLength);
113     *info_in = (AliasInfo *) AddCommonInfo(&(*info_in)->def, &info->def);
114     return True;
115 }
116
117 void
118 ClearAliases(AliasInfo ** info_in)
119 {
120     if ((info_in) && (*info_in))
121         ClearCommonInfo(&(*info_in)->def);
122 }
123
124 Bool
125 MergeAliases(AliasInfo ** into, AliasInfo ** merge, unsigned how_merge)
126 {
127     AliasInfo *tmp;
128     KeyAliasDef def;
129
130     if ((*merge) == NULL)
131         return True;
132     if ((*into) == NULL)
133     {
134         *into = *merge;
135         *merge = NULL;
136         return True;
137     }
138     memset(&def, 0, sizeof(KeyAliasDef));
139     for (tmp = *merge; tmp != NULL; tmp = (AliasInfo *) tmp->def.next)
140     {
141         if (how_merge == MergeDefault)
142             def.merge = tmp->def.merge;
143         else
144             def.merge = how_merge;
145         memcpy(def.alias, tmp->alias, XkbKeyNameLength);
146         memcpy(def.real, tmp->real, XkbKeyNameLength);
147         if (!HandleAliasDef(&def, def.merge, tmp->def.fileID, into))
148             return False;
149     }
150     return True;
151 }
152
153 int
154 ApplyAliases(struct xkb_desc * xkb, AliasInfo ** info_in)
155 {
156     int i;
157     struct xkb_key_alias *old, *a;
158     AliasInfo *info;
159     int nNew, nOld;
160     int status;
161
162     if (*info_in == NULL)
163         return True;
164     nOld = (xkb->names ? xkb->names->num_key_aliases : 0);
165     old = (xkb->names ? xkb->names->key_aliases : NULL);
166     for (nNew = 0, info = *info_in; info != NULL;
167          info = (AliasInfo *) info->def.next)
168     {
169         unsigned long lname;
170         xkb_keycode_t kc;
171
172         lname = KeyNameToLong(info->real);
173         if (!FindNamedKey(xkb, lname, &kc, False, CreateKeyNames(xkb), 0))
174         {
175             if (warningLevel > 4)
176             {
177                 WARN("Attempt to alias %s to non-existent key %s\n",
178                       XkbcKeyNameText(info->alias), XkbcKeyNameText(info->real));
179                 ACTION("Ignored\n");
180             }
181             info->alias[0] = '\0';
182             continue;
183         }
184         lname = KeyNameToLong(info->alias);
185         if (FindNamedKey(xkb, lname, &kc, False, False, 0))
186         {
187             if (warningLevel > 4)
188             {
189                 WARN("Attempt to create alias with the name of a real key\n");
190                 ACTION("Alias \"%s = %s\" ignored\n",
191                         XkbcKeyNameText(info->alias),
192                         XkbcKeyNameText(info->real));
193             }
194             info->alias[0] = '\0';
195             continue;
196         }
197         nNew++;
198         if (old)
199         {
200             for (i = 0, a = old; i < nOld; i++, a++)
201             {
202                 if (strncmp(a->alias, info->alias, XkbKeyNameLength) == 0)
203                 {
204                     AliasInfo old_info;
205                     InitAliasInfo(&old_info, MergeAugment, 0, a->alias, a->real);
206                     HandleCollision(&old_info, info);
207                     memcpy(old_info.real, a->real, XkbKeyNameLength);
208                     info->alias[0] = '\0';
209                     nNew--;
210                     break;
211                 }
212             }
213         }
214     }
215     if (nNew == 0)
216     {
217         ClearCommonInfo(&(*info_in)->def);
218         *info_in = NULL;
219         return True;
220     }
221     status = XkbcAllocNames(xkb, XkbKeyAliasesMask, nOld + nNew);
222     if (xkb->names)
223         old = xkb->names->key_aliases;
224     if (status != Success)
225     {
226         WSGO("Allocation failure in ApplyAliases\n");
227         return False;
228     }
229     a = xkb->names ? &xkb->names->key_aliases[nOld] : NULL;
230     for (info = *info_in; info != NULL; info = (AliasInfo *) info->def.next)
231     {
232         if (info->alias[0] != '\0')
233         {
234             strncpy(a->alias, info->alias, XkbKeyNameLength);
235             strncpy(a->real, info->real, XkbKeyNameLength);
236             a++;
237         }
238     }
239 #ifdef DEBUG
240     if ((a - old) != (nOld + nNew))
241     {
242         WSGO("Expected %d aliases total but created %d\n", nOld + nNew,
243               a - old);
244     }
245 #endif
246     ClearCommonInfo(&(*info_in)->def);
247     *info_in = NULL;
248     return True;
249 }