~ubuntu-branches/ubuntu/karmic/x11-xserver-utils/karmic

« back to all changes in this revision

Viewing changes to xmodmap/handle.c

  • Committer: Bazaar Package Importer
  • Author(s): Brice Goglin, Julien Cristau, Brice Goglin
  • Date: 2007-08-17 09:58:34 UTC
  • Revision ID: james.westby@ubuntu.com-20070817095834-ywge2nyzj1s3rqnd
Tags: 7.3+1
[ Julien Cristau ]
* iceauth 1.0.2.
  + removes blank line in the manpage (closes: #25285).
* xmodmap 1.0.3.
  + manpage updated to state that -pm is the default (closes: #236198)
* xgamma 1.0.2.
  + the manpage now explains how to print the gamma value more clearly
    (closes: #296021).
* xsetroot 1.0.2.
* xrdb 1.0.4.
  + fixes manpage typo (closes: #276286).
* Add upstream URL to debian/copyright, and update it from xgamma's COPYING
  file.

[ Brice Goglin ]
* Add menu entries for xrefresh and xvidtune.
* sessreg 1.0.3.
* xset 1.0.3.
* Add myself to Uploaders, and remove Branden with his permission.

Show diffs side-by-side

added added

removed removed

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