11a30de1fSmrg/* 21a30de1fSmrg 31a30de1fSmrgCopyright 1988, 1998 The Open Group 41a30de1fSmrg 51a30de1fSmrgPermission to use, copy, modify, distribute, and sell this software and its 61a30de1fSmrgdocumentation for any purpose is hereby granted without fee, provided that 71a30de1fSmrgthe above copyright notice appear in all copies and that both that 81a30de1fSmrgcopyright notice and this permission notice appear in supporting 91a30de1fSmrgdocumentation. 101a30de1fSmrg 111a30de1fSmrgThe above copyright notice and this permission notice shall be included 121a30de1fSmrgin all copies or substantial portions of the Software. 131a30de1fSmrg 141a30de1fSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 151a30de1fSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 161a30de1fSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 171a30de1fSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 181a30de1fSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 191a30de1fSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 201a30de1fSmrgOTHER DEALINGS IN THE SOFTWARE. 211a30de1fSmrg 221a30de1fSmrgExcept as contained in this notice, the name of The Open Group shall 231a30de1fSmrgnot be used in advertising or otherwise to promote the sale, use or 241a30de1fSmrgother dealings in this Software without prior written authorization 251a30de1fSmrgfrom The Open Group. 261a30de1fSmrg 271a30de1fSmrg*/ 28a733a5bfSmrg 29a733a5bfSmrg#ifdef HAVE_CONFIG_H 30a733a5bfSmrg# include "config.h" 31a733a5bfSmrg#endif 321a30de1fSmrg 331a30de1fSmrg#include <X11/Xos.h> 341a30de1fSmrg#include <X11/Xlib.h> 351a30de1fSmrg#include <stdio.h> 361a30de1fSmrg#include <stdlib.h> 371a30de1fSmrg#include <ctype.h> 38a733a5bfSmrg#include <stdarg.h> 391a30de1fSmrg#include "xmodmap.h" 401a30de1fSmrg 411a30de1fSmrgconst char *ProgramName; 421a30de1fSmrgDisplay *dpy = NULL; 431a30de1fSmrgint min_keycode, max_keycode; 441a30de1fSmrgBool verbose = False; 451a30de1fSmrgBool dontExecute = False; 461a30de1fSmrg 47a733a5bfSmrgvoid 48a733a5bfSmrg_X_NORETURN 491a30de1fSmrgExit(int status) 501a30de1fSmrg{ 511a30de1fSmrg if (dpy) { 521a30de1fSmrg XCloseDisplay (dpy); 531a30de1fSmrg dpy = NULL; 541a30de1fSmrg } 551a30de1fSmrg exit (status); 561a30de1fSmrg} 571a30de1fSmrg 58a733a5bfSmrgstatic void _X_NORETURN 59a733a5bfSmrgFatalError(const char *message) 60a733a5bfSmrg{ 61a733a5bfSmrg fprintf(stderr, "%s: %s\n", ProgramName, message); 62a733a5bfSmrg Exit(-1); 63a733a5bfSmrg} 64a733a5bfSmrg 65a733a5bfSmrg#ifndef HAVE_ASPRINTF 66a733a5bfSmrg/* sprintf variant found in newer libc's which allocates string to print to */ 67a733a5bfSmrgstatic int _X_ATTRIBUTE_PRINTF(2,3) 68a733a5bfSmrgasprintf(char ** ret, const char *format, ...) 691a30de1fSmrg{ 70a733a5bfSmrg char buf[256]; 71a733a5bfSmrg int len; 72a733a5bfSmrg va_list ap; 73a733a5bfSmrg 74a733a5bfSmrg va_start(ap, format); 75a733a5bfSmrg len = vsnprintf(buf, sizeof(buf), format, ap); 76a733a5bfSmrg va_end(ap); 77a733a5bfSmrg 78a733a5bfSmrg if (len < 0) 79a733a5bfSmrg return -1; 80a733a5bfSmrg 81a733a5bfSmrg if (len < sizeof(buf)) 82a733a5bfSmrg { 83a733a5bfSmrg *ret = strdup(buf); 841a30de1fSmrg } 85a733a5bfSmrg else 86a733a5bfSmrg { 87a733a5bfSmrg *ret = malloc(len + 1); /* snprintf doesn't count trailing '\0' */ 88a733a5bfSmrg if (*ret != NULL) 89a733a5bfSmrg { 90a733a5bfSmrg va_start(ap, format); 91a733a5bfSmrg len = vsnprintf(*ret, len + 1, format, ap); 92a733a5bfSmrg va_end(ap); 93a733a5bfSmrg if (len < 0) { 94a733a5bfSmrg free(*ret); 95a733a5bfSmrg *ret = NULL; 96a733a5bfSmrg } 97a733a5bfSmrg } 98a733a5bfSmrg } 99a733a5bfSmrg 100a733a5bfSmrg if (*ret == NULL) 101a733a5bfSmrg return -1; 102a733a5bfSmrg 103a733a5bfSmrg return len; 1041a30de1fSmrg} 105a733a5bfSmrg#endif /* HAVE_ASPRINTF */ 1061a30de1fSmrg 1071a30de1fSmrgstatic const char help_message[] = 1081a30de1fSmrg"\nwhere options include:\n" 1091a30de1fSmrg" -display host:dpy X server to use\n" 1101a30de1fSmrg" -verbose, -quiet turn logging on or off\n" 1111a30de1fSmrg" -n don't execute changes, just show like make\n" 1121a30de1fSmrg" -e expression execute string\n" 1131a30de1fSmrg" -pm print modifier map\n" 1141a30de1fSmrg" -pk print keymap table\n" 1151a30de1fSmrg" -pke print keymap table as expressions\n" 1161a30de1fSmrg" -pp print pointer map\n" 117a733a5bfSmrg" -help print this usage message\n" 1181a30de1fSmrg" -grammar print out short help on allowable input\n" 1191b983734Smrg" -version print program version\n" 1201a30de1fSmrg" - read standard input\n" 1211a30de1fSmrg"\n"; 1221a30de1fSmrg 1231a30de1fSmrg 1241b983734Smrgstatic void 1251b983734Smrg_X_NORETURN _X_COLD 126a733a5bfSmrgusage(int exitcode) 1271a30de1fSmrg{ 1281a30de1fSmrg fprintf (stderr, "usage: %s [-options ...] [filename]\n", ProgramName); 1291a30de1fSmrg fprintf (stderr, "%s\n", help_message); 130a733a5bfSmrg Exit (exitcode); 1311a30de1fSmrg} 1321a30de1fSmrg 1331b983734Smrgstatic void 1341b983734Smrg_X_NORETURN _X_COLD 1351b983734Smrgmissing_arg(const char *arg) 1361b983734Smrg{ 1371b983734Smrg fprintf (stderr, "%s: %s requires an argument\n\n", ProgramName, arg); 1381b983734Smrg usage(1); 1391b983734Smrg} 1401b983734Smrg 1411b983734Smrgstatic void 1421b983734Smrg_X_NORETURN _X_COLD 1431b983734Smrgunknown_arg(const char *arg) 1441b983734Smrg{ 1451b983734Smrg fprintf (stderr, "%s: unrecognized argument %s\n\n", ProgramName, arg); 1461b983734Smrg usage(1); 1471b983734Smrg} 1481b983734Smrg 1491a30de1fSmrgstatic const char grammar_message[] = 1501a30de1fSmrg" pointer = default reset pointer buttons to default\n" 1511a30de1fSmrg" pointer = NUMBER ... set pointer button codes\n" 1521a30de1fSmrg" keycode NUMBER = [KEYSYM ...] map keycode to given keysyms\n" 1531a30de1fSmrg" keysym KEYSYM = [KEYSYM ...] look up keysym and do a keycode operation\n" 1541a30de1fSmrg" clear MODIFIER remove all keys for this modifier\n" 1551a30de1fSmrg" add MODIFIER = KEYSYM ... add the keysyms to the modifier\n" 1561a30de1fSmrg" remove MODIFIER = KEYSYM ... remove the keysyms from the modifier\n" 1571a30de1fSmrg"\n" 1581a30de1fSmrg"where NUMBER is a decimal, octal, or hex constant; KEYSYM is a valid\n" 1591a30de1fSmrg"Key Symbol name; and MODIFIER is one of the eight modifier names: Shift,\n" 1601a30de1fSmrg"Lock, Control, Mod1, Mod2, Mod3, Mod4, or Mod5. Lines beginning with\n" 1611a30de1fSmrg"an exclamation mark (!) are taken as comments. Case is significant except\n" 1621a30de1fSmrg"for MODIFIER names.\n" 1631a30de1fSmrg"\n" 1641a30de1fSmrg"Keysyms on the left hand side of the = sign are looked up before any changes\n" 1651a30de1fSmrg"are made; keysyms on the right are looked up after all of those on the left\n" 1661a30de1fSmrg"have been resolved. This makes it possible to swap modifier keys.\n" 1671a30de1fSmrg"\n"; 1681a30de1fSmrg 1691a30de1fSmrg 1701a30de1fSmrgstatic void 171a733a5bfSmrg_X_NORETURN 1721a30de1fSmrggrammar_usage(void) 1731a30de1fSmrg{ 1741a30de1fSmrg fprintf (stderr, "%s accepts the following input expressions:\n\n", 1751a30de1fSmrg ProgramName); 1761a30de1fSmrg fprintf (stderr, "%s\n", grammar_message); 1771a30de1fSmrg Exit (0); 1781a30de1fSmrg} 1791a30de1fSmrg 1801a30de1fSmrgint parse_errors = 0; 1811a30de1fSmrg 1821a30de1fSmrgint 1831a30de1fSmrgmain(int argc, char *argv[]) 1841a30de1fSmrg{ 1851a30de1fSmrg int i; 1861a30de1fSmrg char *displayname = NULL; 1871a30de1fSmrg int status; 1881a30de1fSmrg Bool printMap = False; 1891a30de1fSmrg Bool printKeyTable = False; 1901a30de1fSmrg Bool printKeyTableExprs = False; 1911a30de1fSmrg Bool printPointerMap = False; 1921a30de1fSmrg Bool didAnything = False; 1931a30de1fSmrg 1941a30de1fSmrg ProgramName = argv[0]; 1951a30de1fSmrg 1961a30de1fSmrg /* 1971a30de1fSmrg * scan the arg list once to find out which display to use 1981a30de1fSmrg */ 1991a30de1fSmrg 2001a30de1fSmrg for (i = 1; i < argc; i++) { 201a733a5bfSmrg const char *arg = argv[i]; 202a733a5bfSmrg 203a733a5bfSmrg if (arg[0] == '-') { 204a733a5bfSmrg switch (arg[1]) { 205a733a5bfSmrg case 'd': /* -display host:dpy */ 2061b983734Smrg if (++i >= argc) missing_arg(arg); 207a733a5bfSmrg displayname = argv[i]; 208a733a5bfSmrg break; 209a733a5bfSmrg case 'g': /* -grammar */ 210a733a5bfSmrg grammar_usage (); 211a733a5bfSmrg /*NOTREACHED*/ 212a733a5bfSmrg case 'h': /* -help */ 213a733a5bfSmrg case '?': 214a733a5bfSmrg usage(0); 2151b983734Smrg case 'v': 2161b983734Smrg if (strcmp(arg, "-version") == 0) { 2171b983734Smrg puts(PACKAGE_STRING); 2181b983734Smrg exit(0); 2191b983734Smrg } 220a733a5bfSmrg } 2211a30de1fSmrg } 2221a30de1fSmrg } 2231a30de1fSmrg 2241a30de1fSmrg dpy = XOpenDisplay (displayname); 2251a30de1fSmrg if (!dpy) { 2261a30de1fSmrg fprintf (stderr, "%s: unable to open display '%s'\n", 2271a30de1fSmrg ProgramName, XDisplayName (displayname)); 2281a30de1fSmrg Exit (1); 2291a30de1fSmrg } 2301a30de1fSmrg 2311a30de1fSmrg XDisplayKeycodes (dpy, &min_keycode, &max_keycode); 2321a30de1fSmrg 2331a30de1fSmrg initialize_map (); 2341a30de1fSmrg 2351a30de1fSmrg /* 2361a30de1fSmrg * scan the arg list again to do the actual work (since it requires 2371a30de1fSmrg * the display being open. 2381a30de1fSmrg */ 2391a30de1fSmrg 2401a30de1fSmrg for (i = 1; i < argc; i++) { 2411a30de1fSmrg char *arg = argv[i]; 2421a30de1fSmrg 2431a30de1fSmrg if (arg[0] == '-') { 2441a30de1fSmrg switch (arg[1]) { 2451a30de1fSmrg case 'd': /* -display host:dpy */ 2461a30de1fSmrg ++i; /* handled above */ 2471a30de1fSmrg continue; 2481a30de1fSmrg case 'v': /* -verbose */ 2491a30de1fSmrg verbose = True; 2501a30de1fSmrg continue; 2511a30de1fSmrg case 'q': /* -quiet */ 2521a30de1fSmrg verbose = False; 2531a30de1fSmrg continue; 2541a30de1fSmrg case 'n': /* -n (like make) */ 2551a30de1fSmrg dontExecute = True; 2561a30de1fSmrg continue; 2571a30de1fSmrg case 'e': /* -e expression */ 2581a30de1fSmrg didAnything = True; 2591b983734Smrg if (++i >= argc) missing_arg(arg); 2601a30de1fSmrg process_line (argv[i]); 2611a30de1fSmrg continue; 2621a30de1fSmrg case 'p': /* -p... */ 2631a30de1fSmrg switch (arg[2]) { 2641a30de1fSmrg case '\0': 2651a30de1fSmrg case 'm': /* -pm */ 2661a30de1fSmrg printMap = True; 2671a30de1fSmrg break; 2681a30de1fSmrg case 'k': /* -pk, -pke */ 2691a30de1fSmrg switch (arg[3]) { 2701a30de1fSmrg case '\0': 2711a30de1fSmrg printKeyTable = True; 2721a30de1fSmrg break; 2731a30de1fSmrg case 'e': 2741a30de1fSmrg printKeyTableExprs = True; 2751a30de1fSmrg break; 2761a30de1fSmrg default: 2771b983734Smrg unknown_arg(arg); 2781a30de1fSmrg } 2791a30de1fSmrg break; 2801a30de1fSmrg case 'p': /* -pp */ 2811a30de1fSmrg printPointerMap = True; 2821a30de1fSmrg break; 2831a30de1fSmrg default: 2841b983734Smrg unknown_arg(arg); 2851a30de1fSmrg /* NOTREACHED */ 2861a30de1fSmrg } 2871a30de1fSmrg didAnything = True; 2881a30de1fSmrg continue; 2891a30de1fSmrg case 'g': /* -grammar */ 2901a30de1fSmrg grammar_usage (); 2911a30de1fSmrg /*NOTREACHED*/ 2921a30de1fSmrg case '\0': /* - (use standard input) */ 2931a30de1fSmrg didAnything = True; 2941a30de1fSmrg process_file (NULL); 2951a30de1fSmrg continue; 2961a30de1fSmrg 2971a30de1fSmrg /* 2981a30de1fSmrg * provide old xmodmap args 2991a30de1fSmrg */ 3001a30de1fSmrg case 'S': 3011a30de1fSmrg didAnything = True; 3021a30de1fSmrg process_line ("clear shift"); 3031a30de1fSmrg continue; 3041a30de1fSmrg case 'L': 3051a30de1fSmrg didAnything = True; 3061a30de1fSmrg process_line ("clear lock"); 3071a30de1fSmrg continue; 3081a30de1fSmrg case 'C': 3091a30de1fSmrg didAnything = True; 3101a30de1fSmrg process_line ("clear control"); 3111a30de1fSmrg continue; 3121a30de1fSmrg case '1': 3131a30de1fSmrg case '2': 3141a30de1fSmrg case '3': 3151a30de1fSmrg case '4': 3161a30de1fSmrg case '5': { 3171a30de1fSmrg char cmd[11] = "clear modX"; 3181a30de1fSmrg cmd[9] = arg[1]; 3191a30de1fSmrg process_line (cmd); 3201a30de1fSmrg continue; 3211a30de1fSmrg } 3221a30de1fSmrg case 's': 3231a30de1fSmrg case 'l': 3241a30de1fSmrg case 'c': { 3251a30de1fSmrg char *cmd; 3261a30de1fSmrg didAnything = True; 3271b983734Smrg if (++i >= argc) missing_arg(arg); 328a733a5bfSmrg if (asprintf (&cmd, "remove %s = %s", 3291a30de1fSmrg ((arg[1] == 's') ? "shift" : 3301a30de1fSmrg ((arg[1] == 'l') ? "lock" : 331a733a5bfSmrg "control")), argv[i]) == -1) 332a733a5bfSmrg FatalError("Could not allocate memory for remove cmd"); 3331a30de1fSmrg process_line (cmd); 3341a30de1fSmrg continue; 3351a30de1fSmrg } 3361a30de1fSmrg default: 3371b983734Smrg unknown_arg(arg); 3381a30de1fSmrg /*NOTREACHED*/ 3391a30de1fSmrg } 3401a30de1fSmrg } else if (arg[0] == '+') { /* old xmodmap args */ 3411a30de1fSmrg switch (arg[1]) { 3421a30de1fSmrg case '1': 3431a30de1fSmrg case '2': 3441a30de1fSmrg case '3': 3451a30de1fSmrg case '4': 3461a30de1fSmrg case '5': { 3471a30de1fSmrg char *cmd; 3481a30de1fSmrg didAnything = True; 3491b983734Smrg if (++i >= argc) missing_arg(arg); 350a733a5bfSmrg if (asprintf (&cmd, "add mod%c = %s", arg[1], argv[i]) == -1) 351a733a5bfSmrg FatalError("Could not allocate memory for add cmd"); 3521a30de1fSmrg process_line (cmd); 3531a30de1fSmrg continue; 3541a30de1fSmrg } 3551a30de1fSmrg case 'S': 3561a30de1fSmrg case 'L': 3571a30de1fSmrg case 'C': 3581a30de1fSmrg arg[1] = tolower (arg[1]); 359423b239cSmrg /* fall through - to handler below */ 3601a30de1fSmrg case 's': 3611a30de1fSmrg case 'l': 3621a30de1fSmrg case 'c': { 3631a30de1fSmrg char *cmd; 3641a30de1fSmrg didAnything = True; 3651b983734Smrg if (++i >= argc) missing_arg(arg); 366a733a5bfSmrg if (asprintf (&cmd, "add %s = %s", 3671a30de1fSmrg ((arg[1] == 's') ? "shift" : 3681a30de1fSmrg ((arg[1] == 'l') ? "lock" : 369a733a5bfSmrg "control")), argv[i]) == -1) 370a733a5bfSmrg FatalError("Could not allocate memory for remove cmd"); 3711a30de1fSmrg process_line (cmd); 3721a30de1fSmrg continue; 3731a30de1fSmrg } 3741a30de1fSmrg default: 3751b983734Smrg unknown_arg(arg); 3761a30de1fSmrg } 3771a30de1fSmrg } else { 3781a30de1fSmrg didAnything = True; 3791a30de1fSmrg process_file (arg); 3801a30de1fSmrg continue; 3811a30de1fSmrg } 3821a30de1fSmrg } /* end for loop */ 3831a30de1fSmrg 3841a30de1fSmrg /* for compatibility */ 3851a30de1fSmrg if (!didAnything) printMap = True; 3861a30de1fSmrg 3871a30de1fSmrg /* 3881a30de1fSmrg * at this point, the work list has been built and we can view it or 3891a30de1fSmrg * execute it 3901a30de1fSmrg */ 3911a30de1fSmrg 3921a30de1fSmrg if (dontExecute) { 3931a30de1fSmrg print_work_queue (); 3941a30de1fSmrg Exit (0); 3951a30de1fSmrg } 3961a30de1fSmrg 3971a30de1fSmrg if (parse_errors != 0) { 3981a30de1fSmrg fprintf (stderr, "%s: %d error%s encountered, aborting.\n", 3991a30de1fSmrg ProgramName, parse_errors, 4001a30de1fSmrg (parse_errors == 1 ? "" : "s")); 4011a30de1fSmrg status = -1; /* return an error condition */ 4021a30de1fSmrg } else { 4031a30de1fSmrg status = execute_work_queue (); 4041a30de1fSmrg } 4051a30de1fSmrg 4061a30de1fSmrg if (printMap) { 4071a30de1fSmrg print_modifier_map (); 4081a30de1fSmrg } 4091a30de1fSmrg 4101a30de1fSmrg if (printKeyTable) { 4111a30de1fSmrg print_key_table (False); 4121a30de1fSmrg } 4131a30de1fSmrg 4141a30de1fSmrg if (printKeyTableExprs) { 4151a30de1fSmrg print_key_table (True); 4161a30de1fSmrg } 4171a30de1fSmrg 4181a30de1fSmrg if (printPointerMap) { 4191a30de1fSmrg print_pointer_map (); 4201a30de1fSmrg } 4211a30de1fSmrg 4221a30de1fSmrg Exit (status < 0 ? 1 : 0); 4231a30de1fSmrg 4241a30de1fSmrg /* Muffle gcc */ 4251a30de1fSmrg return 0; 4261a30de1fSmrg} 4271a30de1fSmrg 428