| File: | handle.c |
| Location: | line 672, column 24 |
| Description: | Potential leak of memory pointed to by 'kcs' |
| 1 | /* | |||
| 2 | ||||
| 3 | Copyright 1988, 1998 The Open Group | |||
| 4 | ||||
| 5 | Permission to use, copy, modify, distribute, and sell this software and its | |||
| 6 | documentation for any purpose is hereby granted without fee, provided that | |||
| 7 | the above copyright notice appear in all copies and that both that | |||
| 8 | copyright notice and this permission notice appear in supporting | |||
| 9 | documentation. | |||
| 10 | ||||
| 11 | The above copyright notice and this permission notice shall be included | |||
| 12 | in all copies or substantial portions of the Software. | |||
| 13 | ||||
| 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| 15 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
| 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |||
| 17 | IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR | |||
| 18 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |||
| 19 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |||
| 20 | OTHER DEALINGS IN THE SOFTWARE. | |||
| 21 | ||||
| 22 | Except as contained in this notice, the name of The Open Group shall | |||
| 23 | not be used in advertising or otherwise to promote the sale, use or | |||
| 24 | other dealings in this Software without prior written authorization | |||
| 25 | from The Open Group. | |||
| 26 | ||||
| 27 | */ | |||
| 28 | ||||
| 29 | #ifdef HAVE_CONFIG_H1 | |||
| 30 | #include "config.h" | |||
| 31 | #endif | |||
| 32 | ||||
| 33 | #include <X11/Xos.h> | |||
| 34 | #include <X11/Xlib.h> | |||
| 35 | #include <stdio.h> | |||
| 36 | #include <ctype.h> | |||
| 37 | #include "xmodmap.h" | |||
| 38 | #include "wq.h" | |||
| 39 | #include <stdlib.h> | |||
| 40 | ||||
| 41 | #ifdef HAVE_STRNCASECMP1 | |||
| 42 | #include <strings.h> | |||
| 43 | #endif | |||
| 44 | ||||
| 45 | static XModifierKeymap *map = NULL((void*)0); | |||
| 46 | ||||
| 47 | ||||
| 48 | /* | |||
| 49 | * The routines in this file manipulate a queue of intructions. Instead of | |||
| 50 | * executing each line as it is entered, we build up a list of actions to | |||
| 51 | * take and execute them all at the end. This allows us to find all errors | |||
| 52 | * at once, and to preserve the context in which we are looking up keysyms. | |||
| 53 | */ | |||
| 54 | ||||
| 55 | struct wq work_queue = {NULL((void*)0), NULL((void*)0)}; | |||
| 56 | ||||
| 57 | ||||
| 58 | /* | |||
| 59 | * common utility routines | |||
| 60 | */ | |||
| 61 | ||||
| 62 | static KeyCode * | |||
| 63 | KeysymToKeycodes(Display *dpy, KeySym keysym, int *pnum_kcs) | |||
| 64 | { | |||
| 65 | KeyCode *kcs = NULL((void*)0); | |||
| 66 | int i, j; | |||
| 67 | ||||
| 68 | *pnum_kcs = 0; | |||
| 69 | for (i = min_keycode; i <= max_keycode; i++) { | |||
| 70 | for (j = 0; j < 8; j++) { | |||
| 71 | if (XKeycodeToKeysym(dpy, (KeyCode) i, j) == keysym) { | |||
| 72 | if (!kcs) | |||
| 73 | kcs = malloc(sizeof(KeyCode)); | |||
| 74 | else | |||
| 75 | kcs = realloc(kcs, sizeof(KeyCode) * (*pnum_kcs + 1)); | |||
| 76 | kcs[*pnum_kcs] = i; | |||
| 77 | *pnum_kcs += 1; | |||
| 78 | break; | |||
| 79 | } | |||
| 80 | } | |||
| 81 | } | |||
| 82 | return kcs; | |||
| 83 | } | |||
| 84 | ||||
| 85 | static char * | |||
| 86 | copy_to_scratch(const char *s, int len) | |||
| 87 | { | |||
| 88 | static char *buf = NULL((void*)0); | |||
| 89 | static int buflen = 0; | |||
| 90 | ||||
| 91 | if (len < 0) | |||
| 92 | len = 0; | |||
| 93 | ||||
| 94 | if (len >= buflen) { | |||
| 95 | if (buf) free (buf); | |||
| 96 | buflen = (len < 40) ? 80 : (len * 2); | |||
| 97 | buf = malloc (buflen+1); | |||
| 98 | if (!buf) { | |||
| 99 | fprintf (stderr__stderrp, "attempt to allocate %d byte scratch buffer\n", buflen + 1); | |||
| 100 | return NULL((void*)0); | |||
| 101 | } | |||
| 102 | } | |||
| 103 | ||||
| 104 | strncpy (buf, s, len)__builtin___strncpy_chk (buf, s, len, __builtin_object_size ( buf, 2 > 1 ? 1 : 0)); | |||
| 105 | buf[len] = '\0'; | |||
| 106 | ||||
| 107 | return (buf); | |||
| 108 | } | |||
| 109 | ||||
| 110 | static void | |||
| 111 | badheader(void) | |||
| 112 | { | |||
| 113 | fprintf (stderr__stderrp, "%s: %s:%d: bad ", ProgramName, inputFilename, lineno+1); | |||
| 114 | parse_errors++; | |||
| 115 | } | |||
| 116 | ||||
| 117 | #define badmsg0(what){ badheader(); fprintf (__stderrp, what); putc ('\n', __stderrp ); } { badheader(); fprintf (stderr__stderrp, what); \ | |||
| 118 | putc ('\n', stderr__stderrp); } | |||
| 119 | ||||
| 120 | #define badmsg(what,arg){ badheader(); fprintf (__stderrp, what, arg); putc ('\n', __stderrp ); } { badheader(); fprintf (stderr__stderrp, what, arg); \ | |||
| 121 | putc ('\n', stderr__stderrp); } | |||
| 122 | ||||
| 123 | #define badmsgn(what,s,len){ badheader(); fprintf (__stderrp, what, copy_to_scratch (s, len )); putc ('\n', __stderrp); } badmsg (what, copy_to_scratch (s, len)){ badheader(); fprintf (__stderrp, what, copy_to_scratch (s, len )); putc ('\n', __stderrp); } | |||
| 124 | ||||
| 125 | void | |||
| 126 | initialize_map (void) | |||
| 127 | { | |||
| 128 | map = XGetModifierMapping (dpy); | |||
| 129 | return; | |||
| 130 | } | |||
| 131 | ||||
| 132 | static void do_keycode ( char *line, int len ); | |||
| 133 | static void do_keysym ( char *line, int len ); | |||
| 134 | static void finish_keycodes ( const char *line, int len, KeyCode *keycodes, | |||
| 135 | int count ); | |||
| 136 | static void do_add ( char *line, int len ); | |||
| 137 | static void do_remove ( char *line, int len ); | |||
| 138 | static void do_clear ( char *line, int len ); | |||
| 139 | static void do_pointer ( char *line, int len ); | |||
| 140 | static int get_keysym_list ( const char *line, int len, int *np, KeySym **kslistp ); | |||
| 141 | ||||
| 142 | static void print_opcode(union op *op); | |||
| 143 | ||||
| 144 | static int skip_word ( const char *s, int len ); | |||
| 145 | static int skip_chars ( const char *s, int len ); | |||
| 146 | static int skip_space ( const char *s, int len ); | |||
| 147 | ||||
| 148 | static struct dt { | |||
| 149 | const char *command; /* name of input command */ | |||
| 150 | int length; /* length of command */ | |||
| 151 | void (*proc)(char *, int); /* handler */ | |||
| 152 | } dispatch_table[] = { | |||
| 153 | { "keycode", 7, do_keycode }, | |||
| 154 | { "keysym", 6, do_keysym }, | |||
| 155 | { "add", 3, do_add }, | |||
| 156 | { "remove", 6, do_remove }, | |||
| 157 | { "clear", 5, do_clear }, | |||
| 158 | { "pointer", 7, do_pointer }, | |||
| 159 | { NULL((void*)0), 0, NULL((void*)0) }}; | |||
| 160 | ||||
| 161 | /* | |||
| 162 | * handle_line - this routine parses the input line (which has had all leading | |||
| 163 | * and trailing whitespace removed) and builds up the work queue. | |||
| 164 | */ | |||
| 165 | ||||
| 166 | void | |||
| 167 | handle_line(char *line, /* string to parse */ | |||
| 168 | int len) /* length of line */ | |||
| 169 | { | |||
| 170 | int n; | |||
| 171 | struct dt *dtp; | |||
| 172 | ||||
| 173 | n = skip_chars (line, len); | |||
| 174 | if (n < 0) { | |||
| 175 | badmsg ("input line '%s'", line){ badheader(); fprintf (__stderrp, "input line '%s'", line); putc ('\n', __stderrp); }; | |||
| 176 | return; | |||
| 177 | } | |||
| 178 | ||||
| 179 | for (dtp = dispatch_table; dtp->command != NULL((void*)0); dtp++) { | |||
| 180 | if (n == dtp->length && | |||
| 181 | strncmp (line, dtp->command, dtp->length) == 0) { | |||
| 182 | ||||
| 183 | n += skip_space (line+n, len-n); | |||
| 184 | line += n, len -= n; | |||
| 185 | ||||
| 186 | (*(dtp->proc)) (line, len); | |||
| 187 | return; | |||
| 188 | } | |||
| 189 | } | |||
| 190 | ||||
| 191 | fprintf (stderr__stderrp, "%s: unknown command on line %s:%d\n", | |||
| 192 | ProgramName, inputFilename, lineno+1); | |||
| 193 | parse_errors++; | |||
| 194 | } | |||
| 195 | ||||
| 196 | /* | |||
| 197 | * the following routines are useful for parsing | |||
| 198 | */ | |||
| 199 | ||||
| 200 | static int | |||
| 201 | skip_word (const char *s, int len) | |||
| 202 | { | |||
| 203 | register int n; | |||
| 204 | ||||
| 205 | n = skip_chars (s, len); | |||
| 206 | return (n + skip_space (s+n, len-n)); | |||
| 207 | } | |||
| 208 | ||||
| 209 | static int | |||
| 210 | skip_chars(const char *s, int len) | |||
| 211 | { | |||
| 212 | register int i; | |||
| 213 | ||||
| 214 | if (len <= 0 || !s || *s == '\0') return (0); | |||
| 215 | ||||
| 216 | for (i = 0; i < len; i++) { | |||
| 217 | if (isspace(s[i])) break; | |||
| 218 | } | |||
| 219 | return (i); | |||
| 220 | } | |||
| 221 | ||||
| 222 | static int | |||
| 223 | skip_space(const char *s, int len) | |||
| 224 | { | |||
| 225 | register int i; | |||
| 226 | ||||
| 227 | if (len <= 0 || !s || *s == '\0') return (0); | |||
| 228 | ||||
| 229 | for (i = 0; i < len; i++) { | |||
| 230 | if (!s[i] || !isspace(s[i])) break; | |||
| 231 | } | |||
| 232 | return (i); | |||
| 233 | } | |||
| 234 | ||||
| 235 | ||||
| 236 | static int | |||
| 237 | skip_until_char(const char *s, int len, char c) | |||
| 238 | { | |||
| 239 | register int i; | |||
| 240 | ||||
| 241 | for (i = 0; i < len; i++) { | |||
| 242 | if (s[i] == c) break; | |||
| 243 | } | |||
| 244 | return (i); | |||
| 245 | } | |||
| 246 | ||||
| 247 | ||||
| 248 | /* | |||
| 249 | * The action routines. | |||
| 250 | * | |||
| 251 | * This is where the real work gets done. Each routine is responsible for | |||
| 252 | * parsing its input (note that the command keyword has been stripped off) | |||
| 253 | * and adding to the work queue. They are also in charge of outputting | |||
| 254 | * error messages and returning non-zero if there is a problem. | |||
| 255 | * | |||
| 256 | * The following global variables are available: | |||
| 257 | * dpy the display descriptor | |||
| 258 | * work_queue linked list of opcodes | |||
| 259 | * inputFilename name of the file being processed | |||
| 260 | * lineno line number of current line in input file | |||
| 261 | */ | |||
| 262 | static void | |||
| 263 | add_to_work_queue(union op *p) /* this can become a macro someday */ | |||
| 264 | { | |||
| 265 | if (work_queue.head == NULL((void*)0)) { /* nothing on the list */ | |||
| 266 | work_queue.head = work_queue.tail = p; /* head, tail, no prev */ | |||
| 267 | } else { | |||
| 268 | work_queue.tail->generic.next = p; /* head okay, prev */ | |||
| 269 | work_queue.tail = p; /* tail */ | |||
| 270 | } | |||
| 271 | p->generic.next = NULL((void*)0); | |||
| 272 | ||||
| 273 | if (verbose) { | |||
| 274 | print_opcode (p); | |||
| 275 | } | |||
| 276 | return; | |||
| 277 | } | |||
| 278 | ||||
| 279 | static Boolint | |||
| 280 | parse_number(const char *str, unsigned long *val) | |||
| 281 | { | |||
| 282 | const char *fmt = "%ld"; | |||
| 283 | ||||
| 284 | if (*str == '0') { | |||
| 285 | str++; | |||
| 286 | while (isspace(*str)) | |||
| 287 | str++; | |||
| 288 | fmt = "%lo"; | |||
| 289 | if (*str == '\0') { | |||
| 290 | *val = 0; | |||
| 291 | return 1; | |||
| 292 | } | |||
| 293 | if (*str == 'x' || *str == 'X') { | |||
| 294 | str++; | |||
| 295 | fmt = "%lx"; | |||
| 296 | } | |||
| 297 | } | |||
| 298 | return (sscanf (str, fmt, val) == 1); | |||
| 299 | } | |||
| 300 | ||||
| 301 | static Boolint | |||
| 302 | parse_keysym(const char *line, int n, char **name, KeySym *keysym) | |||
| 303 | { | |||
| 304 | *name = copy_to_scratch (line, n); | |||
| 305 | if (!strcmp(*name, "NoSymbol")) { | |||
| 306 | *keysym = NoSymbol0L; | |||
| 307 | return (True1); | |||
| 308 | } | |||
| 309 | *keysym = XStringToKeysym (*name); | |||
| 310 | if (*keysym == NoSymbol0L && '0' <= **name && **name <= '9') | |||
| 311 | return parse_number(*name, keysym); | |||
| 312 | return (*keysym != NoSymbol0L); | |||
| 313 | } | |||
| 314 | ||||
| 315 | /* | |||
| 316 | * do_keycode - parse off lines of the form | |||
| 317 | * | |||
| 318 | * "keycode" number "=" [keysym ...] | |||
| 319 | * ^ | |||
| 320 | * | |||
| 321 | * where number is in decimal, hex, or octal. Any number of keysyms may be | |||
| 322 | * listed. | |||
| 323 | */ | |||
| 324 | ||||
| 325 | static void | |||
| 326 | do_keycode(char *line, int len) | |||
| 327 | { | |||
| 328 | int dummy; | |||
| 329 | const char *fmt = "%d"; | |||
| 330 | KeyCode keycode; | |||
| 331 | ||||
| 332 | if (len < 3 || !line || *line == '\0') { /* 5=a minimum */ | |||
| 333 | badmsg0 ("keycode input line"){ badheader(); fprintf (__stderrp, "keycode input line"); putc ('\n', __stderrp); }; | |||
| 334 | return; | |||
| 335 | } | |||
| 336 | ||||
| 337 | /* | |||
| 338 | * We need not bother to advance line/len past the | |||
| 339 | * number (or the string 'any') as finish_keycodes() will | |||
| 340 | * first advance past the '='. | |||
| 341 | */ | |||
| 342 | if (!strncmp("any", line, 3)) { | |||
| 343 | keycode = 0; | |||
| 344 | } else { | |||
| 345 | if (*line == '0') line++, len--, fmt = "%o"; | |||
| 346 | if (*line == 'x' || *line == 'X') line++, len--, fmt = "%x"; | |||
| 347 | ||||
| 348 | dummy = 0; | |||
| 349 | if (sscanf (line, fmt, &dummy) != 1 || dummy == 0) { | |||
| 350 | badmsg0 ("keycode value"){ badheader(); fprintf (__stderrp, "keycode value"); putc ('\n' , __stderrp); }; | |||
| 351 | return; | |||
| 352 | } | |||
| 353 | keycode = (KeyCode) dummy; | |||
| 354 | if ((int)keycode < min_keycode || (int)keycode > max_keycode) { | |||
| 355 | badmsg0 ("keycode value (out of range)"){ badheader(); fprintf (__stderrp, "keycode value (out of range)" ); putc ('\n', __stderrp); }; | |||
| 356 | return; | |||
| 357 | } | |||
| 358 | } | |||
| 359 | ||||
| 360 | finish_keycodes (line, len, &keycode, 1); | |||
| 361 | } | |||
| 362 | ||||
| 363 | ||||
| 364 | /* | |||
| 365 | * do_keysym - parse off lines of the form | |||
| 366 | * | |||
| 367 | * "keysym" keysym "=" [keysym ...] | |||
| 368 | * ^ | |||
| 369 | * | |||
| 370 | * The left keysyms has to be checked for validity and evaluated. | |||
| 371 | */ | |||
| 372 | ||||
| 373 | static void | |||
| 374 | do_keysym(char *line, int len) | |||
| 375 | { | |||
| 376 | int n; | |||
| 377 | KeyCode *keycodes; | |||
| 378 | KeySym keysym; | |||
| 379 | char *tmpname; | |||
| 380 | ||||
| 381 | if (len < 3 || !line || *line == '\0') { /* a=b minimum */ | |||
| 382 | badmsg0 ("keysym input line"){ badheader(); fprintf (__stderrp, "keysym input line"); putc ('\n', __stderrp); }; | |||
| 383 | return; | |||
| 384 | } | |||
| 385 | ||||
| 386 | n = skip_chars (line, len); | |||
| 387 | if (n < 1) { | |||
| 388 | badmsg0 ("target keysym name"){ badheader(); fprintf (__stderrp, "target keysym name"); putc ('\n', __stderrp); }; | |||
| 389 | return; | |||
| 390 | } | |||
| 391 | if (!parse_keysym(line, n, &tmpname, &keysym)) { | |||
| 392 | badmsg ("keysym target key symbol '%s'", tmpname){ badheader(); fprintf (__stderrp, "keysym target key symbol '%s'" , tmpname); putc ('\n', __stderrp); }; | |||
| 393 | return; | |||
| 394 | } | |||
| 395 | ||||
| 396 | keycodes = KeysymToKeycodes (dpy, keysym, &n); | |||
| 397 | if (n == 0) { | |||
| 398 | badmsg ("keysym target keysym '%s', no corresponding keycodes",{ badheader(); fprintf (__stderrp, "keysym target keysym '%s', no corresponding keycodes" , tmpname); putc ('\n', __stderrp); } | |||
| 399 | tmpname){ badheader(); fprintf (__stderrp, "keysym target keysym '%s', no corresponding keycodes" , tmpname); putc ('\n', __stderrp); }; | |||
| 400 | return; | |||
| 401 | } | |||
| 402 | if (verbose) { | |||
| 403 | int i; | |||
| 404 | printf ("! Keysym %s (0x%lx) corresponds to keycode(s)", | |||
| 405 | tmpname, (long) keysym); | |||
| 406 | for (i = 0; i < n; i++) | |||
| 407 | printf (" 0x%x", keycodes[i]); | |||
| 408 | printf("\n"); | |||
| 409 | } | |||
| 410 | ||||
| 411 | finish_keycodes (line, len, keycodes, n); | |||
| 412 | } | |||
| 413 | ||||
| 414 | static void | |||
| 415 | finish_keycodes(const char *line, int len, KeyCode *keycodes, int count) | |||
| 416 | { | |||
| 417 | int n; | |||
| 418 | KeySym *kslist; | |||
| 419 | union op *uop; | |||
| 420 | struct op_keycode *opk; | |||
| 421 | ||||
| 422 | n = skip_until_char (line, len, '='); | |||
| 423 | line += n, len -= n; | |||
| 424 | ||||
| 425 | if (len < 1 || *line != '=') { /* = minimum */ | |||
| 426 | badmsg0 ("keycode command (missing keysym list),"){ badheader(); fprintf (__stderrp, "keycode command (missing keysym list)," ); putc ('\n', __stderrp); }; | |||
| 427 | return; | |||
| 428 | } | |||
| 429 | line++, len--; /* skip past the = */ | |||
| 430 | ||||
| 431 | n = skip_space (line, len); | |||
| 432 | line += n, len -= n; | |||
| 433 | ||||
| 434 | /* allow empty list */ | |||
| 435 | if (get_keysym_list (line, len, &n, &kslist) < 0) | |||
| 436 | return; | |||
| 437 | ||||
| 438 | while (--count >= 0) { | |||
| 439 | uop = AllocStruct (union op)(malloc (sizeof (union op))); | |||
| 440 | if (!uop) { | |||
| 441 | badmsg ("attempt to allocate a %ld byte keycode opcode",{ badheader(); fprintf (__stderrp, "attempt to allocate a %ld byte keycode opcode" , (long) sizeof (struct op_keycode)); putc ('\n', __stderrp); } | |||
| 442 | (long) sizeof (struct op_keycode)){ badheader(); fprintf (__stderrp, "attempt to allocate a %ld byte keycode opcode" , (long) sizeof (struct op_keycode)); putc ('\n', __stderrp); }; | |||
| 443 | return; | |||
| 444 | } | |||
| 445 | opk = &uop->keycode; | |||
| 446 | ||||
| 447 | opk->type = doKeycode; | |||
| 448 | opk->target_keycode = keycodes[count]; | |||
| 449 | opk->count = n; | |||
| 450 | opk->keysyms = kslist; | |||
| 451 | ||||
| 452 | add_to_work_queue (uop); | |||
| 453 | } | |||
| 454 | ||||
| 455 | #ifdef later | |||
| 456 | /* make sure we handle any special keys */ | |||
| 457 | check_special_keys (keycode, n, kslist); | |||
| 458 | #endif | |||
| 459 | } | |||
| 460 | ||||
| 461 | ||||
| 462 | /* | |||
| 463 | * parse_modifier - convert a modifier string name to its index | |||
| 464 | */ | |||
| 465 | ||||
| 466 | struct modtab modifier_table[] = { /* keep in order so it can be index */ | |||
| 467 | { "shift", 5, 0 }, | |||
| 468 | { "lock", 4, 1 }, | |||
| 469 | { "control", 7, 2 }, | |||
| 470 | { "mod1", 4, 3 }, | |||
| 471 | { "mod2", 4, 4 }, | |||
| 472 | { "mod3", 4, 5 }, | |||
| 473 | { "mod4", 4, 6 }, | |||
| 474 | { "mod5", 4, 7 }, | |||
| 475 | { "ctrl", 4, 2 }, | |||
| 476 | { NULL((void*)0), 0, 0 }}; | |||
| 477 | ||||
| 478 | static int | |||
| 479 | parse_modifier(char *line, int n) | |||
| 480 | { | |||
| 481 | register int i; | |||
| 482 | struct modtab *mt; | |||
| 483 | ||||
| 484 | /* lowercase for comparison against table */ | |||
| 485 | for (i = 0; i < n; i++) { | |||
| 486 | if (isupper (line[i])) line[i] = tolower (line[i]); | |||
| 487 | } | |||
| 488 | ||||
| 489 | for (mt = modifier_table; mt->name; mt++) { | |||
| 490 | if (n == mt->length && strncmp (line, mt->name, n) == 0) | |||
| 491 | return (mt->value); | |||
| 492 | } | |||
| 493 | return (-1); | |||
| 494 | } | |||
| 495 | ||||
| 496 | ||||
| 497 | /* | |||
| 498 | * do_add - parse off lines of the form | |||
| 499 | * | |||
| 500 | * add MODIFIER = keysym ... | |||
| 501 | * ^ | |||
| 502 | * where the MODIFIER is one of Shift, Lock, Control, Mod[1-5] where case | |||
| 503 | * is not important. There should also be an alias Ctrl for control. | |||
| 504 | */ | |||
| 505 | ||||
| 506 | static void | |||
| 507 | do_add(char *line, int len) | |||
| 508 | { | |||
| 509 | int n; | |||
| 510 | int modifier; | |||
| 511 | KeySym *kslist; | |||
| 512 | union op *uop; | |||
| 513 | struct op_addmodifier *opam; | |||
| 514 | ||||
| 515 | if (len < 6 || !line || *line == '\0') { /* Lock=a minimum */ | |||
| 516 | badmsg0 ("add modifier input line"){ badheader(); fprintf (__stderrp, "add modifier input line") ; putc ('\n', __stderrp); }; | |||
| 517 | return; | |||
| 518 | } | |||
| 519 | ||||
| 520 | n = skip_chars (line, len); | |||
| 521 | if (n < 1) { | |||
| 522 | badmsg ("add modifier name %s", line){ badheader(); fprintf (__stderrp, "add modifier name %s", line ); putc ('\n', __stderrp); }; | |||
| 523 | return; | |||
| 524 | } | |||
| 525 | ||||
| 526 | modifier = parse_modifier (line, n); | |||
| 527 | if (modifier < 0) { | |||
| 528 | badmsgn ("add modifier name '%s', not allowed", line, n){ badheader(); fprintf (__stderrp, "add modifier name '%s', not allowed" , copy_to_scratch (line, n)); putc ('\n', __stderrp); }; | |||
| 529 | return; | |||
| 530 | } | |||
| 531 | ||||
| 532 | line += n, len -= n; | |||
| 533 | n = skip_until_char (line, len, '='); | |||
| 534 | if (n < 0) { | |||
| 535 | badmsg0 ("add modifier = keysym"){ badheader(); fprintf (__stderrp, "add modifier = keysym"); putc ('\n', __stderrp); }; | |||
| 536 | return; | |||
| 537 | } | |||
| 538 | ||||
| 539 | n++; /* skip = */ | |||
| 540 | n += skip_space (line+n, len-n); | |||
| 541 | line += n, len -= n; | |||
| 542 | ||||
| 543 | if (get_keysym_list (line, len, &n, &kslist) < 0) | |||
| 544 | return; | |||
| 545 | if (n == 0) { | |||
| 546 | badmsg0 ("add modifier keysym list (empty)"){ badheader(); fprintf (__stderrp, "add modifier keysym list (empty)" ); putc ('\n', __stderrp); }; | |||
| 547 | return; | |||
| 548 | } | |||
| 549 | ||||
| 550 | uop = AllocStruct (union op)(malloc (sizeof (union op))); | |||
| 551 | if (!uop) { | |||
| 552 | badmsg ("attempt to allocate %ld byte addmodifier opcode",{ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte addmodifier opcode" , (long) sizeof (struct op_addmodifier)); putc ('\n', __stderrp ); } | |||
| 553 | (long) sizeof (struct op_addmodifier)){ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte addmodifier opcode" , (long) sizeof (struct op_addmodifier)); putc ('\n', __stderrp ); }; | |||
| 554 | return; | |||
| 555 | } | |||
| 556 | opam = &uop->addmodifier; | |||
| 557 | ||||
| 558 | opam->type = doAddModifier; | |||
| 559 | opam->modifier = modifier; | |||
| 560 | opam->count = n; | |||
| 561 | opam->keysyms = kslist; | |||
| 562 | ||||
| 563 | add_to_work_queue (uop); | |||
| 564 | } | |||
| 565 | ||||
| 566 | #ifdef AUTO_ADD_REMOVE | |||
| 567 | /* | |||
| 568 | * make_add - stick a single add onto the queue | |||
| 569 | */ | |||
| 570 | static void | |||
| 571 | make_add(int modifier, KeySym keysym) | |||
| 572 | { | |||
| 573 | union op *uop; | |||
| 574 | struct op_addmodifier *opam; | |||
| 575 | ||||
| 576 | uop = AllocStruct (union op)(malloc (sizeof (union op))); | |||
| 577 | if (!uop) { | |||
| 578 | badmsg ("attempt to allocate %ld byte addmodifier opcode",{ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte addmodifier opcode" , (long) sizeof (struct op_addmodifier)); putc ('\n', __stderrp ); } | |||
| 579 | (long) sizeof (struct op_addmodifier)){ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte addmodifier opcode" , (long) sizeof (struct op_addmodifier)); putc ('\n', __stderrp ); }; | |||
| 580 | return; | |||
| 581 | } | |||
| 582 | opam = &uop->addmodifier; | |||
| 583 | ||||
| 584 | opam->type = doAddModifier; | |||
| 585 | opam->modifier = modifier; | |||
| 586 | opam->count = 1; | |||
| 587 | opam->keysyms = malloc (sizeof (KeySym)); | |||
| 588 | if (!opam->keysyms) { | |||
| 589 | badmsg ("attempt to allocate %ld byte KeySym", (long) sizeof (KeySym)){ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte KeySym" , (long) sizeof (KeySym)); putc ('\n', __stderrp); }; | |||
| 590 | free (opam); | |||
| 591 | return; | |||
| 592 | } | |||
| 593 | opam->keysyms[0] = keysym; | |||
| 594 | ||||
| 595 | add_to_work_queue (uop); | |||
| 596 | return; | |||
| 597 | } | |||
| 598 | #endif /* AUTO_ADD_REMOVE */ | |||
| 599 | ||||
| 600 | ||||
| 601 | /* | |||
| 602 | * do_remove - parse off lines of the form | |||
| 603 | * | |||
| 604 | * remove MODIFIER = oldkeysym ... | |||
| 605 | * ^ | |||
| 606 | * where the MODIFIER is one of Shift, Lock, Control, Mod[1-5] where case | |||
| 607 | * is not important. There should also be an alias Ctrl for control. | |||
| 608 | */ | |||
| 609 | ||||
| 610 | static void | |||
| 611 | do_remove(char *line, int len) | |||
| 612 | { | |||
| 613 | int n; | |||
| 614 | int nc; | |||
| 615 | int i; | |||
| 616 | int tot; | |||
| 617 | int modifier; | |||
| 618 | KeySym *kslist; | |||
| 619 | KeyCode *kclist; | |||
| 620 | union op *uop; | |||
| 621 | struct op_removemodifier *oprm; | |||
| 622 | ||||
| 623 | if (len < 6 || !line || *line == '\0') { /* Lock=a minimum */ | |||
| ||||
| 624 | badmsg0 ("remove modifier input line"){ badheader(); fprintf (__stderrp, "remove modifier input line" ); putc ('\n', __stderrp); }; | |||
| 625 | return; | |||
| 626 | } | |||
| 627 | ||||
| 628 | n = skip_chars (line, len); | |||
| 629 | if (n < 1) { | |||
| 630 | badmsg ("remove modifier name %s", line){ badheader(); fprintf (__stderrp, "remove modifier name %s", line); putc ('\n', __stderrp); }; | |||
| 631 | return; | |||
| 632 | } | |||
| 633 | ||||
| 634 | modifier = parse_modifier (line, n); | |||
| 635 | if (modifier < 0) { | |||
| 636 | badmsgn ("remove modifier name '%s', not allowed", line, n){ badheader(); fprintf (__stderrp, "remove modifier name '%s', not allowed" , copy_to_scratch (line, n)); putc ('\n', __stderrp); }; | |||
| 637 | return; | |||
| 638 | } | |||
| 639 | ||||
| 640 | line += n, len -= n; | |||
| 641 | n = skip_until_char (line, len, '='); | |||
| 642 | if (n < 0) { | |||
| 643 | badmsg0 ("remove modifier = keysym"){ badheader(); fprintf (__stderrp, "remove modifier = keysym" ); putc ('\n', __stderrp); }; | |||
| 644 | return; | |||
| 645 | } | |||
| 646 | ||||
| 647 | n++; | |||
| 648 | n += skip_space (line+n, len-n); | |||
| 649 | line += n, len -= n; | |||
| 650 | ||||
| 651 | if (get_keysym_list (line, len, &n, &kslist) < 0) | |||
| 652 | return; | |||
| 653 | if (n == 0) { | |||
| 654 | badmsg0 ("remove modifier keysym list (empty)"){ badheader(); fprintf (__stderrp, "remove modifier keysym list (empty)" ); putc ('\n', __stderrp); }; | |||
| 655 | return; | |||
| 656 | } | |||
| 657 | ||||
| 658 | /* | |||
| 659 | * unlike the add command, we have to now evaluate the keysyms | |||
| 660 | */ | |||
| 661 | ||||
| 662 | kclist = malloc (n * sizeof (KeyCode)); | |||
| 663 | if (!kclist) { | |||
| 664 | badmsg ("attempt to allocate %ld byte keycode list",{ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte keycode list" , (long) (n * sizeof (KeyCode))); putc ('\n', __stderrp); } | |||
| 665 | (long) (n * sizeof (KeyCode))){ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte keycode list" , (long) (n * sizeof (KeyCode))); putc ('\n', __stderrp); }; | |||
| 666 | free (kslist); | |||
| 667 | return; | |||
| 668 | } | |||
| 669 | ||||
| 670 | tot = n; | |||
| 671 | nc = 0; | |||
| 672 | for (i = 0; i < n; i++) { | |||
| ||||
| 673 | int num_kcs; | |||
| 674 | KeyCode *kcs; | |||
| 675 | kcs = KeysymToKeycodes (dpy, kslist[i], &num_kcs); | |||
| 676 | if (num_kcs == 0) { | |||
| 677 | char *tmpname = XKeysymToString (kslist[i]); | |||
| 678 | badmsg ("keysym in remove modifier list '%s', no corresponding keycodes",{ badheader(); fprintf (__stderrp, "keysym in remove modifier list '%s', no corresponding keycodes" , tmpname ? tmpname : "?"); putc ('\n', __stderrp); } | |||
| 679 | tmpname ? tmpname : "?"){ badheader(); fprintf (__stderrp, "keysym in remove modifier list '%s', no corresponding keycodes" , tmpname ? tmpname : "?"); putc ('\n', __stderrp); }; | |||
| 680 | continue; | |||
| 681 | } | |||
| 682 | if (verbose) { | |||
| 683 | int j; | |||
| 684 | char *tmpname = XKeysymToString (kslist[i]); | |||
| 685 | printf ("! Keysym %s (0x%lx) corresponds to keycode(s)", | |||
| 686 | tmpname ? tmpname : "?", (long) kslist[i]); | |||
| 687 | for (j = 0; j < num_kcs; j++) | |||
| 688 | printf(" 0x%x", kcs[j]); | |||
| 689 | printf("\n"); | |||
| 690 | } | |||
| 691 | if (nc + num_kcs > tot) { | |||
| 692 | tot = nc + num_kcs; | |||
| 693 | kclist = realloc(kclist, tot * sizeof(KeyCode)); | |||
| 694 | if (!kclist) { | |||
| 695 | badmsg ("attempt to allocate %ld byte keycode list",{ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte keycode list" , (long) (tot * sizeof (KeyCode))); putc ('\n', __stderrp); } | |||
| 696 | (long) (tot * sizeof (KeyCode))){ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte keycode list" , (long) (tot * sizeof (KeyCode))); putc ('\n', __stderrp); }; | |||
| 697 | free (kslist); | |||
| 698 | return; | |||
| 699 | } | |||
| 700 | } | |||
| 701 | while (--num_kcs >= 0) | |||
| 702 | kclist[nc++] = *kcs++; /* okay, add it to list */ | |||
| 703 | } | |||
| 704 | ||||
| 705 | free (kslist); /* all done with it */ | |||
| 706 | ||||
| 707 | uop = AllocStruct (union op)(malloc (sizeof (union op))); | |||
| 708 | if (!uop) { | |||
| 709 | badmsg ("attempt to allocate %ld byte removemodifier opcode",{ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte removemodifier opcode" , (long) sizeof (struct op_removemodifier)); putc ('\n', __stderrp ); } | |||
| 710 | (long) sizeof (struct op_removemodifier)){ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte removemodifier opcode" , (long) sizeof (struct op_removemodifier)); putc ('\n', __stderrp ); }; | |||
| 711 | return; | |||
| 712 | } | |||
| 713 | oprm = &uop->removemodifier; | |||
| 714 | ||||
| 715 | oprm->type = doRemoveModifier; | |||
| 716 | oprm->modifier = modifier; | |||
| 717 | oprm->count = nc; | |||
| 718 | oprm->keycodes = kclist; | |||
| 719 | ||||
| 720 | add_to_work_queue (uop); | |||
| 721 | } | |||
| 722 | ||||
| 723 | #ifdef AUTO_ADD_REMOVE | |||
| 724 | /* | |||
| 725 | * make_remove - stick a single remove onto the queue | |||
| 726 | */ | |||
| 727 | static void | |||
| 728 | make_remove(int modifier, KeyCode keycode) | |||
| 729 | { | |||
| 730 | union op *uop; | |||
| 731 | struct op_removemodifier *oprm; | |||
| 732 | ||||
| 733 | uop = AllocStruct (union op)(malloc (sizeof (union op))); | |||
| 734 | if (!uop) { | |||
| 735 | badmsg ("attempt to allocate %ld byte removemodifier opcode",{ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte removemodifier opcode" , (long) sizeof (struct op_removemodifier)); putc ('\n', __stderrp ); } | |||
| 736 | (long) sizeof (struct op_removemodifier)){ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte removemodifier opcode" , (long) sizeof (struct op_removemodifier)); putc ('\n', __stderrp ); }; | |||
| 737 | return; | |||
| 738 | } | |||
| 739 | oprm = &uop->removemodifier; | |||
| 740 | ||||
| 741 | oprm->type = doRemoveModifier; | |||
| 742 | oprm->modifier = modifier; | |||
| 743 | oprm->count = 1; | |||
| 744 | oprm->keycodes = malloc (sizeof (KeyCode)); | |||
| 745 | if (!oprm->keycodes) { | |||
| 746 | badmsg ("attempt to allocate %ld byte KeyCode",{ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte KeyCode" , (long) sizeof (KeyCode)); putc ('\n', __stderrp); } | |||
| 747 | (long) sizeof (KeyCode)){ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte KeyCode" , (long) sizeof (KeyCode)); putc ('\n', __stderrp); }; | |||
| 748 | free (oprm); | |||
| 749 | return; | |||
| 750 | } | |||
| 751 | oprm->keycodes[0] = keycode; | |||
| 752 | ||||
| 753 | add_to_work_queue (uop); | |||
| 754 | return; | |||
| 755 | } | |||
| 756 | #endif /* AUTO_ADD_REMOVE */ | |||
| 757 | ||||
| 758 | ||||
| 759 | /* | |||
| 760 | * do_clear - parse off lines of the form | |||
| 761 | * | |||
| 762 | * clear MODIFIER | |||
| 763 | * ^ | |||
| 764 | */ | |||
| 765 | ||||
| 766 | static void | |||
| 767 | do_clear(char *line, int len) | |||
| 768 | { | |||
| 769 | int n; | |||
| 770 | int modifier; | |||
| 771 | union op *uop; | |||
| 772 | struct op_clearmodifier *opcm; | |||
| 773 | ||||
| 774 | if (len < 4 || !line || *line == '\0') { /* Lock minimum */ | |||
| 775 | badmsg0 ("clear modifier input line"){ badheader(); fprintf (__stderrp, "clear modifier input line" ); putc ('\n', __stderrp); }; | |||
| 776 | return; | |||
| 777 | } | |||
| 778 | ||||
| 779 | n = skip_chars (line, len); | |||
| 780 | ||||
| 781 | modifier = parse_modifier (line, n); | |||
| 782 | if (modifier < 0) { | |||
| 783 | badmsgn ("clear modifier name '%s'", line, n){ badheader(); fprintf (__stderrp, "clear modifier name '%s'" , copy_to_scratch (line, n)); putc ('\n', __stderrp); }; | |||
| 784 | return; | |||
| 785 | } | |||
| 786 | n += skip_space (line+n, len-n); | |||
| 787 | if (n != len) { | |||
| 788 | badmsgn ("extra argument '%s' to clear modifier", line+n, len-n){ badheader(); fprintf (__stderrp, "extra argument '%s' to clear modifier" , copy_to_scratch (line+n, len-n)); putc ('\n', __stderrp); }; | |||
| 789 | /* okay to continue */ | |||
| 790 | } | |||
| 791 | ||||
| 792 | uop = AllocStruct (union op)(malloc (sizeof (union op))); | |||
| 793 | if (!uop) { | |||
| 794 | badmsg ("attempt to allocate %ld byte clearmodifier opcode",{ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte clearmodifier opcode" , (long) sizeof (struct op_clearmodifier)); putc ('\n', __stderrp ); } | |||
| 795 | (long) sizeof (struct op_clearmodifier)){ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte clearmodifier opcode" , (long) sizeof (struct op_clearmodifier)); putc ('\n', __stderrp ); }; | |||
| 796 | return; | |||
| 797 | } | |||
| 798 | opcm = &uop->clearmodifier; | |||
| 799 | ||||
| 800 | opcm->type = doClearModifier; | |||
| 801 | opcm->modifier = modifier; | |||
| 802 | ||||
| 803 | add_to_work_queue (uop); | |||
| 804 | } | |||
| 805 | ||||
| 806 | #ifndef HAVE_STRNCASECMP1 | |||
| 807 | static int | |||
| 808 | strncasecmp(const char *a, const char *b, int n) | |||
| 809 | { | |||
| 810 | int i; | |||
| 811 | int a1, b1; | |||
| 812 | ||||
| 813 | for (i = 0; i < n; i++, a++, b++) { | |||
| 814 | if (!*a) return -1; | |||
| 815 | if (!*b) return 1; | |||
| 816 | ||||
| 817 | if (*a != *b) { | |||
| 818 | a1 = (isascii(*a) && isupper(*a)) ? tolower(*a) : *a; | |||
| 819 | b1 = (isascii(*b) && isupper(*b)) ? tolower(*b) : *b; | |||
| 820 | if (a1 != b1) return b1 - a1; | |||
| 821 | } | |||
| 822 | } | |||
| 823 | return 0; | |||
| 824 | } | |||
| 825 | #endif | |||
| 826 | ||||
| 827 | /* | |||
| 828 | * do_pointer = get list of numbers of the form | |||
| 829 | * | |||
| 830 | * buttons = NUMBER ... | |||
| 831 | * ^ | |||
| 832 | */ | |||
| 833 | ||||
| 834 | static void | |||
| 835 | do_pointer(char *line, int len) | |||
| 836 | { | |||
| 837 | int n; | |||
| 838 | int i; | |||
| 839 | unsigned long val; | |||
| 840 | union op *uop; | |||
| 841 | struct op_pointer *opp; | |||
| 842 | unsigned char buttons[MAXBUTTONCODES256]; | |||
| 843 | int nbuttons; | |||
| 844 | char *strval; | |||
| 845 | Boolint ok; | |||
| 846 | ||||
| 847 | if (len < 2 || !line || *line == '\0') { /* =1 minimum */ | |||
| 848 | badmsg0 ("buttons input line"){ badheader(); fprintf (__stderrp, "buttons input line"); putc ('\n', __stderrp); }; | |||
| 849 | return; | |||
| 850 | } | |||
| 851 | ||||
| 852 | nbuttons = XGetPointerMapping (dpy, buttons, MAXBUTTONCODES256); | |||
| 853 | ||||
| 854 | n = skip_space (line, len); | |||
| 855 | line += n, len -= n; | |||
| 856 | ||||
| 857 | if (line[0] != '=') { | |||
| 858 | badmsg0 ("buttons pointer code list, missing equal sign"){ badheader(); fprintf (__stderrp, "buttons pointer code list, missing equal sign" ); putc ('\n', __stderrp); }; | |||
| 859 | return; | |||
| 860 | } | |||
| 861 | ||||
| 862 | line++, len--; /* skip = */ | |||
| 863 | n = skip_space (line, len); | |||
| 864 | line += n, len -= n; | |||
| 865 | ||||
| 866 | i = 0; | |||
| 867 | if (len < 7 || strncasecmp (line, "default", 7) != 0) { | |||
| 868 | while (len > 0) { | |||
| 869 | n = skip_space (line, len); | |||
| 870 | line += n, len -= n; | |||
| 871 | if (line[0] == '\0') break; | |||
| 872 | n = skip_word (line, len); | |||
| 873 | if (n < 1) { | |||
| 874 | badmsg ("skip of word in buttons line: %s", line){ badheader(); fprintf (__stderrp, "skip of word in buttons line: %s" , line); putc ('\n', __stderrp); }; | |||
| 875 | return; | |||
| 876 | } | |||
| 877 | strval = copy_to_scratch(line, n); | |||
| 878 | if (strval == NULL((void*)0)) | |||
| 879 | /* copy_to_scratch already printed error message */ | |||
| 880 | return; | |||
| 881 | ok = parse_number (strval, &val); | |||
| 882 | if (!ok || val >= MAXBUTTONCODES256) { | |||
| 883 | badmsg ("value %s given for buttons list", strval){ badheader(); fprintf (__stderrp, "value %s given for buttons list" , strval); putc ('\n', __stderrp); }; | |||
| 884 | return; | |||
| 885 | } | |||
| 886 | buttons[i++] = (unsigned char) val; | |||
| 887 | line += n, len -= n; | |||
| 888 | } | |||
| 889 | } | |||
| 890 | ||||
| 891 | if (i > 0 && i != nbuttons) { | |||
| 892 | fprintf (stderr__stderrp, "Warning: Only changing the first %d of %d buttons.\n", | |||
| 893 | i, nbuttons); | |||
| 894 | i = nbuttons; | |||
| 895 | } | |||
| 896 | ||||
| 897 | uop = AllocStruct (union op)(malloc (sizeof (union op))); | |||
| 898 | if (!uop) { | |||
| 899 | badmsg ("attempt to allocate a %ld byte pointer opcode",{ badheader(); fprintf (__stderrp, "attempt to allocate a %ld byte pointer opcode" , (long) sizeof (struct op_pointer)); putc ('\n', __stderrp); } | |||
| 900 | (long) sizeof (struct op_pointer)){ badheader(); fprintf (__stderrp, "attempt to allocate a %ld byte pointer opcode" , (long) sizeof (struct op_pointer)); putc ('\n', __stderrp); }; | |||
| 901 | return; | |||
| 902 | } | |||
| 903 | opp = &uop->pointer; | |||
| 904 | ||||
| 905 | opp->type = doPointer; | |||
| 906 | opp->count = i; | |||
| 907 | for (i = 0; i < opp->count; i++) { | |||
| 908 | opp->button_codes[i] = buttons[i]; | |||
| 909 | } | |||
| 910 | ||||
| 911 | add_to_work_queue (uop); | |||
| 912 | } | |||
| 913 | ||||
| 914 | ||||
| 915 | /* | |||
| 916 | * get_keysym_list - parses the rest of the line into a keysyms assumes | |||
| 917 | * that the = sign has been parsed off but there may be leading whitespace | |||
| 918 | * | |||
| 919 | * keysym ... | |||
| 920 | * ^ | |||
| 921 | * | |||
| 922 | * this involves getting the word containing the keysym, checking its range, | |||
| 923 | * and adding it to the list. | |||
| 924 | */ | |||
| 925 | ||||
| 926 | static int | |||
| 927 | get_keysym_list(const char *line, int len, int *np, KeySym **kslistp) | |||
| 928 | { | |||
| 929 | int havesofar, maxcanhave; | |||
| 930 | KeySym *keysymlist; | |||
| 931 | ||||
| 932 | *np = 0; | |||
| 933 | *kslistp = NULL((void*)0); | |||
| 934 | ||||
| 935 | if (len == 0) return (0); /* empty list */ | |||
| 936 | ||||
| 937 | havesofar = 0; | |||
| 938 | maxcanhave = 4; /* most lists are small */ | |||
| 939 | keysymlist = malloc (maxcanhave * sizeof (KeySym)); | |||
| 940 | if (!keysymlist) { | |||
| 941 | badmsg ("attempt to allocate %ld byte initial keysymlist",{ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte initial keysymlist" , (long) (maxcanhave * sizeof (KeySym))); putc ('\n', __stderrp ); } | |||
| 942 | (long) (maxcanhave * sizeof (KeySym))){ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte initial keysymlist" , (long) (maxcanhave * sizeof (KeySym))); putc ('\n', __stderrp ); }; | |||
| 943 | return (-1); | |||
| 944 | } | |||
| 945 | ||||
| 946 | while (len > 0) { | |||
| 947 | KeySym keysym; | |||
| 948 | int n; | |||
| 949 | char *tmpname; | |||
| 950 | Boolint ok; | |||
| 951 | ||||
| 952 | n = skip_space (line, len); | |||
| 953 | line += n, len -= n; | |||
| 954 | ||||
| 955 | n = skip_chars (line, len); | |||
| 956 | if (n < 0) { | |||
| 957 | badmsg0 ("keysym name list"){ badheader(); fprintf (__stderrp, "keysym name list"); putc ( '\n', __stderrp); }; | |||
| 958 | free(keysymlist); | |||
| 959 | return (-1); | |||
| 960 | } | |||
| 961 | ||||
| 962 | ok = parse_keysym (line, n, &tmpname, &keysym); | |||
| 963 | line += n, len -= n; | |||
| 964 | if (!ok) { | |||
| 965 | badmsg ("keysym name '%s' in keysym list", tmpname){ badheader(); fprintf (__stderrp, "keysym name '%s' in keysym list" , tmpname); putc ('\n', __stderrp); }; | |||
| 966 | /* do NOT return here, look for others */ | |||
| 967 | continue; | |||
| 968 | } | |||
| 969 | ||||
| 970 | /* | |||
| 971 | * Do NOT test to see if the keysym translates to a keycode or you | |||
| 972 | * won't be able to assign new ones.... | |||
| 973 | */ | |||
| 974 | ||||
| 975 | /* grow the list bigger if necessary */ | |||
| 976 | if (havesofar >= maxcanhave) { | |||
| 977 | KeySym *origkeysymlist = keysymlist; | |||
| 978 | maxcanhave *= 2; | |||
| 979 | keysymlist = realloc (keysymlist, maxcanhave * sizeof (KeySym)); | |||
| 980 | if (!keysymlist) { | |||
| 981 | badmsg ("attempt to grow keysym list to %ld bytes",{ badheader(); fprintf (__stderrp, "attempt to grow keysym list to %ld bytes" , (long) (maxcanhave * sizeof (KeySym))); putc ('\n', __stderrp ); } | |||
| 982 | (long) (maxcanhave * sizeof (KeySym))){ badheader(); fprintf (__stderrp, "attempt to grow keysym list to %ld bytes" , (long) (maxcanhave * sizeof (KeySym))); putc ('\n', __stderrp ); }; | |||
| 983 | free(origkeysymlist); | |||
| 984 | return (-1); | |||
| 985 | } | |||
| 986 | } | |||
| 987 | ||||
| 988 | /* and add it to the list */ | |||
| 989 | keysymlist[havesofar++] = keysym; | |||
| 990 | } | |||
| 991 | ||||
| 992 | *kslistp = keysymlist; | |||
| 993 | *np = havesofar; | |||
| 994 | return (0); | |||
| 995 | } | |||
| 996 | ||||
| 997 | ||||
| 998 | #ifdef later | |||
| 999 | /* | |||
| 1000 | * check_special_keys - run through list of keysyms and generate "add" or | |||
| 1001 | * "remove" commands for for any of the key syms that appear in the modifier | |||
| 1002 | * list. this involves running down the modifier map which is an array of | |||
| 1003 | * 8 by map->max_keypermod keycodes. | |||
| 1004 | */ | |||
| 1005 | ||||
| 1006 | static void | |||
| 1007 | check_special_keys(KeyCode keycode, int n, KeySym *kslist) | |||
| 1008 | { | |||
| 1009 | int i; /* iterator variable */ | |||
| 1010 | KeyCode *kcp; /* keycode pointer */ | |||
| 1011 | ||||
| 1012 | /* | |||
| 1013 | * walk the modifiermap array. since its dimensions are not known at | |||
| 1014 | * compile time, we have to walk it by hand instead of indexing. this | |||
| 1015 | * is why it is initialized outside the loop, but incremented inside the | |||
| 1016 | * second loop. | |||
| 1017 | */ | |||
| 1018 | ||||
| 1019 | kcp = map->modifiermap; /* start at beginning and iterate */ | |||
| 1020 | for (i = 0; i < 8; i++) { /* there are 8 modifier keys */ | |||
| 1021 | int j; | |||
| 1022 | ||||
| 1023 | for (j = 0; j < map->max_keypermod; j++, kcp++) { | |||
| 1024 | KeySym keysym; | |||
| 1025 | int k; | |||
| 1026 | ||||
| 1027 | if (!*kcp) continue; /* only non-zero entries significant */ | |||
| 1028 | ||||
| 1029 | /* | |||
| 1030 | * check to see if the target keycode is already a modifier; if so, | |||
| 1031 | * then we have to remove it | |||
| 1032 | */ | |||
| 1033 | if (keycode == *kcp) { | |||
| 1034 | make_remove (i, keycode); | |||
| 1035 | } | |||
| 1036 | ||||
| 1037 | /* | |||
| 1038 | * now, check to see if any of the keysyms map to keycodes | |||
| 1039 | * that are in the modifier list | |||
| 1040 | */ | |||
| 1041 | for (k = 0; k < n; k++) { | |||
| 1042 | KeyCodes kc; | |||
| 1043 | ||||
| 1044 | kc = XKeysymToKeycode (dpy, kslist[k]); | |||
| 1045 | if (kc == *kcp) { /* yup, found one */ | |||
| 1046 | /* | |||
| 1047 | * have to generate a remove of the CURRENT keycode | |||
| 1048 | * and then an add of the new KEYCODE | |||
| 1049 | */ | |||
| 1050 | make_remove (i, kc); /* modifier, keycode */ | |||
| 1051 | make_add (i, kslist[k]); /* modifier, keysym */ | |||
| 1052 | } | |||
| 1053 | } | |||
| 1054 | } | |||
| 1055 | } | |||
| 1056 | return; | |||
| 1057 | } | |||
| 1058 | #endif | |||
| 1059 | ||||
| 1060 | /* | |||
| 1061 | * print_work_queue - disassemble the work queue and print it on stdout | |||
| 1062 | */ | |||
| 1063 | ||||
| 1064 | void | |||
| 1065 | print_work_queue(void) | |||
| 1066 | { | |||
| 1067 | union op *op; | |||
| 1068 | ||||
| 1069 | printf ("! dump of work queue\n"); | |||
| 1070 | for (op = work_queue.head; op; op = op->generic.next) { | |||
| 1071 | print_opcode (op); | |||
| 1072 | } | |||
| 1073 | return; | |||
| 1074 | } | |||
| 1075 | ||||
| 1076 | static void | |||
| 1077 | print_opcode(union op *op) | |||
| 1078 | { | |||
| 1079 | int i; | |||
| 1080 | ||||
| 1081 | printf (" "); | |||
| 1082 | switch (op->generic.type) { | |||
| 1083 | case doKeycode: | |||
| 1084 | if (op->keycode.target_keycode) | |||
| 1085 | printf ("keycode 0x%lx =", (long) op->keycode.target_keycode); | |||
| 1086 | else | |||
| 1087 | printf ("keycode any ="); | |||
| 1088 | for (i = 0; i < op->keycode.count; i++) { | |||
| 1089 | char *name = XKeysymToString (op->keycode.keysyms[i]); | |||
| 1090 | ||||
| 1091 | printf (" %s", name ? name : "BADKEYSYM"); | |||
| 1092 | } | |||
| 1093 | printf ("\n"); | |||
| 1094 | break; | |||
| 1095 | case doAddModifier: | |||
| 1096 | printf ("add %s =", modifier_table[op->addmodifier.modifier].name); | |||
| 1097 | for (i = 0; i < op->addmodifier.count; i++) { | |||
| 1098 | char *name = XKeysymToString (op->addmodifier.keysyms[i]); | |||
| 1099 | printf (" %s", name ? name : "BADKEYSYM"); | |||
| 1100 | } | |||
| 1101 | printf ("\n"); | |||
| 1102 | break; | |||
| 1103 | case doRemoveModifier: | |||
| 1104 | printf ("remove %s = ", | |||
| 1105 | modifier_table[op->removemodifier.modifier].name); | |||
| 1106 | for (i = 0; i < op->removemodifier.count; i++) { | |||
| 1107 | printf (" 0x%lx", (long) op->removemodifier.keycodes[i]); | |||
| 1108 | } | |||
| 1109 | printf ("\n"); | |||
| 1110 | break; | |||
| 1111 | case doClearModifier: | |||
| 1112 | printf ("clear %s\n", modifier_table[op->clearmodifier.modifier].name); | |||
| 1113 | break; | |||
| 1114 | case doPointer: | |||
| 1115 | printf ("pointer = "); | |||
| 1116 | if (op->pointer.count == 0) | |||
| 1117 | printf(" default"); | |||
| 1118 | else for (i=0; i < op->pointer.count; i++) | |||
| 1119 | printf(" %d", op->pointer.button_codes[i]); | |||
| 1120 | printf ("\n"); | |||
| 1121 | break; | |||
| 1122 | default: | |||
| 1123 | printf ("! unknown opcode %d\n", op->generic.type); | |||
| 1124 | break; | |||
| 1125 | } /* end switch */ | |||
| 1126 | return; | |||
| 1127 | } | |||
| 1128 | ||||
| 1129 | /* | |||
| 1130 | * execute_work_queue - do the real meat and potatoes now that we know what | |||
| 1131 | * we need to do and that all of the input is correct. | |||
| 1132 | */ | |||
| 1133 | static int exec_keycode ( struct op_keycode *opk ); | |||
| 1134 | static int exec_add ( struct op_addmodifier *opam ); | |||
| 1135 | static int exec_remove ( struct op_removemodifier *oprm ); | |||
| 1136 | static int exec_clear ( struct op_clearmodifier *opcm ); | |||
| 1137 | static int exec_pointer ( struct op_pointer *opp ); | |||
| 1138 | ||||
| 1139 | ||||
| 1140 | int | |||
| 1141 | execute_work_queue (void) | |||
| 1142 | { | |||
| 1143 | union op *op; | |||
| 1144 | int errors; | |||
| 1145 | Boolint update_map = False0; | |||
| 1146 | int dosync; | |||
| 1147 | ||||
| 1148 | if (verbose) { | |||
| 1149 | printf ("!\n"); | |||
| 1150 | printf ("! executing work queue\n"); | |||
| 1151 | printf ("!\n"); | |||
| 1152 | } | |||
| 1153 | ||||
| 1154 | errors = 0; | |||
| 1155 | dosync = 0; | |||
| 1156 | ||||
| 1157 | for (op = work_queue.head; op; op = op->generic.next) { | |||
| 1158 | if (verbose) print_opcode (op); | |||
| 1159 | ||||
| 1160 | /* check to see if we have to update the keyboard mapping */ | |||
| 1161 | if (dosync && | |||
| 1162 | (dosync < 0 || | |||
| 1163 | op->generic.type != doKeycode || | |||
| 1164 | !op->keycode.target_keycode)) { | |||
| 1165 | XSync (dpy, 0); | |||
| 1166 | while (XEventsQueued (dpy, QueuedAlready0) > 0) { | |||
| 1167 | XEvent event; | |||
| 1168 | XNextEvent (dpy, &event); | |||
| 1169 | if (event.type == MappingNotify34) { | |||
| 1170 | /* read all MappingNotify events */ | |||
| 1171 | while (XCheckTypedEvent (dpy, MappingNotify34, &event)) ; | |||
| 1172 | XRefreshKeyboardMapping (&event.xmapping); | |||
| 1173 | } else { | |||
| 1174 | fprintf (stderr__stderrp, "%s: unknown event %ld\n", | |||
| 1175 | ProgramName, (long) event.type); | |||
| 1176 | } | |||
| 1177 | } | |||
| 1178 | } | |||
| 1179 | dosync = 0; | |||
| 1180 | switch (op->generic.type) { | |||
| 1181 | case doKeycode: | |||
| 1182 | if (exec_keycode (&op->keycode) < 0) errors++; | |||
| 1183 | if (op->keycode.target_keycode) | |||
| 1184 | dosync = 1; | |||
| 1185 | else | |||
| 1186 | dosync = -1; | |||
| 1187 | break; | |||
| 1188 | case doAddModifier: | |||
| 1189 | if (exec_add (&op->addmodifier) < 0) errors++; | |||
| 1190 | else update_map = True1; | |||
| 1191 | break; | |||
| 1192 | case doRemoveModifier: | |||
| 1193 | if (exec_remove (&op->removemodifier) < 0) errors++; | |||
| 1194 | else update_map = True1; | |||
| 1195 | break; | |||
| 1196 | case doClearModifier: | |||
| 1197 | if (exec_clear (&op->clearmodifier) < 0) errors++; | |||
| 1198 | else update_map = True1; | |||
| 1199 | break; | |||
| 1200 | case doPointer: | |||
| 1201 | if (exec_pointer (&op->pointer) < 0) errors++; | |||
| 1202 | break; | |||
| 1203 | default: | |||
| 1204 | fprintf (stderr__stderrp, "%s: unknown opcode %d\n", | |||
| 1205 | ProgramName, op->generic.type); | |||
| 1206 | break; | |||
| 1207 | } | |||
| 1208 | } | |||
| 1209 | ||||
| 1210 | if (update_map) { | |||
| 1211 | if (UpdateModifierMapping (map) < 0) errors++; | |||
| 1212 | } | |||
| 1213 | ||||
| 1214 | return (errors > 0 ? -1 : 0); | |||
| 1215 | } | |||
| 1216 | ||||
| 1217 | static int | |||
| 1218 | exec_keycode(struct op_keycode *opk) | |||
| 1219 | { | |||
| 1220 | if (!opk->target_keycode) { | |||
| 1221 | int i, j; | |||
| 1222 | KeyCode free; | |||
| 1223 | if (!opk->count) | |||
| 1224 | return (0); | |||
| 1225 | free = 0; | |||
| 1226 | for (i = min_keycode; i <= max_keycode; i++) { | |||
| 1227 | for (j = 0; j < opk->count; j++) { | |||
| 1228 | if (XKeycodeToKeysym(dpy, (KeyCode) i, j) != opk->keysyms[j]) | |||
| 1229 | break; | |||
| 1230 | } | |||
| 1231 | if (j >= opk->count) | |||
| 1232 | return (0); | |||
| 1233 | if (free) | |||
| 1234 | continue; | |||
| 1235 | for (j = 0; j < 8; j++) { | |||
| 1236 | if (XKeycodeToKeysym(dpy, (KeyCode) i, j) != None0L) | |||
| 1237 | break; | |||
| 1238 | } | |||
| 1239 | if (j >= 8) | |||
| 1240 | free = i; | |||
| 1241 | } | |||
| 1242 | if (!free) { | |||
| 1243 | fprintf(stderr__stderrp, "%s: no available keycode for assignment\n", | |||
| 1244 | ProgramName); | |||
| 1245 | return (-1); | |||
| 1246 | } | |||
| 1247 | XChangeKeyboardMapping (dpy, free, opk->count, opk->keysyms, 1); | |||
| 1248 | } else if (opk->count == 0) { | |||
| 1249 | KeySym dummy = NoSymbol0L; | |||
| 1250 | XChangeKeyboardMapping (dpy, opk->target_keycode, 1, | |||
| 1251 | &dummy, 1); | |||
| 1252 | } else { | |||
| 1253 | XChangeKeyboardMapping (dpy, opk->target_keycode, opk->count, | |||
| 1254 | opk->keysyms, 1); | |||
| 1255 | } | |||
| 1256 | return (0); | |||
| 1257 | } | |||
| 1258 | ||||
| 1259 | static int | |||
| 1260 | exec_add(struct op_addmodifier *opam) | |||
| 1261 | { | |||
| 1262 | int i; | |||
| 1263 | int status; | |||
| 1264 | ||||
| 1265 | status = 0; | |||
| 1266 | for (i = 0; i < opam->count; i++) { | |||
| 1267 | int num_kcs; | |||
| 1268 | KeyCode *kcs; | |||
| 1269 | ||||
| 1270 | kcs = KeysymToKeycodes (dpy, opam->keysyms[i], &num_kcs); | |||
| 1271 | if (num_kcs == 0) | |||
| 1272 | status = -1; | |||
| 1273 | while (--num_kcs >= 0) { | |||
| 1274 | if (AddModifier (&map, *kcs++, opam->modifier) < 0) | |||
| 1275 | status = -1; | |||
| 1276 | } | |||
| 1277 | } | |||
| 1278 | return (status); | |||
| 1279 | } | |||
| 1280 | ||||
| 1281 | static int | |||
| 1282 | exec_remove(struct op_removemodifier *oprm) | |||
| 1283 | { | |||
| 1284 | int i; | |||
| 1285 | int status; | |||
| 1286 | ||||
| 1287 | status = 0; | |||
| 1288 | for (i = 0; i < oprm->count; i++) { | |||
| 1289 | if (RemoveModifier (&map, oprm->keycodes[i], oprm->modifier) < 0) | |||
| 1290 | status = -1; | |||
| 1291 | } | |||
| 1292 | return (status); | |||
| 1293 | } | |||
| 1294 | ||||
| 1295 | static int | |||
| 1296 | exec_clear(struct op_clearmodifier *opcm) | |||
| 1297 | { | |||
| 1298 | return (ClearModifier (&map, opcm->modifier)); | |||
| 1299 | } | |||
| 1300 | ||||
| 1301 | ||||
| 1302 | static int | |||
| 1303 | exec_pointer(struct op_pointer *opp) | |||
| 1304 | { | |||
| 1305 | return (SetPointerMap (opp->button_codes, opp->count)); | |||
| 1306 | } | |||
| 1307 | ||||
| 1308 | void | |||
| 1309 | print_modifier_map(void) | |||
| 1310 | { | |||
| 1311 | PrintModifierMapping (map, stdout__stdoutp); | |||
| 1312 | return; | |||
| 1313 | } | |||
| 1314 | ||||
| 1315 | void | |||
| 1316 | print_key_table(Boolint exprs) | |||
| 1317 | { | |||
| 1318 | PrintKeyTable (exprs, stdout__stdoutp); | |||
| 1319 | return; | |||
| 1320 | } | |||
| 1321 | ||||
| 1322 | void | |||
| 1323 | print_pointer_map(void) | |||
| 1324 | { | |||
| 1325 | PrintPointerMap (stdout__stdoutp); | |||
| 1326 | return; | |||
| 1327 | } | |||
| 1328 | ||||
| 1329 |