10e20ee16Smrg/************************************************************
20e20ee16Smrg Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
30e20ee16Smrg
40e20ee16Smrg Permission to use, copy, modify, and distribute this
50e20ee16Smrg software and its documentation for any purpose and without
60e20ee16Smrg fee is hereby granted, provided that the above copyright
70e20ee16Smrg notice appear in all copies and that both that copyright
80e20ee16Smrg notice and this permission notice appear in supporting
92f167a42Smrg documentation, and that the name of Silicon Graphics not be
102f167a42Smrg used in advertising or publicity pertaining to distribution
110e20ee16Smrg of the software without specific prior written permission.
122f167a42Smrg Silicon Graphics makes no representation about the suitability
130e20ee16Smrg of this software for any purpose. It is provided "as is"
140e20ee16Smrg without any express or implied warranty.
152f167a42Smrg
162f167a42Smrg SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
172f167a42Smrg SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
180e20ee16Smrg AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
192f167a42Smrg GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
202f167a42Smrg DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
212f167a42Smrg DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
220e20ee16Smrg OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
230e20ee16Smrg THE USE OR PERFORMANCE OF THIS SOFTWARE.
240e20ee16Smrg
250e20ee16Smrg ********************************************************/
262f167a42Smrg
272f167a42Smrg#ifdef HAVE_CONFIG_H
282f167a42Smrg#include "config.h"
292f167a42Smrg#endif
300e20ee16Smrg
310e20ee16Smrg#define	XK_TECHNICAL
320e20ee16Smrg#define	XK_PUBLISHING
330e20ee16Smrg#define	XK_KATAKANA
340e20ee16Smrg#include <stdio.h>
350e20ee16Smrg#include <ctype.h>
360e20ee16Smrg#include <X11/X.h>
370e20ee16Smrg#include <X11/Xlib.h>
380e20ee16Smrg#include <X11/XKBlib.h>
390e20ee16Smrg#include <X11/extensions/XKBgeom.h>
400e20ee16Smrg#include <X11/extensions/XKM.h>
410e20ee16Smrg#include <X11/extensions/XKBfile.h>
420e20ee16Smrg#include <X11/keysym.h>
430e20ee16Smrg#include <X11/Xutil.h>
440e20ee16Smrg
450e20ee16Smrg
460e20ee16Smrg#include <stdlib.h>
470e20ee16Smrg
480e20ee16Smrg#include "utils.h"
490e20ee16Smrg#include "xkbprint.h"
500e20ee16Smrg#include "isokeys.h"
510e20ee16Smrg
520e20ee16Smrg#define	FONT_NONE	-1
530e20ee16Smrg#define	FONT_TEXT	0
540e20ee16Smrg#define	FONT_LATIN1	1
550e20ee16Smrg#define	FONT_SYMBOL	2
560e20ee16Smrg#define	FONT_ISOCAPS	3
570e20ee16Smrg#define	FONT_MOUSECAPS	4
580e20ee16Smrg
590e20ee16Smrgtypedef struct {
602f167a42Smrg    Display *           dpy;
612f167a42Smrg    XkbDescPtr          xkb;
622f167a42Smrg    XkbGeometryPtr      geom;
632f167a42Smrg    int                 totalKB;
642f167a42Smrg    int                 kbPerPage;
652f167a42Smrg    int                 black;
662f167a42Smrg    int                 white;
672f167a42Smrg    int                 color;
682f167a42Smrg    int                 font;
692f167a42Smrg    int                 fontSize;
702f167a42Smrg    int                 nPages;
712f167a42Smrg    int                 x1, y1;
722f167a42Smrg    int                 x2, y2;
732f167a42Smrg    XKBPrintArgs *      args;
740e20ee16Smrg} PSState;
750e20ee16Smrg
760e20ee16Smrg#define	G1L1		0
770e20ee16Smrg#define	G1L2		1
780e20ee16Smrg#define	G2L1		2
790e20ee16Smrg#define	G2L2		3
800e20ee16Smrg#define	CENTER		4
810e20ee16Smrg
820e20ee16Smrg#define	G1L1_MASK	(1<<G1L1)
830e20ee16Smrg#define	G1L2_MASK	(1<<G1L2)
840e20ee16Smrg#define	G2L1_MASK	(1<<G2L1)
850e20ee16Smrg#define	G2L2_MASK	(1<<G2L2)
860e20ee16Smrg#define	CENTER_MASK	(1<<CENTER)
870e20ee16Smrg
880e20ee16Smrg#define	LABEL_MASK	(0x1f)
890e20ee16Smrg#define	GXL1_MASK	(G1L1_MASK|G2L1_MASK)
900e20ee16Smrg#define	GXL2_MASK	(G1L2_MASK|G2L2_MASK)
910e20ee16Smrg#define	G1LX_MASK	(G1L1_MASK|G1L2_MASK)
920e20ee16Smrg#define	G2LX_MASK	(G2L1_MASK|G2L2_MASK)
930e20ee16Smrg#define	GXLX_MASK	(0x0f)
940e20ee16Smrg
950e20ee16Smrg#define	NLABELS		5
960e20ee16Smrg#define	LABEL_LEN	30
970e20ee16Smrg
980e20ee16Smrg#define	SZ_AUTO		0
990e20ee16Smrg#define	SZ_TINY		1
1000e20ee16Smrg#define	SZ_SMALL	2
1010e20ee16Smrg#define	SZ_MEDIUM	3
1020e20ee16Smrg#define	SZ_LARGE	4
1030e20ee16Smrg#define	SZ_XLARGE	5
1040e20ee16Smrg
1050e20ee16Smrgtypedef struct {
1062f167a42Smrg    unsigned    present;
1072f167a42Smrg    Bool        alpha[2];
1082f167a42Smrg    char        label[NLABELS][LABEL_LEN];
1092f167a42Smrg    int         font[NLABELS];
1102f167a42Smrg    int         size[NLABELS];
1110e20ee16Smrg} KeyTop;
1120e20ee16Smrg
1130e20ee16Smrg#define	DFLT_LABEL_FONT "Helvetica-Narrow-Bold"
1140e20ee16Smrg#define DFLT_LABEL_FONT_SIZE 10
1150e20ee16Smrg
1160e20ee16Smrg/***====================================================================***/
1170e20ee16Smrg
1180e20ee16Smrgtypedef struct _PSFontDef {
1192f167a42Smrg    const char *name;
1202f167a42Smrg    const char **def;
1210e20ee16Smrg} PSFontDef;
1220e20ee16Smrg
1230e20ee16Smrgstatic PSFontDef internalFonts[] = {
1242f167a42Smrg    { "IsoKeyCaps", &IsoKeyCaps }
1250e20ee16Smrg};
1262f167a42Smrgstatic int nInternalFonts = (sizeof(internalFonts) / sizeof(PSFontDef));
1270e20ee16Smrg
1280e20ee16Smrgstatic void
1290e20ee16SmrgListInternalFonts(FILE *out, int first, int indent)
1300e20ee16Smrg{
1318b648e79Smrg    register int i, nThisLine;
1320e20ee16Smrg
1338b648e79Smrg    for (int n = 0; n < first; n++) {
1342f167a42Smrg        putc(' ', out);
1350e20ee16Smrg    }
1360e20ee16Smrg
1372f167a42Smrg    for (nThisLine = i = 0; i < nInternalFonts; i++) {
1382f167a42Smrg        if (nThisLine == 4) {
1392f167a42Smrg            fprintf(out, ",\n");
1408b648e79Smrg            for (int n = 0; n < indent; n++) {
1412f167a42Smrg                putc(' ', out);
1422f167a42Smrg            }
1432f167a42Smrg            nThisLine = 0;
1442f167a42Smrg        }
1452f167a42Smrg        if (nThisLine == 0)
1462f167a42Smrg            fprintf(out, "%s", internalFonts[i].name);
1472f167a42Smrg        else
1482f167a42Smrg            fprintf(out, ", %s", internalFonts[i].name);
1492f167a42Smrg        nThisLine++;
1500e20ee16Smrg    }
1512f167a42Smrg    if (nThisLine != 0)
1522f167a42Smrg        fprintf(out, "\n");
1530e20ee16Smrg    return;
1540e20ee16Smrg}
1550e20ee16Smrg
1560e20ee16Smrgstatic Bool
1572f167a42SmrgPSIncludeFont(FILE *out, const char *font)
1580e20ee16Smrg{
1592f167a42Smrg    const char **pstr;
1600e20ee16Smrg
1612f167a42Smrg    pstr = NULL;
1628b648e79Smrg    for (int i = 0; (i < nInternalFonts) && (pstr == NULL); i++) {
1632f167a42Smrg        if (uStringEqual(internalFonts[i].name, font))
1642f167a42Smrg            pstr = internalFonts[i].def;
1650e20ee16Smrg    }
1662f167a42Smrg    if (pstr != NULL) {
1672f167a42Smrg        fprintf(out, "%%%%BeginFont: %s\n", font);
1682f167a42Smrg        fprintf(out, "%s", *pstr);
1692f167a42Smrg        fprintf(out, "%%%%EndFont\n");
1702f167a42Smrg        return True;
1710e20ee16Smrg    }
1720e20ee16Smrg    return False;
1730e20ee16Smrg}
1740e20ee16Smrg
1750e20ee16SmrgBool
1762f167a42SmrgDumpInternalFont(FILE *out, const char *fontName)
1770e20ee16Smrg{
1782f167a42Smrg    if (strcmp(fontName, "IsoKeyCaps") != 0) {
1792f167a42Smrg        uError("No internal font named \"%s\"\n", fontName);
1802f167a42Smrg        uAction("No font dumped\n");
1812f167a42Smrg        fprintf(stderr, "Current internal fonts are: ");
1822f167a42Smrg        ListInternalFonts(stderr, 0, 8);
1832f167a42Smrg        return False;
1840e20ee16Smrg    }
1852f167a42Smrg    PSIncludeFont(out, fontName);
1860e20ee16Smrg    return True;
1870e20ee16Smrg}
1880e20ee16Smrg
1890e20ee16Smrg/***====================================================================***/
1900e20ee16Smrg
1910e20ee16Smrgstatic void
1920e20ee16SmrgPSColorDef(FILE *out, PSState *state, XkbColorPtr color)
1930e20ee16Smrg{
1942f167a42Smrg    int tmp;
1950e20ee16Smrg
1962f167a42Smrg    fprintf(out, "/C%03d ", color->pixel);
1972f167a42Smrg    if (uStrCaseEqual(color->spec, "black")) {
1982f167a42Smrg        state->black = color->pixel;
1992f167a42Smrg        fprintf(out, "{ 0 setgray } def      %% %s\n", color->spec);
2000e20ee16Smrg    }
2012f167a42Smrg    else if (uStrCaseEqual(color->spec, "white")) {
2022f167a42Smrg        state->white = color->pixel;
2032f167a42Smrg        fprintf(out, "{ 1 setgray } def      %% %s\n", color->spec);
2040e20ee16Smrg    }
2052f167a42Smrg    else if ((sscanf(color->spec, "grey%d", &tmp) == 1) ||
2062f167a42Smrg             (sscanf(color->spec, "gray%d", &tmp) == 1) ||
2072f167a42Smrg             (sscanf(color->spec, "Grey%d", &tmp) == 1) ||
2082f167a42Smrg             (sscanf(color->spec, "Gray%d", &tmp) == 1)) {
2092f167a42Smrg        fprintf(out, "{ %f setgray } def	    %% %s\n",
2102f167a42Smrg                1.0 - (((float) tmp) / 100.0), color->spec);
2110e20ee16Smrg    }
2122f167a42Smrg    else if ((tmp = (uStrCaseEqual(color->spec, "red") * 100)) ||
2132f167a42Smrg             (sscanf(color->spec, "red%d", &tmp) == 1)) {
2142f167a42Smrg        fprintf(out, "{ %f 0 0 setrgbcolor } def %% %s\n",
2152f167a42Smrg                (((float) tmp) / 100.0), color->spec);
2160e20ee16Smrg    }
2172f167a42Smrg    else if ((tmp = (uStrCaseEqual(color->spec, "green") * 100)) ||
2182f167a42Smrg             (sscanf(color->spec, "green%d", &tmp) == 1)) {
2192f167a42Smrg        fprintf(out, "{ 0 %f 0 setrgbcolor } def %% %s\n",
2202f167a42Smrg                (((float) tmp) / 100.0), color->spec);
2210e20ee16Smrg    }
2222f167a42Smrg    else if ((tmp = (uStrCaseEqual(color->spec, "blue") * 100)) ||
2232f167a42Smrg             (sscanf(color->spec, "blue%d", &tmp) == 1)) {
2242f167a42Smrg        fprintf(out, "{ 0 0 %f setrgbcolor } def %% %s\n",
2252f167a42Smrg                (((float) tmp) / 100.0), color->spec);
2260e20ee16Smrg    }
2272f167a42Smrg    else
2282f167a42Smrg        fprintf(out, "{ 0.9 setgray       } def %% BOGUS! %s\n", color->spec);
2290e20ee16Smrg}
2300e20ee16Smrg
2310e20ee16Smrgstatic void
2322f167a42SmrgPSSetColor(FILE *out, PSState *state, int color)
2330e20ee16Smrg{
2342f167a42Smrg    if ((state->args->wantColor) && (state->color != color)) {
2352f167a42Smrg        fprintf(out, "C%03d %% set color\n", color);
2362f167a42Smrg        state->color = color;
2370e20ee16Smrg    }
2380e20ee16Smrg    return;
2390e20ee16Smrg}
2400e20ee16Smrg
2410e20ee16Smrgstatic void
2420e20ee16SmrgPSGSave(FILE *out, PSState *state)
2430e20ee16Smrg{
2442f167a42Smrg    fprintf(out, "gsave\n");
2450e20ee16Smrg    return;
2460e20ee16Smrg}
2470e20ee16Smrg
2480e20ee16Smrgstatic void
2490e20ee16SmrgPSGRestore(FILE *out, PSState *state)
2500e20ee16Smrg{
2512f167a42Smrg    fprintf(out, "grestore\n");
2522f167a42Smrg    state->color = -1;
2532f167a42Smrg    state->font = FONT_NONE;
2542f167a42Smrg    state->fontSize = -1;
2550e20ee16Smrg    return;
2560e20ee16Smrg}
2570e20ee16Smrg
2580e20ee16Smrgstatic void
2590e20ee16SmrgPSShapeDef(FILE *out, PSState *state, XkbShapePtr shape)
2600e20ee16Smrg{
2618b648e79Smrg    int o;
2622f167a42Smrg    XkbOutlinePtr ol;
2632f167a42Smrg
264e6bced22Smrg    {
265e6bced22Smrg        char *a = XkbAtomGetString(state->dpy, shape->name);
266e6bced22Smrg        fprintf(out, "/%s {\n", a);
267e6bced22Smrg        XFree(a);
268e6bced22Smrg    }
2692f167a42Smrg    fprintf(out, "	gsave translate rotate /SOLID exch def\n");
2702f167a42Smrg    for (o = 0, ol = shape->outlines; o < shape->num_outlines; o++, ol++) {
2712f167a42Smrg        XkbPointPtr pt;
2722f167a42Smrg
2732f167a42Smrg        if ((shape->num_outlines > 1) && (ol == shape->approx))
2742f167a42Smrg            continue;
2752f167a42Smrg        pt = ol->points;
2762f167a42Smrg        fprintf(out, "%%	Outline %d\n", o + 1);
2772f167a42Smrg        if (ol->num_points == 1) {
2782f167a42Smrg            if (ol->corner_radius < 1) {
2792f167a42Smrg                fprintf(out, "	  0   0 moveto\n");
2802f167a42Smrg                fprintf(out, "	%3d   0 lineto\n", pt->x);
2812f167a42Smrg                fprintf(out, "	%3d %3d lineto\n", pt->x, pt->y);
2822f167a42Smrg                fprintf(out, "	  0 %3d lineto\n", pt->y);
2832f167a42Smrg                fprintf(out, "	  0   0 lineto\n");
2842f167a42Smrg                fprintf(out, "	SOLID { fill } { stroke } ifelse\n");
2852f167a42Smrg            }
2862f167a42Smrg            else {
2872f167a42Smrg                fprintf(out, "	mark\n");
2882f167a42Smrg                fprintf(out, "	%3d   0 moveto\n", ol->corner_radius);
2892f167a42Smrg                fprintf(out, "	%3d   0 %3d %3d %3d arcto\n", pt->x, pt->x,
2902f167a42Smrg                        pt->y, ol->corner_radius);
2912f167a42Smrg                fprintf(out, "	%3d %3d   0 %3d %3d arcto\n", pt->x, pt->y,
2922f167a42Smrg                        pt->y, ol->corner_radius);
2932f167a42Smrg                fprintf(out, "	  0 %3d   0   0 %3d arcto\n", pt->y,
2942f167a42Smrg                        ol->corner_radius);
2952f167a42Smrg                fprintf(out, "     0   0 %3d   0 %3d arcto\n", pt->x,
2962f167a42Smrg                        ol->corner_radius);
2972f167a42Smrg                fprintf(out, "	SOLID { fill } { stroke } ifelse\n");
2982f167a42Smrg                fprintf(out, "	cleartomark\n");
2992f167a42Smrg            }
3002f167a42Smrg        }
3012f167a42Smrg        else if (ol->num_points == 2) {
3022f167a42Smrg            if (ol->corner_radius < 1) {
3032f167a42Smrg                fprintf(out, "	%3d %3d moveto\n", pt[0].x, pt[0].y);
3042f167a42Smrg                fprintf(out, "	%3d %3d lineto\n", pt[1].x, pt[0].y);
3052f167a42Smrg                fprintf(out, "	%3d %3d lineto\n", pt[1].x, pt[1].y);
3062f167a42Smrg                fprintf(out, "	%3d %3d lineto\n", pt[0].x, pt[1].y);
3072f167a42Smrg                fprintf(out, "	%3d %3d lineto\n", pt[0].x, pt[0].y);
3082f167a42Smrg                fprintf(out, "	SOLID { fill } { stroke } ifelse\n");
3092f167a42Smrg            }
3102f167a42Smrg            else {
3112f167a42Smrg                fprintf(out, "	mark\n");
3122f167a42Smrg                fprintf(out, "	%3d %3d moveto\n", pt[0].x + ol->corner_radius,
3132f167a42Smrg                        pt[0].y);
3142f167a42Smrg                fprintf(out, "	%3d %3d %3d %3d %3d arcto\n", pt[1].x, pt[0].y,
3152f167a42Smrg                        pt[1].x, pt[1].y, ol->corner_radius);
3162f167a42Smrg                fprintf(out, "	%3d %3d %3d %3d %3d arcto\n", pt[1].x, pt[1].y,
3172f167a42Smrg                        pt[0].x, pt[1].y, ol->corner_radius);
3182f167a42Smrg                fprintf(out, "	%3d %3d %3d %3d %3d arcto\n", pt[0].x, pt[1].y,
3192f167a42Smrg                        pt[0].x, pt[0].y, ol->corner_radius);
3202f167a42Smrg                fprintf(out, "   %3d %3d %3d %3d %3d arcto\n", pt[0].x, pt[0].y,
3212f167a42Smrg                        pt[1].x, pt[0].y, ol->corner_radius);
3222f167a42Smrg                fprintf(out, "	SOLID { fill } { stroke } ifelse\n");
3232f167a42Smrg                fprintf(out, "	cleartomark\n");
3242f167a42Smrg            }
3252f167a42Smrg        }
3262f167a42Smrg        else {
3272f167a42Smrg            if (ol->corner_radius < 1) {
3282f167a42Smrg                fprintf(out, "	%3d %3d moveto\n", pt->x, pt->y);
3292f167a42Smrg                pt++;
3308b648e79Smrg                for (int p = 1; p < ol->num_points; p++, pt++) {
3312f167a42Smrg                    fprintf(out, "	%3d %3d lineto\n", pt->x, pt->y);
3322f167a42Smrg                }
3332f167a42Smrg                if ((pt->x != ol->points[0].x) || (pt->y != ol->points[0].y))
3342f167a42Smrg                    fprintf(out, "	closepath\n");
3352f167a42Smrg                fprintf(out, "	SOLID { fill } { stroke } ifelse\n");
3362f167a42Smrg            }
3372f167a42Smrg            else {
3382f167a42Smrg                XkbPointPtr last;
3392f167a42Smrg
3402f167a42Smrg                last = &pt[ol->num_points - 1];
3412f167a42Smrg                if ((last->x == pt->x) && (last->y == pt->y))
3422f167a42Smrg                    last--;
3432f167a42Smrg                fprintf(out, "	mark\n");
3442f167a42Smrg                fprintf(out, "	%% Determine tangent point of first corner\n");
3452f167a42Smrg                fprintf(out, "	%3d %3d moveto %d %d %d %d %d arcto\n",
3462f167a42Smrg                        last->x, last->y,
3472f167a42Smrg                        pt[0].x, pt[0].y, pt[1].x, pt[1].y, ol->corner_radius);
3482f167a42Smrg                fprintf(out, "	/TY exch def /TX exch def pop pop newpath\n");
3492f167a42Smrg                fprintf(out, "	%% Now draw the shape\n");
3502f167a42Smrg                fprintf(out, "	TX TY moveto\n");
3518b648e79Smrg                for (int p = 1; p < ol->num_points; p++) {
3522f167a42Smrg                    if (p < (ol->num_points - 1))
3532f167a42Smrg                        last = &pt[p + 1];
3542f167a42Smrg                    else
3552f167a42Smrg                        last = &pt[0];
3562f167a42Smrg                    fprintf(out, "	%3d %3d %3d %3d %3d arcto\n",
3572f167a42Smrg                            pt[p].x, pt[p].y,
3582f167a42Smrg                            last->x, last->y, ol->corner_radius);
3592f167a42Smrg                }
3602f167a42Smrg                last = &pt[ol->num_points - 1];
3612f167a42Smrg                if ((last->x != pt->x) || (last->y != pt->y)) {
3622f167a42Smrg                    fprintf(out, "	%3d %3d %3d %3d %3d arcto\n",
3632f167a42Smrg                            pt[0].x, pt[0].y,
3642f167a42Smrg                            pt[1].x, pt[1].y, ol->corner_radius);
3652f167a42Smrg                }
3662f167a42Smrg                fprintf(out, "	SOLID { fill } { stroke } ifelse\n");
3672f167a42Smrg                fprintf(out, "	cleartomark\n");
3682f167a42Smrg            }
3692f167a42Smrg        }
3700e20ee16Smrg    }
3712f167a42Smrg    fprintf(out, "	grestore\n");
3722f167a42Smrg    fprintf(out, "} def\n");
3730e20ee16Smrg    return;
3740e20ee16Smrg}
3750e20ee16Smrg
3760e20ee16Smrg/***====================================================================***/
3770e20ee16Smrg
3782f167a42Smrgtypedef struct {
3792f167a42Smrg    char *      foundry;
3802f167a42Smrg    char *      face;
3812f167a42Smrg    char *      weight;
3822f167a42Smrg    char *      slant;
3832f167a42Smrg    char *      setWidth;
3842f167a42Smrg    char *      variant;
3852f167a42Smrg    int         pixelSize;
3862f167a42Smrg    int         ptSize;
3872f167a42Smrg    int         resX;
3882f167a42Smrg    int         resY;
3892f167a42Smrg    char *      spacing;
3902f167a42Smrg    int         avgWidth;
3912f167a42Smrg    char *      encoding;
3920e20ee16Smrg} FontStuff;
3930e20ee16Smrg
3940e20ee16Smrgstatic void
3950e20ee16SmrgClearFontStuff(FontStuff *stuff)
3960e20ee16Smrg{
3978b648e79Smrg    if (stuff) {
3982f167a42Smrg        free(stuff->foundry);
3998b648e79Smrg        bzero(stuff, sizeof(FontStuff));
4008b648e79Smrg    }
4010e20ee16Smrg    return;
4020e20ee16Smrg}
4030e20ee16Smrg
4040e20ee16Smrgstatic Bool
4052f167a42SmrgCrackXLFDName(const char *name, FontStuff *stuff)
4060e20ee16Smrg{
4072f167a42Smrg    char *tmp;
4082f167a42Smrg
4092f167a42Smrg    if ((name == NULL) || (stuff == NULL))
4102f167a42Smrg        return False;
4112f167a42Smrg    if (name[0] == '-')
4122f167a42Smrg        tmp = strdup(&name[1]);
4132f167a42Smrg    else
4142f167a42Smrg        tmp = strdup(name);
4152f167a42Smrg    if (tmp == NULL)
4162f167a42Smrg        return False;
4172f167a42Smrg    stuff->foundry = tmp;
4182f167a42Smrg
4192f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4202f167a42Smrg        goto BAILOUT;
4212f167a42Smrg    else
4222f167a42Smrg        *tmp++ = '\0';
4232f167a42Smrg    stuff->face = tmp;
4242f167a42Smrg
4252f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4262f167a42Smrg        goto BAILOUT;
4272f167a42Smrg    else
4282f167a42Smrg        *tmp++ = '\0';
4292f167a42Smrg    stuff->weight = tmp;
4302f167a42Smrg
4312f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4322f167a42Smrg        goto BAILOUT;
4332f167a42Smrg    else
4342f167a42Smrg        *tmp++ = '\0';
4352f167a42Smrg    stuff->slant = tmp;
4362f167a42Smrg
4372f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4382f167a42Smrg        goto BAILOUT;
4392f167a42Smrg    else
4402f167a42Smrg        *tmp++ = '\0';
4412f167a42Smrg    stuff->setWidth = tmp;
4422f167a42Smrg
4432f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4442f167a42Smrg        goto BAILOUT;
4452f167a42Smrg    else
4462f167a42Smrg        *tmp++ = '\0';
4472f167a42Smrg    stuff->variant = tmp;
4482f167a42Smrg
4492f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4502f167a42Smrg        goto BAILOUT;
4512f167a42Smrg    else
4522f167a42Smrg        *tmp++ = '\0';
4532f167a42Smrg    if (*tmp == '*')
4542f167a42Smrg        stuff->pixelSize = 0;
4552f167a42Smrg    else if (sscanf(tmp, "%i", &stuff->pixelSize) != 1)
4562f167a42Smrg        goto BAILOUT;
4572f167a42Smrg
4582f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4592f167a42Smrg        goto BAILOUT;
4602f167a42Smrg    else
4612f167a42Smrg        *tmp++ = '\0';
4622f167a42Smrg    if (*tmp == '*')
4632f167a42Smrg        stuff->ptSize = 0;
4642f167a42Smrg    else if (sscanf(tmp, "%i", &stuff->ptSize) != 1)
4652f167a42Smrg        goto BAILOUT;
4662f167a42Smrg
4672f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4682f167a42Smrg        goto BAILOUT;
4692f167a42Smrg    else
4702f167a42Smrg        *tmp++ = '\0';
4712f167a42Smrg    if (*tmp == '*')
4722f167a42Smrg        stuff->resX = 0;
4732f167a42Smrg    else if (sscanf(tmp, "%i", &stuff->resX) != 1)
4742f167a42Smrg        goto BAILOUT;
4752f167a42Smrg
4762f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4772f167a42Smrg        goto BAILOUT;
4782f167a42Smrg    else
4792f167a42Smrg        *tmp++ = '\0';
4802f167a42Smrg    if (*tmp == '*')
4812f167a42Smrg        stuff->resY = 0;
4822f167a42Smrg    else if (sscanf(tmp, "%i", &stuff->resY) != 1)
4832f167a42Smrg        goto BAILOUT;
4842f167a42Smrg
4852f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4862f167a42Smrg        goto BAILOUT;
4872f167a42Smrg    else
4882f167a42Smrg        *tmp++ = '\0';
4892f167a42Smrg    stuff->spacing = tmp;
4902f167a42Smrg
4912f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4922f167a42Smrg        goto BAILOUT;
4932f167a42Smrg    else
4942f167a42Smrg        *tmp++ = '\0';
4952f167a42Smrg    if (*tmp == '*')
4962f167a42Smrg        stuff->avgWidth = 0;
4972f167a42Smrg    else if (sscanf(tmp, "%i", &stuff->avgWidth) != 1)
4982f167a42Smrg        goto BAILOUT;
4992f167a42Smrg
5002f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
5012f167a42Smrg        goto BAILOUT;
5022f167a42Smrg    else
5032f167a42Smrg        *tmp++ = '\0';
5042f167a42Smrg    stuff->encoding = tmp;
5050e20ee16Smrg    return True;
5062f167a42Smrg BAILOUT:
5070e20ee16Smrg    ClearFontStuff(stuff);
5080e20ee16Smrg    return False;
5090e20ee16Smrg}
5100e20ee16Smrg
5110e20ee16Smrgstatic void
5120e20ee16SmrgPSSetUpForLatin1(FILE *out, PSState *state)
5130e20ee16Smrg{
5142f167a42Smrg    fprintf(out, "%s",
5152f167a42Smrg            "save\n"
5162f167a42Smrg            "/ISOLatin1Encoding where {pop save true}{false} ifelse\n"
5172f167a42Smrg            "/ISOLatin1Encoding [\n"
5182f167a42Smrg            "   /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
5192f167a42Smrg            "   /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
5202f167a42Smrg            "   /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
5212f167a42Smrg            "   /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
5222f167a42Smrg            "   /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
5232f167a42Smrg            "   /.notdef /.notdef /space /exclam /quotedbl /numbersign\n"
5242f167a42Smrg            "   /dollar /percent /ampersand /quoteright /parenleft\n"
5252f167a42Smrg            "   /parenright /asterisk /plus /comma /minus /period\n"
5262f167a42Smrg            "   /slash /zero /one /two /three /four /five /six /seven\n"
5272f167a42Smrg            "   /eight /nine /colon /semicolon /less /equal /greater\n"
5282f167a42Smrg            "   /question /at /A /B /C /D /E /F /G /H /I /J /K /L /M\n"
5292f167a42Smrg            "   /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft\n"
5302f167a42Smrg            "   /backslash /bracketright /asciicircum /underscore\n"
5312f167a42Smrg            "   /quoteleft /a /b /c /d /e /f /g /h /i /j /k /l /m\n"
5322f167a42Smrg            "   /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft\n"
5332f167a42Smrg            "   /bar /braceright /asciitilde /guilsinglright /fraction\n"
5342f167a42Smrg            "   /florin /quotesingle /quotedblleft /guilsinglleft /fi\n"
5352f167a42Smrg            "   /fl /endash /dagger /daggerdbl /bullet /quotesinglbase\n"
5362f167a42Smrg            "   /quotedblbase /quotedblright /ellipsis /trademark\n"
5372f167a42Smrg            "   /perthousand /grave /scaron /circumflex /Scaron /tilde\n"
5382f167a42Smrg            "   /breve /zcaron /dotaccent /dotlessi /Zcaron /ring\n"
5392f167a42Smrg            "   /hungarumlaut /ogonek /caron /emdash /space /exclamdown\n"
5402f167a42Smrg            "   /cent /sterling /currency /yen /brokenbar /section\n"
5412f167a42Smrg            "   /dieresis /copyright /ordfeminine /guillemotleft\n"
5422f167a42Smrg            "   /logicalnot /hyphen /registered /macron /degree\n"
5432f167a42Smrg            "   /plusminus /twosuperior /threesuperior /acute /mu\n"
5442f167a42Smrg            "   /paragraph /periodcentered /cedilla /onesuperior\n"
5452f167a42Smrg            "   /ordmasculine /guillemotright /onequarter /onehalf\n"
5462f167a42Smrg            "   /threequarters /questiondown /Agrave /Aacute\n"
5472f167a42Smrg            "   /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n"
5482f167a42Smrg            "   /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute\n"
5492f167a42Smrg            "   /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute\n"
5502f167a42Smrg            "   /Ocircumflex /Otilde /Odieresis /multiply /Oslash\n"
5512f167a42Smrg            "   /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn\n"
5522f167a42Smrg            "   /germandbls /agrave /aacute /acircumflex /atilde\n"
5532f167a42Smrg            "   /adieresis /aring /ae /ccedilla /egrave /eacute\n"
5542f167a42Smrg            "   /ecircumflex /edieresis /igrave /iacute /icircumflex\n"
5552f167a42Smrg            "   /idieresis /eth /ntilde /ograve /oacute /ocircumflex\n"
5562f167a42Smrg            "   /otilde /odieresis /divide /oslash /ugrave /uacute\n"
5572f167a42Smrg            "   /ucircumflex /udieresis /yacute /thorn /ydieresis\n"
5582f167a42Smrg            "] def {restore} if\n"
5592f167a42Smrg            "/reencodeISO-1 {\n"
5602f167a42Smrg            "    dup length dict begin\n"
5612f167a42Smrg            "        {1 index /FID ne {def}{pop pop} ifelse} forall\n"
5622f167a42Smrg            "        /Encoding ISOLatin1Encoding def\n"
5632f167a42Smrg            "        currentdict\n"
5642f167a42Smrg            "    end\n"
5652f167a42Smrg            "} def\n"
5662f167a42Smrg        );
5670e20ee16Smrg}
5680e20ee16Smrg
5690e20ee16Smrgstatic void
5702f167a42SmrgPSReencodeLatin1Font(FILE *out, const char *font)
5710e20ee16Smrg{
5722f167a42Smrg    fprintf(out, "/%s findfont reencodeISO-1\n", font);
5732f167a42Smrg    fprintf(out, "	/%s-8859-1 exch definefont pop\n", font);
5740e20ee16Smrg    return;
5750e20ee16Smrg}
5760e20ee16Smrg
5770e20ee16Smrgstatic void
5782f167a42SmrgPSSetUpFonts(FILE *out, const char *textFont, int size)
5790e20ee16Smrg{
5802f167a42Smrg    fprintf(out, "/F%d { /%s findfont exch scalefont setfont } def\n",
5812f167a42Smrg            FONT_TEXT, textFont);
5822f167a42Smrg    fprintf(out, "/F%d { /%s-8859-1 findfont exch scalefont setfont } def\n",
5832f167a42Smrg            FONT_LATIN1, textFont);
5842f167a42Smrg    fprintf(out, "/F%d { /%s findfont exch scalefont setfont } def\n",
5852f167a42Smrg            FONT_SYMBOL, "Symbol");
5862f167a42Smrg    fprintf(out, "/F%d { /%s findfont exch scalefont setfont } def\n",
5872f167a42Smrg            FONT_ISOCAPS, "IsoKeyCaps");
5880e20ee16Smrg    return;
5890e20ee16Smrg}
5900e20ee16Smrg
5910e20ee16Smrgstatic void
5920e20ee16SmrgPSSetFont(FILE *out, PSState *state, int font, int size, int pts)
5930e20ee16Smrg{
5942f167a42Smrg    if ((state->font != font) || (state->fontSize != size)) {
5952f167a42Smrg        fprintf(out, "%d %sF%d\n", size, (pts ? "pts " : ""), font);
5962f167a42Smrg        state->font = font;
5972f167a42Smrg        state->fontSize = size;
5980e20ee16Smrg    }
5990e20ee16Smrg    return;
6000e20ee16Smrg}
6010e20ee16Smrg
6020e20ee16Smrgstatic void
6030e20ee16SmrgPSProlog(FILE *out, PSState *state)
6040e20ee16Smrg{
6050e20ee16Smrg    if (!state->args->wantEPS) {
6062f167a42Smrg        fprintf(out,
6072f167a42Smrg                "%%!PS-Adobe-2.0\n"
6082f167a42Smrg                "%%%%Creator: xkbprint\n");
609e6bced22Smrg        if (state->geom->name != None) {
610e6bced22Smrg            char *a = XkbAtomGetString(state->dpy, state->geom->name);
611e6bced22Smrg            fprintf(out, "%%%%Title: %s\n", a);
612e6bced22Smrg            XFree(a);
613e6bced22Smrg        }
6142f167a42Smrg        fprintf(out,
6152f167a42Smrg                "%%%%BoundingBox: (atend)\n"
6162f167a42Smrg                "%%%%Pages: 1\n"
6172f167a42Smrg                "%%%%PageOrder: Ascend\n"
6182f167a42Smrg                "%%%%DocumentFonts: (atend)\n"
6192f167a42Smrg                "%%%%DocumentData: Clean7Bit\n"
6202f167a42Smrg                "%%%%Orientation: Landscape\n"
6212f167a42Smrg                "%%%%EndComments\n"
6222f167a42Smrg                "%%%%BeginProlog\n"
6232f167a42Smrg                "%% Resolution is 1/10mm -- need pt sizes for fonts\n"
6242f167a42Smrg                "clippath pathbbox\n"
6252f167a42Smrg                "    /ury exch def /urx exch def\n"
6262f167a42Smrg                "    /llx exch def /lly exch def\n"
6272f167a42Smrg                "    newpath\n"
6282f167a42Smrg                "/devwidth  urx llx sub def\n"
6292f167a42Smrg                "/devheight ury lly sub def\n");
6300e20ee16Smrg    }
6310e20ee16Smrg    else {
6322f167a42Smrg        int w, h;
6332f167a42Smrg        int pw, ph;
6342f167a42Smrg
6352f167a42Smrg        w = (((state->geom->width_mm * 72) / 254) * 11) / 10;
6362f167a42Smrg        h = (((state->geom->height_mm * 72) / 254) * 11) / 10;
6372f167a42Smrg        if (state->kbPerPage > 1)
6382f167a42Smrg            h *= (state->kbPerPage + 1);
6392f167a42Smrg
6402f167a42Smrg        if (w <= h) {
6412f167a42Smrg            pw = 7.5 * 72;
6422f167a42Smrg            ph = 10 * 72;
6432f167a42Smrg        }
6442f167a42Smrg        else {
6452f167a42Smrg            pw = 10 * 72;
6462f167a42Smrg            ph = 7.5 * 72;
6472f167a42Smrg        }
6482f167a42Smrg        while ((w > pw) || (h > ph)) {
6492f167a42Smrg            w = (w * 9) / 10;
6502f167a42Smrg            h = (h * 9) / 10;
6512f167a42Smrg        }
6522f167a42Smrg
6532f167a42Smrg        fprintf(out, "%%!PS-Adobe-2.0 EPSF-2.0\n");
6542f167a42Smrg        fprintf(out, "%%%%BoundingBox: 0 0 %d %d\n", w, h);
6552f167a42Smrg        fprintf(out, "%%%%Creator: xkbprint\n");
656e6bced22Smrg        if (state->geom->name != None) {
657e6bced22Smrg            char *a = XkbAtomGetString(state->dpy, state->geom->name);
658e6bced22Smrg            fprintf(out, "%%%%Title: %s\n", a);
659e6bced22Smrg            XFree(a);
660e6bced22Smrg        }
6612f167a42Smrg        fprintf(out, "%%%%Pages: 1\n");
6622f167a42Smrg        fprintf(out, "%%%%EndComments\n");
6632f167a42Smrg        fprintf(out, "%%%%BeginProlog\n");
6642f167a42Smrg        fprintf(out, "/ury 0 def /urx 0 def\n");
6652f167a42Smrg        fprintf(out, "/llx %d def /lly %d def\n", w, h);
6662f167a42Smrg        fprintf(out, "/devwidth %d def /devheight %d def\n", w, h);
6670e20ee16Smrg    }
6682f167a42Smrg    fprintf(out, "/kbdwidth %d def\n", state->geom->width_mm);
6692f167a42Smrg    fprintf(out, "/kbdheight %d def\n", state->geom->height_mm);
6702f167a42Smrg    fprintf(out, "%s",
6712f167a42Smrg            "/pts { 254 mul 72 div } def\n"
6722f167a42Smrg            "/mm10 { 72 mul 254 div } def\n"
6732f167a42Smrg            "/landscape? {\n"
6742f167a42Smrg            "	devheight devwidth gt {\n"
6752f167a42Smrg            "		/pwidth devheight def /pheight devwidth def\n"
6762f167a42Smrg            "		0 devheight translate\n"
6772f167a42Smrg            "		-90 rotate\n"
6782f167a42Smrg            "	} {\n"
6792f167a42Smrg            "		/pwidth devwidth def /pheight devheight def\n"
6802f167a42Smrg            "	} ifelse\n"
6812f167a42Smrg            "	0 pheight translate\n"
6822f167a42Smrg            "	1 -1 scale\n"
6832f167a42Smrg            "} def\n"
6842f167a42Smrg            "/centeroffset {\n"
6852f167a42Smrg            "    /S     exch def\n"
6862f167a42Smrg            "    /HEIGHT exch def\n"
6872f167a42Smrg            "    /WIDTH exch def\n"
6882f167a42Smrg            "    S stringwidth /SH exch def /SW exch def\n"
6892f167a42Smrg            "    WIDTH SW sub 2 div\n"
6902f167a42Smrg            "    HEIGHT SH sub 2 div\n"
6912f167a42Smrg            "} def\n");
6922f167a42Smrg    PSSetUpForLatin1(out, state);
6932f167a42Smrg    PSReencodeLatin1Font(out, DFLT_LABEL_FONT);
6940e20ee16Smrg    if (state->args->wantColor) {
6952f167a42Smrg        XkbGeometryPtr geom = state->geom;
6962f167a42Smrg
6978b648e79Smrg        for (int i = 0; i < geom->num_colors; i++) {
6982f167a42Smrg            PSColorDef(out, state, &geom->colors[i]);
6992f167a42Smrg        }
7002f167a42Smrg        if (state->black < 0) {
7012f167a42Smrg            XkbColorPtr color;
7022f167a42Smrg
7032f167a42Smrg            if (!(color = XkbAddGeomColor(geom, "black", geom->num_colors)))
7042f167a42Smrg                uFatalError("Couldn't allocate black color!\n");
7052f167a42Smrg            PSColorDef(out, state, color);
7062f167a42Smrg        }
7072f167a42Smrg        if (state->white < 0) {
7082f167a42Smrg            XkbColorPtr color;
7092f167a42Smrg
7102f167a42Smrg            if (!(color = XkbAddGeomColor(geom, "white", geom->num_colors)))
7112f167a42Smrg                uFatalError("Couldn't allocate white color!\n");
7122f167a42Smrg            PSColorDef(out, state, color);
7132f167a42Smrg        }
7140e20ee16Smrg    }
7158b648e79Smrg    for (int i = 0; i < state->geom->num_shapes; i++) {
7162f167a42Smrg        PSShapeDef(out, state, &state->geom->shapes[i]);
7170e20ee16Smrg    }
7182f167a42Smrg    if (state->args->label == LABEL_SYMBOLS) {
7192f167a42Smrg        PSIncludeFont(out, "IsoKeyCaps");
7200e20ee16Smrg    }
7212f167a42Smrg    PSSetUpFonts(out, DFLT_LABEL_FONT, DFLT_LABEL_FONT_SIZE);
7222f167a42Smrg    fprintf(out, "%%%%EndProlog\n");
7230e20ee16Smrg    return;
7240e20ee16Smrg}
7250e20ee16Smrg
7260e20ee16Smrgstatic void
7270e20ee16SmrgPSFileTrailer(FILE *out, PSState *state)
7280e20ee16Smrg{
7292f167a42Smrg    fprintf(out, "restore\n");
7300e20ee16Smrg    if (!state->args->wantEPS)
7312f167a42Smrg        fprintf(out, "%%%%Trailer\n");
7322f167a42Smrg    fprintf(out, "%%%%EOF\n");
7330e20ee16Smrg    return;
7340e20ee16Smrg}
7350e20ee16Smrg
7360e20ee16Smrgstatic void
7370e20ee16SmrgPSPageSetup(FILE *out, PSState *state, Bool drawBorder)
7380e20ee16Smrg{
7392f167a42Smrg    XkbGeometryPtr geom;
7400e20ee16Smrg
7412f167a42Smrg    geom = state->geom;
7422f167a42Smrg    if (state->kbPerPage == 1) {
7432f167a42Smrg        fprintf(out, "%%%%Page: %d %d\n", state->nPages + 1, state->nPages + 1);
7442f167a42Smrg        fprintf(out, "%%%%BeginPageSetup\n");
7450e20ee16Smrg    }
7462f167a42Smrg    else if ((state->nPages & 1) == 0) {        /* even page */
7472f167a42Smrg        int realPage;
7482f167a42Smrg
7492f167a42Smrg        realPage = state->nPages / 2 + 1;
7502f167a42Smrg        fprintf(out, "%%%%Page: %d %d\n", realPage, realPage);
7512f167a42Smrg        fprintf(out, "%%%%BeginPageSetup\n");
7522f167a42Smrg        fprintf(out, "%% Keyboard %d\n", state->nPages + 1);
7532f167a42Smrg        if (state->nPages == 0) {
7542f167a42Smrg            fprintf(out,
7552f167a42Smrg                    "/realwidth devwidth def\n"
7562f167a42Smrg                    "/realheight devheight def\n"
7572f167a42Smrg                    "/devheight realheight 3 div def\n");
7582f167a42Smrg        }
7592f167a42Smrg        fprintf(out, "0 devheight dup 2 div add translate\n");
7600e20ee16Smrg    }
7612f167a42Smrg    else {
7622f167a42Smrg        fprintf(out, "%% Keyboard %d\n", state->nPages + 1);
7630e20ee16Smrg    }
7642f167a42Smrg    fprintf(out, "save\n");
7652f167a42Smrg    fprintf(out, "landscape?\n");
7660e20ee16Smrg    if (state->args->scaleToFit) {
7672f167a42Smrg        fprintf(out,
7682f167a42Smrg                "%% Scale keyboard to fit on the page\n"
7692f167a42Smrg                "/kbdscale pwidth 72 sub kbdwidth div def\n"
7702f167a42Smrg                "/kbdscalewidth kbdwidth kbdscale mul def\n"
7712f167a42Smrg                "/kbdscaleheight kbdheight kbdscale mul def\n"
7722f167a42Smrg                "/kbx 36 def\n"
7732f167a42Smrg                "/kby pheight kbdscaleheight sub 2 div def\n");
7742f167a42Smrg        PSGSave(out, state);
7752f167a42Smrg        fprintf(out,
7762f167a42Smrg                "kbx kby translate\n"
7772f167a42Smrg                "kbdscale kbdscale scale\n");
7780e20ee16Smrg    }
7790e20ee16Smrg    else {
7802f167a42Smrg        fprintf(out,
7812f167a42Smrg                "%% Draw keyboard full size\n"
7822f167a42Smrg                "/kbdscale 1 def\n"
7832f167a42Smrg                "/kbdscalewidth kbdwidth mm10 def\n"
7842f167a42Smrg                "/kbdscaleheight kbdheight mm10 def\n"
7852f167a42Smrg                "/kbx pwidth kbdscalewidth sub 2 div def\n"
7862f167a42Smrg                "/kby pheight kbdscaleheight sub 2 div def\n");
7872f167a42Smrg        PSGSave(out, state);
7882f167a42Smrg        fprintf(out,
7892f167a42Smrg                "kbx kby translate\n"
7902f167a42Smrg                "72 254 div dup scale\n");
7910e20ee16Smrg    }
7920e20ee16Smrg    if (drawBorder) {
7932f167a42Smrg        if (state->args->wantColor) {
7942f167a42Smrg            PSSetColor(out, state, geom->base_color->pixel);
7952f167a42Smrg            fprintf(out, "  0   0 moveto\n");
7962f167a42Smrg            fprintf(out, "%3d   0 lineto\n", geom->width_mm);
7972f167a42Smrg            fprintf(out, "%3d %3d lineto\n", geom->width_mm, geom->height_mm);
7982f167a42Smrg            fprintf(out, "  0 %3d lineto\n", geom->height_mm);
7992f167a42Smrg            fprintf(out, "closepath fill\n");
8002f167a42Smrg        }
8012f167a42Smrg        PSSetColor(out, state, state->black);
8022f167a42Smrg        fprintf(out, "  0   0 moveto\n");
8032f167a42Smrg        fprintf(out, "%3d   0 lineto\n", geom->width_mm);
8042f167a42Smrg        fprintf(out, "%3d %3d lineto\n", geom->width_mm, geom->height_mm);
8052f167a42Smrg        fprintf(out, "  0 %3d lineto\n", geom->height_mm);
8062f167a42Smrg        fprintf(out, "closepath stroke\n");
8070e20ee16Smrg    }
8082f167a42Smrg    fprintf(out, "%%%%EndPageSetup\n");
8090e20ee16Smrg    return;
8100e20ee16Smrg}
8110e20ee16Smrg
8120e20ee16Smrgstatic void
8130e20ee16SmrgPSPageTrailer(FILE *out, PSState *state)
8140e20ee16Smrg{
8152f167a42Smrg    char *name;
8162f167a42Smrg    XkbDescPtr xkb;
8172f167a42Smrg    XkbGeometryPtr geom;
8182f167a42Smrg    XkbPropertyPtr prop;
8192f167a42Smrg    int p, baseline;
8202f167a42Smrg
8212f167a42Smrg    xkb = state->xkb;
8222f167a42Smrg    geom = state->geom;
8232f167a42Smrg    if (state->args->grid > 0) {
8242f167a42Smrg        fprintf(out, "%% Draw a %dmm grid\n", state->args->grid);
8252f167a42Smrg        fprintf(out, "0 setlinewidth\n");
8262f167a42Smrg        fprintf(out, "0.25 setgray\n");
8272f167a42Smrg        fprintf(out, " 0 %d %d {\n", state->args->grid * 10, geom->width_mm);
8282f167a42Smrg        fprintf(out, "    /GX exch def\n");
8292f167a42Smrg        fprintf(out, "    GX 0 moveto GX %d lineto stroke\n", geom->height_mm);
8302f167a42Smrg        fprintf(out, "} for\n");
8312f167a42Smrg        fprintf(out, " 0 %d %d {\n", state->args->grid * 10, geom->height_mm);
8322f167a42Smrg        fprintf(out, "    /GY exch def\n");
8332f167a42Smrg        fprintf(out, "    0 GY moveto %d GY lineto stroke\n", geom->width_mm);
8342f167a42Smrg        fprintf(out, "} for\n");
8350e20ee16Smrg    }
8362f167a42Smrg    PSGRestore(out, state);
8372f167a42Smrg    name = NULL;
8382f167a42Smrg    for (p = 0, prop = geom->properties; p < geom->num_properties; p++, prop++) {
8392f167a42Smrg        if ((prop->value != NULL) && (uStrCaseEqual(prop->name, "description"))) {
8402f167a42Smrg            name = prop->value;
8412f167a42Smrg            break;
8422f167a42Smrg        }
8430e20ee16Smrg    }
8442f167a42Smrg    if ((!state->args->wantEPS) &&
8452f167a42Smrg        ((state->kbPerPage == 1) || ((state->nPages & 1) == 1) ||
8462f167a42Smrg         (state->nPages == state->totalKB))) {
847e6bced22Smrg        char *a1 = NULL;
848e6bced22Smrg
8492f167a42Smrg        if ((name == NULL) && (geom->name != None))
850e6bced22Smrg            name = a1 = XkbAtomGetString(state->dpy, geom->name);
8512f167a42Smrg
8522f167a42Smrg        baseline = 16;
8532f167a42Smrg        if ((name != NULL) || (state->args->label == LABEL_SYMBOLS)) {
8542f167a42Smrg            PSSetColor(out, state, state->black);
8552f167a42Smrg            PSSetFont(out, state, FONT_LATIN1, 14, False);
8562f167a42Smrg        }
8572f167a42Smrg        if (state->args->label == LABEL_SYMBOLS) {
8582f167a42Smrg            char buf[40], *lbuf;
8592f167a42Smrg            const char *sName = NULL;
860e6bced22Smrg            char *a2 = NULL;
8612f167a42Smrg            Atom sAtom;
8622f167a42Smrg
8632f167a42Smrg            if (state->args->nLabelGroups == 1)
8642f167a42Smrg                snprintf(buf, sizeof(buf), "Group %d",
8652f167a42Smrg                         state->args->baseLabelGroup + 1);
8662f167a42Smrg            else
8672f167a42Smrg                snprintf(buf, sizeof(buf), "Groups %d-%d",
8682f167a42Smrg                         state->args->baseLabelGroup + 1,
8692f167a42Smrg                         state->args->baseLabelGroup +
8702f167a42Smrg                         state->args->nLabelGroups);
8712f167a42Smrg            fprintf(out, "kbx kbdscalewidth 0 (%s) centeroffset pop add\n",
8722f167a42Smrg                    buf);
8732f167a42Smrg            fprintf(out, "    kby kbdscaleheight add %d add\n", baseline);
8742f167a42Smrg            fprintf(out, "    moveto\n");
8752f167a42Smrg            fprintf(out, "1 -1 scale (%s) show 1 -1 scale\n", buf);
8762f167a42Smrg            baseline += 16;
8772f167a42Smrg
8782f167a42Smrg            if (xkb->names != NULL)
8792f167a42Smrg                sAtom = xkb->names->symbols;
8802f167a42Smrg            else
8812f167a42Smrg                sAtom = None;
8822f167a42Smrg            if (sAtom != None)
883e6bced22Smrg                sName = a2 = XkbAtomGetString(state->dpy, sAtom);
8842f167a42Smrg            if (sName == NULL)
8852f167a42Smrg                sName = "(unknown)";
8862f167a42Smrg
8872f167a42Smrg            if (asprintf(&lbuf, "Layout: %s", sName) == -1) {
8882f167a42Smrg                uFatalError("Can't allocate memory for string\n");
8892f167a42Smrg            }
8902f167a42Smrg            fprintf(out, "kbx kbdscalewidth 0 (%s) centeroffset pop add\n",
8912f167a42Smrg                    lbuf);
8922f167a42Smrg            fprintf(out, "    kby kbdscaleheight add %d add\n", baseline);
8932f167a42Smrg            fprintf(out, "    moveto\n");
8942f167a42Smrg            fprintf(out, "1 -1 scale (%s) show 1 -1 scale\n", lbuf);
8952f167a42Smrg            baseline += 16;
8962f167a42Smrg            free(lbuf);
897e6bced22Smrg            XFree(a2);
8982f167a42Smrg        }
8992f167a42Smrg        if (name != NULL) {
9002f167a42Smrg            fprintf(out, "kbx kbdscalewidth 0 (%s) centeroffset pop add\n",
9012f167a42Smrg                    name);
9022f167a42Smrg            fprintf(out, "    kby kbdscaleheight add %d add\n", baseline);
9032f167a42Smrg            fprintf(out, "    moveto\n");
9042f167a42Smrg            fprintf(out, "1 -1 scale (%s) show 1 -1 scale\n", name);
9052f167a42Smrg            baseline += 16;
906e6bced22Smrg            name = NULL;
907e6bced22Smrg            XFree(a1);
9082f167a42Smrg        }
9092f167a42Smrg        if (state->args->label == LABEL_KEYCODE) {
9102f167a42Smrg            const char *sName = NULL;
9112f167a42Smrg            char *lbuf;
912e6bced22Smrg            char *a3 = NULL;
9132f167a42Smrg            Atom sAtom;
9142f167a42Smrg
9152f167a42Smrg            if (xkb->names != NULL)
9162f167a42Smrg                sAtom = xkb->names->keycodes;
9172f167a42Smrg            else
9182f167a42Smrg                sAtom = None;
9192f167a42Smrg            if (sAtom != None)
920e6bced22Smrg                sName = a3 = XkbAtomGetString(state->dpy, sAtom);
9212f167a42Smrg            if (sName == NULL)
9222f167a42Smrg                sName = "(unknown)";
9232f167a42Smrg
9242f167a42Smrg            if (asprintf(&lbuf, "Keycodes: %s", sName) == -1) {
9252f167a42Smrg                uFatalError("Can't allocate memory for string\n");
9262f167a42Smrg            }
9272f167a42Smrg            fprintf(out, "kbx kbdscalewidth 0 (%s) centeroffset pop add\n",
9282f167a42Smrg                    lbuf);
9292f167a42Smrg            fprintf(out, "    kby kbdscaleheight add %d add\n", baseline);
9302f167a42Smrg            fprintf(out, "    moveto\n");
9312f167a42Smrg            fprintf(out, "1 -1 scale (%s) show 1 -1 scale\n", lbuf);
9322f167a42Smrg            baseline += 16;
9332f167a42Smrg            free(lbuf);
934e6bced22Smrg            XFree(a3);
9352f167a42Smrg        }
9362f167a42Smrg        if (state->args->copies > 1) {
9372f167a42Smrg            for (p = 1; p < state->args->copies; p++)
9382f167a42Smrg                fprintf(out, "copypage\n");
9392f167a42Smrg        }
9402f167a42Smrg        fprintf(out, "showpage\n");
9412f167a42Smrg        fprintf(out, "restore\n");
9422f167a42Smrg        fprintf(out, "%% Done with keyboard/page %d\n", state->nPages + 1);
9430e20ee16Smrg    }
9440e20ee16Smrg    else {
9452f167a42Smrg        if ((!state->args->wantEPS) && (state->args->label == LABEL_SYMBOLS)) {
9462f167a42Smrg            char buf[40];
9472f167a42Smrg
9482f167a42Smrg            baseline = 16;
9492f167a42Smrg            PSSetColor(out, state, state->black);
9502f167a42Smrg            PSSetFont(out, state, FONT_LATIN1, 14, False);
9512f167a42Smrg            if (state->args->nLabelGroups == 1)
9522f167a42Smrg                snprintf(buf, sizeof(buf), "Group %d",
9532f167a42Smrg                         state->args->baseLabelGroup + 1);
9542f167a42Smrg            else
9552f167a42Smrg                snprintf(buf, sizeof(buf), "Groups %d-%d",
9562f167a42Smrg                         state->args->baseLabelGroup + 1,
9572f167a42Smrg                         state->args->baseLabelGroup +
9582f167a42Smrg                         state->args->nLabelGroups + 1);
9592f167a42Smrg            fprintf(out, "kbx kbdscalewidth 0 (%s) centeroffset pop add\n",
9602f167a42Smrg                    buf);
9612f167a42Smrg            fprintf(out, "    kby kbdscaleheight add %d add\n", baseline);
9622f167a42Smrg            fprintf(out, "    moveto\n");
9632f167a42Smrg            fprintf(out, "1 -1 scale (%s) show 1 -1 scale\n", buf);
9642f167a42Smrg            baseline += 16;
9652f167a42Smrg        }
9662f167a42Smrg        fprintf(out, "restore\n");
9672f167a42Smrg        fprintf(out, "%% Done with keyboard %d\n", state->nPages + 1);
9682f167a42Smrg        fprintf(out, "0 devheight -1 mul translate %% next keyboard\n");
9690e20ee16Smrg    }
9700e20ee16Smrg    state->nPages++;
9712f167a42Smrg    state->color = state->black;
9722f167a42Smrg    state->font = -1;
9730e20ee16Smrg    return;
9740e20ee16Smrg}
9750e20ee16Smrg
9760e20ee16Smrgstatic void
9770e20ee16SmrgPSDoodad(FILE *out, PSState *state, XkbDoodadPtr doodad)
9780e20ee16Smrg{
9792f167a42Smrg    XkbDescPtr xkb;
9802f167a42Smrg    const char *name, *dname;
981e6bced22Smrg    char *a1 = NULL, *a2 = NULL;
9822f167a42Smrg    int sz, leading;
9832f167a42Smrg
9842f167a42Smrg    xkb = state->xkb;
9852f167a42Smrg    if (doodad->any.name != None)
986e6bced22Smrg        dname = a1 = XkbAtomGetString(xkb->dpy, doodad->any.name);
9872f167a42Smrg    else
9882f167a42Smrg        dname = "NoName";
9890e20ee16Smrg    switch (doodad->any.type) {
9902f167a42Smrg    case XkbOutlineDoodad:
9912f167a42Smrg    case XkbSolidDoodad:
992e6bced22Smrg        name = a2 = XkbAtomGetString(xkb->dpy,
9932f167a42Smrg                                XkbShapeDoodadShape(xkb->geom,
9942f167a42Smrg                                                    &doodad->shape)->name);
9952f167a42Smrg        if (state->args->wantColor) {
9962f167a42Smrg            PSSetColor(out, state, doodad->shape.color_ndx);
9972f167a42Smrg            if (doodad->any.type != XkbOutlineDoodad) {
9982f167a42Smrg                fprintf(out, "true %d %d %d %s %% Doodad %s\n",
9992f167a42Smrg                        doodad->shape.angle,
10002f167a42Smrg                        doodad->shape.left, doodad->shape.top, name, dname);
10012f167a42Smrg                PSSetColor(out, state, state->black);
10022f167a42Smrg            }
10032f167a42Smrg            fprintf(out, "false %d %d %d %s %% Doodad %s\n",
10042f167a42Smrg                    doodad->shape.angle,
10052f167a42Smrg                    doodad->shape.left, doodad->shape.top, name, dname);
10062f167a42Smrg        }
10072f167a42Smrg        else {
10082f167a42Smrg            fprintf(out, "false %d %d %d %s %% Doodad %s\n",
10092f167a42Smrg                    doodad->shape.angle,
10102f167a42Smrg                    doodad->shape.left, doodad->shape.top, name, dname);
10112f167a42Smrg        }
1012e6bced22Smrg        name = NULL;
1013e6bced22Smrg        XFree(a2);
10142f167a42Smrg        break;
10152f167a42Smrg    case XkbTextDoodad:
10162f167a42Smrg        fprintf(out, "%% Doodad %s\n", dname);
10172f167a42Smrg        PSSetColor(out, state, doodad->text.color_ndx);
10182f167a42Smrg        PSGSave(out, state);
10192f167a42Smrg        fprintf(out, "%d %d translate\n", doodad->text.left, doodad->text.top);
10202f167a42Smrg        if (doodad->text.angle != 0)
10212f167a42Smrg            fprintf(out, "%s rotate\n",
10222f167a42Smrg                    XkbGeomFPText(doodad->text.angle, XkbMessage));
10232f167a42Smrg        sz = 14;
10242f167a42Smrg        if (doodad->text.font) {
10252f167a42Smrg            FontStuff stuff;
10262f167a42Smrg
10272f167a42Smrg            if (CrackXLFDName(doodad->text.font, &stuff)) {
10282f167a42Smrg                if (stuff.ptSize > 0)
10292f167a42Smrg                    sz = stuff.ptSize / 10;
10302f167a42Smrg                ClearFontStuff(&stuff);
10312f167a42Smrg            }
10322f167a42Smrg        }
10332f167a42Smrg        PSSetFont(out, state, FONT_LATIN1, sz, True);
10342f167a42Smrg        leading = (sz * 12) / 10;
10352f167a42Smrg        if (strchr(doodad->text.text, '\n') == NULL) {
10362f167a42Smrg            fprintf(out, "0 %d pts moveto 1 -1 scale\n", (leading * 8) / 10);
10372f167a42Smrg            fprintf(out, "(%s) show\n", doodad->text.text);
10382f167a42Smrg        }
10392f167a42Smrg        else {
10402f167a42Smrg            char *tmp, *buf, *end;
10412f167a42Smrg            int offset = (leading * 8 / 10);
10422f167a42Smrg
10432f167a42Smrg            tmp = buf = strdup(doodad->text.text);
10442f167a42Smrg            while (tmp != NULL) {
10452f167a42Smrg                end = strchr(tmp, '\n');
10462f167a42Smrg                if (end != NULL)
10472f167a42Smrg                    *end++ = '\0';
10482f167a42Smrg                fprintf(out, "0 %d pts moveto 1 -1 scale\n", offset);
10492f167a42Smrg                fprintf(out, "(%s) show 1 -1 scale\n", tmp);
10502f167a42Smrg                offset += leading;
10512f167a42Smrg                tmp = end;
10522f167a42Smrg            }
10532f167a42Smrg            free(buf);
10542f167a42Smrg        }
10552f167a42Smrg        PSGRestore(out, state);
10562f167a42Smrg        break;
10572f167a42Smrg    case XkbIndicatorDoodad:
1058e6bced22Smrg        name = a2 = XkbAtomGetString(xkb->dpy,
10592f167a42Smrg                                XkbIndicatorDoodadShape(xkb->geom,
10602f167a42Smrg                                                        &doodad->indicator)->
10612f167a42Smrg                                name);
10622f167a42Smrg        if (state->args->wantColor) {
10632f167a42Smrg            PSSetColor(out, state, doodad->indicator.off_color_ndx);
10642f167a42Smrg            fprintf(out, "true 0 %d %d %s %% Doodad %s\n",
10652f167a42Smrg                    doodad->indicator.left, doodad->indicator.top, name, dname);
10662f167a42Smrg            PSSetColor(out, state, state->black);
10672f167a42Smrg        }
10682f167a42Smrg        fprintf(out, "false 0 %d %d %s %% Doodad %s\n",
10692f167a42Smrg                doodad->indicator.left, doodad->indicator.top, name, dname);
1070e6bced22Smrg        name = NULL;
1071e6bced22Smrg        XFree(a2);
10722f167a42Smrg        break;
10732f167a42Smrg    case XkbLogoDoodad:
1074e6bced22Smrg        name = a2 = XkbAtomGetString(xkb->dpy,
10752f167a42Smrg                                XkbLogoDoodadShape(xkb->geom,
10762f167a42Smrg                                                   &doodad->logo)->name);
10772f167a42Smrg        if (state->args->wantColor)
10782f167a42Smrg            PSSetColor(out, state, doodad->shape.color_ndx);
10792f167a42Smrg        fprintf(out, "false %d %d %d %s %% Doodad %s\n",
10802f167a42Smrg                doodad->shape.angle,
10812f167a42Smrg                doodad->shape.left, doodad->shape.top, name, dname);
1082e6bced22Smrg        name = NULL;
1083e6bced22Smrg        XFree(a2);
10842f167a42Smrg        break;
10850e20ee16Smrg    }
1086e6bced22Smrg    XFree(a1);
10870e20ee16Smrg    return;
10880e20ee16Smrg}
10890e20ee16Smrg
10900e20ee16Smrg/***====================================================================***/
10910e20ee16Smrg
10920e20ee16Smrgstatic Bool
10932f167a42SmrgPSKeycapsSymbol(KeySym sym, unsigned char *buf,
10942f167a42Smrg                int *font_rtrn, int *sz_rtrn, PSState *state)
10950e20ee16Smrg{
10962f167a42Smrg    if (state->args->wantSymbols == NO_SYMBOLS)
10972f167a42Smrg        return False;
10982f167a42Smrg
10992f167a42Smrg    if (font_rtrn != NULL)
11002f167a42Smrg        *font_rtrn = FONT_ISOCAPS;
11012f167a42Smrg    if (sz_rtrn != NULL)
11022f167a42Smrg        *sz_rtrn = SZ_LARGE;
11032f167a42Smrg    buf[1] = '\0';
11040e20ee16Smrg    switch (sym) {
11052f167a42Smrg    case XK_Shift_L:
11062f167a42Smrg    case XK_Shift_R:
11072f167a42Smrg        buf[0] = XKC_ISO_Shift;
11082f167a42Smrg        return True;
11092f167a42Smrg    case XK_Shift_Lock:
11102f167a42Smrg        buf[0] = XKC_ISO_Shift_Lock;
11112f167a42Smrg        return True;
11122f167a42Smrg    case XK_ISO_Lock:
11132f167a42Smrg        buf[0] = XKC_ISO_Caps_Lock;
11142f167a42Smrg        return True;
11152f167a42Smrg    case XK_BackSpace:
11162f167a42Smrg        buf[0] = XKC_ISO_Backspace;
11172f167a42Smrg        return True;
11182f167a42Smrg    case XK_Return:
11192f167a42Smrg        buf[0] = XKC_ISO_Return;
11202f167a42Smrg        return True;
11212f167a42Smrg    case XK_Up:
11222f167a42Smrg    case XK_KP_Up:
11232f167a42Smrg        buf[0] = XKC_ISO_Up;
11242f167a42Smrg        return True;
11252f167a42Smrg    case XK_Down:
11262f167a42Smrg    case XK_KP_Down:
11272f167a42Smrg        buf[0] = XKC_ISO_Down;
11282f167a42Smrg        return True;
11292f167a42Smrg    case XK_Left:
11302f167a42Smrg    case XK_KP_Left:
11312f167a42Smrg        buf[0] = XKC_ISO_Left;
11322f167a42Smrg        return True;
11332f167a42Smrg    case XK_Right:
11342f167a42Smrg    case XK_KP_Right:
11352f167a42Smrg        buf[0] = XKC_ISO_Right;
11362f167a42Smrg        return True;
11372f167a42Smrg    case XK_Tab:
11382f167a42Smrg        buf[0] = XKC_ISO_Tab;
11392f167a42Smrg        return True;
11402f167a42Smrg    case XK_ISO_Left_Tab:
11412f167a42Smrg        buf[0] = XKC_ISO_Left_Tab;
11422f167a42Smrg        return True;
11430e20ee16Smrg    }
11442f167a42Smrg    if (state->args->wantSymbols != ALL_SYMBOLS)
11452f167a42Smrg        return False;
11460e20ee16Smrg    switch (sym) {
11472f167a42Smrg    case XK_Caps_Lock:
11482f167a42Smrg        buf[0] = XKC_ISO_Caps_Lock;
11492f167a42Smrg        return True;
11502f167a42Smrg    case XK_Num_Lock:
11512f167a42Smrg        buf[0] = XKC_ISO_Num_Lock;
11522f167a42Smrg        return True;
11532f167a42Smrg    case XK_ISO_Level3_Shift:
11542f167a42Smrg        buf[0] = XKC_ISO_Level3_Shift;
11552f167a42Smrg        return True;
11562f167a42Smrg    case XK_ISO_Level3_Lock:
11572f167a42Smrg        buf[0] = XKC_ISO_Level3_Lock;
11582f167a42Smrg        return True;
11592f167a42Smrg    case XK_ISO_Next_Group:
11602f167a42Smrg    case XK_ISO_Group_Shift:
11612f167a42Smrg        buf[0] = XKC_ISO_Next_Group;
11622f167a42Smrg        return True;
11632f167a42Smrg    case XK_ISO_Next_Group_Lock:
11642f167a42Smrg        buf[0] = XKC_ISO_Next_Group_Lock;
11652f167a42Smrg        return True;
11662f167a42Smrg    case XK_space:
11672f167a42Smrg        buf[0] = XKC_ISO_Space;
11682f167a42Smrg        return True;
11692f167a42Smrg    case XK_nobreakspace:
11702f167a42Smrg        buf[0] = XKC_ISO_No_Break_Space;
11712f167a42Smrg        return True;
11722f167a42Smrg    case XK_Insert:
11732f167a42Smrg        buf[0] = XKC_ISO_Insert;
11742f167a42Smrg        return True;
11752f167a42Smrg    case XK_ISO_Continuous_Underline:
11762f167a42Smrg        buf[0] = XKC_ISO_Continuous_Underline;
11772f167a42Smrg        return True;
11782f167a42Smrg    case XK_ISO_Discontinuous_Underline:
11792f167a42Smrg        buf[0] = XKC_ISO_Discontinuous_Underline;
11802f167a42Smrg        return True;
11812f167a42Smrg    case XK_ISO_Emphasize:
11822f167a42Smrg        buf[0] = XKC_ISO_Emphasize;
11832f167a42Smrg        return True;
11842f167a42Smrg    case XK_Multi_key:
11852f167a42Smrg        buf[0] = XKC_ISO_Compose;
11862f167a42Smrg        return True;
11872f167a42Smrg    case XK_ISO_Center_Object:
11882f167a42Smrg        buf[0] = XKC_ISO_Center_Object;
11892f167a42Smrg        return True;
11902f167a42Smrg    case XK_Delete:
11912f167a42Smrg        buf[0] = XKC_ISO_Delete;
11922f167a42Smrg        return True;
11932f167a42Smrg    case XK_Clear:
11942f167a42Smrg        buf[0] = XKC_ISO_Clear_Screen;
11952f167a42Smrg        return True;
11962f167a42Smrg    case XK_Scroll_Lock:
11972f167a42Smrg        buf[0] = XKC_ISO_Scroll_Lock;
11982f167a42Smrg        return True;
11992f167a42Smrg    case XK_Help:
12002f167a42Smrg        buf[0] = XKC_ISO_Help;
12012f167a42Smrg        return True;
12022f167a42Smrg    case XK_Print:
12032f167a42Smrg        buf[0] = XKC_ISO_Print_Screen;
12042f167a42Smrg        return True;
12052f167a42Smrg    case XK_ISO_Enter:
12062f167a42Smrg        buf[0] = XKC_ISO_Enter;
12072f167a42Smrg        return True;
12082f167a42Smrg    case XK_Alt_L:
12092f167a42Smrg    case XK_Alt_R:
12102f167a42Smrg        buf[0] = XKC_ISO_Alt;
12112f167a42Smrg        return True;
12122f167a42Smrg    case XK_Control_L:
12132f167a42Smrg    case XK_Control_R:
12142f167a42Smrg        buf[0] = XKC_ISO_Control;
12152f167a42Smrg        return True;
12162f167a42Smrg    case XK_Pause:
12172f167a42Smrg        buf[0] = XKC_ISO_Pause;
12182f167a42Smrg        return True;
12192f167a42Smrg    case XK_Break:
12202f167a42Smrg        buf[0] = XKC_ISO_Break;
12212f167a42Smrg        return True;
12222f167a42Smrg    case XK_Escape:
12232f167a42Smrg        buf[0] = XKC_ISO_Escape;
12242f167a42Smrg        return True;
12252f167a42Smrg    case XK_Undo:
12262f167a42Smrg        buf[0] = XKC_ISO_Undo;
12272f167a42Smrg        return True;
12282f167a42Smrg    case XK_ISO_Fast_Cursor_Up:
12292f167a42Smrg        buf[0] = XKC_ISO_Fast_Cursor_Up;
12302f167a42Smrg        return True;
12312f167a42Smrg    case XK_ISO_Fast_Cursor_Down:
12322f167a42Smrg        buf[0] = XKC_ISO_Fast_Cursor_Down;
12332f167a42Smrg        return True;
12342f167a42Smrg    case XK_ISO_Fast_Cursor_Left:
12352f167a42Smrg        buf[0] = XKC_ISO_Fast_Cursor_Left;
12362f167a42Smrg        return True;
12372f167a42Smrg    case XK_ISO_Fast_Cursor_Right:
12382f167a42Smrg        buf[0] = XKC_ISO_Fast_Cursor_Right;
12392f167a42Smrg        return True;
12402f167a42Smrg    case XK_Home:
12412f167a42Smrg        buf[0] = XKC_ISO_Home;
12422f167a42Smrg        return True;
12432f167a42Smrg    case XK_End:
12442f167a42Smrg        buf[0] = XKC_ISO_End;
12452f167a42Smrg        return True;
12462f167a42Smrg    case XK_Page_Up:
12472f167a42Smrg        buf[0] = XKC_ISO_Page_Up;
12482f167a42Smrg        return True;
12492f167a42Smrg    case XK_Page_Down:
12502f167a42Smrg        buf[0] = XKC_ISO_Page_Down;
12512f167a42Smrg        return True;
12522f167a42Smrg    case XK_ISO_Move_Line_Up:
12532f167a42Smrg        buf[0] = XKC_ISO_Move_Line_Up;
12542f167a42Smrg        return True;
12552f167a42Smrg    case XK_ISO_Move_Line_Down:
12562f167a42Smrg        buf[0] = XKC_ISO_Move_Line_Down;
12572f167a42Smrg        return True;
12582f167a42Smrg    case XK_ISO_Partial_Line_Up:
12592f167a42Smrg        buf[0] = XKC_ISO_Partial_Line_Up;
12602f167a42Smrg        return True;
12612f167a42Smrg    case XK_ISO_Partial_Line_Down:
12622f167a42Smrg        buf[0] = XKC_ISO_Partial_Line_Down;
12632f167a42Smrg        return True;
12642f167a42Smrg    case XK_ISO_Partial_Space_Left:
12652f167a42Smrg        buf[0] = XKC_ISO_Partial_Space_Left;
12662f167a42Smrg        return True;
12672f167a42Smrg    case XK_ISO_Partial_Space_Right:
12682f167a42Smrg        buf[0] = XKC_ISO_Partial_Space_Right;
12692f167a42Smrg        return True;
12702f167a42Smrg    case XK_ISO_Set_Margin_Left:
12712f167a42Smrg        buf[0] = XKC_ISO_Set_Margin_Left;
12722f167a42Smrg        return True;
12732f167a42Smrg    case XK_ISO_Set_Margin_Right:
12742f167a42Smrg        buf[0] = XKC_ISO_Set_Margin_Right;
12752f167a42Smrg        return True;
12762f167a42Smrg    case XK_ISO_Release_Margin_Left:
12772f167a42Smrg        buf[0] = XKC_ISO_Release_Margin_Left;
12782f167a42Smrg        return True;
12792f167a42Smrg    case XK_ISO_Release_Margin_Right:
12802f167a42Smrg        buf[0] = XKC_ISO_Release_Margin_Right;
12812f167a42Smrg        return True;
12822f167a42Smrg    case XK_ISO_Release_Both_Margins:
12832f167a42Smrg        buf[0] = XKC_ISO_Release_Both_Margins;
12842f167a42Smrg        return True;
12852f167a42Smrg    case XK_ISO_Prev_Group:
12862f167a42Smrg        buf[0] = XKC_ISO_Prev_Group;
12872f167a42Smrg        return True;
12882f167a42Smrg    case XK_ISO_Prev_Group_Lock:
12892f167a42Smrg        buf[0] = XKC_ISO_Prev_Group_Lock;
12902f167a42Smrg        return True;
12910e20ee16Smrg    }
12920e20ee16Smrg    return False;
12930e20ee16Smrg}
12940e20ee16Smrg
12950e20ee16Smrgstatic Bool
12960e20ee16SmrgPSNonLatin1Symbol(KeySym sym, unsigned char *buf,
12972f167a42Smrg                  int *font_rtrn, int *sz_rtrn, PSState *state)
12980e20ee16Smrg{
12992f167a42Smrg    if (state->args->wantSymbols == NO_SYMBOLS)
13002f167a42Smrg        return False;
13012f167a42Smrg
13022f167a42Smrg    if (font_rtrn != NULL)
13032f167a42Smrg        *font_rtrn = FONT_TEXT;
13042f167a42Smrg    if (sz_rtrn != NULL)
13052f167a42Smrg        *sz_rtrn = SZ_LARGE;
13062f167a42Smrg    buf[1] = '\0';
13070e20ee16Smrg    switch (sym) {
13082f167a42Smrg    case XK_breve:
13092f167a42Smrg        buf[0] = 0xC6;
13102f167a42Smrg        return True;
13112f167a42Smrg    case XK_abovedot:
13122f167a42Smrg        buf[0] = 0xC7;
13132f167a42Smrg        return True;
13142f167a42Smrg    case XK_doubleacute:
13152f167a42Smrg        buf[0] = 0xCD;
13162f167a42Smrg        return True;
13172f167a42Smrg    case XK_ogonek:
13182f167a42Smrg        buf[0] = 0xCE;
13192f167a42Smrg        return True;
13202f167a42Smrg    case XK_caron:
13212f167a42Smrg        buf[0] = 0xCF;
13222f167a42Smrg        return True;
13232f167a42Smrg    case XK_Lstroke:
13242f167a42Smrg        buf[0] = 0xE8;
13252f167a42Smrg        return True;
13262f167a42Smrg    case XK_idotless:
13272f167a42Smrg        buf[0] = 0xF5;
13282f167a42Smrg        return True;
13292f167a42Smrg    case XK_lstroke:
13302f167a42Smrg        buf[0] = 0xF8;
13312f167a42Smrg        return True;
13320e20ee16Smrg    }
13332f167a42Smrg    if (font_rtrn != NULL)
13342f167a42Smrg        *font_rtrn = FONT_SYMBOL;
13352f167a42Smrg    if (sz_rtrn != NULL)
13362f167a42Smrg        *sz_rtrn = SZ_MEDIUM;
13372f167a42Smrg    if ((sym & (~0xffUL)) == 0x700) {
13382f167a42Smrg        switch (sym) {
13392f167a42Smrg            /* Greek symbol */
13402f167a42Smrg        case XK_Greek_ALPHA:
13412f167a42Smrg            buf[0] = 0x41;
13422f167a42Smrg            return True;
13432f167a42Smrg        case XK_Greek_BETA:
13442f167a42Smrg            buf[0] = 0x42;
13452f167a42Smrg            return True;
13462f167a42Smrg        case XK_Greek_CHI:
13472f167a42Smrg            buf[0] = 0x43;
13482f167a42Smrg            return True;
13492f167a42Smrg        case XK_Greek_DELTA:
13502f167a42Smrg            buf[0] = 0x44;
13512f167a42Smrg            return True;
13522f167a42Smrg        case XK_Greek_EPSILON:
13532f167a42Smrg            buf[0] = 0x45;
13542f167a42Smrg            return True;
13552f167a42Smrg        case XK_Greek_PHI:
13562f167a42Smrg            buf[0] = 0x46;
13572f167a42Smrg            return True;
13582f167a42Smrg        case XK_Greek_GAMMA:
13592f167a42Smrg            buf[0] = 0x47;
13602f167a42Smrg            return True;
13612f167a42Smrg        case XK_Greek_ETA:
13622f167a42Smrg            buf[0] = 0x48;
13632f167a42Smrg            return True;
13642f167a42Smrg        case XK_Greek_IOTA:
13652f167a42Smrg            buf[0] = 0x49;
13662f167a42Smrg            return True;
13672f167a42Smrg        case XK_Greek_KAPPA:
13682f167a42Smrg            buf[0] = 0x4B;
13692f167a42Smrg            return True;
13702f167a42Smrg        case XK_Greek_LAMDA:
13712f167a42Smrg            buf[0] = 0x4C;
13722f167a42Smrg            return True;
13732f167a42Smrg        case XK_Greek_MU:
13742f167a42Smrg            buf[0] = 0x4D;
13752f167a42Smrg            return True;
13762f167a42Smrg        case XK_Greek_NU:
13772f167a42Smrg            buf[0] = 0x4E;
13782f167a42Smrg            return True;
13792f167a42Smrg        case XK_Greek_OMICRON:
13802f167a42Smrg            buf[0] = 0x4F;
13812f167a42Smrg            return True;
13822f167a42Smrg        case XK_Greek_PI:
13832f167a42Smrg            buf[0] = 0x50;
13842f167a42Smrg            return True;
13852f167a42Smrg        case XK_Greek_THETA:
13862f167a42Smrg            buf[0] = 0x51;
13872f167a42Smrg            return True;
13882f167a42Smrg        case XK_Greek_RHO:
13892f167a42Smrg            buf[0] = 0x52;
13902f167a42Smrg            return True;
13912f167a42Smrg        case XK_Greek_SIGMA:
13922f167a42Smrg            buf[0] = 0x53;
13932f167a42Smrg            return True;
13942f167a42Smrg        case XK_Greek_TAU:
13952f167a42Smrg            buf[0] = 0x54;
13962f167a42Smrg            return True;
13972f167a42Smrg        case XK_Greek_UPSILON:
13982f167a42Smrg            buf[0] = 0x55;
13992f167a42Smrg            return True;
14002f167a42Smrg        case XK_Greek_OMEGA:
14012f167a42Smrg            buf[0] = 0x57;
14022f167a42Smrg            return True;
14032f167a42Smrg        case XK_Greek_XI:
14042f167a42Smrg            buf[0] = 0x58;
14052f167a42Smrg            return True;
14062f167a42Smrg        case XK_Greek_PSI:
14072f167a42Smrg            buf[0] = 0x59;
14082f167a42Smrg            return True;
14092f167a42Smrg        case XK_Greek_ZETA:
14102f167a42Smrg            buf[0] = 0x5A;
14112f167a42Smrg            return True;
14122f167a42Smrg
14132f167a42Smrg        case XK_Greek_alpha:
14142f167a42Smrg            buf[0] = 0x61;
14152f167a42Smrg            return True;
14162f167a42Smrg        case XK_Greek_beta:
14172f167a42Smrg            buf[0] = 0x62;
14182f167a42Smrg            return True;
14192f167a42Smrg        case XK_Greek_chi:
14202f167a42Smrg            buf[0] = 0x63;
14212f167a42Smrg            return True;
14222f167a42Smrg        case XK_Greek_delta:
14232f167a42Smrg            buf[0] = 0x64;
14242f167a42Smrg            return True;
14252f167a42Smrg        case XK_Greek_epsilon:
14262f167a42Smrg            buf[0] = 0x65;
14272f167a42Smrg            return True;
14282f167a42Smrg        case XK_Greek_phi:
14292f167a42Smrg            buf[0] = 0x66;
14302f167a42Smrg            return True;
14312f167a42Smrg        case XK_Greek_gamma:
14322f167a42Smrg            buf[0] = 0x67;
14332f167a42Smrg            return True;
14342f167a42Smrg        case XK_Greek_eta:
14352f167a42Smrg            buf[0] = 0x68;
14362f167a42Smrg            return True;
14372f167a42Smrg        case XK_Greek_iota:
14382f167a42Smrg            buf[0] = 0x69;
14392f167a42Smrg            return True;
14402f167a42Smrg        case XK_Greek_kappa:
14412f167a42Smrg            buf[0] = 0x6B;
14422f167a42Smrg            return True;
14432f167a42Smrg        case XK_Greek_lamda:
14442f167a42Smrg            buf[0] = 0x6C;
14452f167a42Smrg            return True;
14462f167a42Smrg        case XK_Greek_mu:
14472f167a42Smrg            buf[0] = 0x6D;
14482f167a42Smrg            return True;
14492f167a42Smrg        case XK_Greek_nu:
14502f167a42Smrg            buf[0] = 0x6E;
14512f167a42Smrg            return True;
14522f167a42Smrg        case XK_Greek_omicron:
14532f167a42Smrg            buf[0] = 0x6F;
14542f167a42Smrg            return True;
14552f167a42Smrg        case XK_Greek_pi:
14562f167a42Smrg            buf[0] = 0x70;
14572f167a42Smrg            return True;
14582f167a42Smrg        case XK_Greek_theta:
14592f167a42Smrg            buf[0] = 0x71;
14602f167a42Smrg            return True;
14612f167a42Smrg        case XK_Greek_rho:
14622f167a42Smrg            buf[0] = 0x72;
14632f167a42Smrg            return True;
14642f167a42Smrg        case XK_Greek_sigma:
14652f167a42Smrg            buf[0] = 0x73;
14662f167a42Smrg            return True;
14672f167a42Smrg        case XK_Greek_tau:
14682f167a42Smrg            buf[0] = 0x74;
14692f167a42Smrg            return True;
14702f167a42Smrg        case XK_Greek_upsilon:
14712f167a42Smrg            buf[0] = 0x75;
14722f167a42Smrg            return True;
14732f167a42Smrg        case XK_Greek_omega:
14742f167a42Smrg            buf[0] = 0x77;
14752f167a42Smrg            return True;
14762f167a42Smrg        case XK_Greek_xi:
14772f167a42Smrg            buf[0] = 0x78;
14782f167a42Smrg            return True;
14792f167a42Smrg        case XK_Greek_psi:
14802f167a42Smrg            buf[0] = 0x79;
14812f167a42Smrg            return True;
14822f167a42Smrg        case XK_Greek_zeta:
14832f167a42Smrg            buf[0] = 0x7A;
14842f167a42Smrg            return True;
14852f167a42Smrg        }
14860e20ee16Smrg    }
14870e20ee16Smrg    switch (sym) {
14882f167a42Smrg    case XK_leftarrow:
14892f167a42Smrg        buf[0] = 0xAC;
14902f167a42Smrg        return True;
14912f167a42Smrg    case XK_uparrow:
14922f167a42Smrg        buf[0] = 0xAD;
14932f167a42Smrg        return True;
14942f167a42Smrg    case XK_rightarrow:
14952f167a42Smrg        buf[0] = 0xAE;
14962f167a42Smrg        return True;
14972f167a42Smrg    case XK_downarrow:
14982f167a42Smrg        buf[0] = 0xAF;
14992f167a42Smrg        return True;
15002f167a42Smrg    case XK_horizconnector:
15012f167a42Smrg        buf[0] = 0xBE;
15022f167a42Smrg        return True;
15032f167a42Smrg    case XK_trademark:
15042f167a42Smrg        buf[0] = 0xE4;
15052f167a42Smrg        return True;
15060e20ee16Smrg    }
15070e20ee16Smrg    return False;
15080e20ee16Smrg}
15090e20ee16Smrg
15100e20ee16Smrgstatic KeySym
15110e20ee16SmrgCheckSymbolAlias(KeySym sym, PSState *state)
15120e20ee16Smrg{
15130e20ee16Smrg    if (XkbKSIsKeypad(sym)) {
15142f167a42Smrg        if ((sym >= XK_KP_0) && (sym <= XK_KP_9))
15152f167a42Smrg            sym = (sym - XK_KP_0) + XK_0;
15162f167a42Smrg        else
15172f167a42Smrg            switch (sym) {
15182f167a42Smrg            case XK_KP_Space:
15192f167a42Smrg                return XK_space;
15202f167a42Smrg            case XK_KP_Tab:
15212f167a42Smrg                return XK_Tab;
15222f167a42Smrg            case XK_KP_Enter:
15232f167a42Smrg                return XK_Return;
15242f167a42Smrg            case XK_KP_F1:
15252f167a42Smrg                return XK_F1;
15262f167a42Smrg            case XK_KP_F2:
15272f167a42Smrg                return XK_F2;
15282f167a42Smrg            case XK_KP_F3:
15292f167a42Smrg                return XK_F3;
15302f167a42Smrg            case XK_KP_F4:
15312f167a42Smrg                return XK_F4;
15322f167a42Smrg            case XK_KP_Home:
15332f167a42Smrg                return XK_Home;
15342f167a42Smrg            case XK_KP_Left:
15352f167a42Smrg                return XK_Left;
15362f167a42Smrg            case XK_KP_Up:
15372f167a42Smrg                return XK_Up;
15382f167a42Smrg            case XK_KP_Right:
15392f167a42Smrg                return XK_Right;
15402f167a42Smrg            case XK_KP_Down:
15412f167a42Smrg                return XK_Down;
15422f167a42Smrg            case XK_KP_Page_Up:
15432f167a42Smrg                return XK_Page_Up;
15442f167a42Smrg            case XK_KP_Page_Down:
15452f167a42Smrg                return XK_Page_Down;
15462f167a42Smrg            case XK_KP_End:
15472f167a42Smrg                return XK_End;
15482f167a42Smrg            case XK_KP_Begin:
15492f167a42Smrg                return XK_Begin;
15502f167a42Smrg            case XK_KP_Insert:
15512f167a42Smrg                return XK_Insert;
15522f167a42Smrg            case XK_KP_Delete:
15532f167a42Smrg                return XK_Delete;
15542f167a42Smrg            case XK_KP_Equal:
15552f167a42Smrg                return XK_equal;
15562f167a42Smrg            case XK_KP_Multiply:
15572f167a42Smrg                return XK_asterisk;
15582f167a42Smrg            case XK_KP_Add:
15592f167a42Smrg                return XK_plus;
15602f167a42Smrg            case XK_KP_Subtract:
15612f167a42Smrg                return XK_minus;
15622f167a42Smrg            case XK_KP_Divide:
15632f167a42Smrg                return XK_slash;
15642f167a42Smrg            }
15650e20ee16Smrg    }
15660e20ee16Smrg    else if (XkbKSIsDeadKey(sym)) {
15672f167a42Smrg        switch (sym) {
15682f167a42Smrg        case XK_dead_grave:
15692f167a42Smrg            sym = XK_grave;
15702f167a42Smrg            break;
15712f167a42Smrg        case XK_dead_acute:
15722f167a42Smrg            sym = XK_acute;
15732f167a42Smrg            break;
15742f167a42Smrg        case XK_dead_circumflex:
15752f167a42Smrg            sym = XK_asciicircum;
15762f167a42Smrg            break;
15772f167a42Smrg        case XK_dead_tilde:
15782f167a42Smrg            sym = XK_asciitilde;
15792f167a42Smrg            break;
15802f167a42Smrg        case XK_dead_macron:
15812f167a42Smrg            sym = XK_macron;
15822f167a42Smrg            break;
15832f167a42Smrg        case XK_dead_breve:
15842f167a42Smrg            sym = XK_breve;
15852f167a42Smrg            break;
15862f167a42Smrg        case XK_dead_abovedot:
15872f167a42Smrg            sym = XK_abovedot;
15882f167a42Smrg            break;
15892f167a42Smrg        case XK_dead_diaeresis:
15902f167a42Smrg            sym = XK_diaeresis;
15912f167a42Smrg            break;
15922f167a42Smrg        case XK_dead_abovering:
15932f167a42Smrg            sym = XK_degree;
15942f167a42Smrg            break;
15952f167a42Smrg        case XK_dead_doubleacute:
15962f167a42Smrg            sym = XK_doubleacute;
15972f167a42Smrg            break;
15982f167a42Smrg        case XK_dead_caron:
15992f167a42Smrg            sym = XK_caron;
16002f167a42Smrg            break;
16012f167a42Smrg        case XK_dead_cedilla:
16022f167a42Smrg            sym = XK_cedilla;
16032f167a42Smrg            break;
16042f167a42Smrg        case XK_dead_ogonek:
16052f167a42Smrg            sym = XK_ogonek;
16062f167a42Smrg            break;
16072f167a42Smrg        case XK_dead_iota:
16082f167a42Smrg            sym = XK_Greek_iota;
16092f167a42Smrg            break;
16102f167a42Smrg        case XK_dead_voiced_sound:
16112f167a42Smrg            sym = XK_voicedsound;
16122f167a42Smrg            break;
16132f167a42Smrg        case XK_dead_semivoiced_sound:
16142f167a42Smrg            sym = XK_semivoicedsound;
16152f167a42Smrg            break;
16162f167a42Smrg        }
16170e20ee16Smrg    }
16180e20ee16Smrg    return sym;
16190e20ee16Smrg}
16200e20ee16Smrg
16210e20ee16Smrgstatic Bool
16220e20ee16SmrgFindKeysymsByName(XkbDescPtr xkb, char *name, PSState *state, KeyTop *top)
16230e20ee16Smrg{
16242f167a42Smrg    static unsigned char buf[30];
16252f167a42Smrg    int kc;
16262f167a42Smrg    KeySym sym, *syms, topSyms[NLABELS];
16272f167a42Smrg    int level, group;
16288b648e79Smrg    int eG, nG, gI;
16292f167a42Smrg
16302f167a42Smrg    bzero(top, sizeof(KeyTop));
16312f167a42Smrg    kc = XkbFindKeycodeByName(xkb, name, True);
16322f167a42Smrg    if (state->args != NULL) {
16332f167a42Smrg        level = state->args->labelLevel;
16342f167a42Smrg        group = state->args->baseLabelGroup;
16350e20ee16Smrg    }
16362f167a42Smrg    else
16372f167a42Smrg        level = group = 0;
16382f167a42Smrg    syms = XkbKeySymsPtr(xkb, kc);
16392f167a42Smrg    eG = group;
16402f167a42Smrg    nG = XkbKeyNumGroups(xkb, kc);
16412f167a42Smrg    gI = XkbKeyGroupInfo(xkb, kc);
16428b648e79Smrg    if ((state->args != NULL) && (state->args->wantDiffs) &&
16438b648e79Smrg        (eG >= XkbKeyNumGroups(xkb, kc)))
16442f167a42Smrg        return False;           /* XXX was a return with no value */
16452f167a42Smrg    if (nG == 0) {
16462f167a42Smrg        return False;
16470e20ee16Smrg    }
16482f167a42Smrg    else if (nG == 1) {
16492f167a42Smrg        eG = 0;
16500e20ee16Smrg    }
16512f167a42Smrg    else if (eG >= XkbKeyNumGroups(xkb, kc)) {
16522f167a42Smrg        switch (XkbOutOfRangeGroupAction(gI)) {
16532f167a42Smrg        default:
16542f167a42Smrg            eG %= nG;
16552f167a42Smrg            break;
16562f167a42Smrg        case XkbClampIntoRange:
16572f167a42Smrg            eG = nG - 1;
16582f167a42Smrg            break;
16592f167a42Smrg        case XkbRedirectIntoRange:
16602f167a42Smrg            eG = XkbOutOfRangeGroupNumber(gI);
16612f167a42Smrg            if (eG >= nG)
16622f167a42Smrg                eG = 0;
16632f167a42Smrg            break;
16642f167a42Smrg        }
16650e20ee16Smrg    }
16668b648e79Smrg    for (int g = 0; g < state->args->nLabelGroups; g++) {
16672f167a42Smrg        if ((eG + g) >= nG)
16682f167a42Smrg            continue;
16698b648e79Smrg        for (int l = 0; l < 2; l++) {
16702f167a42Smrg            int font, sz;
16712f167a42Smrg
16722f167a42Smrg            if (level + l >= XkbKeyGroupWidth(xkb, kc, (eG + g)))
16732f167a42Smrg                continue;
16742f167a42Smrg            sym = syms[((eG + g) * XkbKeyGroupsWidth(xkb, kc)) + (level + l)];
16752f167a42Smrg
16762f167a42Smrg            if (state->args->wantSymbols != NO_SYMBOLS)
16772f167a42Smrg                sym = CheckSymbolAlias(sym, state);
16782f167a42Smrg            topSyms[(g * 2) + l] = sym;
16792f167a42Smrg
16802f167a42Smrg            if (PSKeycapsSymbol(sym, buf, &font, &sz, state)) {
16812f167a42Smrg                top->font[(g * 2) + l] = font;
16822f167a42Smrg                top->size[(g * 2) + l] = sz;
16832f167a42Smrg            }
16842f167a42Smrg            else if (((sym & (~0xffUL)) == 0) && isprint(sym) && (!isspace(sym))) {
16852f167a42Smrg                if (sym == '(')
16862f167a42Smrg                    snprintf((char *) buf, sizeof(buf), "\\(");
16872f167a42Smrg                else if (sym == ')')
16882f167a42Smrg                    snprintf((char *) buf, sizeof(buf), "\\)");
16892f167a42Smrg                else if (sym == '\\')
16902f167a42Smrg                    snprintf((char *) buf, sizeof(buf), "\\\\");
16912f167a42Smrg                else
16922f167a42Smrg                    snprintf((char *) buf, sizeof(buf), "%c", (char) sym);
16932f167a42Smrg                top->font[(g * 2) + l] = FONT_LATIN1;
16942f167a42Smrg                top->size[(g * 2) + l] = SZ_MEDIUM;
16952f167a42Smrg                switch (buf[0]) {
16962f167a42Smrg                case '.':
16972f167a42Smrg                case ':':
16982f167a42Smrg                case ',':
16992f167a42Smrg                case ';':
17002f167a42Smrg                case '\'':
17012f167a42Smrg                case '"':
17022f167a42Smrg                case '`':
17032f167a42Smrg                case '~':
17042f167a42Smrg                case '^':
17052f167a42Smrg                case 0250:
17062f167a42Smrg                case 0270:
17072f167a42Smrg                case 0267:
17082f167a42Smrg                case 0260:
17092f167a42Smrg                case 0252:
17102f167a42Smrg                case 0272:
17112f167a42Smrg                case 0271:
17122f167a42Smrg                case 0262:
17132f167a42Smrg                case 0263:
17142f167a42Smrg                case 0264:
17152f167a42Smrg                case 0255:
17162f167a42Smrg                case 0254:
17172f167a42Smrg                case 0257:
17182f167a42Smrg                    top->size[(g * 2) + l] = SZ_LARGE;
17192f167a42Smrg                    break;
17202f167a42Smrg                }
17212f167a42Smrg            }
17222f167a42Smrg            else if (PSNonLatin1Symbol(sym, buf, &font, &sz, state)) {
17232f167a42Smrg                top->font[(g * 2) + l] = font;
17242f167a42Smrg                top->size[(g * 2) + l] = sz;
17252f167a42Smrg            }
17262f167a42Smrg            else {
17272f167a42Smrg                char *tmp;
17282f167a42Smrg
17292f167a42Smrg                tmp = XKeysymToString(sym);
17302f167a42Smrg                if (tmp != NULL)
17312f167a42Smrg                    strcpy((char *) buf, tmp);
17322f167a42Smrg                else
17332f167a42Smrg                    snprintf((char *) buf, sizeof(buf), "(%ld)", sym);
17342f167a42Smrg                top->font[(g * 2) + l] = FONT_LATIN1;
17352f167a42Smrg                if (strlen((char *) buf) < 9)
17362f167a42Smrg                    top->size[(g * 2) + l] = SZ_SMALL;
17372f167a42Smrg                else
17382f167a42Smrg                    top->size[(g * 2) + l] = SZ_TINY;
17392f167a42Smrg            }
17402f167a42Smrg            top->present |= (1 << ((g * 2) + l));
17412f167a42Smrg            strncpy(top->label[(g * 2) + l], (char *) buf, LABEL_LEN - 1);
17422f167a42Smrg            top->label[(g * 2) + l][LABEL_LEN - 1] = '\0';
17432f167a42Smrg        }
17442f167a42Smrg        if (((g == 0) && (top->present & G1LX_MASK) == G1LX_MASK) ||
17452f167a42Smrg            ((g == 1) && (top->present & G2LX_MASK) == G2LX_MASK)) {
17462f167a42Smrg            KeySym lower, upper;
17472f167a42Smrg
17482f167a42Smrg            XConvertCase(topSyms[(g * 2)], &lower, &upper);
17492f167a42Smrg            if ((topSyms[(g * 2)] == lower) && (topSyms[(g * 2) + 1] == upper)) {
17502f167a42Smrg                top->alpha[g] = True;
17512f167a42Smrg            }
17522f167a42Smrg        }
17530e20ee16Smrg    }
17540e20ee16Smrg    return True;
17550e20ee16Smrg}
17560e20ee16Smrg
17570e20ee16Smrgstatic void
17582f167a42SmrgPSDrawLabel(FILE *out, const char *label, int x, int y, int w, int h)
17590e20ee16Smrg{
17602f167a42Smrg    fprintf(out, "%d %d (%s) centeroffset\n", w, h, label);
17612f167a42Smrg    fprintf(out, "%d add exch\n", y);
17622f167a42Smrg    fprintf(out, "%d add exch moveto\n", x);
17632f167a42Smrg    fprintf(out, "1 -1 scale (%s) show 1 -1 scale\n", label);
17640e20ee16Smrg    return;
17650e20ee16Smrg}
17660e20ee16Smrg
17670e20ee16Smrg#define	TOP_ROW		0
17680e20ee16Smrg#define	BOTTOM_ROW	1
17690e20ee16Smrg#define	CENTER_ROW	2
17700e20ee16Smrg
17710e20ee16Smrg#define	LEFT_COL	0
17720e20ee16Smrg#define	RIGHT_COL	1
17730e20ee16Smrg#define	CENTER_COL	2
17740e20ee16Smrg
17750e20ee16Smrgstatic void
17760e20ee16SmrgPSLabelKey(FILE *out, PSState *state, KeyTop *top, int x, int y,
17772f167a42Smrg           XkbBoundsPtr bounds, int kc, int btm)
17780e20ee16Smrg{
17798b648e79Smrg    int w, h;
17802f167a42Smrg    int row_y[3];
17812f167a42Smrg    int col_x[3];
17822f167a42Smrg    int row_h[3];
17832f167a42Smrg    int col_w[3];
17842f167a42Smrg    Bool present[NLABELS];
17852f167a42Smrg    int sym_row[NLABELS];
17862f167a42Smrg    int sym_col[NLABELS];
17872f167a42Smrg
17882f167a42Smrg    w = XkbBoundsWidth(bounds);
17892f167a42Smrg    h = XkbBoundsHeight(bounds);
17902f167a42Smrg    row_y[TOP_ROW] = y + bounds->y1 + (h / 10);
17912f167a42Smrg    row_y[BOTTOM_ROW] = y + bounds->y1 + (h / 2) + (h / 10);
17922f167a42Smrg    row_y[CENTER_ROW] = y + bounds->y1 + (h / 10);
17932f167a42Smrg    row_h[TOP_ROW] = h / 2;
17942f167a42Smrg    row_h[BOTTOM_ROW] = h / 2;
17952f167a42Smrg    row_h[CENTER_ROW] = h;
17962f167a42Smrg
17972f167a42Smrg    col_x[LEFT_COL] = x + bounds->x1;
17982f167a42Smrg    col_x[RIGHT_COL] = x + bounds->x1 + w / 2;
17992f167a42Smrg    col_x[CENTER_COL] = x + bounds->x1;
18002f167a42Smrg    col_w[LEFT_COL] = w / 2;
18012f167a42Smrg    col_w[RIGHT_COL] = w / 2;
18022f167a42Smrg    col_w[CENTER_COL] = w;
18032f167a42Smrg
18042f167a42Smrg    present[G1L1] = False;
18052f167a42Smrg    sym_row[G1L1] = BOTTOM_ROW;
18062f167a42Smrg    sym_col[G1L1] = LEFT_COL;
18072f167a42Smrg
18082f167a42Smrg    present[G1L2] = False;
18092f167a42Smrg    sym_row[G1L2] = TOP_ROW;
18102f167a42Smrg    sym_col[G1L2] = LEFT_COL;
18112f167a42Smrg
18122f167a42Smrg    present[G2L1] = False;
18132f167a42Smrg    sym_row[G2L1] = BOTTOM_ROW;
18142f167a42Smrg    sym_col[G2L1] = RIGHT_COL;
18152f167a42Smrg
18162f167a42Smrg    present[G2L2] = False;
18172f167a42Smrg    sym_row[G2L2] = TOP_ROW;
18182f167a42Smrg    sym_col[G2L2] = RIGHT_COL;
18192f167a42Smrg
18202f167a42Smrg    present[CENTER] = False;
18212f167a42Smrg    sym_row[CENTER] = CENTER_ROW;
18222f167a42Smrg    sym_col[CENTER] = CENTER_COL;
18232f167a42Smrg
18242f167a42Smrg    if (top->present & CENTER_MASK) {
18252f167a42Smrg        present[CENTER] = True;
18260e20ee16Smrg    }
18272f167a42Smrg    else
18282f167a42Smrg        switch (top->present & GXLX_MASK) {
18292f167a42Smrg        case G1L1_MASK:
18302f167a42Smrg            present[G1L1] = True;
18312f167a42Smrg            sym_row[G1L1] = CENTER_ROW;
18322f167a42Smrg            sym_col[G1L1] = CENTER_COL;
18332f167a42Smrg            break;
18342f167a42Smrg        case G1LX_MASK:
18352f167a42Smrg            present[G1L2] = True;
18362f167a42Smrg            if (!top->alpha[0]) {
18372f167a42Smrg                present[G1L1] = True;
18382f167a42Smrg                if ((strlen(top->label[G1L1]) > 1) &&
18392f167a42Smrg                    (top->label[G1L1][0] != '\\'))
18402f167a42Smrg                    sym_col[G1L1] = CENTER_COL;
18412f167a42Smrg                if ((strlen(top->label[G1L2]) > 1) &&
18422f167a42Smrg                    (top->label[G1L1][0] != '\\'))
18432f167a42Smrg                    sym_col[G1L2] = CENTER_COL;
18442f167a42Smrg            }
18452f167a42Smrg            break;
18462f167a42Smrg        default:
18472f167a42Smrg            if ((top->present & G1LX_MASK) == G1LX_MASK) {
18482f167a42Smrg                present[G1L2] = True;
18492f167a42Smrg                if (!top->alpha[0])
18502f167a42Smrg                    present[G1L1] = True;
18512f167a42Smrg            }
18522f167a42Smrg            else if ((top->present & G1LX_MASK) == G1L1_MASK) {
18532f167a42Smrg                present[G1L1] = True;
18542f167a42Smrg            }
18552f167a42Smrg            else if ((top->present & G1LX_MASK) == G1L2_MASK) {
18562f167a42Smrg                present[G1L2] = True;
18572f167a42Smrg            }
18582f167a42Smrg            if ((top->present & G2LX_MASK) == G2LX_MASK) {
18592f167a42Smrg                present[G2L2] = True;
18602f167a42Smrg                if (!top->alpha[1])
18612f167a42Smrg                    present[G2L1] = True;
18622f167a42Smrg            }
18632f167a42Smrg            else if ((top->present & G2LX_MASK) == G2L1_MASK) {
18642f167a42Smrg                present[G2L1] = True;
18652f167a42Smrg            }
18662f167a42Smrg            else if ((top->present & G2LX_MASK) == G2L2_MASK) {
18672f167a42Smrg                present[G2L2] = True;
18682f167a42Smrg            }
18692f167a42Smrg            break;
18702f167a42Smrg        case 0:
18712f167a42Smrg            return;
18722f167a42Smrg        }
18738b648e79Smrg    for (int i = 0; i < NLABELS; i++) {
18742f167a42Smrg        if (present[i]) {
18752f167a42Smrg            int size;
18762f167a42Smrg
18772f167a42Smrg            if (top->size[i] == SZ_AUTO) {
18782f167a42Smrg                size_t len = strlen(top->label[i]);
18792f167a42Smrg                if (len == 1) {
18802f167a42Smrg                    if (top->font[i] == FONT_ISOCAPS)
18812f167a42Smrg                        size = 18;
18822f167a42Smrg                    else
18832f167a42Smrg                        size = 14;
18842f167a42Smrg                }
18852f167a42Smrg                else if (len < 10)
18862f167a42Smrg                    size = 12;
18872f167a42Smrg                else
18882f167a42Smrg                    size = 10;
18892f167a42Smrg            }
18902f167a42Smrg            else if (top->size[i] == SZ_TINY)
18912f167a42Smrg                size = 10;
18922f167a42Smrg            else if (top->size[i] == SZ_SMALL)
18932f167a42Smrg                size = 12;
18942f167a42Smrg            else if (top->size[i] == SZ_LARGE)
18952f167a42Smrg                size = 18;
18962f167a42Smrg            else if (top->size[i] == SZ_XLARGE)
18972f167a42Smrg                size = 24;
18982f167a42Smrg            else
18992f167a42Smrg                size = 14;
19002f167a42Smrg            PSSetFont(out, state, top->font[i], size, True);
19012f167a42Smrg            PSDrawLabel(out, top->label[i], col_x[sym_col[i]],
19022f167a42Smrg                        row_y[sym_row[i]], col_w[sym_col[i]],
19032f167a42Smrg                        row_h[sym_row[i]]);
19042f167a42Smrg        }
19050e20ee16Smrg    }
19060e20ee16Smrg    if (state->args->wantKeycodes) {
19072f167a42Smrg        char keycode[10];
19082f167a42Smrg
19092f167a42Smrg        snprintf(keycode, sizeof(keycode), "%d", kc);
19102f167a42Smrg        PSSetFont(out, state, FONT_LATIN1, 8, True);
19112f167a42Smrg        PSDrawLabel(out, keycode, x + bounds->x1, y + btm - 5, w, 0);
19120e20ee16Smrg    }
19130e20ee16Smrg    return;
19140e20ee16Smrg}
19150e20ee16Smrg
19160e20ee16Smrgstatic void
19170e20ee16SmrgPSSection(FILE *out, PSState *state, XkbSectionPtr section)
19180e20ee16Smrg{
19192f167a42Smrg    int r, offset;
19202f167a42Smrg    XkbRowPtr row;
19212f167a42Smrg    Display *dpy;
19222f167a42Smrg    XkbDescPtr xkb;
19232f167a42Smrg
19242f167a42Smrg    xkb = state->xkb;
19252f167a42Smrg    dpy = xkb->dpy;
1926e6bced22Smrg    {
1927e6bced22Smrg        const char *section_name;
1928e6bced22Smrg        char *atom_name = NULL;
1929e6bced22Smrg
1930e6bced22Smrg        if (section->name != None)
1931e6bced22Smrg            section_name = atom_name = XkbAtomGetString(dpy, section->name);
1932e6bced22Smrg        else
1933e6bced22Smrg            section_name = "NoName";
1934e6bced22Smrg        fprintf(out, "%% Begin Section '%s'\n", section_name);
1935e6bced22Smrg        XFree(atom_name);
1936e6bced22Smrg    }
19372f167a42Smrg    PSGSave(out, state);
19382f167a42Smrg    fprintf(out, "%d %d translate\n", section->left, section->top);
19392f167a42Smrg    if (section->angle != 0)
19402f167a42Smrg        fprintf(out, "%s rotate\n", XkbGeomFPText(section->angle, XkbMessage));
19410e20ee16Smrg    if (section->doodads) {
19422f167a42Smrg        XkbDrawablePtr first, draw;
19432f167a42Smrg
19442f167a42Smrg        first = draw = XkbGetOrderedDrawables(NULL, section);
19452f167a42Smrg        while (draw) {
19462f167a42Smrg            if (draw->type == XkbDW_Section)
19472f167a42Smrg                PSSection(out, state, draw->u.section);
19482f167a42Smrg            else
19492f167a42Smrg                PSDoodad(out, state, draw->u.doodad);
19502f167a42Smrg            draw = draw->next;
19512f167a42Smrg        }
19522f167a42Smrg        XkbFreeOrderedDrawables(first);
19530e20ee16Smrg    }
19542f167a42Smrg    for (r = 0, row = section->rows; r < section->num_rows; r++, row++) {
19552f167a42Smrg        int k;
19562f167a42Smrg        XkbKeyPtr key;
19572f167a42Smrg
19582f167a42Smrg        if (row->vertical)
19592f167a42Smrg            offset = row->top;
19602f167a42Smrg        else
19612f167a42Smrg            offset = row->left;
19622f167a42Smrg        fprintf(out, "%% Begin %s %d\n", row->vertical ? "column" : "row",
19632f167a42Smrg                r + 1);
19642f167a42Smrg        for (k = 0, key = row->keys; k < row->num_keys; k++, key++) {
1965e6bced22Smrg            XkbShapePtr shape = XkbKeyShape(xkb->geom, key);
1966e6bced22Smrg            char *shape_name  = XkbAtomGetString(dpy, shape->name);
1967e6bced22Smrg
19682f167a42Smrg            offset += key->gap;
19692f167a42Smrg            if (row->vertical) {
19702f167a42Smrg                if (state->args->wantColor) {
19712f167a42Smrg                    if (key->color_ndx != state->white) {
19722f167a42Smrg                        PSSetColor(out, state, key->color_ndx);
19732f167a42Smrg                        fprintf(out, "true 0 %d %d %s %% %s\n",
1974e6bced22Smrg                                row->left, offset, shape_name,
19752f167a42Smrg                                XkbKeyNameText(key->name.name, XkbMessage));
19762f167a42Smrg                    }
19772f167a42Smrg                    PSSetColor(out, state, state->black);
19782f167a42Smrg                }
19792f167a42Smrg                fprintf(out, "false 0 %d %d %s %% %s\n", row->left, offset,
1980e6bced22Smrg                        shape_name,
19812f167a42Smrg                        XkbKeyNameText(key->name.name, XkbMessage));
19822f167a42Smrg                offset += shape->bounds.y2;
19832f167a42Smrg            }
19842f167a42Smrg            else {
19852f167a42Smrg                if (state->args->wantColor) {
19862f167a42Smrg                    if (key->color_ndx != state->white) {
19872f167a42Smrg                        PSSetColor(out, state, key->color_ndx);
19882f167a42Smrg                        fprintf(out, "true 0 %d %d %s %% %s\n", offset,
1989e6bced22Smrg                                row->top, shape_name,
19902f167a42Smrg                                XkbKeyNameText(key->name.name, XkbMessage));
19912f167a42Smrg                    }
19922f167a42Smrg                    PSSetColor(out, state, state->black);
19932f167a42Smrg                }
19942f167a42Smrg                fprintf(out, "false 0 %d %d %s %% %s\n", offset, row->top,
1995e6bced22Smrg                        shape_name,
19962f167a42Smrg                        XkbKeyNameText(key->name.name, XkbMessage));
19972f167a42Smrg                offset += shape->bounds.x2;
19982f167a42Smrg            }
1999e6bced22Smrg            XFree(shape_name);
20002f167a42Smrg        }
20010e20ee16Smrg    }
20022f167a42Smrg    for (r = 0, row = section->rows; r < section->num_rows; r++, row++) {
20032f167a42Smrg        int k, kc = 0;
20042f167a42Smrg        XkbKeyPtr key;
20052f167a42Smrg
20062f167a42Smrg        if (state->args->label == LABEL_NONE)
20072f167a42Smrg            break;
20082f167a42Smrg        if (row->vertical)
20092f167a42Smrg            offset = row->top;
20102f167a42Smrg        else
20112f167a42Smrg            offset = row->left;
20122f167a42Smrg        fprintf(out, "%% Begin %s %d labels\n",
20132f167a42Smrg                row->vertical ? "column" : "row", r + 1);
20142f167a42Smrg        PSSetColor(out, state, xkb->geom->label_color->pixel);
20152f167a42Smrg        PSSetFont(out, state, FONT_LATIN1, 12, True);
20162f167a42Smrg        for (k = 0, key = row->keys; k < row->num_keys; k++, key++) {
20172f167a42Smrg            char *name, *name2, buf[30], buf2[30];
20182f167a42Smrg            int x, y;
20192f167a42Smrg            KeyTop top;
20208b648e79Smrg            XkbShapePtr shape;
20218b648e79Smrg            XkbBoundsRec bounds;
20222f167a42Smrg
20232f167a42Smrg            shape = XkbKeyShape(xkb->geom, key);
20242f167a42Smrg            XkbComputeShapeTop(shape, &bounds);
20252f167a42Smrg            offset += key->gap;
20262f167a42Smrg            name = name2 = NULL;
20272f167a42Smrg            if (state->args->label == LABEL_SYMBOLS) {
20282f167a42Smrg                if (!FindKeysymsByName(xkb, key->name.name, state, &top)) {
20292f167a42Smrg                    fprintf(out, "%% No label for %s\n",
20302f167a42Smrg                            XkbKeyNameText(key->name.name, XkbMessage));
20312f167a42Smrg                }
20322f167a42Smrg            }
20332f167a42Smrg            else {
20342f167a42Smrg                char *olKey;
20352f167a42Smrg
20362f167a42Smrg                if (section->num_overlays > 0)
20372f167a42Smrg                    olKey = XkbFindOverlayForKey(xkb->geom, section,
20382f167a42Smrg                                                 key->name.name);
20392f167a42Smrg                else
20402f167a42Smrg                    olKey = NULL;
20412f167a42Smrg
20422f167a42Smrg                if (state->args->label == LABEL_KEYNAME) {
20432f167a42Smrg                    name = XkbKeyNameText(key->name.name, XkbMessage);
20442f167a42Smrg                    if (olKey)
20452f167a42Smrg                        name2 = XkbKeyNameText(olKey, XkbMessage);
20462f167a42Smrg                }
20472f167a42Smrg                else if (state->args->label == LABEL_KEYCODE) {
20482f167a42Smrg                    name = buf;
20492f167a42Smrg                    snprintf(name, sizeof(buf), "%d",
20502f167a42Smrg                            XkbFindKeycodeByName(xkb, key->name.name, True));
20512f167a42Smrg                    if (olKey) {
20522f167a42Smrg                        name2 = buf2;
20532f167a42Smrg                        snprintf(name2, sizeof(buf2), "%d",
20542f167a42Smrg                                 XkbFindKeycodeByName(xkb, olKey, True));
20552f167a42Smrg                    }
20562f167a42Smrg                }
20572f167a42Smrg                bzero(&top, sizeof(KeyTop));
20582f167a42Smrg                if (name2 != NULL) {
20592f167a42Smrg                    top.present |= G1LX_MASK;
20602f167a42Smrg                    strncpy(top.label[G1L1], name, LABEL_LEN - 1);
20612f167a42Smrg                    top.label[G1L1][LABEL_LEN - 1] = '\0';
20622f167a42Smrg                    strncpy(top.label[G1L2], name2, LABEL_LEN - 1);
20632f167a42Smrg                    top.label[G1L2][LABEL_LEN - 1] = '\0';
20642f167a42Smrg                }
20652f167a42Smrg                else if (name != NULL) {
20662f167a42Smrg                    top.present |= CENTER_MASK;
20672f167a42Smrg                    strncpy(top.label[CENTER], name, LABEL_LEN - 1);
20682f167a42Smrg                    top.label[CENTER][LABEL_LEN - 1] = '\0';
20692f167a42Smrg                }
20702f167a42Smrg                else {
20712f167a42Smrg                    fprintf(out, "%% No label for %s\n",
20722f167a42Smrg                            XkbKeyNameText(key->name.name, XkbMessage));
20732f167a42Smrg                }
20742f167a42Smrg            }
20752f167a42Smrg            if (row->vertical) {
20762f167a42Smrg                x = row->left;
20772f167a42Smrg                y = offset;
20782f167a42Smrg                offset += shape->bounds.y2;
20792f167a42Smrg            }
20802f167a42Smrg            else {
20812f167a42Smrg                x = offset;
20822f167a42Smrg                y = row->top;
20832f167a42Smrg                offset += shape->bounds.x2;
20842f167a42Smrg            }
20852f167a42Smrg            name = key->name.name;
20862f167a42Smrg            fprintf(out, "%% %s\n", XkbKeyNameText(name, XkbMessage));
20872f167a42Smrg            if (state->args->wantKeycodes)
20882f167a42Smrg                kc = XkbFindKeycodeByName(xkb, key->name.name, True);
20892f167a42Smrg            PSLabelKey(out, state, &top, x, y, &bounds, kc, shape->bounds.y2);
20902f167a42Smrg        }
20910e20ee16Smrg    }
20922f167a42Smrg    PSGRestore(out, state);
20930e20ee16Smrg    return;
20940e20ee16Smrg}
20950e20ee16Smrg
20960e20ee16SmrgBool
20970e20ee16SmrgGeometryToPostScript(FILE *out, XkbFileInfo *pResult, XKBPrintArgs *args)
20980e20ee16Smrg{
20992f167a42Smrg    XkbDrawablePtr first, draw;
21002f167a42Smrg    PSState state;
21012f167a42Smrg    Bool dfltBorder;
21022f167a42Smrg
21032f167a42Smrg    if ((!pResult) || (!pResult->xkb) || (!pResult->xkb->geom))
21042f167a42Smrg        return False;
21058b648e79Smrg    state = (PSState) {
21068b648e79Smrg        .xkb = pResult->xkb,
21078b648e79Smrg        .dpy = pResult->xkb->dpy,
21088b648e79Smrg        .geom = pResult->xkb->geom,
21098b648e79Smrg        .color = -1,
21108b648e79Smrg        .black = -1,
21118b648e79Smrg        .white = -1,
21128b648e79Smrg        .font = -1,
21138b648e79Smrg        .nPages = 0,
21148b648e79Smrg        .totalKB = 1,
21158b648e79Smrg        .kbPerPage = 1,
21168b648e79Smrg        .x1 = 0,
21178b648e79Smrg        .y1 = 0,
21188b648e79Smrg        .x2 = 0,
21198b648e79Smrg        .y2 = 0,
21208b648e79Smrg        .args = args
21218b648e79Smrg    };
21222f167a42Smrg
21232f167a42Smrg    if ((args->label == LABEL_SYMBOLS) && (pResult->xkb->ctrls)) {
21242f167a42Smrg        if (args->nTotalGroups == 0)
21252f167a42Smrg            state.totalKB =
21262f167a42Smrg                pResult->xkb->ctrls->num_groups / args->nLabelGroups;
21272f167a42Smrg        else
21282f167a42Smrg            state.totalKB = args->nTotalGroups;
21292f167a42Smrg        if (state.totalKB < 1)
21302f167a42Smrg            state.totalKB = 1;
21312f167a42Smrg        else if (state.totalKB > 1)
21322f167a42Smrg            state.kbPerPage = 2;
21330e20ee16Smrg    }
21342f167a42Smrg    if (args->nKBPerPage != 0)
21352f167a42Smrg        state.kbPerPage = args->nKBPerPage;
21362f167a42Smrg
21372f167a42Smrg    PSProlog(out, &state);
21382f167a42Smrg    first = XkbGetOrderedDrawables(state.geom, NULL);
21392f167a42Smrg
21402f167a42Smrg    for (draw = first, dfltBorder = True; draw != NULL; draw = draw->next) {
21412f167a42Smrg        if ((draw->type != XkbDW_Section) &&
21422f167a42Smrg            ((draw->u.doodad->any.type == XkbOutlineDoodad) ||
21432f167a42Smrg             (draw->u.doodad->any.type == XkbSolidDoodad))) {
21442f167a42Smrg            char *name;
21452f167a42Smrg
21462f167a42Smrg            name = XkbAtomGetString(state.dpy, draw->u.doodad->any.name);
21472f167a42Smrg            if ((name != NULL) && (uStrCaseEqual(name, "edges"))) {
21482f167a42Smrg                dfltBorder = False;
2149e6bced22Smrg                XFree(name);
21502f167a42Smrg                break;
21512f167a42Smrg            }
2152e6bced22Smrg            XFree(name);
21532f167a42Smrg        }
21540e20ee16Smrg    }
21558b648e79Smrg    for (int i = 0; i < state.totalKB; i++) {
21562f167a42Smrg        PSPageSetup(out, &state, dfltBorder);
21572f167a42Smrg        for (draw = first; draw != NULL; draw = draw->next) {
21582f167a42Smrg            if (draw->type == XkbDW_Section)
21592f167a42Smrg                PSSection(out, &state, draw->u.section);
21602f167a42Smrg            else {
21612f167a42Smrg                PSDoodad(out, &state, draw->u.doodad);
21622f167a42Smrg            }
21632f167a42Smrg        }
21642f167a42Smrg        PSPageTrailer(out, &state);
21652f167a42Smrg        state.args->baseLabelGroup += state.args->nLabelGroups;
21660e20ee16Smrg    }
21670e20ee16Smrg    XkbFreeOrderedDrawables(first);
21682f167a42Smrg    PSFileTrailer(out, &state);
21690e20ee16Smrg    return True;
21700e20ee16Smrg}
2171