client/locale: properly check popen return value
[platform/upstream/freerdp.git] / libfreerdp / locale / keyboard_x11.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  * X11 Keyboard Mapping
4  *
5  * Copyright 2009-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include <winpr/crt.h>
29 #include <winpr/input.h>
30
31 #include "liblocale.h"
32
33 #include <freerdp/locale/locale.h>
34 #include <freerdp/locale/keyboard.h>
35
36 #include "keyboard_x11.h"
37 #include "xkb_layout_ids.h"
38
39 int freerdp_detect_keyboard_layout_from_xkb(DWORD* keyboardLayoutId)
40 {
41         char* pch;
42         char* beg;
43         char* end;
44         FILE* xprop;
45         char buffer[1024];
46         char* layout = NULL;
47         char* variant = NULL;
48
49         /* We start by looking for _XKB_RULES_NAMES_BACKUP which appears to be used by libxklavier */
50
51     if (!(xprop = popen("xprop -root _XKB_RULES_NAMES_BACKUP", "r")))
52                 return 0;
53
54         /* Sample output for "Canadian Multilingual Standard"
55          *
56          * _XKB_RULES_NAMES_BACKUP(STRING) = "xorg", "pc105", "ca", "multix", ""
57          * Where "xorg" is the set of rules
58          * "pc105" the keyboard type
59          * "ca" the keyboard layout
60          * "multi" the keyboard layout variant
61          */
62
63         while (fgets(buffer, sizeof(buffer), xprop) != NULL)
64         {
65                 if ((pch = strstr(buffer, "_XKB_RULES_NAMES_BACKUP(STRING) = ")) != NULL)
66                 {
67                         /* "rules" */
68                         pch = strchr(&buffer[34], ','); /* We assume it is xorg */
69                         pch += 1;
70
71                         /* "type" */
72                         pch = strchr(pch, ',');
73
74                         /* "layout" */
75                         beg = strchr(pch + 1, '"');
76                         beg += 1;
77
78                         end = strchr(beg, '"');
79                         *end = '\0';
80
81                         layout = beg;
82
83                         /* "variant" */
84                         beg = strchr(end + 1, '"');
85                         beg += 1;
86
87                         end = strchr(beg, '"');
88                         *end = '\0';
89
90                         variant = beg;
91                 }
92         }
93
94         pclose(xprop);
95
96         DEBUG_KBD("_XKB_RULES_NAMES_BACKUP layout: %s, variant: %s", layout, variant);
97         *keyboardLayoutId = find_keyboard_layout_in_xorg_rules(layout, variant);
98
99         if (*keyboardLayoutId > 0)
100                 return 0;
101
102         /* Check _XKB_RULES_NAMES if _XKB_RULES_NAMES_BACKUP fails */
103
104         if (!(xprop = popen("xprop -root _XKB_RULES_NAMES", "r")))
105                 return 0;
106
107         while (fgets(buffer, sizeof(buffer), xprop) != NULL)
108         {
109                 if ((pch = strstr(buffer, "_XKB_RULES_NAMES(STRING) = ")) != NULL)
110                 {
111                         /* "rules" */
112                         pch = strchr(&buffer[27], ','); // We assume it is xorg
113                         pch += 1;
114
115                         /* "type" */
116                         pch = strchr(pch, ',');
117
118                         /* "layout" */
119                         beg = strchr(pch + 1, '"');
120                         beg += 1;
121
122                         end = strchr(beg, '"');
123                         *end = '\0';
124
125                         layout = beg;
126
127                         /* "variant" */
128                         beg = strchr(end + 1, '"');
129                         beg += 1;
130
131                         end = strchr(beg, '"');
132                         *end = '\0';
133
134                         variant = beg;
135                 }
136         }
137
138         pclose(xprop);
139
140         DEBUG_KBD("_XKB_RULES_NAMES layout: %s, variant: %s", layout, variant);
141         *keyboardLayoutId = find_keyboard_layout_in_xorg_rules(layout, variant);
142
143         if (*keyboardLayoutId > 0)
144                 return *keyboardLayoutId;
145
146         return 0;
147 }
148
149 char* freerdp_detect_keymap_from_xkb()
150 {
151         char* pch;
152         char* beg;
153         char* end;
154         int length;
155         FILE* setxkbmap;
156         char buffer[1024];
157         char* keymap = NULL;
158
159         /* this tells us about the current XKB configuration, if XKB is available */
160         setxkbmap = popen("setxkbmap -print", "r");
161
162         if (!setxkbmap)
163                 return NULL;
164
165         while (fgets(buffer, sizeof(buffer), setxkbmap) != NULL)
166         {
167                 /* the line with xkb_keycodes is what interests us */
168                 pch = strstr(buffer, "xkb_keycodes");
169
170                 if (pch != NULL)
171                 {
172                         pch = strstr(pch, "include");
173
174                         if (pch != NULL)
175                         {
176                                 /* check for " " delimiter presence */
177                                 if ((beg = strchr(pch, '"')) == NULL)
178                                         break;
179                                 else
180                                         beg++;
181
182                                 if ((pch = strchr(beg + 1, '"')) == NULL)
183                                         break;
184
185                                 end = strcspn(beg + 1, "\"") + beg + 1;
186                                 *end = '\0';
187
188                                 length = (end - beg);
189                                 keymap = (char*) malloc(length + 1);
190                                 if (keymap) {
191                                         strncpy(keymap, beg, length);
192                                         keymap[length] = '\0';
193                                 }
194
195                                 break;
196                         }
197                 }
198         }
199
200         pclose(setxkbmap);
201
202         return keymap;
203 }