1/************************************************************
2 Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
3
4 Permission to use, copy, modify, and distribute this
5 software and its documentation for any purpose and without
6 fee is hereby granted, provided that the above copyright
7 notice appear in all copies and that both that copyright
8 notice and this permission notice appear in supporting
9 documentation, and that the name of Silicon Graphics not be
10 used in advertising or publicity pertaining to distribution
11 of the software without specific prior written permission.
12 Silicon Graphics makes no representation about the suitability
13 of this software for any purpose. It is provided "as is"
14 without any express or implied warranty.
15
16 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23 THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25 ********************************************************/
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include <stdio.h>
32#include <ctype.h>
33#include <X11/Xlocale.h>
34#include <X11/X.h>
35#include <X11/Xlib.h>
36#include <X11/XKBlib.h>
37#include <X11/extensions/XKBgeom.h>
38#include <X11/extensions/XKM.h>
39#include <X11/extensions/XKBfile.h>
40#include <X11/keysym.h>
41
42
43#include <stdlib.h>
44
45#include "utils.h"
46#include "xkbprint.h"
47
48/***====================================================================***/
49
50
51#define	WANT_DEFAULT	0
52#define	WANT_PS_FILE	1
53#define	WANT_X_SERVER	2
54
55
56static unsigned         outputFormat = WANT_DEFAULT;
57static const char *     wantLocale = "C";
58static char *           rootDir;
59static char *           inputFile;
60static char *           outputFile;
61static char *           outputFont = NULL;
62static char *           inDpyName;
63static char *           outDpyName;
64static Display *        inDpy;
65static Display *        outDpy;
66static XKBPrintArgs     args;
67static unsigned         warningLevel = 5;
68static Bool             synch;
69
70/***====================================================================***/
71
72static void
73Usage(int argc, char *argv[])
74{
75    fprintf(stderr, "Usage: %s [options] input-file [ output-file ]\n%s",
76            argv[0],
77            "Legal options:\n"
78            "-?,-help      Print this message\n"
79            "-color        Use colors from geometry\n"
80#ifdef DEBUG
81            "-d [flags]    Report debugging information\n"
82#endif
83            "-dflts        Compute defaults for missing components\n"
84            "-diffs        Only show explicit key definitions\n"
85            "-eps          Generate an EPS file\n"
86            "-fit          Fit keyboard image on page (default)\n"
87            "-full         Print keyboard image full sized\n"
88            "-grid <n>     Print a grid with <n> mm resolution\n"
89            "-if <name>    Specifies the name of an internal font to dump\n"
90#ifdef DEBUG
91            "-I[<dir>]     Specifies a top level directory\n"
92            "              for include directives.  You can\n"
93            "              specify multiple directories.\n"
94#endif
95            "-kc           Also print keycodes, if possible\n"
96            "-label <what> Specifies the label to be drawn on keys\n"
97            "              Legal values for <what> are:\n"
98            "                  none,name,code,symbols\n"
99            "-lc <locale>  Use <locale> for fonts and symbols\n"
100            "-level1       Use level 1 PostScript (default)\n"
101            "-level2       Use level 2 PostScript\n"
102            "-lg <num>     Use keyboard group <num> to print labels\n"
103            "-ll <num>     Use shift level <num> to print labels\n"
104            "-mono         Ignore colors from geometry (default)\n"
105            "-n <num>      Print <num> copies (default 1)\n"
106            "-nkg <num>    Number of groups to print on each key\n"
107            "-nokc         Don't print keycodes, even if possible\n"
108            "-npk <num>    Number of keyboards to print on each page\n"
109            "-ntg <num>    Total number of groups to print\n"
110            "-o <file>     Specifies output file name\n"
111            "-R[<DIR>]     Specifies the root directory for relative\n"
112            "              path names\n"
113            "-pict <what>  Specifies use of pictographs instead of\n"
114            "              keysym names where available, <what> can\n"
115            "              be \"all\", \"none\" or \"common\" (default)\n"
116            "-synch        Force synchronization\n"
117            "-version      Print program version\n"
118            "-w <lvl>      Set warning level (0=none, 10=all)\n"
119        );
120}
121
122/***====================================================================***/
123
124static Bool
125parseArgs(int argc, char *argv[])
126{
127    args = (XKBPrintArgs) {
128        .copies = 1,
129        .grid = 0,
130        .level1 = True,
131        .scaleToFit = True,
132        .wantColor = False,
133        .wantSymbols = COMMON_SYMBOLS,
134        .wantKeycodes = True,
135        .wantDiffs = False,
136        .wantEPS = False,
137        .label = LABEL_AUTO,
138        .baseLabelGroup = 0,
139        .nLabelGroups = 1,
140        .nTotalGroups = 0,
141        .nKBPerPage = 0,
142        .labelLevel = 0
143    };
144    for (int i = 1; i < argc; i++) {
145        if ((argv[i][0] != '-') || (uStringEqual(argv[i], "-"))) {
146            if (inputFile == NULL) {
147                inputFile = argv[i];
148            }
149            else if (outputFile == NULL) {
150                outputFile = argv[i];
151            }
152            else {
153                uWarning("Too many file names on command line\n");
154                uAction("Compiling %s, writing to %s, ignoring %s\n",
155                        inputFile, outputFile, argv[i]);
156            }
157        }
158        else if ((strcmp(argv[i], "-?") == 0) ||
159                 (strcmp(argv[i], "-help") == 0)) {
160            Usage(argc, argv);
161            exit(0);
162        }
163        else if (strcmp(argv[i], "-color") == 0) {
164            args.wantColor = True;
165        }
166#ifdef DEBUG
167        else if (strcmp(argv[i], "-d") == 0) {
168            if ((i >= (argc - 1)) || (!isdigit(argv[i + 1][0]))) {
169                debugFlags = 1;
170            }
171            else {
172                sscanf(argv[++i], "%i", &debugFlags);
173            }
174            uInformation("Setting debug flags to %d\n", debugFlags);
175        }
176#endif
177        else if (strcmp(argv[i], "-dflts") == 0) {
178            uWarning("Compute defaults not implemented yet\n");
179        }
180        else if (strcmp(argv[i], "-diffs") == 0) {
181            args.wantDiffs = True;
182        }
183        else if (strcmp(argv[i], "-eps") == 0) {
184            args.wantEPS = True;
185        }
186        else if (strcmp(argv[i], "-fit") == 0) {
187            args.scaleToFit = True;
188        }
189        else if (strcmp(argv[i], "-full") == 0) {
190            args.scaleToFit = False;
191        }
192        else if (strcmp(argv[i], "-grid") == 0) {
193            int tmp;
194
195            if (++i >= argc) {
196                uWarning("Grid frequency not specified\n");
197                uAction("Trailing \"-grid\" option ignored\n");
198            }
199            else if ((sscanf(argv[i], "%i", &tmp) != 1) || (tmp < 1)) {
200                uWarning("Grid frequency must be an integer > zero\n");
201                uAction("Illegal frequency %d ignored\n", tmp);
202            }
203            else
204                args.grid = tmp;
205        }
206        else if (strcmp(argv[i], "-if") == 0) {
207            if (++i >= argc) {
208                uWarning("Internal Font name not specified\n");
209                uAction("Trailing \"-if\" option ignored\n");
210            }
211            else
212                outputFont = argv[i];
213        }
214        else if (strcmp(argv[i], "-kc") == 0) {
215            args.wantKeycodes = True;
216        }
217        else if (strcmp(argv[i], "-label") == 0) {
218            if (++i >= argc) {
219                uWarning("Label type not specified\n");
220                uAction("Trailing \"-label\" option ignored\n");
221            }
222            else if (uStrCaseEqual(argv[i], "none"))
223                args.label = LABEL_NONE;
224            else if (uStrCaseEqual(argv[i], "name"))
225                args.label = LABEL_KEYNAME;
226            else if (uStrCaseEqual(argv[i], "code"))
227                args.label = LABEL_KEYCODE;
228            else if (uStrCaseEqual(argv[i], "symbols"))
229                args.label = LABEL_SYMBOLS;
230            else {
231                uWarning("Unknown label type \"%s\" specified\n", argv[i]);
232                uAction("Ignored\n");
233            }
234        }
235        else if (strcmp(argv[i], "-lc") == 0) {
236            if (++i >= argc) {
237                uWarning("Locale not specified\n");
238                uAction("Trailing \"-lc\" option ignored\n");
239            }
240            else
241                wantLocale = argv[i];
242        }
243        else if (strcmp(argv[i], "-lg") == 0) {
244            int tmp;
245
246            if (++i >= argc) {
247                uWarning("Label group not specified\n");
248                uAction("Trailing \"-lg\" option ignored\n");
249            }
250            else if ((sscanf(argv[i], "%i", &tmp) != 1) || (tmp < 1) ||
251                     (tmp > 4)) {
252                uWarning("Label group must be an integer in the range 1..4\n");
253                uAction("Illegal group %d ignored\n", tmp);
254            }
255            else
256                args.baseLabelGroup = tmp - 1;
257        }
258        else if (strcmp(argv[i], "-ll") == 0) {
259            int tmp;
260
261            if (++i >= argc) {
262                uWarning("Label level not specified\n");
263                uAction("Trailing \"-ll\" option ignored\n");
264            }
265            else if ((sscanf(argv[i], "%i", &tmp) != 1) || (tmp < 1) ||
266                     (tmp > 255)) {
267                uWarning("Label level must be in the range 1..255\n");
268                uAction("Illegal level %d ignored\n", tmp);
269            }
270            else
271                args.labelLevel = tmp - 1;
272        }
273        else if (strcmp(argv[i], "-level1") == 0)
274            args.level1 = True;
275        else if (strcmp(argv[i], "-level2") == 0)
276            args.level1 = False;
277        else if (strcmp(argv[i], "-mono") == 0) {
278            args.wantColor = False;
279        }
280        else if (strcmp(argv[i], "-n") == 0) {
281            int tmp;
282
283            if (++i >= argc) {
284                uWarning("Number of copies not specified\n");
285                uAction("Trailing \"-n\" option ignored\n");
286            }
287            else if ((sscanf(argv[i], "%i", &tmp) != 1) || (tmp < 1)) {
288                uWarning("Number of copies must be an integer > zero\n");
289                uAction("Illegal count %d ignored\n", tmp);
290            }
291            else
292                args.copies = tmp;
293        }
294        else if (strcmp(argv[i], "-nokc") == 0) {
295            args.wantKeycodes = False;
296        }
297        else if (strcmp(argv[i], "-nkg") == 0) {
298            int tmp;
299
300            if (++i >= argc) {
301                uWarning("Number of groups per key not specified\n");
302                uAction("Trailing \"-nkg\" option ignored\n");
303            }
304            else if ((sscanf(argv[i], "%i", &tmp) != 1) || (tmp < 1) ||
305                     (tmp > 2)) {
306                uWarning("Groups per key must be in the range 1..2\n");
307                uAction("Illegal number of groups %d ignored\n", tmp);
308            }
309            else
310                args.nLabelGroups = tmp;
311        }
312        else if (strcmp(argv[i], "-npk") == 0) {
313            int tmp;
314
315            if (++i >= argc) {
316                uWarning("Number of keyboards per page not specified\n");
317                uAction("Trailing \"-npk\" option ignored\n");
318            }
319            else if ((sscanf(argv[i], "%i", &tmp) != 1) || (tmp < 1) ||
320                     (tmp > 2)) {
321                uWarning("Keyboards per page must be in the range 1..2\n");
322                uAction("Illegal number of keyboards %d ignored\n", tmp);
323            }
324            else
325                args.nKBPerPage = tmp;
326        }
327        else if (strcmp(argv[i], "-ntg") == 0) {
328            int tmp;
329
330            if (++i >= argc) {
331                uWarning("Total number of groups not specified\n");
332                uAction("Trailing \"-ntg\" option ignored\n");
333            }
334            else if ((sscanf(argv[i], "%i", &tmp) != 1) || (tmp < 1) ||
335                     (tmp > 4)) {
336                uWarning("Total number of groups must be in the range 1..4\n");
337                uAction("Illegal number of groups %d ignored\n", tmp);
338            }
339            else
340                args.nTotalGroups = tmp;
341        }
342        else if (strcmp(argv[i], "-o") == 0) {
343            if (++i >= argc) {
344                uWarning("No output file specified\n");
345                uAction("Trailing \"-o\" option ignored\n");
346            }
347            else if (outputFile != NULL) {
348                uWarning("Multiple output files specified\n");
349                uAction("Compiling %s, ignoring %s\n", outputFile, argv[i]);
350            }
351            else
352                outputFile = argv[i];
353        }
354        else if (strncmp(argv[i], "-R", 2) == 0) {
355            if (argv[i][2] == '\0') {
356                uWarning("No root directory specified\n");
357                uAction("Ignoring -R option\n");
358            }
359            else if (rootDir != NULL) {
360                uWarning("Multiple root directories specified\n");
361                uAction("Using %s, ignoring %s\n", rootDir, argv[i]);
362            }
363            else
364                rootDir = &argv[i][2];
365        }
366        else if (strcmp(argv[i], "-pict") == 0) {
367            if (++i >= argc) {
368                uWarning("No level of pictographs specified\n");
369                uAction("Trailing \"-pict\" option ignored\n");
370            }
371            else if (strcmp(argv[i], "none") == 0)
372                args.wantSymbols = NO_SYMBOLS;
373            else if (strcmp(argv[i], "common") == 0)
374                args.wantSymbols = COMMON_SYMBOLS;
375            else if (strcmp(argv[i], "all") == 0)
376                args.wantSymbols = ALL_SYMBOLS;
377            else if (outputFile != NULL) {
378                uWarning("Unknown pictograph level specified\n");
379                uAction("Ignoring illegal value %s\n", argv[i]);
380            }
381        }
382        else if ((strcmp(argv[i], "-synch") == 0) ||
383                 (strcmp(argv[i], "-s") == 0)) {
384            synch = True;
385        }
386        else if (strcmp(argv[i], "-version") == 0) {
387            puts(PACKAGE_STRING);
388            exit(0);
389        }
390        else if (strcmp(argv[i], "-w") == 0) {
391            if ((i >= (argc - 1)) || (!isdigit(argv[i + 1][0]))) {
392                warningLevel = 0;
393            }
394            else {
395                int itmp;
396
397                if (sscanf(argv[++i], "%i", &itmp))
398                    warningLevel = itmp;
399            }
400        }
401        else {
402            uError("Unknown flag \"%s\" on command line\n", argv[i]);
403            Usage(argc, argv);
404            return False;
405        }
406    }
407    if (rootDir) {
408        if (warningLevel > 8) {
409            uWarning("Changing root directory to \"%s\"\n", rootDir);
410        }
411        if ((chdir(rootDir) < 0) && (warningLevel > 0)) {
412            uWarning("Couldn't change root directory to \"%s\"\n", rootDir);
413            uAction("Root directory (-R) option ignored\n");
414        }
415    }
416    if (outputFont != NULL) {
417        Bool ok;
418        FILE *file = NULL;
419
420        if (outputFile == NULL) {
421            asprintf(&outputFile, "%s.pfa", outputFont);
422        }
423        else if (uStringEqual(outputFile, "-"))
424            file = stdout;
425
426        if (file == NULL)
427            file = fopen(outputFile, "w");
428
429        if (!file) {
430            uError("Couldn't open \"%s\" to dump internal font \"%s\"\n",
431                   outputFile, outputFont);
432            uAction("Exiting\n");
433            exit(1);
434        }
435        ok = DumpInternalFont(file, outputFont);
436        if (file != stdout)
437            fclose(file);
438        if (!ok) {
439            uWarning("No internal font to dump\n");
440            if (file != stdout) {
441                uAction("Removing \"%s\"\n", outputFile);
442                unlink(outputFile);
443            }
444        }
445        exit((ok != 0));
446    }
447    if (inputFile == NULL) {
448        uError("No input file specified\n");
449        Usage(argc, argv);
450        return False;
451    }
452    else if (uStringEqual(inputFile, "-")) {
453        /* Nothing */
454    }
455    else if (strchr(inputFile, ':') == NULL) {
456        size_t len = strlen(inputFile);
457
458        if ((len > 4) && (strcmp(&inputFile[len - 4], ".xkm") == 0)) {
459            /* Nothing */
460        }
461        else {
462            FILE *file;
463
464            file = fopen(inputFile, "r");
465            if (file) {
466                fclose(file);
467            }
468            else {
469                fprintf(stderr, "Cannot open \"%s\" for reading\n", inputFile);
470                return False;
471            }
472        }
473    }
474    else {
475        inDpyName = inputFile;
476        inputFile = NULL;
477    }
478
479    if (outputFormat == WANT_DEFAULT)
480        outputFormat = WANT_PS_FILE;
481    if ((outputFile == NULL) && (inputFile != NULL) &&
482        uStringEqual(inputFile, "-")) {
483        size_t len;
484
485        len = strlen("stdin.eps") + 2;
486        outputFile = calloc(len, sizeof(char));
487
488        if (outputFile == NULL) {
489            uInternalError("Cannot allocate space for output file name\n");
490            uAction("Exiting\n");
491            exit(1);
492        }
493        if (args.wantEPS)
494            snprintf(outputFile, len, "stdin.eps");
495        else
496            snprintf(outputFile, len, "stdin.ps");
497    }
498    else if ((outputFile == NULL) && (inputFile != NULL)) {
499        size_t len;
500        char *base, *ext;
501
502        base = strrchr(inputFile, '/');
503        if (base == NULL)
504            base = inputFile;
505        else
506            base++;
507
508        len = strlen(base) + strlen("eps") + 2;
509        outputFile = calloc(len, sizeof(char));
510
511        if (outputFile == NULL) {
512            uInternalError("Cannot allocate space for output file name\n");
513            uAction("Exiting\n");
514            exit(1);
515        }
516        ext = strrchr(base, '.');
517        if (ext == NULL) {
518            if (args.wantEPS)
519                snprintf(outputFile, len, "%s.eps", base);
520            else
521                snprintf(outputFile, len, "%s.ps", base);
522        }
523        else {
524            strcpy(outputFile, base);
525            if (args.wantEPS)
526                strcpy(&outputFile[ext - base + 1], "eps");
527            else
528                strcpy(&outputFile[ext - base + 1], "ps");
529        }
530    }
531    else if (outputFile == NULL) {
532        size_t len;
533        char *ch, *name, buf[128];
534
535        if (inDpyName[0] == ':')
536            snprintf(name = buf, sizeof(buf), "server%s", inDpyName);
537        else
538            name = inDpyName;
539
540        len = strlen(name) + strlen("eps") + 2;
541        outputFile = calloc(len, sizeof(char));
542
543        if (outputFile == NULL) {
544            uInternalError("Cannot allocate space for output file name\n");
545            uAction("Exiting\n");
546            exit(1);
547        }
548        strcpy(outputFile, name);
549        for (ch = outputFile; (*ch) != '\0'; ch++) {
550            if (*ch == ':')
551                *ch = '-';
552            else if (*ch == '.')
553                *ch = '_';
554        }
555        *ch++ = '.';
556        if (args.wantEPS)
557            strcpy(ch, "eps");
558        else
559            strcpy(ch, "ps");
560    }
561    else if (strchr(outputFile, ':') != NULL) {
562        outDpyName = outputFile;
563        outputFile = NULL;
564        outputFormat = WANT_X_SERVER;
565        uInternalError("Output to an X server not implemented yet\n");
566        return False;
567    }
568    return True;
569}
570
571static Display *
572GetDisplay(char *program, char *dpyName)
573{
574    int mjr, mnr, error;
575    Display *dpy;
576
577    mjr = XkbMajorVersion;
578    mnr = XkbMinorVersion;
579    dpy = XkbOpenDisplay(dpyName, NULL, NULL, &mjr, &mnr, &error);
580    if (dpy == NULL) {
581        switch (error) {
582        case XkbOD_BadLibraryVersion:
583            uInformation("%s was compiled with XKB version %d.%02d\n",
584                         program, XkbMajorVersion, XkbMinorVersion);
585            uError("X library supports incompatible version %d.%02d\n",
586                   mjr, mnr);
587            break;
588        case XkbOD_ConnectionRefused:
589            uError("Cannot open display \"%s\"\n", dpyName);
590            break;
591        case XkbOD_NonXkbServer:
592            uError("XKB extension not present on %s\n", dpyName);
593            break;
594        case XkbOD_BadServerVersion:
595            uInformation("%s was compiled with XKB version %d.%02d\n",
596                         program, XkbMajorVersion, XkbMinorVersion);
597            uError("Server %s uses incompatible version %d.%02d\n",
598                   dpyName, mjr, mnr);
599            break;
600        default:
601            uInternalError("Unknown error %d from XkbOpenDisplay\n", error);
602        }
603    }
604    else if (synch)
605        XSynchronize(dpy, True);
606    return dpy;
607}
608
609/***====================================================================***/
610
611
612int
613main(int argc, char *argv[])
614{
615    FILE *file;
616    int ok;
617    XkbFileInfo result;
618
619    uSetErrorFile(NullString);
620    if (!parseArgs(argc, argv))
621        exit(1);
622    file = NULL;
623    XkbInitAtoms(NULL);
624/*     XkbInitIncludePath(); */
625    if (inputFile != NULL) {
626        if (uStringEqual(inputFile, "-")) {
627            static char in[] = "stdin";
628
629            file = stdin;
630            inputFile = in;
631        }
632        else {
633            file = fopen(inputFile, "r");
634        }
635    }
636    else if (inDpyName != NULL) {
637        inDpy = GetDisplay(argv[0], inDpyName);
638        if (!inDpy) {
639            uAction("Exiting\n");
640            exit(1);
641        }
642    }
643    if (outDpyName != NULL) {
644        uInternalError("Output to an X server not implemented yet\n");
645        outDpy = GetDisplay(argv[0], outDpyName);
646        if (!outDpy) {
647            uAction("Exiting\n");
648            exit(1);
649        }
650    }
651    if ((inDpy == NULL) && (outDpy == NULL)) {
652        int mjr, mnr;
653
654        mjr = XkbMajorVersion;
655        mnr = XkbMinorVersion;
656        if (!XkbLibraryVersion(&mjr, &mnr)) {
657            uInformation("%s was compiled with XKB version %d.%02d\n",
658                         argv[0], XkbMajorVersion, XkbMinorVersion);
659            uError("X library supports incompatible version %d.%02d\n",
660                   mjr, mnr);
661            uAction("Exiting\n");
662            exit(1);
663        }
664    }
665    ok = True;
666    if (file) {
667        unsigned tmp;
668
669        bzero((char *) &result, sizeof(result));
670        if ((result.xkb = XkbAllocKeyboard()) == NULL) {
671            uFatalError("Cannot allocate keyboard description\n");
672            /* NOTREACHED */
673        }
674        tmp = XkmReadFile(file, XkmGeometryMask, XkmKeymapLegal, &result);
675        if ((tmp & XkmGeometryMask) != 0) {
676            uError("Couldn't read geometry from XKM file \"%s\"\n", inputFile);
677            uAction("Exiting\n");
678            ok = False;
679        }
680        if ((tmp & XkmKeyNamesMask) != 0)
681            args.wantKeycodes = False;
682        if (args.label == LABEL_AUTO) {
683            if (result.defined & XkmSymbolsMask)
684                args.label = LABEL_SYMBOLS;
685            else if (result.defined & XkmKeyNamesMask)
686                args.label = LABEL_KEYCODE;
687            else
688                args.label = LABEL_KEYNAME;
689        }
690        else if ((args.label == LABEL_KEYCODE) &&
691                 ((tmp & XkmKeyNamesMask) != 0)) {
692            uError("XKM file \"%s\" doesn't have keycodes\n", inputFile);
693            uAction("Cannot label keys as requested. Exiting\n");
694            ok = False;
695        }
696        else if ((args.label == LABEL_SYMBOLS) && ((tmp & XkmSymbolsMask) != 0)) {
697            uError("XKM file \"%s\" doesn't have symbols\n", inputFile);
698            uAction("Cannot label keys as requested. Exiting\n");
699            ok = False;
700        }
701    }
702    else if (inDpy != NULL) {
703        bzero((char *) &result, sizeof(result));
704        result.type = XkmKeymapFile;
705        result.xkb = XkbGetMap(inDpy, XkbAllMapComponentsMask, XkbUseCoreKbd);
706        if (result.xkb == NULL)
707            uWarning("Cannot load keyboard description\n");
708        if (XkbGetNames(inDpy, XkbAllNamesMask, result.xkb) != Success)
709            uWarning("Cannot load names\n");
710        if (XkbGetGeometry(inDpy, result.xkb) != Success) {
711            uFatalError("Cannot load geometry for %s\n", inDpyName);
712        }
713        if (args.label == LABEL_AUTO)
714            args.label = LABEL_SYMBOLS;
715    }
716    else {
717        fprintf(stderr, "Cannot open \"%s\" to read geometry\n", inputFile);
718        ok = 0;
719    }
720    if (ok) {
721        FILE *out = NULL;
722
723        if (setlocale(LC_ALL, (wantLocale)) == NULL) {
724            if (wantLocale != NULL) {
725                uWarning("Couldn't change to locale %s\n", wantLocale);
726                uAction("Using \"C\" locale, instead\n");
727            }
728        }
729        /* need C numerics so decimal point doesn't get screwed up */
730        setlocale(LC_NUMERIC, "C");
731        if ((inDpy != outDpy) &&
732            (XkbChangeKbdDisplay(outDpy, &result) != Success)) {
733            uInternalError("Error converting keyboard display from %s to %s\n",
734                           inDpyName, outDpyName);
735            exit(1);
736        }
737        if (outputFile != NULL) {
738            if (uStringEqual(outputFile, "-")) {
739                static char of[] = "stdout";
740
741                out = stdout;
742                outputFile = of;
743            }
744            else {
745                out = fopen(outputFile, "w");
746                if (out == NULL) {
747                    uError("Cannot open \"%s\" to write keyboard description\n",
748                           outputFile);
749                    uAction("Exiting\n");
750                    exit(1);
751                }
752            }
753        }
754        switch (outputFormat) {
755        case WANT_PS_FILE:
756            ok = GeometryToPostScript(out, &result, &args);
757            break;
758        case WANT_X_SERVER:
759            uInternalError("Output to X server not implemented yet\n");
760            break;
761        default:
762            uInternalError("Unknown output format %d\n", outputFormat);
763            uAction("No output file created\n");
764            ok = False;
765            break;
766        }
767        if (!ok) {
768            uError("Error creating output file\n");
769        }
770    }
771    if (inDpy)
772        XCloseDisplay(inDpy);
773    inDpy = NULL;
774    if (outDpy)
775        XCloseDisplay(outDpy);
776    return (ok == 0);
777}
778