handle.c revision b7fb5eac
11a30de1fSmrg/* $Xorg: handle.c,v 1.6 2001/02/09 02:05:56 xorgcvs Exp $ */
21a30de1fSmrg/*
31a30de1fSmrg
41a30de1fSmrgCopyright 1988, 1998  The Open Group
51a30de1fSmrg
61a30de1fSmrgPermission to use, copy, modify, distribute, and sell this software and its
71a30de1fSmrgdocumentation for any purpose is hereby granted without fee, provided that
81a30de1fSmrgthe above copyright notice appear in all copies and that both that
91a30de1fSmrgcopyright notice and this permission notice appear in supporting
101a30de1fSmrgdocumentation.
111a30de1fSmrg
121a30de1fSmrgThe above copyright notice and this permission notice shall be included
131a30de1fSmrgin all copies or substantial portions of the Software.
141a30de1fSmrg
151a30de1fSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
161a30de1fSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
171a30de1fSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
181a30de1fSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
191a30de1fSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
201a30de1fSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
211a30de1fSmrgOTHER DEALINGS IN THE SOFTWARE.
221a30de1fSmrg
231a30de1fSmrgExcept as contained in this notice, the name of The Open Group shall
241a30de1fSmrgnot be used in advertising or otherwise to promote the sale, use or
251a30de1fSmrgother dealings in this Software without prior written authorization
261a30de1fSmrgfrom The Open Group.
271a30de1fSmrg
281a30de1fSmrg*/
291a30de1fSmrg/* $XFree86: xc/programs/xmodmap/handle.c,v 3.6 2001/07/25 15:05:27 dawes Exp $ */
301a30de1fSmrg
311a30de1fSmrg#include "config.h"
321a30de1fSmrg#include <X11/Xos.h>
331a30de1fSmrg#include <X11/Xlib.h>
341a30de1fSmrg#include <stdio.h>
351a30de1fSmrg#include <ctype.h>
361a30de1fSmrg#include "xmodmap.h"
371a30de1fSmrg#include "wq.h"
381a30de1fSmrg#include <stdlib.h>
391a30de1fSmrg
401a30de1fSmrgstatic XModifierKeymap *map = NULL;
411a30de1fSmrg
421a30de1fSmrg
431a30de1fSmrg/*
441a30de1fSmrg * The routines in this file manipulate a queue of intructions.  Instead of
451a30de1fSmrg * executing each line as it is entered, we build up a list of actions to
461a30de1fSmrg * take and execute them all at the end.  This allows us to find all errors
471a30de1fSmrg * at once, and to preserve the context in which we are looking up keysyms.
481a30de1fSmrg */
491a30de1fSmrg
501a30de1fSmrgstruct wq work_queue = {NULL, NULL};
511a30de1fSmrg
521a30de1fSmrg
531a30de1fSmrg/*
541a30de1fSmrg * common utility routines
551a30de1fSmrg */
561a30de1fSmrg
571a30de1fSmrgstatic KeyCode *
581a30de1fSmrgKeysymToKeycodes(Display *dpy, KeySym keysym, int *pnum_kcs)
591a30de1fSmrg{
601a30de1fSmrg    KeyCode *kcs = NULL;
611a30de1fSmrg    int i, j;
621a30de1fSmrg
631a30de1fSmrg    *pnum_kcs = 0;
641a30de1fSmrg    for (i = min_keycode; i <= max_keycode; i++) {
651a30de1fSmrg	for (j = 0; j < 8; j++) {
661a30de1fSmrg	    if (XKeycodeToKeysym(dpy, (KeyCode) i, j) == keysym) {
671a30de1fSmrg		if (!kcs)
681a30de1fSmrg		    kcs = (KeyCode *)malloc(sizeof(KeyCode));
691a30de1fSmrg		else
701a30de1fSmrg		    kcs = (KeyCode *)realloc((char *)kcs,
711a30de1fSmrg					 sizeof(KeyCode) * (*pnum_kcs + 1));
721a30de1fSmrg		kcs[*pnum_kcs] = i;
731a30de1fSmrg		*pnum_kcs += 1;
741a30de1fSmrg		break;
751a30de1fSmrg	    }
761a30de1fSmrg	}
771a30de1fSmrg    }
781a30de1fSmrg    return kcs;
791a30de1fSmrg}
801a30de1fSmrg
811a30de1fSmrgstatic char *
821a30de1fSmrgcopy_to_scratch(const char *s, int len)
831a30de1fSmrg{
841a30de1fSmrg    static char *buf = NULL;
851a30de1fSmrg    static int buflen = 0;
861a30de1fSmrg
871a30de1fSmrg    if (len > buflen) {
881a30de1fSmrg	if (buf) free (buf);
891a30de1fSmrg	buflen = (len < 40) ? 80 : (len * 2);
901a30de1fSmrg	buf = (char *) malloc (buflen+1);
911a30de1fSmrg    }
921a30de1fSmrg    if (len > 0)
931a30de1fSmrg      strncpy (buf, s, len);
941a30de1fSmrg    else
951a30de1fSmrg      len = 0;
961a30de1fSmrg
971a30de1fSmrg    buf[len] = '\0';
981a30de1fSmrg    return (buf);
991a30de1fSmrg}
1001a30de1fSmrg
1011a30de1fSmrgstatic void
1021a30de1fSmrgbadheader(void)
1031a30de1fSmrg{
1041a30de1fSmrg    fprintf (stderr, "%s:  %s:%d:  bad ", ProgramName, inputFilename, lineno+1);
1051a30de1fSmrg    parse_errors++;
1061a30de1fSmrg}
1071a30de1fSmrg
1081a30de1fSmrg#define badmsg0(what) { badheader(); fprintf (stderr, what); \
1091a30de1fSmrg			   putc ('\n', stderr); }
1101a30de1fSmrg
1111a30de1fSmrg#define badmsg(what,arg) { badheader(); fprintf (stderr, what, arg); \
1121a30de1fSmrg			   putc ('\n', stderr); }
1131a30de1fSmrg
1141a30de1fSmrg#define badmsgn(what,s,len) badmsg (what, copy_to_scratch (s, len))
1151a30de1fSmrg
1161a30de1fSmrgvoid
1171a30de1fSmrginitialize_map (void)
1181a30de1fSmrg{
1191a30de1fSmrg    map = XGetModifierMapping (dpy);
1201a30de1fSmrg    return;
1211a30de1fSmrg}
1221a30de1fSmrg
1231a30de1fSmrgstatic void do_keycode ( char *line, int len );
1241a30de1fSmrgstatic void do_keysym ( char *line, int len );
1251a30de1fSmrgstatic void finish_keycodes ( const char *line, int len, KeyCode *keycodes,
1261a30de1fSmrg			      int count );
1271a30de1fSmrgstatic void do_add ( char *line, int len );
1281a30de1fSmrgstatic void do_remove ( char *line, int len );
1291a30de1fSmrgstatic void do_clear ( char *line, int len );
1301a30de1fSmrgstatic void do_pointer ( char *line, int len );
1311a30de1fSmrgstatic int get_keysym_list ( const char *line, int len, int *np, KeySym **kslistp );
1321a30de1fSmrg
1331a30de1fSmrgstatic void print_opcode(union op *op);
1341a30de1fSmrg
1351a30de1fSmrgstatic int skip_word ( const char *s, int len );
1361a30de1fSmrgstatic int skip_chars ( const char *s, int len );
1371a30de1fSmrgstatic int skip_space ( const char *s, int len );
1381a30de1fSmrg
1391a30de1fSmrgstatic struct dt {
1401a30de1fSmrg    char *command;			/* name of input command */
1411a30de1fSmrg    int length;				/* length of command */
1421a30de1fSmrg    void (*proc)(char *, int);		/* handler */
1431a30de1fSmrg} dispatch_table[] = {
1441a30de1fSmrg    { "keycode", 7, do_keycode },
1451a30de1fSmrg    { "keysym", 6, do_keysym },
1461a30de1fSmrg    { "add", 3, do_add },
1471a30de1fSmrg    { "remove", 6, do_remove },
1481a30de1fSmrg    { "clear", 5, do_clear },
1491a30de1fSmrg    { "pointer", 7, do_pointer },
1501a30de1fSmrg    { NULL, 0, NULL }};
1511a30de1fSmrg
1521a30de1fSmrg/*
1531a30de1fSmrg * handle_line - this routine parses the input line (which has had all leading
1541a30de1fSmrg * and trailing whitespace removed) and builds up the work queue.
1551a30de1fSmrg */
1561a30de1fSmrg
1571a30de1fSmrgvoid
1581a30de1fSmrghandle_line(char *line,		/* string to parse */
1591a30de1fSmrg	    int len)		/* length of line */
1601a30de1fSmrg{
1611a30de1fSmrg    int n;
1621a30de1fSmrg    struct dt *dtp;
1631a30de1fSmrg
1641a30de1fSmrg    n = skip_chars (line, len);
1651a30de1fSmrg    if (n < 0) {
1661a30de1fSmrg	badmsg ("input line '%s'", line);
1671a30de1fSmrg	return;
1681a30de1fSmrg    }
1691a30de1fSmrg
1701a30de1fSmrg    for (dtp = dispatch_table; dtp->command != NULL; dtp++) {
1711a30de1fSmrg	if (n == dtp->length &&
1721a30de1fSmrg	    strncmp (line, dtp->command, dtp->length) == 0) {
1731a30de1fSmrg
1741a30de1fSmrg	    n += skip_space (line+n, len-n);
1751a30de1fSmrg	    line += n, len -= n;
1761a30de1fSmrg
1771a30de1fSmrg	    (*(dtp->proc)) (line, len);
1781a30de1fSmrg	    return;
1791a30de1fSmrg	}
1801a30de1fSmrg    }
1811a30de1fSmrg
1821a30de1fSmrg    fprintf (stderr, "%s:  unknown command on line %s:%d\n",
1831a30de1fSmrg	     ProgramName, inputFilename, lineno+1);
1841a30de1fSmrg    parse_errors++;
1851a30de1fSmrg}
1861a30de1fSmrg
1871a30de1fSmrg/*
1881a30de1fSmrg * the following routines are useful for parsing
1891a30de1fSmrg */
1901a30de1fSmrg
1911a30de1fSmrgstatic int
1921a30de1fSmrgskip_word (const char *s, int len)
1931a30de1fSmrg{
1941a30de1fSmrg    register int n;
1951a30de1fSmrg
1961a30de1fSmrg    n = skip_chars (s, len);
1971a30de1fSmrg    return (n + skip_space (s+n, len-n));
1981a30de1fSmrg}
1991a30de1fSmrg
2001a30de1fSmrgstatic int
2011a30de1fSmrgskip_chars(const char *s, int len)
2021a30de1fSmrg{
2031a30de1fSmrg    register int i;
2041a30de1fSmrg
2051a30de1fSmrg    if (len <= 0 || !s || *s == '\0') return (0);
2061a30de1fSmrg
2071a30de1fSmrg    for (i = 0; i < len; i++) {
2081a30de1fSmrg	if (isspace(s[i])) break;
2091a30de1fSmrg    }
2101a30de1fSmrg    return (i);
2111a30de1fSmrg}
2121a30de1fSmrg
2131a30de1fSmrgstatic int
2141a30de1fSmrgskip_space(const char *s, int len)
2151a30de1fSmrg{
2161a30de1fSmrg    register int i;
2171a30de1fSmrg
2181a30de1fSmrg    if (len <= 0 || !s || *s == '\0') return (0);
2191a30de1fSmrg
2201a30de1fSmrg    for (i = 0; i < len; i++) {
2211a30de1fSmrg	if (!s[i] || !isspace(s[i])) break;
2221a30de1fSmrg    }
2231a30de1fSmrg    return (i);
2241a30de1fSmrg}
2251a30de1fSmrg
2261a30de1fSmrg
2271a30de1fSmrgstatic int
2281a30de1fSmrgskip_until_char(const char *s, int len, char c)
2291a30de1fSmrg{
2301a30de1fSmrg    register int i;
2311a30de1fSmrg
2321a30de1fSmrg    for (i = 0; i < len; i++) {
2331a30de1fSmrg	if (s[i] == c) break;
2341a30de1fSmrg    }
2351a30de1fSmrg    return (i);
2361a30de1fSmrg}
2371a30de1fSmrg
2381a30de1fSmrg
2391a30de1fSmrg/*
2401a30de1fSmrg * The action routines.
2411a30de1fSmrg *
2421a30de1fSmrg * This is where the real work gets done.  Each routine is responsible for
2431a30de1fSmrg * parsing its input (note that the command keyword has been stripped off)
2441a30de1fSmrg * and adding to the work queue.  They are also in charge of outputting
2451a30de1fSmrg * error messages and returning non-zero if there is a problem.
2461a30de1fSmrg *
2471a30de1fSmrg * The following global variables are available:
2481a30de1fSmrg *     dpy                the display descriptor
2491a30de1fSmrg *     work_queue         linked list of opcodes
2501a30de1fSmrg *     inputFilename      name of the file being processed
2511a30de1fSmrg *     lineno             line number of current line in input file
2521a30de1fSmrg */
2531a30de1fSmrgstatic void
2541a30de1fSmrgadd_to_work_queue(union op *p)	/* this can become a macro someday */
2551a30de1fSmrg{
2561a30de1fSmrg    if (work_queue.head == NULL) {	/* nothing on the list */
2571a30de1fSmrg	work_queue.head = work_queue.tail = p;	/* head, tail, no prev */
2581a30de1fSmrg    } else {
2591a30de1fSmrg	work_queue.tail->generic.next = p;  /* head okay, prev */
2601a30de1fSmrg	work_queue.tail = p;		/* tail */
2611a30de1fSmrg    }
2621a30de1fSmrg    p->generic.next = NULL;
2631a30de1fSmrg
2641a30de1fSmrg    if (verbose) {
2651a30de1fSmrg	print_opcode (p);
2661a30de1fSmrg    }
2671a30de1fSmrg    return;
2681a30de1fSmrg}
2691a30de1fSmrg
2701a30de1fSmrgstatic Bool
2711a30de1fSmrgparse_number(const char *str, unsigned long *val)
2721a30de1fSmrg{
2731a30de1fSmrg    char *fmt = "%ld";
2741a30de1fSmrg
2751a30de1fSmrg    if (*str == '0') {
2761a30de1fSmrg	str++;
277b7fb5eacSmrg	while (isspace(*str))
278b7fb5eacSmrg	    str++;
2791a30de1fSmrg	fmt = "%lo";
2801a30de1fSmrg	if (*str == '\0') {
2811a30de1fSmrg	    *val = 0;
2821a30de1fSmrg	    return 1;
2831a30de1fSmrg	}
2841a30de1fSmrg	if (*str == 'x' || *str == 'X') {
2851a30de1fSmrg	    str++;
2861a30de1fSmrg	    fmt = "%lx";
2871a30de1fSmrg	}
2881a30de1fSmrg    }
2891a30de1fSmrg    return (sscanf (str, fmt, val) == 1);
2901a30de1fSmrg}
2911a30de1fSmrg
2921a30de1fSmrgstatic Bool
2931a30de1fSmrgparse_keysym(const char *line, int n, char **name, KeySym *keysym)
2941a30de1fSmrg{
2951a30de1fSmrg    *name = copy_to_scratch (line, n);
2961a30de1fSmrg    if (!strcmp(*name, "NoSymbol")) {
2971a30de1fSmrg	*keysym = NoSymbol;
2981a30de1fSmrg	return (True);
2991a30de1fSmrg    }
3001a30de1fSmrg    *keysym = XStringToKeysym (*name);
3011a30de1fSmrg    if (*keysym == NoSymbol && '0' <= **name && **name <= '9')
3021a30de1fSmrg	return parse_number(*name, keysym);
3031a30de1fSmrg    return (*keysym != NoSymbol);
3041a30de1fSmrg}
3051a30de1fSmrg
3061a30de1fSmrg/*
3071a30de1fSmrg * do_keycode - parse off lines of the form
3081a30de1fSmrg *
3091a30de1fSmrg *                 "keycode" number "=" [keysym ...]
3101a30de1fSmrg *                           ^
3111a30de1fSmrg *
3121a30de1fSmrg * where number is in decimal, hex, or octal.  Any number of keysyms may be
3131a30de1fSmrg * listed.
3141a30de1fSmrg */
3151a30de1fSmrg
3161a30de1fSmrgstatic void
3171a30de1fSmrgdo_keycode(char *line, int len)
3181a30de1fSmrg{
3191a30de1fSmrg    int dummy;
3201a30de1fSmrg    char *fmt = "%d";
3211a30de1fSmrg    KeyCode keycode;
3221a30de1fSmrg
3231a30de1fSmrg    if (len < 3 || !line || *line == '\0') {  /* 5=a minimum */
3241a30de1fSmrg	badmsg0 ("keycode input line");
3251a30de1fSmrg	return;
3261a30de1fSmrg    }
3271a30de1fSmrg
3281a30de1fSmrg    /*
3291a30de1fSmrg     * We need not bother to advance line/len past the
3301a30de1fSmrg     * number (or the string 'any') as finish_keycodes() will
3311a30de1fSmrg     * first advance past the '='.
3321a30de1fSmrg     */
3331a30de1fSmrg    if (!strncmp("any", line, 3)) {
3341a30de1fSmrg	keycode = 0;
3351a30de1fSmrg    } else {
3361a30de1fSmrg	if (*line == '0') line++, len--, fmt = "%o";
3371a30de1fSmrg	if (*line == 'x' || *line == 'X') line++, len--, fmt = "%x";
3381a30de1fSmrg
3391a30de1fSmrg	dummy = 0;
3401a30de1fSmrg	if (sscanf (line, fmt, &dummy) != 1 || dummy == 0) {
3411a30de1fSmrg	    badmsg0 ("keycode value");
3421a30de1fSmrg	    return;
3431a30de1fSmrg	}
3441a30de1fSmrg	keycode = (KeyCode) dummy;
3451a30de1fSmrg	if ((int)keycode < min_keycode || (int)keycode > max_keycode) {
3461a30de1fSmrg	    badmsg0 ("keycode value (out of range)");
3471a30de1fSmrg	    return;
3481a30de1fSmrg	}
3491a30de1fSmrg    }
3501a30de1fSmrg
3511a30de1fSmrg    finish_keycodes (line, len, &keycode, 1);
3521a30de1fSmrg}
3531a30de1fSmrg
3541a30de1fSmrg
3551a30de1fSmrg/*
3561a30de1fSmrg * do_keysym - parse off lines of the form
3571a30de1fSmrg *
3581a30de1fSmrg *                 "keysym" keysym "=" [keysym ...]
3591a30de1fSmrg *                          ^
3601a30de1fSmrg *
3611a30de1fSmrg * The left keysyms has to be checked for validity and evaluated.
3621a30de1fSmrg */
3631a30de1fSmrg
3641a30de1fSmrgstatic void
3651a30de1fSmrgdo_keysym(char *line, int len)
3661a30de1fSmrg{
3671a30de1fSmrg    int n;
3681a30de1fSmrg    KeyCode *keycodes;
3691a30de1fSmrg    KeySym keysym;
3701a30de1fSmrg    char *tmpname;
3711a30de1fSmrg
3721a30de1fSmrg    if (len < 3 || !line || *line == '\0') {  /* a=b minimum */
3731a30de1fSmrg	badmsg0 ("keysym input line");
3741a30de1fSmrg	return;
3751a30de1fSmrg    }
3761a30de1fSmrg
3771a30de1fSmrg    n = skip_chars (line, len);
3781a30de1fSmrg    if (n < 1) {
3791a30de1fSmrg	badmsg0 ("target keysym name");
3801a30de1fSmrg	return;
3811a30de1fSmrg    }
3821a30de1fSmrg    if (!parse_keysym(line, n, &tmpname, &keysym)) {
3831a30de1fSmrg	badmsg ("keysym target key symbol '%s'", tmpname);
3841a30de1fSmrg	return;
3851a30de1fSmrg    }
3861a30de1fSmrg
3871a30de1fSmrg    keycodes = KeysymToKeycodes (dpy, keysym, &n);
3881a30de1fSmrg    if (n == 0) {
3891a30de1fSmrg	badmsg ("keysym target keysym '%s', no corresponding keycodes",
3901a30de1fSmrg		tmpname);
3911a30de1fSmrg	return;
3921a30de1fSmrg    }
3931a30de1fSmrg    if (verbose) {
3941a30de1fSmrg	int i;
3951a30de1fSmrg	printf ("! Keysym %s (0x%lx) corresponds to keycode(s)",
3961a30de1fSmrg		tmpname, (long) keysym);
3971a30de1fSmrg	for (i = 0; i < n; i++)
3981a30de1fSmrg	    printf (" 0x%x", keycodes[i]);
3991a30de1fSmrg	printf("\n");
4001a30de1fSmrg    }
4011a30de1fSmrg
4021a30de1fSmrg    finish_keycodes (line, len, keycodes, n);
4031a30de1fSmrg}
4041a30de1fSmrg
4051a30de1fSmrgstatic void
4061a30de1fSmrgfinish_keycodes(const char *line, int len, KeyCode *keycodes, int count)
4071a30de1fSmrg{
4081a30de1fSmrg    int n;
4091a30de1fSmrg    KeySym *kslist;
4101a30de1fSmrg    union op *uop;
4111a30de1fSmrg    struct op_keycode *opk;
4121a30de1fSmrg
4131a30de1fSmrg    n = skip_until_char (line, len, '=');
4141a30de1fSmrg    line += n, len -= n;
4151a30de1fSmrg
4161a30de1fSmrg    if (len < 1 || *line != '=') {	/* = minimum */
4171a30de1fSmrg	badmsg0 ("keycode command (missing keysym list),");
4181a30de1fSmrg	return;
4191a30de1fSmrg    }
4201a30de1fSmrg    line++, len--;			/* skip past the = */
4211a30de1fSmrg
4221a30de1fSmrg    n = skip_space (line, len);
4231a30de1fSmrg    line += n, len -= n;
4241a30de1fSmrg
4251a30de1fSmrg    /* allow empty list */
4261a30de1fSmrg    if (get_keysym_list (line, len, &n, &kslist) < 0)
4271a30de1fSmrg	return;
4281a30de1fSmrg
4291a30de1fSmrg    while (--count >= 0) {
4301a30de1fSmrg	uop = AllocStruct (union op);
4311a30de1fSmrg	if (!uop) {
4321a30de1fSmrg	    badmsg ("attempt to allocate a %ld byte keycode opcode",
4331a30de1fSmrg		    (long) sizeof (struct op_keycode));
4341a30de1fSmrg	    return;
4351a30de1fSmrg	}
4361a30de1fSmrg	opk = &uop->keycode;
4371a30de1fSmrg
4381a30de1fSmrg	opk->type = doKeycode;
4391a30de1fSmrg	opk->target_keycode = keycodes[count];
4401a30de1fSmrg	opk->count = n;
4411a30de1fSmrg	opk->keysyms = kslist;
4421a30de1fSmrg
4431a30de1fSmrg	add_to_work_queue (uop);
4441a30de1fSmrg    }
4451a30de1fSmrg
4461a30de1fSmrg#ifdef later
4471a30de1fSmrg    /* make sure we handle any special keys */
4481a30de1fSmrg    check_special_keys (keycode, n, kslist);
4491a30de1fSmrg#endif
4501a30de1fSmrg}
4511a30de1fSmrg
4521a30de1fSmrg
4531a30de1fSmrg/*
4541a30de1fSmrg * parse_modifier - convert a modifier string name to its index
4551a30de1fSmrg */
4561a30de1fSmrg
4571a30de1fSmrgstruct modtab modifier_table[] = {	/* keep in order so it can be index */
4581a30de1fSmrg    { "shift", 5, 0 },
4591a30de1fSmrg    { "lock", 4, 1 },
4601a30de1fSmrg    { "control", 7, 2 },
4611a30de1fSmrg    { "mod1", 4, 3 },
4621a30de1fSmrg    { "mod2", 4, 4 },
4631a30de1fSmrg    { "mod3", 4, 5 },
4641a30de1fSmrg    { "mod4", 4, 6 },
4651a30de1fSmrg    { "mod5", 4, 7 },
4661a30de1fSmrg    { "ctrl", 4, 2 },
4671a30de1fSmrg    { NULL, 0, 0 }};
4681a30de1fSmrg
4691a30de1fSmrgstatic int
4701a30de1fSmrgparse_modifier(char *line, int n)
4711a30de1fSmrg{
4721a30de1fSmrg    register int i;
4731a30de1fSmrg    struct modtab *mt;
4741a30de1fSmrg
4751a30de1fSmrg    /* lowercase for comparison against table */
4761a30de1fSmrg    for (i = 0; i < n; i++) {
4771a30de1fSmrg	if (isupper (line[i])) line[i] = tolower (line[i]);
4781a30de1fSmrg    }
4791a30de1fSmrg
4801a30de1fSmrg    for (mt = modifier_table; mt->name; mt++) {
4811a30de1fSmrg	if (n == mt->length && strncmp (line, mt->name, n) == 0)
4821a30de1fSmrg	  return (mt->value);
4831a30de1fSmrg    }
4841a30de1fSmrg    return (-1);
4851a30de1fSmrg}
4861a30de1fSmrg
4871a30de1fSmrg
4881a30de1fSmrg/*
4891a30de1fSmrg * do_add - parse off lines of the form
4901a30de1fSmrg *
4911a30de1fSmrg *                 add MODIFIER = keysym ...
4921a30de1fSmrg *                     ^
4931a30de1fSmrg * where the MODIFIER is one of Shift, Lock, Control, Mod[1-5] where case
4941a30de1fSmrg * is not important.  There should also be an alias Ctrl for control.
4951a30de1fSmrg */
4961a30de1fSmrg
4971a30de1fSmrgstatic void
4981a30de1fSmrgdo_add(char *line, int len)
4991a30de1fSmrg{
5001a30de1fSmrg    int n;
5011a30de1fSmrg    int modifier;
5021a30de1fSmrg    KeySym *kslist;
5031a30de1fSmrg    union op *uop;
5041a30de1fSmrg    struct op_addmodifier *opam;
5051a30de1fSmrg
5061a30de1fSmrg    if (len < 6 || !line || *line == '\0') {  /* Lock=a minimum */
5071a30de1fSmrg	badmsg0 ("add modifier input line");
5081a30de1fSmrg	return;
5091a30de1fSmrg    }
5101a30de1fSmrg
5111a30de1fSmrg    n = skip_chars (line, len);
5121a30de1fSmrg    if (n < 1) {
5131a30de1fSmrg	badmsg ("add modifier name %s", line);
5141a30de1fSmrg	return;
5151a30de1fSmrg    }
5161a30de1fSmrg
5171a30de1fSmrg    modifier = parse_modifier (line, n);
5181a30de1fSmrg    if (modifier < 0) {
5191a30de1fSmrg	badmsgn ("add modifier name '%s', not allowed", line, n);
5201a30de1fSmrg	return;
5211a30de1fSmrg    }
5221a30de1fSmrg
5231a30de1fSmrg    line += n, len -= n;
5241a30de1fSmrg    n = skip_until_char (line, len, '=');
5251a30de1fSmrg    if (n < 0) {
5261a30de1fSmrg	badmsg0 ("add modifier = keysym");
5271a30de1fSmrg	return;
5281a30de1fSmrg    }
5291a30de1fSmrg
5301a30de1fSmrg    n++;				/* skip = */
5311a30de1fSmrg    n += skip_space (line+n, len-n);
5321a30de1fSmrg    line += n, len -= n;
5331a30de1fSmrg
5341a30de1fSmrg    if (get_keysym_list (line, len, &n, &kslist) < 0)
5351a30de1fSmrg	return;
5361a30de1fSmrg    if (n == 0) {
5371a30de1fSmrg	badmsg0 ("add modifier keysym list (empty)");
5381a30de1fSmrg	return;
5391a30de1fSmrg    }
5401a30de1fSmrg
5411a30de1fSmrg    uop = AllocStruct (union op);
5421a30de1fSmrg    if (!uop) {
5431a30de1fSmrg	badmsg ("attempt to allocate %ld byte addmodifier opcode",
5441a30de1fSmrg		(long) sizeof (struct op_addmodifier));
5451a30de1fSmrg	return;
5461a30de1fSmrg    }
5471a30de1fSmrg    opam = &uop->addmodifier;
5481a30de1fSmrg
5491a30de1fSmrg    opam->type = doAddModifier;
5501a30de1fSmrg    opam->modifier = modifier;
5511a30de1fSmrg    opam->count = n;
5521a30de1fSmrg    opam->keysyms = kslist;
5531a30de1fSmrg
5541a30de1fSmrg    add_to_work_queue (uop);
5551a30de1fSmrg}
5561a30de1fSmrg
5571a30de1fSmrg#ifdef AUTO_ADD_REMOVE
5581a30de1fSmrg/*
5591a30de1fSmrg * make_add - stick a single add onto the queue
5601a30de1fSmrg */
5611a30de1fSmrgstatic void
5621a30de1fSmrgmake_add(int modifier, KeySym keysym)
5631a30de1fSmrg{
5641a30de1fSmrg    union op *uop;
5651a30de1fSmrg    struct op_addmodifier *opam;
5661a30de1fSmrg
5671a30de1fSmrg    uop = AllocStruct (union op);
5681a30de1fSmrg    if (!uop) {
5691a30de1fSmrg	badmsg ("attempt to allocate %ld byte addmodifier opcode",
5701a30de1fSmrg		(long) sizeof (struct op_addmodifier));
5711a30de1fSmrg	return;
5721a30de1fSmrg    }
5731a30de1fSmrg    opam = &uop->addmodifier;
5741a30de1fSmrg
5751a30de1fSmrg    opam->type = doAddModifier;
5761a30de1fSmrg    opam->modifier = modifier;
5771a30de1fSmrg    opam->count = 1;
5781a30de1fSmrg    opam->keysyms = (KeySym *) malloc (sizeof (KeySym));
5791a30de1fSmrg    if (!opam->keysyms) {
5801a30de1fSmrg	badmsg ("attempt to allocate %ld byte KeySym", (long) sizeof (KeySym));
5811a30de1fSmrg	free ((char *) opam);
5821a30de1fSmrg	return;
5831a30de1fSmrg    }
5841a30de1fSmrg    opam->keysyms[0] = keysym;
5851a30de1fSmrg
5861a30de1fSmrg    add_to_work_queue (uop);
5871a30de1fSmrg    return;
5881a30de1fSmrg}
5891a30de1fSmrg#endif /* AUTO_ADD_REMOVE */
5901a30de1fSmrg
5911a30de1fSmrg
5921a30de1fSmrg/*
5931a30de1fSmrg * do_remove - parse off lines of the form
5941a30de1fSmrg *
5951a30de1fSmrg *                 remove MODIFIER = oldkeysym ...
5961a30de1fSmrg *                        ^
5971a30de1fSmrg * where the MODIFIER is one of Shift, Lock, Control, Mod[1-5] where case
5981a30de1fSmrg * is not important.  There should also be an alias Ctrl for control.
5991a30de1fSmrg */
6001a30de1fSmrg
6011a30de1fSmrgstatic void
6021a30de1fSmrgdo_remove(char *line, int len)
6031a30de1fSmrg{
6041a30de1fSmrg    int n;
6051a30de1fSmrg    int nc;
6061a30de1fSmrg    int i;
6071a30de1fSmrg    int tot;
6081a30de1fSmrg    int modifier;
6091a30de1fSmrg    KeySym *kslist;
6101a30de1fSmrg    KeyCode *kclist;
6111a30de1fSmrg    union op *uop;
6121a30de1fSmrg    struct op_removemodifier *oprm;
6131a30de1fSmrg
6141a30de1fSmrg    if (len < 6 || !line || *line == '\0') {  /* Lock=a minimum */
6151a30de1fSmrg	badmsg0 ("remove modifier input line");
6161a30de1fSmrg	return;
6171a30de1fSmrg    }
6181a30de1fSmrg
6191a30de1fSmrg    n = skip_chars (line, len);
6201a30de1fSmrg    if (n < 1) {
6211a30de1fSmrg	badmsg ("remove modifier name %s", line);
6221a30de1fSmrg	return;
6231a30de1fSmrg    }
6241a30de1fSmrg
6251a30de1fSmrg    modifier = parse_modifier (line, n);
6261a30de1fSmrg    if (modifier < 0) {
6271a30de1fSmrg	badmsgn ("remove modifier name '%s', not allowed", line, n);
6281a30de1fSmrg	return;
6291a30de1fSmrg    }
6301a30de1fSmrg
6311a30de1fSmrg    line += n, len -= n;
6321a30de1fSmrg    n = skip_until_char (line, len, '=');
6331a30de1fSmrg    if (n < 0) {
6341a30de1fSmrg	badmsg0 ("remove modifier = keysym");
6351a30de1fSmrg	return;
6361a30de1fSmrg    }
6371a30de1fSmrg
6381a30de1fSmrg    n++;
6391a30de1fSmrg    n += skip_space (line+n, len-n);
6401a30de1fSmrg    line += n, len -= n;
6411a30de1fSmrg
6421a30de1fSmrg    if (get_keysym_list (line, len, &n, &kslist) < 0)
6431a30de1fSmrg	return;
6441a30de1fSmrg    if (n == 0) {
6451a30de1fSmrg	badmsg0 ("remove modifier keysym list (empty)");
6461a30de1fSmrg	return;
6471a30de1fSmrg    }
6481a30de1fSmrg
6491a30de1fSmrg    /*
6501a30de1fSmrg     * unlike the add command, we have to now evaluate the keysyms
6511a30de1fSmrg     */
6521a30de1fSmrg
6531a30de1fSmrg    kclist = (KeyCode *) malloc (n * sizeof (KeyCode));
6541a30de1fSmrg    if (!kclist) {
6551a30de1fSmrg	badmsg ("attempt to allocate %ld byte keycode list",
6561a30de1fSmrg		(long) (n * sizeof (KeyCode)));
6571a30de1fSmrg	free ((char *) kslist);
6581a30de1fSmrg	return;
6591a30de1fSmrg    }
6601a30de1fSmrg
6611a30de1fSmrg    tot = n;
6621a30de1fSmrg    nc = 0;
6631a30de1fSmrg    for (i = 0; i < n; i++) {
6641a30de1fSmrg        int num_kcs;
6651a30de1fSmrg	KeyCode *kcs;
6661a30de1fSmrg	kcs = KeysymToKeycodes (dpy, kslist[i], &num_kcs);
6671a30de1fSmrg	if (num_kcs == 0) {
6681a30de1fSmrg	    char *tmpname = XKeysymToString (kslist[i]);
6691a30de1fSmrg	    badmsg ("keysym in remove modifier list '%s', no corresponding keycodes",
6701a30de1fSmrg		    tmpname ? tmpname : "?");
6711a30de1fSmrg	    continue;
6721a30de1fSmrg	}
6731a30de1fSmrg	if (verbose) {
6741a30de1fSmrg	    int j;
6751a30de1fSmrg	    char *tmpname = XKeysymToString (kslist[i]);
6761a30de1fSmrg	    printf ("! Keysym %s (0x%lx) corresponds to keycode(s)",
6771a30de1fSmrg		    tmpname ? tmpname : "?", (long) kslist[i]);
6781a30de1fSmrg	    for (j = 0; j < num_kcs; j++)
6791a30de1fSmrg		printf(" 0x%x", kcs[j]);
6801a30de1fSmrg	    printf("\n");
6811a30de1fSmrg	}
6821a30de1fSmrg	if (nc + num_kcs > tot) {
6831a30de1fSmrg	    tot = nc + num_kcs;
6841a30de1fSmrg	    kclist = (KeyCode *)realloc((char *)kclist, tot * sizeof(KeyCode));
6851a30de1fSmrg	    if (!kclist) {
6861a30de1fSmrg		badmsg ("attempt to allocate %ld byte keycode list",
6871a30de1fSmrg			(long) (tot * sizeof (KeyCode)));
6881a30de1fSmrg		free ((char *) kslist);
6891a30de1fSmrg		return;
6901a30de1fSmrg	    }
6911a30de1fSmrg	}
6921a30de1fSmrg	while (--num_kcs >= 0)
6931a30de1fSmrg	    kclist[nc++] = *kcs++;		/* okay, add it to list */
6941a30de1fSmrg    }
6951a30de1fSmrg
6961a30de1fSmrg    free ((char *) kslist);		/* all done with it */
6971a30de1fSmrg
6981a30de1fSmrg    uop = AllocStruct (union op);
6991a30de1fSmrg    if (!uop) {
7001a30de1fSmrg	badmsg ("attempt to allocate %ld byte removemodifier opcode",
7011a30de1fSmrg		(long) sizeof (struct op_removemodifier));
7021a30de1fSmrg	return;
7031a30de1fSmrg    }
7041a30de1fSmrg    oprm = &uop->removemodifier;
7051a30de1fSmrg
7061a30de1fSmrg    oprm->type = doRemoveModifier;
7071a30de1fSmrg    oprm->modifier = modifier;
7081a30de1fSmrg    oprm->count = nc;
7091a30de1fSmrg    oprm->keycodes = kclist;
7101a30de1fSmrg
7111a30de1fSmrg    add_to_work_queue (uop);
7121a30de1fSmrg}
7131a30de1fSmrg
7141a30de1fSmrg#ifdef AUTO_ADD_REMOVE
7151a30de1fSmrg/*
7161a30de1fSmrg * make_remove - stick a single remove onto the queue
7171a30de1fSmrg */
7181a30de1fSmrgstatic void
7191a30de1fSmrgmake_remove(int modifier, KeyCode keycode)
7201a30de1fSmrg{
7211a30de1fSmrg    union op *uop;
7221a30de1fSmrg    struct op_removemodifier *oprm;
7231a30de1fSmrg
7241a30de1fSmrg    uop = AllocStruct (union op);
7251a30de1fSmrg    if (!uop) {
7261a30de1fSmrg	badmsg ("attempt to allocate %ld byte removemodifier opcode",
7271a30de1fSmrg		(long) sizeof (struct op_removemodifier));
7281a30de1fSmrg	return;
7291a30de1fSmrg    }
7301a30de1fSmrg    oprm = &uop->removemodifier;
7311a30de1fSmrg
7321a30de1fSmrg    oprm->type = doRemoveModifier;
7331a30de1fSmrg    oprm->modifier = modifier;
7341a30de1fSmrg    oprm->count = 1;
7351a30de1fSmrg    oprm->keycodes = (KeyCode *) malloc (sizeof (KeyCode));
7361a30de1fSmrg    if (!oprm->keycodes) {
7371a30de1fSmrg	badmsg ("attempt to allocate %ld byte KeyCode",
7381a30de1fSmrg		(long) sizeof (KeyCode));
7391a30de1fSmrg	free ((char *) oprm);
7401a30de1fSmrg	return;
7411a30de1fSmrg    }
7421a30de1fSmrg    oprm->keycodes[0] = keycode;
7431a30de1fSmrg
7441a30de1fSmrg    add_to_work_queue (uop);
7451a30de1fSmrg    return;
7461a30de1fSmrg}
7471a30de1fSmrg#endif /* AUTO_ADD_REMOVE */
7481a30de1fSmrg
7491a30de1fSmrg
7501a30de1fSmrg/*
7511a30de1fSmrg * do_clear - parse off lines of the form
7521a30de1fSmrg *
7531a30de1fSmrg *                 clear MODIFIER
7541a30de1fSmrg *                       ^
7551a30de1fSmrg */
7561a30de1fSmrg
7571a30de1fSmrgstatic void
7581a30de1fSmrgdo_clear(char *line, int len)
7591a30de1fSmrg{
7601a30de1fSmrg    int n;
7611a30de1fSmrg    int modifier;
7621a30de1fSmrg    union op *uop;
7631a30de1fSmrg    struct op_clearmodifier *opcm;
7641a30de1fSmrg
7651a30de1fSmrg    if (len < 4 || !line || *line == '\0') {  /* Lock minimum */
7661a30de1fSmrg	badmsg0 ("clear modifier input line");
7671a30de1fSmrg	return;
7681a30de1fSmrg    }
7691a30de1fSmrg
7701a30de1fSmrg    n = skip_chars (line, len);
7711a30de1fSmrg
7721a30de1fSmrg    modifier = parse_modifier (line, n);
7731a30de1fSmrg    if (modifier < 0) {
7741a30de1fSmrg	badmsgn ("clear modifier name '%s'", line, n);
7751a30de1fSmrg	return;
7761a30de1fSmrg    }
7771a30de1fSmrg    n += skip_space (line+n, len-n);
7781a30de1fSmrg    if (n != len) {
7791a30de1fSmrg	badmsgn ("extra argument '%s' to clear modifier", line+n, len-n);
7801a30de1fSmrg	/* okay to continue */
7811a30de1fSmrg    }
7821a30de1fSmrg
7831a30de1fSmrg    uop = AllocStruct (union op);
7841a30de1fSmrg    if (!uop) {
7851a30de1fSmrg	badmsg ("attempt to allocate %ld byte clearmodifier opcode",
7861a30de1fSmrg		(long) sizeof (struct op_clearmodifier));
7871a30de1fSmrg	return;
7881a30de1fSmrg    }
7891a30de1fSmrg    opcm = &uop->clearmodifier;
7901a30de1fSmrg
7911a30de1fSmrg    opcm->type = doClearModifier;
7921a30de1fSmrg    opcm->modifier = modifier;
7931a30de1fSmrg
7941a30de1fSmrg    add_to_work_queue (uop);
7951a30de1fSmrg}
7961a30de1fSmrg
7971a30de1fSmrg#ifndef HAVE_STRNCASECMP
7981a30de1fSmrgstatic int
7991a30de1fSmrgstrncasecmp(const char *a, const char *b, int n)
8001a30de1fSmrg{
8011a30de1fSmrg    int i;
8021a30de1fSmrg    int a1, b1;
8031a30de1fSmrg
8041a30de1fSmrg    for (i = 0; i < n; i++, a++, b++) {
8051a30de1fSmrg	if (!*a) return -1;
8061a30de1fSmrg	if (!*b) return 1;
8071a30de1fSmrg
8081a30de1fSmrg	if (*a != *b) {
8091a30de1fSmrg	    a1 = (isascii(*a) && isupper(*a)) ? tolower(*a) : *a;
8101a30de1fSmrg	    b1 = (isascii(*b) && isupper(*b)) ? tolower(*b) : *b;
8111a30de1fSmrg	    if (a1 != b1) return b1 - a1;
8121a30de1fSmrg	}
8131a30de1fSmrg    }
8141a30de1fSmrg    return 0;
8151a30de1fSmrg}
8161a30de1fSmrg#endif
8171a30de1fSmrg
8181a30de1fSmrg/*
8191a30de1fSmrg * do_pointer = get list of numbers of the form
8201a30de1fSmrg *
8211a30de1fSmrg *                 buttons = NUMBER ...
8221a30de1fSmrg *                         ^
8231a30de1fSmrg */
8241a30de1fSmrg
8251a30de1fSmrgstatic void
8261a30de1fSmrgdo_pointer(char *line, int len)
8271a30de1fSmrg{
8281a30de1fSmrg    int n;
8291a30de1fSmrg    int i;
8301a30de1fSmrg    unsigned long val;
8311a30de1fSmrg    union op *uop;
8321a30de1fSmrg    struct op_pointer *opp;
8331a30de1fSmrg    unsigned char buttons[MAXBUTTONCODES];
8341a30de1fSmrg    int nbuttons;
8351a30de1fSmrg    char *strval;
8361a30de1fSmrg    Bool ok;
8371a30de1fSmrg
8381a30de1fSmrg    if (len < 2 || !line || *line == '\0') {  /* =1 minimum */
8391a30de1fSmrg	badmsg0 ("buttons input line");
8401a30de1fSmrg	return;
8411a30de1fSmrg    }
8421a30de1fSmrg
8431a30de1fSmrg    nbuttons = XGetPointerMapping (dpy, buttons, MAXBUTTONCODES);
8441a30de1fSmrg
8451a30de1fSmrg    n = skip_space (line, len);
8461a30de1fSmrg    line += n, len -= n;
8471a30de1fSmrg
8481a30de1fSmrg    if (line[0] != '=') {
8491a30de1fSmrg	badmsg0 ("buttons pointer code list, missing equal sign");
8501a30de1fSmrg	return;
8511a30de1fSmrg    }
8521a30de1fSmrg
8531a30de1fSmrg    line++, len--;			/* skip = */
8541a30de1fSmrg    n = skip_space (line, len);
8551a30de1fSmrg    line += n, len -= n;
8561a30de1fSmrg
8571a30de1fSmrg    i = 0;
8581a30de1fSmrg    if (len < 7 || strncasecmp (line, "default", 7) != 0) {
8591a30de1fSmrg	while (len > 0) {
8601a30de1fSmrg	    n = skip_space (line, len);
8611a30de1fSmrg	    line += n, len -= n;
8621a30de1fSmrg	    if (line[0] == '\0') break;
8631a30de1fSmrg	    n = skip_word (line, len);
8641a30de1fSmrg	    if (n < 1) {
8651a30de1fSmrg		badmsg ("skip of word in buttons line:  %s", line);
8661a30de1fSmrg		return;
8671a30de1fSmrg	    }
8681a30de1fSmrg	    strval = copy_to_scratch(line, n);
8691a30de1fSmrg	    ok = parse_number (strval, &val);
8701a30de1fSmrg	    if (!ok || val >= MAXBUTTONCODES) {
8711a30de1fSmrg		badmsg ("value %s given for buttons list", strval);
8721a30de1fSmrg		return;
8731a30de1fSmrg	    }
8741a30de1fSmrg	    buttons[i++] = (unsigned char) val;
8751a30de1fSmrg	    line += n, len -= n;
8761a30de1fSmrg	}
8771a30de1fSmrg    }
8781a30de1fSmrg
8791a30de1fSmrg    if (i > 0 && i != nbuttons) {
8801a30de1fSmrg	fprintf (stderr, "Warning: Only changing the first %d of %d buttons.\n",
8811a30de1fSmrg		 i, nbuttons);
8821a30de1fSmrg	i = nbuttons;
8831a30de1fSmrg    }
8841a30de1fSmrg
8851a30de1fSmrg    uop = AllocStruct (union op);
8861a30de1fSmrg    if (!uop) {
8871a30de1fSmrg	badmsg ("attempt to allocate a %ld byte pointer opcode",
8881a30de1fSmrg		(long) sizeof (struct op_pointer));
8891a30de1fSmrg	return;
8901a30de1fSmrg    }
8911a30de1fSmrg    opp = &uop->pointer;
8921a30de1fSmrg
8931a30de1fSmrg    opp->type = doPointer;
8941a30de1fSmrg    opp->count = i;
8951a30de1fSmrg    for (i = 0; i < opp->count; i++) {
8961a30de1fSmrg	opp->button_codes[i] = buttons[i];
8971a30de1fSmrg    }
8981a30de1fSmrg
8991a30de1fSmrg    add_to_work_queue (uop);
9001a30de1fSmrg}
9011a30de1fSmrg
9021a30de1fSmrg
9031a30de1fSmrg/*
9041a30de1fSmrg * get_keysym_list - parses the rest of the line into a keysyms assumes
9051a30de1fSmrg * that the = sign has been parsed off but there may be leading whitespace
9061a30de1fSmrg *
9071a30de1fSmrg *                 keysym ...
9081a30de1fSmrg *                 ^
9091a30de1fSmrg *
9101a30de1fSmrg * this involves getting the word containing the keysym, checking its range,
9111a30de1fSmrg * and adding it to the list.
9121a30de1fSmrg */
9131a30de1fSmrg
9141a30de1fSmrgstatic int
9151a30de1fSmrgget_keysym_list(const char *line, int len, int *np, KeySym **kslistp)
9161a30de1fSmrg{
9171a30de1fSmrg    int havesofar, maxcanhave;
9181a30de1fSmrg    KeySym *keysymlist;
9191a30de1fSmrg
9201a30de1fSmrg    *np = 0;
9211a30de1fSmrg    *kslistp = NULL;
9221a30de1fSmrg
9231a30de1fSmrg    if (len == 0) return (0);		/* empty list */
9241a30de1fSmrg
9251a30de1fSmrg    havesofar = 0;
9261a30de1fSmrg    maxcanhave = 4;			/* most lists are small */
9271a30de1fSmrg    keysymlist = (KeySym *) malloc (maxcanhave * sizeof (KeySym));
9281a30de1fSmrg    if (!keysymlist) {
9291a30de1fSmrg	badmsg ("attempt to allocate %ld byte initial keysymlist",
9301a30de1fSmrg		(long) (maxcanhave * sizeof (KeySym)));
9311a30de1fSmrg	return (-1);
9321a30de1fSmrg    }
9331a30de1fSmrg
9341a30de1fSmrg    while (len > 0) {
9351a30de1fSmrg	KeySym keysym;
9361a30de1fSmrg	int n;
9371a30de1fSmrg	char *tmpname;
9381a30de1fSmrg	Bool ok;
9391a30de1fSmrg
9401a30de1fSmrg	n = skip_space (line, len);
9411a30de1fSmrg	line += n, len -= n;
9421a30de1fSmrg
9431a30de1fSmrg	n = skip_chars (line, len);
9441a30de1fSmrg	if (n < 0) {
9451a30de1fSmrg	    badmsg0 ("keysym name list");
9461a30de1fSmrg	    free(keysymlist);
9471a30de1fSmrg	    return (-1);
9481a30de1fSmrg	}
9491a30de1fSmrg
9501a30de1fSmrg	ok = parse_keysym (line, n, &tmpname, &keysym);
9511a30de1fSmrg	line += n, len -= n;
9521a30de1fSmrg	if (!ok) {
9531a30de1fSmrg	    badmsg ("keysym name '%s' in keysym list", tmpname);
9541a30de1fSmrg	    /* do NOT return here, look for others */
9551a30de1fSmrg	    continue;
9561a30de1fSmrg	}
9571a30de1fSmrg
9581a30de1fSmrg	/*
9591a30de1fSmrg	 * Do NOT test to see if the keysym translates to a keycode or you
9601a30de1fSmrg	 * won't be able to assign new ones....
9611a30de1fSmrg	 */
9621a30de1fSmrg
9631a30de1fSmrg	/* grow the list bigger if necessary */
9641a30de1fSmrg	if (havesofar >= maxcanhave) {
9651a30de1fSmrg	    KeySym *origkeysymlist = keysymlist;
9661a30de1fSmrg	    maxcanhave *= 2;
9671a30de1fSmrg	    keysymlist = (KeySym *) realloc (keysymlist,
9681a30de1fSmrg					     maxcanhave * sizeof (KeySym));
9691a30de1fSmrg	    if (!keysymlist) {
9701a30de1fSmrg		badmsg ("attempt to grow keysym list to %ld bytes",
9711a30de1fSmrg			(long) (maxcanhave * sizeof (KeySym)));
9721a30de1fSmrg		free(origkeysymlist);
9731a30de1fSmrg		return (-1);
9741a30de1fSmrg	    }
9751a30de1fSmrg	}
9761a30de1fSmrg
9771a30de1fSmrg	/* and add it to the list */
9781a30de1fSmrg	keysymlist[havesofar++] = keysym;
9791a30de1fSmrg    }
9801a30de1fSmrg
9811a30de1fSmrg    *kslistp = keysymlist;
9821a30de1fSmrg    *np = havesofar;
9831a30de1fSmrg    return (0);
9841a30de1fSmrg}
9851a30de1fSmrg
9861a30de1fSmrg
9871a30de1fSmrg#ifdef later
9881a30de1fSmrg/*
9891a30de1fSmrg * check_special_keys - run through list of keysyms and generate "add" or
9901a30de1fSmrg * "remove" commands for for any of the key syms that appear in the modifier
9911a30de1fSmrg * list.  this involves running down the modifier map which is an array of
9921a30de1fSmrg * 8 by map->max_keypermod keycodes.
9931a30de1fSmrg */
9941a30de1fSmrg
9951a30de1fSmrgstatic void
9961a30de1fSmrgcheck_special_keys(KeyCode keycode, int n, KeySym *kslist)
9971a30de1fSmrg{
9981a30de1fSmrg    int i;				/* iterator variable */
9991a30de1fSmrg    KeyCode *kcp;			/* keycode pointer */
10001a30de1fSmrg
10011a30de1fSmrg    /*
10021a30de1fSmrg     * walk the modifiermap array.  since its dimensions are not known at
10031a30de1fSmrg     * compile time, we have to walk it by hand instead of indexing.  this
10041a30de1fSmrg     * is why it is initialized outside the loop, but incremented inside the
10051a30de1fSmrg     * second loop.
10061a30de1fSmrg     */
10071a30de1fSmrg
10081a30de1fSmrg    kcp = map->modifiermap;		/* start at beginning and iterate */
10091a30de1fSmrg    for (i = 0; i < 8; i++) {		/* there are 8 modifier keys */
10101a30de1fSmrg	int j;
10111a30de1fSmrg
10121a30de1fSmrg	for (j = 0; j < map->max_keypermod; j++, kcp++) {
10131a30de1fSmrg	    KeySym keysym;
10141a30de1fSmrg	    int k;
10151a30de1fSmrg
10161a30de1fSmrg	    if (!*kcp) continue;	/* only non-zero entries significant */
10171a30de1fSmrg
10181a30de1fSmrg	    /*
10191a30de1fSmrg	     * check to see if the target keycode is already a modifier; if so,
10201a30de1fSmrg	     * then we have to remove it
10211a30de1fSmrg	     */
10221a30de1fSmrg	    if (keycode == *kcp) {
10231a30de1fSmrg		make_remove (i, keycode);
10241a30de1fSmrg	    }
10251a30de1fSmrg
10261a30de1fSmrg	    /*
10271a30de1fSmrg	     * now, check to see if any of the keysyms map to keycodes
10281a30de1fSmrg	     * that are in the modifier list
10291a30de1fSmrg	     */
10301a30de1fSmrg	    for (k = 0; k < n; k++) {
10311a30de1fSmrg		KeyCodes kc;
10321a30de1fSmrg
10331a30de1fSmrg		kc = XKeysymToKeycode (dpy, kslist[k]);
10341a30de1fSmrg		if (kc == *kcp) {	/* yup, found one */
10351a30de1fSmrg		    /*
10361a30de1fSmrg		     * have to generate a remove of the CURRENT keycode
10371a30de1fSmrg		     * and then an add of the new KEYCODE
10381a30de1fSmrg		     */
10391a30de1fSmrg		    make_remove (i, kc);  /* modifier, keycode */
10401a30de1fSmrg		    make_add (i, kslist[k]);  /* modifier, keysym */
10411a30de1fSmrg		}
10421a30de1fSmrg	    }
10431a30de1fSmrg	}
10441a30de1fSmrg    }
10451a30de1fSmrg    return;
10461a30de1fSmrg}
10471a30de1fSmrg#endif
10481a30de1fSmrg
10491a30de1fSmrg/*
10501a30de1fSmrg * print_work_queue - disassemble the work queue and print it on stdout
10511a30de1fSmrg */
10521a30de1fSmrg
10531a30de1fSmrgvoid
10541a30de1fSmrgprint_work_queue(void)
10551a30de1fSmrg{
10561a30de1fSmrg    union op *op;
10571a30de1fSmrg
10581a30de1fSmrg    printf ("! dump of work queue\n");
10591a30de1fSmrg    for (op = work_queue.head; op; op = op->generic.next) {
10601a30de1fSmrg	print_opcode (op);
10611a30de1fSmrg    }
10621a30de1fSmrg    return;
10631a30de1fSmrg}
10641a30de1fSmrg
10651a30de1fSmrgstatic void
10661a30de1fSmrgprint_opcode(union op *op)
10671a30de1fSmrg{
10681a30de1fSmrg    int i;
10691a30de1fSmrg
10701a30de1fSmrg    printf ("        ");
10711a30de1fSmrg    switch (op->generic.type) {
10721a30de1fSmrg      case doKeycode:
10731a30de1fSmrg	if (op->keycode.target_keycode)
10741a30de1fSmrg	    printf ("keycode 0x%lx =", (long) op->keycode.target_keycode);
10751a30de1fSmrg	else
10761a30de1fSmrg	    printf ("keycode any =");
10771a30de1fSmrg	for (i = 0; i < op->keycode.count; i++) {
10781a30de1fSmrg	    char *name = XKeysymToString (op->keycode.keysyms[i]);
10791a30de1fSmrg
10801a30de1fSmrg	    printf (" %s", name ? name : "BADKEYSYM");
10811a30de1fSmrg	}
10821a30de1fSmrg	printf ("\n");
10831a30de1fSmrg	break;
10841a30de1fSmrg      case doAddModifier:
10851a30de1fSmrg	printf ("add %s =", modifier_table[op->addmodifier.modifier].name);
10861a30de1fSmrg	for (i = 0; i < op->addmodifier.count; i++) {
10871a30de1fSmrg	    char *name = XKeysymToString (op->addmodifier.keysyms[i]);
10881a30de1fSmrg	    printf (" %s", name ? name : "BADKEYSYM");
10891a30de1fSmrg	}
10901a30de1fSmrg	printf ("\n");
10911a30de1fSmrg	break;
10921a30de1fSmrg      case doRemoveModifier:
10931a30de1fSmrg	printf ("remove %s = ",
10941a30de1fSmrg		modifier_table[op->removemodifier.modifier].name);
10951a30de1fSmrg	for (i = 0; i < op->removemodifier.count; i++) {
10961a30de1fSmrg	    printf (" 0x%lx", (long) op->removemodifier.keycodes[i]);
10971a30de1fSmrg	}
10981a30de1fSmrg	printf ("\n");
10991a30de1fSmrg	break;
11001a30de1fSmrg      case doClearModifier:
11011a30de1fSmrg	printf ("clear %s\n", modifier_table[op->clearmodifier.modifier].name);
11021a30de1fSmrg	break;
11031a30de1fSmrg      case doPointer:
11041a30de1fSmrg	printf ("pointer = ");
11051a30de1fSmrg	if (op->pointer.count == 0)
11061a30de1fSmrg	    printf(" default");
11071a30de1fSmrg	else for (i=0; i < op->pointer.count; i++)
11081a30de1fSmrg	    printf(" %d", op->pointer.button_codes[i]);
11091a30de1fSmrg	printf ("\n");
11101a30de1fSmrg	break;
11111a30de1fSmrg      default:
11121a30de1fSmrg	printf ("! unknown opcode %d\n", op->generic.type);
11131a30de1fSmrg	break;
11141a30de1fSmrg    }				/* end switch */
11151a30de1fSmrg    return;
11161a30de1fSmrg}
11171a30de1fSmrg
11181a30de1fSmrg/*
11191a30de1fSmrg * execute_work_queue - do the real meat and potatoes now that we know what
11201a30de1fSmrg * we need to do and that all of the input is correct.
11211a30de1fSmrg */
11221a30de1fSmrgstatic int exec_keycode ( struct op_keycode *opk );
11231a30de1fSmrgstatic int exec_add ( struct op_addmodifier *opam );
11241a30de1fSmrgstatic int exec_remove ( struct op_removemodifier *oprm );
11251a30de1fSmrgstatic int exec_clear ( struct op_clearmodifier *opcm );
11261a30de1fSmrgstatic int exec_pointer ( struct op_pointer *opp );
11271a30de1fSmrg
11281a30de1fSmrg
11291a30de1fSmrgint
11301a30de1fSmrgexecute_work_queue (void)
11311a30de1fSmrg{
11321a30de1fSmrg    union op *op;
11331a30de1fSmrg    int errors;
11341a30de1fSmrg    Bool update_map = False;
11351a30de1fSmrg    int dosync;
11361a30de1fSmrg
11371a30de1fSmrg    if (verbose) {
11381a30de1fSmrg	printf ("!\n");
11391a30de1fSmrg	printf ("! executing work queue\n");
11401a30de1fSmrg	printf ("!\n");
11411a30de1fSmrg    }
11421a30de1fSmrg
11431a30de1fSmrg    errors = 0;
11441a30de1fSmrg    dosync = 0;
11451a30de1fSmrg
11461a30de1fSmrg    for (op = work_queue.head; op; op = op->generic.next) {
11471a30de1fSmrg	if (verbose) print_opcode (op);
11481a30de1fSmrg
11491a30de1fSmrg	/* check to see if we have to update the keyboard mapping */
11501a30de1fSmrg	if (dosync &&
11511a30de1fSmrg	    (dosync < 0 ||
11521a30de1fSmrg	     op->generic.type != doKeycode ||
11531a30de1fSmrg	     !op->keycode.target_keycode)) {
11541a30de1fSmrg	    XSync (dpy, 0);
11551a30de1fSmrg	    while (XEventsQueued (dpy, QueuedAlready) > 0) {
11561a30de1fSmrg		XEvent event;
11571a30de1fSmrg		XNextEvent (dpy, &event);
11581a30de1fSmrg		if (event.type == MappingNotify) {
11591a30de1fSmrg		    /* read all MappingNotify events */
11601a30de1fSmrg		    while (XCheckTypedEvent (dpy, MappingNotify, &event)) ;
11611a30de1fSmrg		    XRefreshKeyboardMapping (&event.xmapping);
11621a30de1fSmrg		} else {
11631a30de1fSmrg		    fprintf (stderr, "%s:  unknown event %ld\n",
11641a30de1fSmrg		    	     ProgramName, (long) event.type);
11651a30de1fSmrg		}
11661a30de1fSmrg	    }
11671a30de1fSmrg	}
11681a30de1fSmrg	dosync = 0;
11691a30de1fSmrg	switch (op->generic.type) {
11701a30de1fSmrg	  case doKeycode:
11711a30de1fSmrg	    if (exec_keycode (&op->keycode) < 0) errors++;
11721a30de1fSmrg	    if (op->keycode.target_keycode)
11731a30de1fSmrg		dosync = 1;
11741a30de1fSmrg	    else
11751a30de1fSmrg		dosync = -1;
11761a30de1fSmrg	    break;
11771a30de1fSmrg	  case doAddModifier:
11781a30de1fSmrg	    if (exec_add (&op->addmodifier) < 0) errors++;
11791a30de1fSmrg	    else update_map = True;
11801a30de1fSmrg	    break;
11811a30de1fSmrg	  case doRemoveModifier:
11821a30de1fSmrg	    if (exec_remove (&op->removemodifier) < 0) errors++;
11831a30de1fSmrg	    else update_map = True;
11841a30de1fSmrg	    break;
11851a30de1fSmrg	  case doClearModifier:
11861a30de1fSmrg	    if (exec_clear (&op->clearmodifier) < 0) errors++;
11871a30de1fSmrg	    else update_map = True;
11881a30de1fSmrg	    break;
11891a30de1fSmrg	  case doPointer:
11901a30de1fSmrg	    if (exec_pointer (&op->pointer) < 0) errors++;
11911a30de1fSmrg	    break;
11921a30de1fSmrg	  default:
11931a30de1fSmrg	    fprintf (stderr, "%s:  unknown opcode %d\n",
11941a30de1fSmrg		     ProgramName, op->generic.type);
11951a30de1fSmrg	    break;
11961a30de1fSmrg	}
11971a30de1fSmrg    }
11981a30de1fSmrg
11991a30de1fSmrg    if (update_map) {
12001a30de1fSmrg	if (UpdateModifierMapping (map) < 0) errors++;
12011a30de1fSmrg    }
12021a30de1fSmrg
12031a30de1fSmrg    return (errors > 0 ? -1 : 0);
12041a30de1fSmrg}
12051a30de1fSmrg
12061a30de1fSmrgstatic int
12071a30de1fSmrgexec_keycode(struct op_keycode *opk)
12081a30de1fSmrg{
12091a30de1fSmrg    if (!opk->target_keycode) {
12101a30de1fSmrg	int i, j;
12111a30de1fSmrg	KeyCode free;
12121a30de1fSmrg	if (!opk->count)
12131a30de1fSmrg	    return (0);
12141a30de1fSmrg	free = 0;
12151a30de1fSmrg	for (i = min_keycode; i <= max_keycode; i++) {
12161a30de1fSmrg	    for (j = 0; j < opk->count; j++) {
12171a30de1fSmrg		if (XKeycodeToKeysym(dpy, (KeyCode) i, j) != opk->keysyms[j])
12181a30de1fSmrg		    break;
12191a30de1fSmrg	    }
12201a30de1fSmrg	    if (j >= opk->count)
12211a30de1fSmrg		return (0);
12221a30de1fSmrg	    if (free)
12231a30de1fSmrg		continue;
12241a30de1fSmrg	    for (j = 0; j < 8; j++) {
12251a30de1fSmrg		if (XKeycodeToKeysym(dpy, (KeyCode) i, j) != None)
12261a30de1fSmrg		    break;
12271a30de1fSmrg	    }
12281a30de1fSmrg	    if (j >= 8)
12291a30de1fSmrg		free = i;
12301a30de1fSmrg	}
12311a30de1fSmrg	if (!free) {
12321a30de1fSmrg	    fprintf(stderr, "%s: no available keycode for assignment\n",
12331a30de1fSmrg		    ProgramName);
12341a30de1fSmrg	    return (-1);
12351a30de1fSmrg	}
12361a30de1fSmrg	XChangeKeyboardMapping (dpy, free, opk->count, opk->keysyms, 1);
12371a30de1fSmrg    } else if (opk->count == 0) {
12381a30de1fSmrg	KeySym dummy = NoSymbol;
12391a30de1fSmrg	XChangeKeyboardMapping (dpy, opk->target_keycode, 1,
12401a30de1fSmrg				&dummy, 1);
12411a30de1fSmrg    } else {
12421a30de1fSmrg	XChangeKeyboardMapping (dpy, opk->target_keycode, opk->count,
12431a30de1fSmrg				opk->keysyms, 1);
12441a30de1fSmrg    }
12451a30de1fSmrg    return (0);
12461a30de1fSmrg}
12471a30de1fSmrg
12481a30de1fSmrgstatic int
12491a30de1fSmrgexec_add(struct op_addmodifier *opam)
12501a30de1fSmrg{
12511a30de1fSmrg    int i;
12521a30de1fSmrg    int status;
12531a30de1fSmrg
12541a30de1fSmrg    status = 0;
12551a30de1fSmrg    for (i = 0; i < opam->count; i++) {
12561a30de1fSmrg	int num_kcs;
12571a30de1fSmrg	KeyCode *kcs;
12581a30de1fSmrg
12591a30de1fSmrg	kcs = KeysymToKeycodes (dpy, opam->keysyms[i], &num_kcs);
12601a30de1fSmrg	if (num_kcs == 0)
12611a30de1fSmrg	    status = -1;
12621a30de1fSmrg	while (--num_kcs >= 0) {
12631a30de1fSmrg	    if (AddModifier (&map, *kcs++, opam->modifier) < 0)
12641a30de1fSmrg		status = -1;
12651a30de1fSmrg	}
12661a30de1fSmrg    }
12671a30de1fSmrg    return (status);
12681a30de1fSmrg}
12691a30de1fSmrg
12701a30de1fSmrgstatic int
12711a30de1fSmrgexec_remove(struct op_removemodifier *oprm)
12721a30de1fSmrg{
12731a30de1fSmrg    int i;
12741a30de1fSmrg    int status;
12751a30de1fSmrg
12761a30de1fSmrg    status = 0;
12771a30de1fSmrg    for (i = 0; i < oprm->count; i++) {
12781a30de1fSmrg	if (RemoveModifier (&map, oprm->keycodes[i], oprm->modifier) < 0)
12791a30de1fSmrg	  status = -1;
12801a30de1fSmrg    }
12811a30de1fSmrg    return (status);
12821a30de1fSmrg}
12831a30de1fSmrg
12841a30de1fSmrgstatic int
12851a30de1fSmrgexec_clear(struct op_clearmodifier *opcm)
12861a30de1fSmrg{
12871a30de1fSmrg    return (ClearModifier (&map, opcm->modifier));
12881a30de1fSmrg}
12891a30de1fSmrg
12901a30de1fSmrg
12911a30de1fSmrgstatic int
12921a30de1fSmrgexec_pointer(struct op_pointer *opp)
12931a30de1fSmrg{
12941a30de1fSmrg    return (SetPointerMap (opp->button_codes, opp->count));
12951a30de1fSmrg}
12961a30de1fSmrg
12971a30de1fSmrgvoid
12981a30de1fSmrgprint_modifier_map(void)
12991a30de1fSmrg{
13001a30de1fSmrg    PrintModifierMapping (map, stdout);
13011a30de1fSmrg    return;
13021a30de1fSmrg}
13031a30de1fSmrg
13041a30de1fSmrgvoid
13051a30de1fSmrgprint_key_table(Bool exprs)
13061a30de1fSmrg{
13071a30de1fSmrg    PrintKeyTable (exprs, stdout);
13081a30de1fSmrg    return;
13091a30de1fSmrg}
13101a30de1fSmrg
13111a30de1fSmrgvoid
13121a30de1fSmrgprint_pointer_map(void)
13131a30de1fSmrg{
13141a30de1fSmrg    PrintPointerMap (stdout);
13151a30de1fSmrg    return;
13161a30de1fSmrg}
13171a30de1fSmrg
13181a30de1fSmrg
1319