Tizen 2.0 Release
[framework/uifw/xorg/util/x11-xserver-utils.git] / xmodmap / xmodmap.c
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 #include <X11/Xos.h>
30 #include <X11/Xlib.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <ctype.h>
34 #include <stdarg.h>
35 #include "xmodmap.h"
36
37 const char *ProgramName;
38 Display *dpy = NULL;
39 int min_keycode, max_keycode;
40 Bool verbose = False;
41 Bool dontExecute = False;
42
43 void
44 _X_NORETURN
45 Exit(int status)
46 {
47     if (dpy) {
48         XCloseDisplay (dpy);
49         dpy = NULL;
50     }
51     exit (status);
52 }
53
54 static void _X_NORETURN
55 FatalError(const char *message)
56 {
57     fprintf(stderr, "%s: %s\n", ProgramName, message);
58     Exit(-1);
59 }
60
61 #ifndef HAVE_ASPRINTF
62 /* sprintf variant found in newer libc's which allocates string to print to */
63 static int _X_ATTRIBUTE_PRINTF(2,3)
64 asprintf(char ** ret, const char *format, ...)
65 {
66     char buf[256];
67     int len;
68     va_list ap;
69
70     va_start(ap, format);
71     len = vsnprintf(buf, sizeof(buf), format, ap);
72     va_end(ap);
73
74     if (len < 0)
75         return -1;
76
77     if (len < sizeof(buf))
78     {
79         *ret = strdup(buf);
80     }
81     else
82     {
83         *ret = malloc(len + 1); /* snprintf doesn't count trailing '\0' */
84         if (*ret != NULL)
85         {
86             va_start(ap, format);
87             len = vsnprintf(*ret, len + 1, format, ap);
88             va_end(ap);
89             if (len < 0) {
90                 free(*ret);
91                 *ret = NULL;
92             }
93         }
94     }
95
96     if (*ret == NULL)
97         return -1;
98
99     return len;
100 }
101 #endif /* HAVE_ASPRINTF */
102
103 static const char help_message[] = 
104 "\nwhere options include:\n"
105 "    -display host:dpy            X server to use\n"
106 "    -verbose, -quiet             turn logging on or off\n"
107 "    -n                           don't execute changes, just show like make\n"
108 "    -e expression                execute string\n"
109 "    -pm                          print modifier map\n"
110 "    -pk                          print keymap table\n"
111 "    -pke                         print keymap table as expressions\n"
112 "    -pp                          print pointer map\n"
113 "    -grammar                     print out short help on allowable input\n"
114 "    -                            read standard input\n"
115 "\n";
116
117
118 static void 
119 _X_NORETURN
120 usage(void)
121 {
122     fprintf (stderr, "usage:  %s [-options ...] [filename]\n", ProgramName);
123     fprintf (stderr, "%s\n", help_message);
124     Exit (1);
125 }
126
127 static const char grammar_message[] = 
128 "    pointer = default              reset pointer buttons to default\n"
129 "    pointer = NUMBER ...           set pointer button codes\n"
130 "    keycode NUMBER = [KEYSYM ...]  map keycode to given keysyms\n"
131 "    keysym KEYSYM = [KEYSYM ...]   look up keysym and do a keycode operation\n"
132 "    clear MODIFIER                 remove all keys for this modifier\n"
133 "    add MODIFIER = KEYSYM ...      add the keysyms to the modifier\n"
134 "    remove MODIFIER = KEYSYM ...   remove the keysyms from the modifier\n"
135 "\n"
136 "where NUMBER is a decimal, octal, or hex constant; KEYSYM is a valid\n"
137 "Key Symbol name; and MODIFIER is one of the eight modifier names:  Shift,\n"
138 "Lock, Control, Mod1, Mod2, Mod3, Mod4, or Mod5.  Lines beginning with\n"
139 "an exclamation mark (!) are taken as comments.  Case is significant except\n"
140 "for MODIFIER names.\n"
141 "\n"
142 "Keysyms on the left hand side of the = sign are looked up before any changes\n"
143 "are made; keysyms on the right are looked up after all of those on the left\n"
144 "have been resolved.  This makes it possible to swap modifier keys.\n"
145 "\n";
146
147
148 static void 
149 _X_NORETURN
150 grammar_usage(void)
151 {
152     fprintf (stderr, "%s accepts the following input expressions:\n\n",
153              ProgramName);
154     fprintf (stderr, "%s\n", grammar_message);
155     Exit (0);
156 }
157
158 int parse_errors = 0;
159
160 int
161 main(int argc, char *argv[])
162 {
163     int i;
164     char *displayname = NULL;
165     int status;
166     Bool printMap = False;
167     Bool printKeyTable = False;
168     Bool printKeyTableExprs = False;
169     Bool printPointerMap = False;
170     Bool didAnything = False;
171
172     ProgramName = argv[0];
173
174     /*
175      * scan the arg list once to find out which display to use
176      */
177
178     for (i = 1; i < argc; i++) {
179         if (strncmp (argv[i], "-d", 2) == 0) {
180             if (++i >= argc) usage ();
181             displayname = argv[i];
182         }
183     }
184
185     dpy = XOpenDisplay (displayname);
186     if (!dpy) {
187         fprintf (stderr, "%s:  unable to open display '%s'\n",
188                  ProgramName, XDisplayName (displayname));
189         Exit (1);
190     }
191
192     XDisplayKeycodes (dpy, &min_keycode, &max_keycode);
193
194     initialize_map ();
195
196     /*
197      * scan the arg list again to do the actual work (since it requires
198      * the display being open.
199      */
200
201     for (i = 1; i < argc; i++) {
202         char *arg = argv[i];
203
204         if (arg[0] == '-') {
205             switch (arg[1]) {
206               case 'd':                 /* -display host:dpy */
207                 ++i;                    /* handled above */
208                 continue;
209               case 'v':                 /* -verbose */
210                 verbose = True;
211                 continue;
212               case 'q':                 /* -quiet */
213                 verbose = False;
214                 continue;
215               case 'n':                 /* -n (like make) */
216                 dontExecute = True;
217                 continue;
218               case 'e':                 /* -e expression */
219                 didAnything = True;
220                 if (++i >= argc) usage ();
221                 process_line (argv[i]);
222                 continue;
223               case 'p':                 /* -p... */
224                 switch (arg[2]) {
225                   case '\0':
226                   case 'm':             /* -pm */
227                     printMap = True;
228                     break;
229                   case 'k':             /* -pk, -pke */
230                     switch (arg[3]) {
231                     case '\0':
232                         printKeyTable = True;
233                         break;
234                     case 'e':
235                         printKeyTableExprs = True;
236                         break;
237                     default:
238                         usage ();
239                     }
240                     break;
241                   case 'p':             /* -pp */
242                     printPointerMap = True;
243                     break;
244                   default:
245                     usage ();
246                     /* NOTREACHED */
247                 }
248                 didAnything = True;
249                 continue;
250               case 'g':                 /* -grammar */
251                 grammar_usage ();
252                 /*NOTREACHED*/
253               case '\0':                /* - (use standard input) */
254                 didAnything = True;
255                 process_file (NULL);
256                 continue;
257
258               /*
259                * provide old xmodmap args
260                */
261               case 'S':
262                 didAnything = True;
263                 process_line ("clear shift");
264                 continue;
265               case 'L':
266                 didAnything = True;
267                 process_line ("clear lock");
268                 continue;
269               case 'C':
270                 didAnything = True;
271                 process_line ("clear control");
272                 continue;
273               case '1':
274               case '2':
275               case '3':
276               case '4':
277               case '5': {
278                   char cmd[11] = "clear modX";
279                   cmd[9] = arg[1];
280                   process_line (cmd);
281                   continue;
282               }
283               case 's':
284               case 'l':
285               case 'c': {
286                   char *cmd;
287                   didAnything = True;
288                   if (++i >= argc) usage ();
289                   if (asprintf (&cmd, "remove %s = %s",
290                                   ((arg[1] == 's') ? "shift" :
291                                    ((arg[1] == 'l') ? "lock" :
292                                     "control")), argv[i]) == -1)
293                       FatalError("Could not allocate memory for remove cmd");
294                   process_line (cmd);
295                   continue;
296               }
297               default:
298                 usage ();
299                 /*NOTREACHED*/
300             }
301         } else if (arg[0] == '+') {     /* old xmodmap args */
302             switch (arg[1]) {
303               case '1':
304               case '2':
305               case '3':
306               case '4':
307               case '5': {
308                   char *cmd;
309                   didAnything = True;
310                   if (++i >= argc) usage ();
311                   if (asprintf (&cmd, "add mod%c = %s", arg[1], argv[i]) == -1)
312                       FatalError("Could not allocate memory for add cmd");
313                   process_line (cmd);
314                   continue;
315               }
316               case 'S':
317               case 'L':
318               case 'C':
319                 arg[1] = tolower (arg[1]);
320                 /* fall through to handler below */
321               case 's':
322               case 'l':
323               case 'c': {
324                   char *cmd;
325                   didAnything = True;
326                   if (++i >= argc) usage ();
327                   if (asprintf (&cmd, "add %s = %s",
328                                   ((arg[1] == 's') ? "shift" :
329                                    ((arg[1] == 'l') ? "lock" :
330                                     "control")), argv[i]) == -1)
331                       FatalError("Could not allocate memory for remove cmd");
332                   process_line (cmd);
333                   continue;
334               }
335               default:
336                 usage ();
337             }
338         } else {
339             didAnything = True;
340             process_file (arg);
341             continue;
342         }
343     }                                   /* end for loop */
344
345     /* for compatibility */
346     if (!didAnything) printMap = True;
347
348     /*
349      * at this point, the work list has been built and we can view it or
350      * execute it
351      */
352
353     if (dontExecute) {
354         print_work_queue ();
355         Exit (0);
356     }
357
358     if (parse_errors != 0) {
359         fprintf (stderr, "%s:  %d error%s encountered, aborting.\n",
360                  ProgramName, parse_errors,
361                  (parse_errors == 1 ? "" : "s"));
362         status = -1;    /* return an error condition */
363     } else {
364         status = execute_work_queue ();
365     }
366
367     if (printMap) {
368         print_modifier_map ();
369     }
370
371     if (printKeyTable) {
372         print_key_table (False);
373     }
374
375     if (printKeyTableExprs) {
376         print_key_table (True);
377     }
378
379     if (printPointerMap) {
380         print_pointer_map ();
381     }
382
383     Exit (status < 0 ? 1 : 0);
384
385     /* Muffle gcc */
386     return 0;
387 }
388