psgeom.c revision 2f167a42
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#if defined(sgi)
460e20ee16Smrg#include <malloc.h>
470e20ee16Smrg#endif
480e20ee16Smrg
490e20ee16Smrg#include <stdlib.h>
500e20ee16Smrg
510e20ee16Smrg#include "utils.h"
520e20ee16Smrg#include "xkbprint.h"
530e20ee16Smrg#include "isokeys.h"
540e20ee16Smrg
550e20ee16Smrg#define	FONT_NONE	-1
560e20ee16Smrg#define	FONT_TEXT	0
570e20ee16Smrg#define	FONT_LATIN1	1
580e20ee16Smrg#define	FONT_SYMBOL	2
590e20ee16Smrg#define	FONT_ISOCAPS	3
600e20ee16Smrg#define	FONT_MOUSECAPS	4
610e20ee16Smrg
620e20ee16Smrgtypedef struct {
632f167a42Smrg    Display *           dpy;
642f167a42Smrg    XkbDescPtr          xkb;
652f167a42Smrg    XkbGeometryPtr      geom;
662f167a42Smrg    int                 totalKB;
672f167a42Smrg    int                 kbPerPage;
682f167a42Smrg    int                 black;
692f167a42Smrg    int                 white;
702f167a42Smrg    int                 color;
712f167a42Smrg    int                 font;
722f167a42Smrg    int                 fontSize;
732f167a42Smrg    int                 nPages;
742f167a42Smrg    int                 x1, y1;
752f167a42Smrg    int                 x2, y2;
762f167a42Smrg    XKBPrintArgs *      args;
770e20ee16Smrg} PSState;
780e20ee16Smrg
790e20ee16Smrg#define	G1L1		0
800e20ee16Smrg#define	G1L2		1
810e20ee16Smrg#define	G2L1		2
820e20ee16Smrg#define	G2L2		3
830e20ee16Smrg#define	CENTER		4
840e20ee16Smrg
850e20ee16Smrg#define	G1L1_MASK	(1<<G1L1)
860e20ee16Smrg#define	G1L2_MASK	(1<<G1L2)
870e20ee16Smrg#define	G2L1_MASK	(1<<G2L1)
880e20ee16Smrg#define	G2L2_MASK	(1<<G2L2)
890e20ee16Smrg#define	CENTER_MASK	(1<<CENTER)
900e20ee16Smrg
910e20ee16Smrg#define	LABEL_MASK	(0x1f)
920e20ee16Smrg#define	GXL1_MASK	(G1L1_MASK|G2L1_MASK)
930e20ee16Smrg#define	GXL2_MASK	(G1L2_MASK|G2L2_MASK)
940e20ee16Smrg#define	G1LX_MASK	(G1L1_MASK|G1L2_MASK)
950e20ee16Smrg#define	G2LX_MASK	(G2L1_MASK|G2L2_MASK)
960e20ee16Smrg#define	GXLX_MASK	(0x0f)
970e20ee16Smrg
980e20ee16Smrg#define	NLABELS		5
990e20ee16Smrg#define	LABEL_LEN	30
1000e20ee16Smrg
1010e20ee16Smrg#define	SZ_AUTO		0
1020e20ee16Smrg#define	SZ_TINY		1
1030e20ee16Smrg#define	SZ_SMALL	2
1040e20ee16Smrg#define	SZ_MEDIUM	3
1050e20ee16Smrg#define	SZ_LARGE	4
1060e20ee16Smrg#define	SZ_XLARGE	5
1070e20ee16Smrg
1080e20ee16Smrgtypedef struct {
1092f167a42Smrg    unsigned    present;
1102f167a42Smrg    Bool        alpha[2];
1112f167a42Smrg    char        label[NLABELS][LABEL_LEN];
1122f167a42Smrg    int         font[NLABELS];
1132f167a42Smrg    int         size[NLABELS];
1140e20ee16Smrg} KeyTop;
1150e20ee16Smrg
1160e20ee16Smrg#define	DFLT_LABEL_FONT "Helvetica-Narrow-Bold"
1170e20ee16Smrg#define DFLT_LABEL_FONT_SIZE 10
1180e20ee16Smrg
1190e20ee16Smrg/***====================================================================***/
1200e20ee16Smrg
1210e20ee16Smrgtypedef struct _PSFontDef {
1222f167a42Smrg    const char *name;
1232f167a42Smrg    const char **def;
1240e20ee16Smrg} PSFontDef;
1250e20ee16Smrg
1260e20ee16Smrgstatic PSFontDef internalFonts[] = {
1272f167a42Smrg    { "IsoKeyCaps", &IsoKeyCaps }
1280e20ee16Smrg};
1292f167a42Smrgstatic int nInternalFonts = (sizeof(internalFonts) / sizeof(PSFontDef));
1300e20ee16Smrg
1310e20ee16Smrgstatic void
1320e20ee16SmrgListInternalFonts(FILE *out, int first, int indent)
1330e20ee16Smrg{
1342f167a42Smrg    register int i, n, nThisLine;
1350e20ee16Smrg
1362f167a42Smrg    for (n = 0; n < first; n++) {
1372f167a42Smrg        putc(' ', out);
1380e20ee16Smrg    }
1390e20ee16Smrg
1402f167a42Smrg    for (nThisLine = i = 0; i < nInternalFonts; i++) {
1412f167a42Smrg        if (nThisLine == 4) {
1422f167a42Smrg            fprintf(out, ",\n");
1432f167a42Smrg            for (n = 0; n < indent; n++) {
1442f167a42Smrg                putc(' ', out);
1452f167a42Smrg            }
1462f167a42Smrg            nThisLine = 0;
1472f167a42Smrg        }
1482f167a42Smrg        if (nThisLine == 0)
1492f167a42Smrg            fprintf(out, "%s", internalFonts[i].name);
1502f167a42Smrg        else
1512f167a42Smrg            fprintf(out, ", %s", internalFonts[i].name);
1522f167a42Smrg        nThisLine++;
1530e20ee16Smrg    }
1542f167a42Smrg    if (nThisLine != 0)
1552f167a42Smrg        fprintf(out, "\n");
1560e20ee16Smrg    return;
1570e20ee16Smrg}
1580e20ee16Smrg
1590e20ee16Smrgstatic Bool
1602f167a42SmrgPSIncludeFont(FILE *out, const char *font)
1610e20ee16Smrg{
1622f167a42Smrg    const char **pstr;
1632f167a42Smrg    register int i;
1640e20ee16Smrg
1652f167a42Smrg    pstr = NULL;
1662f167a42Smrg    for (i = 0; (i < nInternalFonts) && (pstr == NULL); i++) {
1672f167a42Smrg        if (uStringEqual(internalFonts[i].name, font))
1682f167a42Smrg            pstr = internalFonts[i].def;
1690e20ee16Smrg    }
1702f167a42Smrg    if (pstr != NULL) {
1712f167a42Smrg        fprintf(out, "%%%%BeginFont: %s\n", font);
1722f167a42Smrg        fprintf(out, "%s", *pstr);
1732f167a42Smrg        fprintf(out, "%%%%EndFont\n");
1742f167a42Smrg        return True;
1750e20ee16Smrg    }
1760e20ee16Smrg    return False;
1770e20ee16Smrg}
1780e20ee16Smrg
1790e20ee16SmrgBool
1802f167a42SmrgDumpInternalFont(FILE *out, const char *fontName)
1810e20ee16Smrg{
1822f167a42Smrg    if (strcmp(fontName, "IsoKeyCaps") != 0) {
1832f167a42Smrg        uError("No internal font named \"%s\"\n", fontName);
1842f167a42Smrg        uAction("No font dumped\n");
1852f167a42Smrg        fprintf(stderr, "Current internal fonts are: ");
1862f167a42Smrg        ListInternalFonts(stderr, 0, 8);
1872f167a42Smrg        return False;
1880e20ee16Smrg    }
1892f167a42Smrg    PSIncludeFont(out, fontName);
1900e20ee16Smrg    return True;
1910e20ee16Smrg}
1920e20ee16Smrg
1930e20ee16Smrg/***====================================================================***/
1940e20ee16Smrg
1950e20ee16Smrgstatic void
1960e20ee16SmrgPSColorDef(FILE *out, PSState *state, XkbColorPtr color)
1970e20ee16Smrg{
1982f167a42Smrg    int tmp;
1990e20ee16Smrg
2002f167a42Smrg    fprintf(out, "/C%03d ", color->pixel);
2012f167a42Smrg    if (uStrCaseEqual(color->spec, "black")) {
2022f167a42Smrg        state->black = color->pixel;
2032f167a42Smrg        fprintf(out, "{ 0 setgray } def      %% %s\n", color->spec);
2040e20ee16Smrg    }
2052f167a42Smrg    else if (uStrCaseEqual(color->spec, "white")) {
2062f167a42Smrg        state->white = color->pixel;
2072f167a42Smrg        fprintf(out, "{ 1 setgray } def      %% %s\n", color->spec);
2080e20ee16Smrg    }
2092f167a42Smrg    else if ((sscanf(color->spec, "grey%d", &tmp) == 1) ||
2102f167a42Smrg             (sscanf(color->spec, "gray%d", &tmp) == 1) ||
2112f167a42Smrg             (sscanf(color->spec, "Grey%d", &tmp) == 1) ||
2122f167a42Smrg             (sscanf(color->spec, "Gray%d", &tmp) == 1)) {
2132f167a42Smrg        fprintf(out, "{ %f setgray } def	    %% %s\n",
2142f167a42Smrg                1.0 - (((float) tmp) / 100.0), color->spec);
2150e20ee16Smrg    }
2162f167a42Smrg    else if ((tmp = (uStrCaseEqual(color->spec, "red") * 100)) ||
2172f167a42Smrg             (sscanf(color->spec, "red%d", &tmp) == 1)) {
2182f167a42Smrg        fprintf(out, "{ %f 0 0 setrgbcolor } def %% %s\n",
2192f167a42Smrg                (((float) tmp) / 100.0), color->spec);
2200e20ee16Smrg    }
2212f167a42Smrg    else if ((tmp = (uStrCaseEqual(color->spec, "green") * 100)) ||
2222f167a42Smrg             (sscanf(color->spec, "green%d", &tmp) == 1)) {
2232f167a42Smrg        fprintf(out, "{ 0 %f 0 setrgbcolor } def %% %s\n",
2242f167a42Smrg                (((float) tmp) / 100.0), color->spec);
2250e20ee16Smrg    }
2262f167a42Smrg    else if ((tmp = (uStrCaseEqual(color->spec, "blue") * 100)) ||
2272f167a42Smrg             (sscanf(color->spec, "blue%d", &tmp) == 1)) {
2282f167a42Smrg        fprintf(out, "{ 0 0 %f setrgbcolor } def %% %s\n",
2292f167a42Smrg                (((float) tmp) / 100.0), color->spec);
2300e20ee16Smrg    }
2312f167a42Smrg    else
2322f167a42Smrg        fprintf(out, "{ 0.9 setgray       } def %% BOGUS! %s\n", color->spec);
2330e20ee16Smrg}
2340e20ee16Smrg
2350e20ee16Smrgstatic void
2362f167a42SmrgPSSetColor(FILE *out, PSState *state, int color)
2370e20ee16Smrg{
2382f167a42Smrg    if ((state->args->wantColor) && (state->color != color)) {
2392f167a42Smrg        fprintf(out, "C%03d %% set color\n", color);
2402f167a42Smrg        state->color = color;
2410e20ee16Smrg    }
2420e20ee16Smrg    return;
2430e20ee16Smrg}
2440e20ee16Smrg
2450e20ee16Smrgstatic void
2460e20ee16SmrgPSGSave(FILE *out, PSState *state)
2470e20ee16Smrg{
2482f167a42Smrg    fprintf(out, "gsave\n");
2490e20ee16Smrg    return;
2500e20ee16Smrg}
2510e20ee16Smrg
2520e20ee16Smrgstatic void
2530e20ee16SmrgPSGRestore(FILE *out, PSState *state)
2540e20ee16Smrg{
2552f167a42Smrg    fprintf(out, "grestore\n");
2562f167a42Smrg    state->color = -1;
2572f167a42Smrg    state->font = FONT_NONE;
2582f167a42Smrg    state->fontSize = -1;
2590e20ee16Smrg    return;
2600e20ee16Smrg}
2610e20ee16Smrg
2620e20ee16Smrgstatic void
2630e20ee16SmrgPSShapeDef(FILE *out, PSState *state, XkbShapePtr shape)
2640e20ee16Smrg{
2652f167a42Smrg    int o, p;
2662f167a42Smrg    XkbOutlinePtr ol;
2672f167a42Smrg
2682f167a42Smrg    fprintf(out, "/%s {\n", XkbAtomGetString(state->dpy, shape->name));
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++;
3302f167a42Smrg                for (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");
3512f167a42Smrg                for (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{
3970e20ee16Smrg    if (stuff && stuff->foundry)
3982f167a42Smrg        free(stuff->foundry);
3992f167a42Smrg    bzero(stuff, sizeof(FontStuff));
4000e20ee16Smrg    return;
4010e20ee16Smrg}
4020e20ee16Smrg
4030e20ee16Smrgstatic Bool
4042f167a42SmrgCrackXLFDName(const char *name, FontStuff *stuff)
4050e20ee16Smrg{
4062f167a42Smrg    char *tmp;
4072f167a42Smrg
4082f167a42Smrg    if ((name == NULL) || (stuff == NULL))
4092f167a42Smrg        return False;
4102f167a42Smrg    if (name[0] == '-')
4112f167a42Smrg        tmp = strdup(&name[1]);
4122f167a42Smrg    else
4132f167a42Smrg        tmp = strdup(name);
4142f167a42Smrg    if (tmp == NULL)
4152f167a42Smrg        return False;
4162f167a42Smrg    stuff->foundry = tmp;
4172f167a42Smrg
4182f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4192f167a42Smrg        goto BAILOUT;
4202f167a42Smrg    else
4212f167a42Smrg        *tmp++ = '\0';
4222f167a42Smrg    stuff->face = tmp;
4232f167a42Smrg
4242f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4252f167a42Smrg        goto BAILOUT;
4262f167a42Smrg    else
4272f167a42Smrg        *tmp++ = '\0';
4282f167a42Smrg    stuff->weight = tmp;
4292f167a42Smrg
4302f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4312f167a42Smrg        goto BAILOUT;
4322f167a42Smrg    else
4332f167a42Smrg        *tmp++ = '\0';
4342f167a42Smrg    stuff->slant = tmp;
4352f167a42Smrg
4362f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4372f167a42Smrg        goto BAILOUT;
4382f167a42Smrg    else
4392f167a42Smrg        *tmp++ = '\0';
4402f167a42Smrg    stuff->setWidth = tmp;
4412f167a42Smrg
4422f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4432f167a42Smrg        goto BAILOUT;
4442f167a42Smrg    else
4452f167a42Smrg        *tmp++ = '\0';
4462f167a42Smrg    stuff->variant = tmp;
4472f167a42Smrg
4482f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4492f167a42Smrg        goto BAILOUT;
4502f167a42Smrg    else
4512f167a42Smrg        *tmp++ = '\0';
4522f167a42Smrg    if (*tmp == '*')
4532f167a42Smrg        stuff->pixelSize = 0;
4542f167a42Smrg    else if (sscanf(tmp, "%i", &stuff->pixelSize) != 1)
4552f167a42Smrg        goto BAILOUT;
4562f167a42Smrg
4572f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4582f167a42Smrg        goto BAILOUT;
4592f167a42Smrg    else
4602f167a42Smrg        *tmp++ = '\0';
4612f167a42Smrg    if (*tmp == '*')
4622f167a42Smrg        stuff->ptSize = 0;
4632f167a42Smrg    else if (sscanf(tmp, "%i", &stuff->ptSize) != 1)
4642f167a42Smrg        goto BAILOUT;
4652f167a42Smrg
4662f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4672f167a42Smrg        goto BAILOUT;
4682f167a42Smrg    else
4692f167a42Smrg        *tmp++ = '\0';
4702f167a42Smrg    if (*tmp == '*')
4712f167a42Smrg        stuff->resX = 0;
4722f167a42Smrg    else if (sscanf(tmp, "%i", &stuff->resX) != 1)
4732f167a42Smrg        goto BAILOUT;
4742f167a42Smrg
4752f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4762f167a42Smrg        goto BAILOUT;
4772f167a42Smrg    else
4782f167a42Smrg        *tmp++ = '\0';
4792f167a42Smrg    if (*tmp == '*')
4802f167a42Smrg        stuff->resY = 0;
4812f167a42Smrg    else if (sscanf(tmp, "%i", &stuff->resY) != 1)
4822f167a42Smrg        goto BAILOUT;
4832f167a42Smrg
4842f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4852f167a42Smrg        goto BAILOUT;
4862f167a42Smrg    else
4872f167a42Smrg        *tmp++ = '\0';
4882f167a42Smrg    stuff->spacing = tmp;
4892f167a42Smrg
4902f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
4912f167a42Smrg        goto BAILOUT;
4922f167a42Smrg    else
4932f167a42Smrg        *tmp++ = '\0';
4942f167a42Smrg    if (*tmp == '*')
4952f167a42Smrg        stuff->avgWidth = 0;
4962f167a42Smrg    else if (sscanf(tmp, "%i", &stuff->avgWidth) != 1)
4972f167a42Smrg        goto BAILOUT;
4982f167a42Smrg
4992f167a42Smrg    if ((tmp = strchr(tmp, '-')) == NULL)
5002f167a42Smrg        goto BAILOUT;
5012f167a42Smrg    else
5022f167a42Smrg        *tmp++ = '\0';
5032f167a42Smrg    stuff->encoding = tmp;
5040e20ee16Smrg    return True;
5052f167a42Smrg BAILOUT:
5060e20ee16Smrg    ClearFontStuff(stuff);
5070e20ee16Smrg    return False;
5080e20ee16Smrg}
5090e20ee16Smrg
5100e20ee16Smrgstatic void
5110e20ee16SmrgPSSetUpForLatin1(FILE *out, PSState *state)
5120e20ee16Smrg{
5132f167a42Smrg    fprintf(out, "%s",
5142f167a42Smrg            "save\n"
5152f167a42Smrg            "/ISOLatin1Encoding where {pop save true}{false} ifelse\n"
5162f167a42Smrg            "/ISOLatin1Encoding [\n"
5172f167a42Smrg            "   /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\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 /space /exclam /quotedbl /numbersign\n"
5232f167a42Smrg            "   /dollar /percent /ampersand /quoteright /parenleft\n"
5242f167a42Smrg            "   /parenright /asterisk /plus /comma /minus /period\n"
5252f167a42Smrg            "   /slash /zero /one /two /three /four /five /six /seven\n"
5262f167a42Smrg            "   /eight /nine /colon /semicolon /less /equal /greater\n"
5272f167a42Smrg            "   /question /at /A /B /C /D /E /F /G /H /I /J /K /L /M\n"
5282f167a42Smrg            "   /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft\n"
5292f167a42Smrg            "   /backslash /bracketright /asciicircum /underscore\n"
5302f167a42Smrg            "   /quoteleft /a /b /c /d /e /f /g /h /i /j /k /l /m\n"
5312f167a42Smrg            "   /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft\n"
5322f167a42Smrg            "   /bar /braceright /asciitilde /guilsinglright /fraction\n"
5332f167a42Smrg            "   /florin /quotesingle /quotedblleft /guilsinglleft /fi\n"
5342f167a42Smrg            "   /fl /endash /dagger /daggerdbl /bullet /quotesinglbase\n"
5352f167a42Smrg            "   /quotedblbase /quotedblright /ellipsis /trademark\n"
5362f167a42Smrg            "   /perthousand /grave /scaron /circumflex /Scaron /tilde\n"
5372f167a42Smrg            "   /breve /zcaron /dotaccent /dotlessi /Zcaron /ring\n"
5382f167a42Smrg            "   /hungarumlaut /ogonek /caron /emdash /space /exclamdown\n"
5392f167a42Smrg            "   /cent /sterling /currency /yen /brokenbar /section\n"
5402f167a42Smrg            "   /dieresis /copyright /ordfeminine /guillemotleft\n"
5412f167a42Smrg            "   /logicalnot /hyphen /registered /macron /degree\n"
5422f167a42Smrg            "   /plusminus /twosuperior /threesuperior /acute /mu\n"
5432f167a42Smrg            "   /paragraph /periodcentered /cedilla /onesuperior\n"
5442f167a42Smrg            "   /ordmasculine /guillemotright /onequarter /onehalf\n"
5452f167a42Smrg            "   /threequarters /questiondown /Agrave /Aacute\n"
5462f167a42Smrg            "   /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n"
5472f167a42Smrg            "   /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute\n"
5482f167a42Smrg            "   /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute\n"
5492f167a42Smrg            "   /Ocircumflex /Otilde /Odieresis /multiply /Oslash\n"
5502f167a42Smrg            "   /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn\n"
5512f167a42Smrg            "   /germandbls /agrave /aacute /acircumflex /atilde\n"
5522f167a42Smrg            "   /adieresis /aring /ae /ccedilla /egrave /eacute\n"
5532f167a42Smrg            "   /ecircumflex /edieresis /igrave /iacute /icircumflex\n"
5542f167a42Smrg            "   /idieresis /eth /ntilde /ograve /oacute /ocircumflex\n"
5552f167a42Smrg            "   /otilde /odieresis /divide /oslash /ugrave /uacute\n"
5562f167a42Smrg            "   /ucircumflex /udieresis /yacute /thorn /ydieresis\n"
5572f167a42Smrg            "] def {restore} if\n"
5582f167a42Smrg            "/reencodeISO-1 {\n"
5592f167a42Smrg            "    dup length dict begin\n"
5602f167a42Smrg            "        {1 index /FID ne {def}{pop pop} ifelse} forall\n"
5612f167a42Smrg            "        /Encoding ISOLatin1Encoding def\n"
5622f167a42Smrg            "        currentdict\n"
5632f167a42Smrg            "    end\n"
5642f167a42Smrg            "} def\n"
5652f167a42Smrg        );
5660e20ee16Smrg}
5670e20ee16Smrg
5680e20ee16Smrgstatic void
5692f167a42SmrgPSReencodeLatin1Font(FILE *out, const char *font)
5700e20ee16Smrg{
5712f167a42Smrg    fprintf(out, "/%s findfont reencodeISO-1\n", font);
5722f167a42Smrg    fprintf(out, "	/%s-8859-1 exch definefont pop\n", font);
5730e20ee16Smrg    return;
5740e20ee16Smrg}
5750e20ee16Smrg
5760e20ee16Smrgstatic void
5772f167a42SmrgPSSetUpFonts(FILE *out, const char *textFont, int size)
5780e20ee16Smrg{
5792f167a42Smrg    fprintf(out, "/F%d { /%s findfont exch scalefont setfont } def\n",
5802f167a42Smrg            FONT_TEXT, textFont);
5812f167a42Smrg    fprintf(out, "/F%d { /%s-8859-1 findfont exch scalefont setfont } def\n",
5822f167a42Smrg            FONT_LATIN1, textFont);
5832f167a42Smrg    fprintf(out, "/F%d { /%s findfont exch scalefont setfont } def\n",
5842f167a42Smrg            FONT_SYMBOL, "Symbol");
5852f167a42Smrg    fprintf(out, "/F%d { /%s findfont exch scalefont setfont } def\n",
5862f167a42Smrg            FONT_ISOCAPS, "IsoKeyCaps");
5870e20ee16Smrg    return;
5880e20ee16Smrg}
5890e20ee16Smrg
5900e20ee16Smrgstatic void
5910e20ee16SmrgPSSetFont(FILE *out, PSState *state, int font, int size, int pts)
5920e20ee16Smrg{
5932f167a42Smrg    if ((state->font != font) || (state->fontSize != size)) {
5942f167a42Smrg        fprintf(out, "%d %sF%d\n", size, (pts ? "pts " : ""), font);
5952f167a42Smrg        state->font = font;
5962f167a42Smrg        state->fontSize = size;
5970e20ee16Smrg    }
5980e20ee16Smrg    return;
5990e20ee16Smrg}
6000e20ee16Smrg
6010e20ee16Smrgstatic void
6020e20ee16SmrgPSProlog(FILE *out, PSState *state)
6030e20ee16Smrg{
6042f167a42Smrg    register int i;
6050e20ee16Smrg
6060e20ee16Smrg    if (!state->args->wantEPS) {
6072f167a42Smrg        fprintf(out,
6082f167a42Smrg                "%%!PS-Adobe-2.0\n"
6092f167a42Smrg                "%%%%Creator: xkbprint\n");
6102f167a42Smrg        if (state->geom->name != None)
6112f167a42Smrg            fprintf(out, "%%%%Title: %s\n",
6122f167a42Smrg                    XkbAtomGetString(state->dpy, state->geom->name));
6132f167a42Smrg        fprintf(out,
6142f167a42Smrg                "%%%%BoundingBox: (atend)\n"
6152f167a42Smrg                "%%%%Pages: 1\n"
6162f167a42Smrg                "%%%%PageOrder: Ascend\n"
6172f167a42Smrg                "%%%%DocumentFonts: (atend)\n"
6182f167a42Smrg                "%%%%DocumentData: Clean7Bit\n"
6192f167a42Smrg                "%%%%Orientation: Landscape\n"
6202f167a42Smrg                "%%%%EndComments\n"
6212f167a42Smrg                "%%%%BeginProlog\n"
6222f167a42Smrg                "%% Resolution is 1/10mm -- need pt sizes for fonts\n"
6232f167a42Smrg                "clippath pathbbox\n"
6242f167a42Smrg                "    /ury exch def /urx exch def\n"
6252f167a42Smrg                "    /llx exch def /lly exch def\n"
6262f167a42Smrg                "    newpath\n"
6272f167a42Smrg                "/devwidth  urx llx sub def\n"
6282f167a42Smrg                "/devheight ury lly sub def\n");
6290e20ee16Smrg    }
6300e20ee16Smrg    else {
6312f167a42Smrg        int w, h;
6322f167a42Smrg        int pw, ph;
6332f167a42Smrg
6342f167a42Smrg        w = (((state->geom->width_mm * 72) / 254) * 11) / 10;
6352f167a42Smrg        h = (((state->geom->height_mm * 72) / 254) * 11) / 10;
6362f167a42Smrg        if (state->kbPerPage > 1)
6372f167a42Smrg            h *= (state->kbPerPage + 1);
6382f167a42Smrg
6392f167a42Smrg        if (w <= h) {
6402f167a42Smrg            pw = 7.5 * 72;
6412f167a42Smrg            ph = 10 * 72;
6422f167a42Smrg        }
6432f167a42Smrg        else {
6442f167a42Smrg            pw = 10 * 72;
6452f167a42Smrg            ph = 7.5 * 72;
6462f167a42Smrg        }
6472f167a42Smrg        while ((w > pw) || (h > ph)) {
6482f167a42Smrg            w = (w * 9) / 10;
6492f167a42Smrg            h = (h * 9) / 10;
6502f167a42Smrg        }
6512f167a42Smrg
6522f167a42Smrg        fprintf(out, "%%!PS-Adobe-2.0 EPSF-2.0\n");
6532f167a42Smrg        fprintf(out, "%%%%BoundingBox: 0 0 %d %d\n", w, h);
6542f167a42Smrg        fprintf(out, "%%%%Creator: xkbprint\n");
6552f167a42Smrg        if (state->geom->name != None)
6562f167a42Smrg            fprintf(out, "%%%%Title: %s\n",
6572f167a42Smrg                    XkbAtomGetString(state->dpy, state->geom->name));
6582f167a42Smrg        fprintf(out, "%%%%Pages: 1\n");
6592f167a42Smrg        fprintf(out, "%%%%EndComments\n");
6602f167a42Smrg        fprintf(out, "%%%%BeginProlog\n");
6612f167a42Smrg        fprintf(out, "/ury 0 def /urx 0 def\n");
6622f167a42Smrg        fprintf(out, "/llx %d def /lly %d def\n", w, h);
6632f167a42Smrg        fprintf(out, "/devwidth %d def /devheight %d def\n", w, h);
6640e20ee16Smrg    }
6652f167a42Smrg    fprintf(out, "/kbdwidth %d def\n", state->geom->width_mm);
6662f167a42Smrg    fprintf(out, "/kbdheight %d def\n", state->geom->height_mm);
6672f167a42Smrg    fprintf(out, "%s",
6682f167a42Smrg            "/pts { 254 mul 72 div } def\n"
6692f167a42Smrg            "/mm10 { 72 mul 254 div } def\n"
6702f167a42Smrg            "/landscape? {\n"
6712f167a42Smrg            "	devheight devwidth gt {\n"
6722f167a42Smrg            "		/pwidth devheight def /pheight devwidth def\n"
6732f167a42Smrg            "		0 devheight translate\n"
6742f167a42Smrg            "		-90 rotate\n"
6752f167a42Smrg            "	} {\n"
6762f167a42Smrg            "		/pwidth devwidth def /pheight devheight def\n"
6772f167a42Smrg            "	} ifelse\n"
6782f167a42Smrg            "	0 pheight translate\n"
6792f167a42Smrg            "	1 -1 scale\n"
6802f167a42Smrg            "} def\n"
6812f167a42Smrg            "/centeroffset {\n"
6822f167a42Smrg            "    /S     exch def\n"
6832f167a42Smrg            "    /HEIGHT exch def\n"
6842f167a42Smrg            "    /WIDTH exch def\n"
6852f167a42Smrg            "    S stringwidth /SH exch def /SW exch def\n"
6862f167a42Smrg            "    WIDTH SW sub 2 div\n"
6872f167a42Smrg            "    HEIGHT SH sub 2 div\n"
6882f167a42Smrg            "} def\n");
6892f167a42Smrg    PSSetUpForLatin1(out, state);
6902f167a42Smrg    PSReencodeLatin1Font(out, DFLT_LABEL_FONT);
6910e20ee16Smrg    if (state->args->wantColor) {
6922f167a42Smrg        XkbGeometryPtr geom = state->geom;
6932f167a42Smrg
6942f167a42Smrg        for (i = 0; i < geom->num_colors; i++) {
6952f167a42Smrg            PSColorDef(out, state, &geom->colors[i]);
6962f167a42Smrg        }
6972f167a42Smrg        if (state->black < 0) {
6982f167a42Smrg            XkbColorPtr color;
6992f167a42Smrg
7002f167a42Smrg            if (!(color = XkbAddGeomColor(geom, "black", geom->num_colors)))
7012f167a42Smrg                uFatalError("Couldn't allocate black color!\n");
7022f167a42Smrg            PSColorDef(out, state, color);
7032f167a42Smrg        }
7042f167a42Smrg        if (state->white < 0) {
7052f167a42Smrg            XkbColorPtr color;
7062f167a42Smrg
7072f167a42Smrg            if (!(color = XkbAddGeomColor(geom, "white", geom->num_colors)))
7082f167a42Smrg                uFatalError("Couldn't allocate white color!\n");
7092f167a42Smrg            PSColorDef(out, state, color);
7102f167a42Smrg        }
7110e20ee16Smrg    }
7122f167a42Smrg    for (i = 0; i < state->geom->num_shapes; i++) {
7132f167a42Smrg        PSShapeDef(out, state, &state->geom->shapes[i]);
7140e20ee16Smrg    }
7152f167a42Smrg    if (state->args->label == LABEL_SYMBOLS) {
7162f167a42Smrg        PSIncludeFont(out, "IsoKeyCaps");
7170e20ee16Smrg    }
7182f167a42Smrg    PSSetUpFonts(out, DFLT_LABEL_FONT, DFLT_LABEL_FONT_SIZE);
7192f167a42Smrg    fprintf(out, "%%%%EndProlog\n");
7200e20ee16Smrg    return;
7210e20ee16Smrg}
7220e20ee16Smrg
7230e20ee16Smrgstatic void
7240e20ee16SmrgPSFileTrailer(FILE *out, PSState *state)
7250e20ee16Smrg{
7262f167a42Smrg    fprintf(out, "restore\n");
7270e20ee16Smrg    if (!state->args->wantEPS)
7282f167a42Smrg        fprintf(out, "%%%%Trailer\n");
7292f167a42Smrg    fprintf(out, "%%%%EOF\n");
7300e20ee16Smrg    return;
7310e20ee16Smrg}
7320e20ee16Smrg
7330e20ee16Smrgstatic void
7340e20ee16SmrgPSPageSetup(FILE *out, PSState *state, Bool drawBorder)
7350e20ee16Smrg{
7362f167a42Smrg    XkbGeometryPtr geom;
7370e20ee16Smrg
7382f167a42Smrg    geom = state->geom;
7392f167a42Smrg    if (state->kbPerPage == 1) {
7402f167a42Smrg        fprintf(out, "%%%%Page: %d %d\n", state->nPages + 1, state->nPages + 1);
7412f167a42Smrg        fprintf(out, "%%%%BeginPageSetup\n");
7420e20ee16Smrg    }
7432f167a42Smrg    else if ((state->nPages & 1) == 0) {        /* even page */
7442f167a42Smrg        int realPage;
7452f167a42Smrg
7462f167a42Smrg        realPage = state->nPages / 2 + 1;
7472f167a42Smrg        fprintf(out, "%%%%Page: %d %d\n", realPage, realPage);
7482f167a42Smrg        fprintf(out, "%%%%BeginPageSetup\n");
7492f167a42Smrg        fprintf(out, "%% Keyboard %d\n", state->nPages + 1);
7502f167a42Smrg        if (state->nPages == 0) {
7512f167a42Smrg            fprintf(out,
7522f167a42Smrg                    "/realwidth devwidth def\n"
7532f167a42Smrg                    "/realheight devheight def\n"
7542f167a42Smrg                    "/devheight realheight 3 div def\n");
7552f167a42Smrg        }
7562f167a42Smrg        fprintf(out, "0 devheight dup 2 div add translate\n");
7570e20ee16Smrg    }
7582f167a42Smrg    else {
7592f167a42Smrg        fprintf(out, "%% Keyboard %d\n", state->nPages + 1);
7600e20ee16Smrg    }
7612f167a42Smrg    fprintf(out, "save\n");
7622f167a42Smrg    fprintf(out, "landscape?\n");
7630e20ee16Smrg    if (state->args->scaleToFit) {
7642f167a42Smrg        fprintf(out,
7652f167a42Smrg                "%% Scale keyboard to fit on the page\n"
7662f167a42Smrg                "/kbdscale pwidth 72 sub kbdwidth div def\n"
7672f167a42Smrg                "/kbdscalewidth kbdwidth kbdscale mul def\n"
7682f167a42Smrg                "/kbdscaleheight kbdheight kbdscale mul def\n"
7692f167a42Smrg                "/kbx 36 def\n"
7702f167a42Smrg                "/kby pheight kbdscaleheight sub 2 div def\n");
7712f167a42Smrg        PSGSave(out, state);
7722f167a42Smrg        fprintf(out,
7732f167a42Smrg                "kbx kby translate\n"
7742f167a42Smrg                "kbdscale kbdscale scale\n");
7750e20ee16Smrg    }
7760e20ee16Smrg    else {
7772f167a42Smrg        fprintf(out,
7782f167a42Smrg                "%% Draw keyboard full size\n"
7792f167a42Smrg                "/kbdscale 1 def\n"
7802f167a42Smrg                "/kbdscalewidth kbdwidth mm10 def\n"
7812f167a42Smrg                "/kbdscaleheight kbdheight mm10 def\n"
7822f167a42Smrg                "/kbx pwidth kbdscalewidth sub 2 div def\n"
7832f167a42Smrg                "/kby pheight kbdscaleheight sub 2 div def\n");
7842f167a42Smrg        PSGSave(out, state);
7852f167a42Smrg        fprintf(out,
7862f167a42Smrg                "kbx kby translate\n"
7872f167a42Smrg                "72 254 div dup scale\n");
7880e20ee16Smrg    }
7890e20ee16Smrg    if (drawBorder) {
7902f167a42Smrg        if (state->args->wantColor) {
7912f167a42Smrg            PSSetColor(out, state, geom->base_color->pixel);
7922f167a42Smrg            fprintf(out, "  0   0 moveto\n");
7932f167a42Smrg            fprintf(out, "%3d   0 lineto\n", geom->width_mm);
7942f167a42Smrg            fprintf(out, "%3d %3d lineto\n", geom->width_mm, geom->height_mm);
7952f167a42Smrg            fprintf(out, "  0 %3d lineto\n", geom->height_mm);
7962f167a42Smrg            fprintf(out, "closepath fill\n");
7972f167a42Smrg        }
7982f167a42Smrg        PSSetColor(out, state, state->black);
7992f167a42Smrg        fprintf(out, "  0   0 moveto\n");
8002f167a42Smrg        fprintf(out, "%3d   0 lineto\n", geom->width_mm);
8012f167a42Smrg        fprintf(out, "%3d %3d lineto\n", geom->width_mm, geom->height_mm);
8022f167a42Smrg        fprintf(out, "  0 %3d lineto\n", geom->height_mm);
8032f167a42Smrg        fprintf(out, "closepath stroke\n");
8040e20ee16Smrg    }
8052f167a42Smrg    fprintf(out, "%%%%EndPageSetup\n");
8060e20ee16Smrg    return;
8070e20ee16Smrg}
8080e20ee16Smrg
8090e20ee16Smrgstatic void
8100e20ee16SmrgPSPageTrailer(FILE *out, PSState *state)
8110e20ee16Smrg{
8122f167a42Smrg    char *name;
8132f167a42Smrg    XkbDescPtr xkb;
8142f167a42Smrg    XkbGeometryPtr geom;
8152f167a42Smrg    XkbPropertyPtr prop;
8162f167a42Smrg    int p, baseline;
8172f167a42Smrg
8182f167a42Smrg    xkb = state->xkb;
8192f167a42Smrg    geom = state->geom;
8202f167a42Smrg    if (state->args->grid > 0) {
8212f167a42Smrg        fprintf(out, "%% Draw a %dmm grid\n", state->args->grid);
8222f167a42Smrg        fprintf(out, "0 setlinewidth\n");
8232f167a42Smrg        fprintf(out, "0.25 setgray\n");
8242f167a42Smrg        fprintf(out, " 0 %d %d {\n", state->args->grid * 10, geom->width_mm);
8252f167a42Smrg        fprintf(out, "    /GX exch def\n");
8262f167a42Smrg        fprintf(out, "    GX 0 moveto GX %d lineto stroke\n", geom->height_mm);
8272f167a42Smrg        fprintf(out, "} for\n");
8282f167a42Smrg        fprintf(out, " 0 %d %d {\n", state->args->grid * 10, geom->height_mm);
8292f167a42Smrg        fprintf(out, "    /GY exch def\n");
8302f167a42Smrg        fprintf(out, "    0 GY moveto %d GY lineto stroke\n", geom->width_mm);
8312f167a42Smrg        fprintf(out, "} for\n");
8320e20ee16Smrg    }
8332f167a42Smrg    PSGRestore(out, state);
8342f167a42Smrg    name = NULL;
8352f167a42Smrg    for (p = 0, prop = geom->properties; p < geom->num_properties; p++, prop++) {
8362f167a42Smrg        if ((prop->value != NULL) && (uStrCaseEqual(prop->name, "description"))) {
8372f167a42Smrg            name = prop->value;
8382f167a42Smrg            break;
8392f167a42Smrg        }
8400e20ee16Smrg    }
8412f167a42Smrg    if ((!state->args->wantEPS) &&
8422f167a42Smrg        ((state->kbPerPage == 1) || ((state->nPages & 1) == 1) ||
8432f167a42Smrg         (state->nPages == state->totalKB))) {
8442f167a42Smrg        if ((name == NULL) && (geom->name != None))
8452f167a42Smrg            name = XkbAtomGetString(state->dpy, geom->name);
8462f167a42Smrg
8472f167a42Smrg        baseline = 16;
8482f167a42Smrg        if ((name != NULL) || (state->args->label == LABEL_SYMBOLS)) {
8492f167a42Smrg            PSSetColor(out, state, state->black);
8502f167a42Smrg            PSSetFont(out, state, FONT_LATIN1, 14, False);
8512f167a42Smrg        }
8522f167a42Smrg        if (state->args->label == LABEL_SYMBOLS) {
8532f167a42Smrg            char buf[40], *lbuf;
8542f167a42Smrg            const char *sName = NULL;
8552f167a42Smrg            Atom sAtom;
8562f167a42Smrg
8572f167a42Smrg            if (state->args->nLabelGroups == 1)
8582f167a42Smrg                snprintf(buf, sizeof(buf), "Group %d",
8592f167a42Smrg                         state->args->baseLabelGroup + 1);
8602f167a42Smrg            else
8612f167a42Smrg                snprintf(buf, sizeof(buf), "Groups %d-%d",
8622f167a42Smrg                         state->args->baseLabelGroup + 1,
8632f167a42Smrg                         state->args->baseLabelGroup +
8642f167a42Smrg                         state->args->nLabelGroups);
8652f167a42Smrg            fprintf(out, "kbx kbdscalewidth 0 (%s) centeroffset pop add\n",
8662f167a42Smrg                    buf);
8672f167a42Smrg            fprintf(out, "    kby kbdscaleheight add %d add\n", baseline);
8682f167a42Smrg            fprintf(out, "    moveto\n");
8692f167a42Smrg            fprintf(out, "1 -1 scale (%s) show 1 -1 scale\n", buf);
8702f167a42Smrg            baseline += 16;
8712f167a42Smrg
8722f167a42Smrg            if (xkb->names != NULL)
8732f167a42Smrg                sAtom = xkb->names->symbols;
8742f167a42Smrg            else
8752f167a42Smrg                sAtom = None;
8762f167a42Smrg            if (sAtom != None)
8772f167a42Smrg                sName = XkbAtomGetString(state->dpy, sAtom);
8782f167a42Smrg            if (sName == NULL)
8792f167a42Smrg                sName = "(unknown)";
8802f167a42Smrg
8812f167a42Smrg            if (asprintf(&lbuf, "Layout: %s", sName) == -1) {
8822f167a42Smrg                uFatalError("Can't allocate memory for string\n");
8832f167a42Smrg            }
8842f167a42Smrg            fprintf(out, "kbx kbdscalewidth 0 (%s) centeroffset pop add\n",
8852f167a42Smrg                    lbuf);
8862f167a42Smrg            fprintf(out, "    kby kbdscaleheight add %d add\n", baseline);
8872f167a42Smrg            fprintf(out, "    moveto\n");
8882f167a42Smrg            fprintf(out, "1 -1 scale (%s) show 1 -1 scale\n", lbuf);
8892f167a42Smrg            baseline += 16;
8902f167a42Smrg            free(lbuf);
8912f167a42Smrg        }
8922f167a42Smrg        if (name != NULL) {
8932f167a42Smrg            fprintf(out, "kbx kbdscalewidth 0 (%s) centeroffset pop add\n",
8942f167a42Smrg                    name);
8952f167a42Smrg            fprintf(out, "    kby kbdscaleheight add %d add\n", baseline);
8962f167a42Smrg            fprintf(out, "    moveto\n");
8972f167a42Smrg            fprintf(out, "1 -1 scale (%s) show 1 -1 scale\n", name);
8982f167a42Smrg            baseline += 16;
8992f167a42Smrg        }
9002f167a42Smrg        if (state->args->label == LABEL_KEYCODE) {
9012f167a42Smrg            const char *sName = NULL;
9022f167a42Smrg            char *lbuf;
9032f167a42Smrg            Atom sAtom;
9042f167a42Smrg
9052f167a42Smrg            if (xkb->names != NULL)
9062f167a42Smrg                sAtom = xkb->names->keycodes;
9072f167a42Smrg            else
9082f167a42Smrg                sAtom = None;
9092f167a42Smrg            if (sAtom != None)
9102f167a42Smrg                sName = XkbAtomGetString(state->dpy, sAtom);
9112f167a42Smrg            if (sName == NULL)
9122f167a42Smrg                sName = "(unknown)";
9132f167a42Smrg
9142f167a42Smrg            if (asprintf(&lbuf, "Keycodes: %s", sName) == -1) {
9152f167a42Smrg                uFatalError("Can't allocate memory for string\n");
9162f167a42Smrg            }
9172f167a42Smrg            fprintf(out, "kbx kbdscalewidth 0 (%s) centeroffset pop add\n",
9182f167a42Smrg                    lbuf);
9192f167a42Smrg            fprintf(out, "    kby kbdscaleheight add %d add\n", baseline);
9202f167a42Smrg            fprintf(out, "    moveto\n");
9212f167a42Smrg            fprintf(out, "1 -1 scale (%s) show 1 -1 scale\n", lbuf);
9222f167a42Smrg            baseline += 16;
9232f167a42Smrg            free(lbuf);
9242f167a42Smrg        }
9252f167a42Smrg        if (state->args->copies > 1) {
9262f167a42Smrg            for (p = 1; p < state->args->copies; p++)
9272f167a42Smrg                fprintf(out, "copypage\n");
9282f167a42Smrg        }
9292f167a42Smrg        fprintf(out, "showpage\n");
9302f167a42Smrg        fprintf(out, "restore\n");
9312f167a42Smrg        fprintf(out, "%% Done with keyboard/page %d\n", state->nPages + 1);
9320e20ee16Smrg    }
9330e20ee16Smrg    else {
9342f167a42Smrg        if ((!state->args->wantEPS) && (state->args->label == LABEL_SYMBOLS)) {
9352f167a42Smrg            char buf[40];
9362f167a42Smrg
9372f167a42Smrg            baseline = 16;
9382f167a42Smrg            PSSetColor(out, state, state->black);
9392f167a42Smrg            PSSetFont(out, state, FONT_LATIN1, 14, False);
9402f167a42Smrg            if (state->args->nLabelGroups == 1)
9412f167a42Smrg                snprintf(buf, sizeof(buf), "Group %d",
9422f167a42Smrg                         state->args->baseLabelGroup + 1);
9432f167a42Smrg            else
9442f167a42Smrg                snprintf(buf, sizeof(buf), "Groups %d-%d",
9452f167a42Smrg                         state->args->baseLabelGroup + 1,
9462f167a42Smrg                         state->args->baseLabelGroup +
9472f167a42Smrg                         state->args->nLabelGroups + 1);
9482f167a42Smrg            fprintf(out, "kbx kbdscalewidth 0 (%s) centeroffset pop add\n",
9492f167a42Smrg                    buf);
9502f167a42Smrg            fprintf(out, "    kby kbdscaleheight add %d add\n", baseline);
9512f167a42Smrg            fprintf(out, "    moveto\n");
9522f167a42Smrg            fprintf(out, "1 -1 scale (%s) show 1 -1 scale\n", buf);
9532f167a42Smrg            baseline += 16;
9542f167a42Smrg        }
9552f167a42Smrg        fprintf(out, "restore\n");
9562f167a42Smrg        fprintf(out, "%% Done with keyboard %d\n", state->nPages + 1);
9572f167a42Smrg        fprintf(out, "0 devheight -1 mul translate %% next keyboard\n");
9580e20ee16Smrg    }
9590e20ee16Smrg    state->nPages++;
9602f167a42Smrg    state->color = state->black;
9612f167a42Smrg    state->font = -1;
9620e20ee16Smrg    return;
9630e20ee16Smrg}
9640e20ee16Smrg
9650e20ee16Smrgstatic void
9660e20ee16SmrgPSDoodad(FILE *out, PSState *state, XkbDoodadPtr doodad)
9670e20ee16Smrg{
9682f167a42Smrg    XkbDescPtr xkb;
9692f167a42Smrg    const char *name, *dname;
9702f167a42Smrg    int sz, leading;
9712f167a42Smrg
9722f167a42Smrg    xkb = state->xkb;
9732f167a42Smrg    if (doodad->any.name != None)
9742f167a42Smrg        dname = XkbAtomGetString(xkb->dpy, doodad->any.name);
9752f167a42Smrg    else
9762f167a42Smrg        dname = "NoName";
9770e20ee16Smrg    switch (doodad->any.type) {
9782f167a42Smrg    case XkbOutlineDoodad:
9792f167a42Smrg    case XkbSolidDoodad:
9802f167a42Smrg        name = XkbAtomGetString(xkb->dpy,
9812f167a42Smrg                                XkbShapeDoodadShape(xkb->geom,
9822f167a42Smrg                                                    &doodad->shape)->name);
9832f167a42Smrg        if (state->args->wantColor) {
9842f167a42Smrg            PSSetColor(out, state, doodad->shape.color_ndx);
9852f167a42Smrg            if (doodad->any.type != XkbOutlineDoodad) {
9862f167a42Smrg                fprintf(out, "true %d %d %d %s %% Doodad %s\n",
9872f167a42Smrg                        doodad->shape.angle,
9882f167a42Smrg                        doodad->shape.left, doodad->shape.top, name, dname);
9892f167a42Smrg                PSSetColor(out, state, state->black);
9902f167a42Smrg            }
9912f167a42Smrg            fprintf(out, "false %d %d %d %s %% Doodad %s\n",
9922f167a42Smrg                    doodad->shape.angle,
9932f167a42Smrg                    doodad->shape.left, doodad->shape.top, name, dname);
9942f167a42Smrg        }
9952f167a42Smrg        else {
9962f167a42Smrg            fprintf(out, "false %d %d %d %s %% Doodad %s\n",
9972f167a42Smrg                    doodad->shape.angle,
9982f167a42Smrg                    doodad->shape.left, doodad->shape.top, name, dname);
9992f167a42Smrg        }
10002f167a42Smrg        break;
10012f167a42Smrg    case XkbTextDoodad:
10022f167a42Smrg        fprintf(out, "%% Doodad %s\n", dname);
10032f167a42Smrg        PSSetColor(out, state, doodad->text.color_ndx);
10042f167a42Smrg        PSGSave(out, state);
10052f167a42Smrg        fprintf(out, "%d %d translate\n", doodad->text.left, doodad->text.top);
10062f167a42Smrg        if (doodad->text.angle != 0)
10072f167a42Smrg            fprintf(out, "%s rotate\n",
10082f167a42Smrg                    XkbGeomFPText(doodad->text.angle, XkbMessage));
10092f167a42Smrg        sz = 14;
10102f167a42Smrg        if (doodad->text.font) {
10112f167a42Smrg            FontStuff stuff;
10122f167a42Smrg
10132f167a42Smrg            if (CrackXLFDName(doodad->text.font, &stuff)) {
10142f167a42Smrg                if (stuff.ptSize > 0)
10152f167a42Smrg                    sz = stuff.ptSize / 10;
10162f167a42Smrg                ClearFontStuff(&stuff);
10172f167a42Smrg            }
10182f167a42Smrg        }
10192f167a42Smrg        PSSetFont(out, state, FONT_LATIN1, sz, True);
10202f167a42Smrg        leading = (sz * 12) / 10;
10212f167a42Smrg        if (strchr(doodad->text.text, '\n') == NULL) {
10222f167a42Smrg            fprintf(out, "0 %d pts moveto 1 -1 scale\n", (leading * 8) / 10);
10232f167a42Smrg            fprintf(out, "(%s) show\n", doodad->text.text);
10242f167a42Smrg        }
10252f167a42Smrg        else {
10262f167a42Smrg            char *tmp, *buf, *end;
10272f167a42Smrg            int offset = (leading * 8 / 10);
10282f167a42Smrg
10292f167a42Smrg            tmp = buf = strdup(doodad->text.text);
10302f167a42Smrg            while (tmp != NULL) {
10312f167a42Smrg                end = strchr(tmp, '\n');
10322f167a42Smrg                if (end != NULL)
10332f167a42Smrg                    *end++ = '\0';
10342f167a42Smrg                fprintf(out, "0 %d pts moveto 1 -1 scale\n", offset);
10352f167a42Smrg                fprintf(out, "(%s) show 1 -1 scale\n", tmp);
10362f167a42Smrg                offset += leading;
10372f167a42Smrg                tmp = end;
10382f167a42Smrg            }
10392f167a42Smrg            free(buf);
10402f167a42Smrg        }
10412f167a42Smrg        PSGRestore(out, state);
10422f167a42Smrg        break;
10432f167a42Smrg    case XkbIndicatorDoodad:
10442f167a42Smrg        name = XkbAtomGetString(xkb->dpy,
10452f167a42Smrg                                XkbIndicatorDoodadShape(xkb->geom,
10462f167a42Smrg                                                        &doodad->indicator)->
10472f167a42Smrg                                name);
10482f167a42Smrg        if (state->args->wantColor) {
10492f167a42Smrg            PSSetColor(out, state, doodad->indicator.off_color_ndx);
10502f167a42Smrg            fprintf(out, "true 0 %d %d %s %% Doodad %s\n",
10512f167a42Smrg                    doodad->indicator.left, doodad->indicator.top, name, dname);
10522f167a42Smrg            PSSetColor(out, state, state->black);
10532f167a42Smrg        }
10542f167a42Smrg        fprintf(out, "false 0 %d %d %s %% Doodad %s\n",
10552f167a42Smrg                doodad->indicator.left, doodad->indicator.top, name, dname);
10562f167a42Smrg        break;
10572f167a42Smrg    case XkbLogoDoodad:
10582f167a42Smrg        name = XkbAtomGetString(xkb->dpy,
10592f167a42Smrg                                XkbLogoDoodadShape(xkb->geom,
10602f167a42Smrg                                                   &doodad->logo)->name);
10612f167a42Smrg        if (state->args->wantColor)
10622f167a42Smrg            PSSetColor(out, state, doodad->shape.color_ndx);
10632f167a42Smrg        fprintf(out, "false %d %d %d %s %% Doodad %s\n",
10642f167a42Smrg                doodad->shape.angle,
10652f167a42Smrg                doodad->shape.left, doodad->shape.top, name, dname);
10662f167a42Smrg        break;
10670e20ee16Smrg    }
10680e20ee16Smrg    return;
10690e20ee16Smrg}
10700e20ee16Smrg
10710e20ee16Smrg/***====================================================================***/
10720e20ee16Smrg
10730e20ee16Smrgstatic Bool
10742f167a42SmrgPSKeycapsSymbol(KeySym sym, unsigned char *buf,
10752f167a42Smrg                int *font_rtrn, int *sz_rtrn, PSState *state)
10760e20ee16Smrg{
10772f167a42Smrg    if (state->args->wantSymbols == NO_SYMBOLS)
10782f167a42Smrg        return False;
10792f167a42Smrg
10802f167a42Smrg    if (font_rtrn != NULL)
10812f167a42Smrg        *font_rtrn = FONT_ISOCAPS;
10822f167a42Smrg    if (sz_rtrn != NULL)
10832f167a42Smrg        *sz_rtrn = SZ_LARGE;
10842f167a42Smrg    buf[1] = '\0';
10850e20ee16Smrg    switch (sym) {
10862f167a42Smrg    case XK_Shift_L:
10872f167a42Smrg    case XK_Shift_R:
10882f167a42Smrg        buf[0] = XKC_ISO_Shift;
10892f167a42Smrg        return True;
10902f167a42Smrg    case XK_Shift_Lock:
10912f167a42Smrg        buf[0] = XKC_ISO_Shift_Lock;
10922f167a42Smrg        return True;
10932f167a42Smrg    case XK_ISO_Lock:
10942f167a42Smrg        buf[0] = XKC_ISO_Caps_Lock;
10952f167a42Smrg        return True;
10962f167a42Smrg    case XK_BackSpace:
10972f167a42Smrg        buf[0] = XKC_ISO_Backspace;
10982f167a42Smrg        return True;
10992f167a42Smrg    case XK_Return:
11002f167a42Smrg        buf[0] = XKC_ISO_Return;
11012f167a42Smrg        return True;
11022f167a42Smrg    case XK_Up:
11032f167a42Smrg    case XK_KP_Up:
11042f167a42Smrg        buf[0] = XKC_ISO_Up;
11052f167a42Smrg        return True;
11062f167a42Smrg    case XK_Down:
11072f167a42Smrg    case XK_KP_Down:
11082f167a42Smrg        buf[0] = XKC_ISO_Down;
11092f167a42Smrg        return True;
11102f167a42Smrg    case XK_Left:
11112f167a42Smrg    case XK_KP_Left:
11122f167a42Smrg        buf[0] = XKC_ISO_Left;
11132f167a42Smrg        return True;
11142f167a42Smrg    case XK_Right:
11152f167a42Smrg    case XK_KP_Right:
11162f167a42Smrg        buf[0] = XKC_ISO_Right;
11172f167a42Smrg        return True;
11182f167a42Smrg    case XK_Tab:
11192f167a42Smrg        buf[0] = XKC_ISO_Tab;
11202f167a42Smrg        return True;
11212f167a42Smrg    case XK_ISO_Left_Tab:
11222f167a42Smrg        buf[0] = XKC_ISO_Left_Tab;
11232f167a42Smrg        return True;
11240e20ee16Smrg    }
11252f167a42Smrg    if (state->args->wantSymbols != ALL_SYMBOLS)
11262f167a42Smrg        return False;
11270e20ee16Smrg    switch (sym) {
11282f167a42Smrg    case XK_Caps_Lock:
11292f167a42Smrg        buf[0] = XKC_ISO_Caps_Lock;
11302f167a42Smrg        return True;
11312f167a42Smrg    case XK_Num_Lock:
11322f167a42Smrg        buf[0] = XKC_ISO_Num_Lock;
11332f167a42Smrg        return True;
11342f167a42Smrg    case XK_ISO_Level3_Shift:
11352f167a42Smrg        buf[0] = XKC_ISO_Level3_Shift;
11362f167a42Smrg        return True;
11372f167a42Smrg    case XK_ISO_Level3_Lock:
11382f167a42Smrg        buf[0] = XKC_ISO_Level3_Lock;
11392f167a42Smrg        return True;
11402f167a42Smrg    case XK_ISO_Next_Group:
11412f167a42Smrg    case XK_ISO_Group_Shift:
11422f167a42Smrg        buf[0] = XKC_ISO_Next_Group;
11432f167a42Smrg        return True;
11442f167a42Smrg    case XK_ISO_Next_Group_Lock:
11452f167a42Smrg        buf[0] = XKC_ISO_Next_Group_Lock;
11462f167a42Smrg        return True;
11472f167a42Smrg    case XK_space:
11482f167a42Smrg        buf[0] = XKC_ISO_Space;
11492f167a42Smrg        return True;
11502f167a42Smrg    case XK_nobreakspace:
11512f167a42Smrg        buf[0] = XKC_ISO_No_Break_Space;
11522f167a42Smrg        return True;
11532f167a42Smrg    case XK_Insert:
11542f167a42Smrg        buf[0] = XKC_ISO_Insert;
11552f167a42Smrg        return True;
11562f167a42Smrg    case XK_ISO_Continuous_Underline:
11572f167a42Smrg        buf[0] = XKC_ISO_Continuous_Underline;
11582f167a42Smrg        return True;
11592f167a42Smrg    case XK_ISO_Discontinuous_Underline:
11602f167a42Smrg        buf[0] = XKC_ISO_Discontinuous_Underline;
11612f167a42Smrg        return True;
11622f167a42Smrg    case XK_ISO_Emphasize:
11632f167a42Smrg        buf[0] = XKC_ISO_Emphasize;
11642f167a42Smrg        return True;
11652f167a42Smrg    case XK_Multi_key:
11662f167a42Smrg        buf[0] = XKC_ISO_Compose;
11672f167a42Smrg        return True;
11682f167a42Smrg    case XK_ISO_Center_Object:
11692f167a42Smrg        buf[0] = XKC_ISO_Center_Object;
11702f167a42Smrg        return True;
11712f167a42Smrg    case XK_Delete:
11722f167a42Smrg        buf[0] = XKC_ISO_Delete;
11732f167a42Smrg        return True;
11742f167a42Smrg    case XK_Clear:
11752f167a42Smrg        buf[0] = XKC_ISO_Clear_Screen;
11762f167a42Smrg        return True;
11772f167a42Smrg    case XK_Scroll_Lock:
11782f167a42Smrg        buf[0] = XKC_ISO_Scroll_Lock;
11792f167a42Smrg        return True;
11802f167a42Smrg    case XK_Help:
11812f167a42Smrg        buf[0] = XKC_ISO_Help;
11822f167a42Smrg        return True;
11832f167a42Smrg    case XK_Print:
11842f167a42Smrg        buf[0] = XKC_ISO_Print_Screen;
11852f167a42Smrg        return True;
11862f167a42Smrg    case XK_ISO_Enter:
11872f167a42Smrg        buf[0] = XKC_ISO_Enter;
11882f167a42Smrg        return True;
11892f167a42Smrg    case XK_Alt_L:
11902f167a42Smrg    case XK_Alt_R:
11912f167a42Smrg        buf[0] = XKC_ISO_Alt;
11922f167a42Smrg        return True;
11932f167a42Smrg    case XK_Control_L:
11942f167a42Smrg    case XK_Control_R:
11952f167a42Smrg        buf[0] = XKC_ISO_Control;
11962f167a42Smrg        return True;
11972f167a42Smrg    case XK_Pause:
11982f167a42Smrg        buf[0] = XKC_ISO_Pause;
11992f167a42Smrg        return True;
12002f167a42Smrg    case XK_Break:
12012f167a42Smrg        buf[0] = XKC_ISO_Break;
12022f167a42Smrg        return True;
12032f167a42Smrg    case XK_Escape:
12042f167a42Smrg        buf[0] = XKC_ISO_Escape;
12052f167a42Smrg        return True;
12062f167a42Smrg    case XK_Undo:
12072f167a42Smrg        buf[0] = XKC_ISO_Undo;
12082f167a42Smrg        return True;
12092f167a42Smrg    case XK_ISO_Fast_Cursor_Up:
12102f167a42Smrg        buf[0] = XKC_ISO_Fast_Cursor_Up;
12112f167a42Smrg        return True;
12122f167a42Smrg    case XK_ISO_Fast_Cursor_Down:
12132f167a42Smrg        buf[0] = XKC_ISO_Fast_Cursor_Down;
12142f167a42Smrg        return True;
12152f167a42Smrg    case XK_ISO_Fast_Cursor_Left:
12162f167a42Smrg        buf[0] = XKC_ISO_Fast_Cursor_Left;
12172f167a42Smrg        return True;
12182f167a42Smrg    case XK_ISO_Fast_Cursor_Right:
12192f167a42Smrg        buf[0] = XKC_ISO_Fast_Cursor_Right;
12202f167a42Smrg        return True;
12212f167a42Smrg    case XK_Home:
12222f167a42Smrg        buf[0] = XKC_ISO_Home;
12232f167a42Smrg        return True;
12242f167a42Smrg    case XK_End:
12252f167a42Smrg        buf[0] = XKC_ISO_End;
12262f167a42Smrg        return True;
12272f167a42Smrg    case XK_Page_Up:
12282f167a42Smrg        buf[0] = XKC_ISO_Page_Up;
12292f167a42Smrg        return True;
12302f167a42Smrg    case XK_Page_Down:
12312f167a42Smrg        buf[0] = XKC_ISO_Page_Down;
12322f167a42Smrg        return True;
12332f167a42Smrg    case XK_ISO_Move_Line_Up:
12342f167a42Smrg        buf[0] = XKC_ISO_Move_Line_Up;
12352f167a42Smrg        return True;
12362f167a42Smrg    case XK_ISO_Move_Line_Down:
12372f167a42Smrg        buf[0] = XKC_ISO_Move_Line_Down;
12382f167a42Smrg        return True;
12392f167a42Smrg    case XK_ISO_Partial_Line_Up:
12402f167a42Smrg        buf[0] = XKC_ISO_Partial_Line_Up;
12412f167a42Smrg        return True;
12422f167a42Smrg    case XK_ISO_Partial_Line_Down:
12432f167a42Smrg        buf[0] = XKC_ISO_Partial_Line_Down;
12442f167a42Smrg        return True;
12452f167a42Smrg    case XK_ISO_Partial_Space_Left:
12462f167a42Smrg        buf[0] = XKC_ISO_Partial_Space_Left;
12472f167a42Smrg        return True;
12482f167a42Smrg    case XK_ISO_Partial_Space_Right:
12492f167a42Smrg        buf[0] = XKC_ISO_Partial_Space_Right;
12502f167a42Smrg        return True;
12512f167a42Smrg    case XK_ISO_Set_Margin_Left:
12522f167a42Smrg        buf[0] = XKC_ISO_Set_Margin_Left;
12532f167a42Smrg        return True;
12542f167a42Smrg    case XK_ISO_Set_Margin_Right:
12552f167a42Smrg        buf[0] = XKC_ISO_Set_Margin_Right;
12562f167a42Smrg        return True;
12572f167a42Smrg    case XK_ISO_Release_Margin_Left:
12582f167a42Smrg        buf[0] = XKC_ISO_Release_Margin_Left;
12592f167a42Smrg        return True;
12602f167a42Smrg    case XK_ISO_Release_Margin_Right:
12612f167a42Smrg        buf[0] = XKC_ISO_Release_Margin_Right;
12622f167a42Smrg        return True;
12632f167a42Smrg    case XK_ISO_Release_Both_Margins:
12642f167a42Smrg        buf[0] = XKC_ISO_Release_Both_Margins;
12652f167a42Smrg        return True;
12662f167a42Smrg    case XK_ISO_Prev_Group:
12672f167a42Smrg        buf[0] = XKC_ISO_Prev_Group;
12682f167a42Smrg        return True;
12692f167a42Smrg    case XK_ISO_Prev_Group_Lock:
12702f167a42Smrg        buf[0] = XKC_ISO_Prev_Group_Lock;
12712f167a42Smrg        return True;
12720e20ee16Smrg    }
12730e20ee16Smrg    return False;
12740e20ee16Smrg}
12750e20ee16Smrg
12760e20ee16Smrgstatic Bool
12770e20ee16SmrgPSNonLatin1Symbol(KeySym sym, unsigned char *buf,
12782f167a42Smrg                  int *font_rtrn, int *sz_rtrn, PSState *state)
12790e20ee16Smrg{
12802f167a42Smrg    if (state->args->wantSymbols == NO_SYMBOLS)
12812f167a42Smrg        return False;
12822f167a42Smrg
12832f167a42Smrg    if (font_rtrn != NULL)
12842f167a42Smrg        *font_rtrn = FONT_TEXT;
12852f167a42Smrg    if (sz_rtrn != NULL)
12862f167a42Smrg        *sz_rtrn = SZ_LARGE;
12872f167a42Smrg    buf[1] = '\0';
12880e20ee16Smrg    switch (sym) {
12892f167a42Smrg    case XK_breve:
12902f167a42Smrg        buf[0] = 0xC6;
12912f167a42Smrg        return True;
12922f167a42Smrg    case XK_abovedot:
12932f167a42Smrg        buf[0] = 0xC7;
12942f167a42Smrg        return True;
12952f167a42Smrg    case XK_doubleacute:
12962f167a42Smrg        buf[0] = 0xCD;
12972f167a42Smrg        return True;
12982f167a42Smrg    case XK_ogonek:
12992f167a42Smrg        buf[0] = 0xCE;
13002f167a42Smrg        return True;
13012f167a42Smrg    case XK_caron:
13022f167a42Smrg        buf[0] = 0xCF;
13032f167a42Smrg        return True;
13042f167a42Smrg    case XK_Lstroke:
13052f167a42Smrg        buf[0] = 0xE8;
13062f167a42Smrg        return True;
13072f167a42Smrg    case XK_idotless:
13082f167a42Smrg        buf[0] = 0xF5;
13092f167a42Smrg        return True;
13102f167a42Smrg    case XK_lstroke:
13112f167a42Smrg        buf[0] = 0xF8;
13122f167a42Smrg        return True;
13130e20ee16Smrg    }
13142f167a42Smrg    if (font_rtrn != NULL)
13152f167a42Smrg        *font_rtrn = FONT_SYMBOL;
13162f167a42Smrg    if (sz_rtrn != NULL)
13172f167a42Smrg        *sz_rtrn = SZ_MEDIUM;
13182f167a42Smrg    if ((sym & (~0xffUL)) == 0x700) {
13192f167a42Smrg        switch (sym) {
13202f167a42Smrg            /* Greek symbol */
13212f167a42Smrg        case XK_Greek_ALPHA:
13222f167a42Smrg            buf[0] = 0x41;
13232f167a42Smrg            return True;
13242f167a42Smrg        case XK_Greek_BETA:
13252f167a42Smrg            buf[0] = 0x42;
13262f167a42Smrg            return True;
13272f167a42Smrg        case XK_Greek_CHI:
13282f167a42Smrg            buf[0] = 0x43;
13292f167a42Smrg            return True;
13302f167a42Smrg        case XK_Greek_DELTA:
13312f167a42Smrg            buf[0] = 0x44;
13322f167a42Smrg            return True;
13332f167a42Smrg        case XK_Greek_EPSILON:
13342f167a42Smrg            buf[0] = 0x45;
13352f167a42Smrg            return True;
13362f167a42Smrg        case XK_Greek_PHI:
13372f167a42Smrg            buf[0] = 0x46;
13382f167a42Smrg            return True;
13392f167a42Smrg        case XK_Greek_GAMMA:
13402f167a42Smrg            buf[0] = 0x47;
13412f167a42Smrg            return True;
13422f167a42Smrg        case XK_Greek_ETA:
13432f167a42Smrg            buf[0] = 0x48;
13442f167a42Smrg            return True;
13452f167a42Smrg        case XK_Greek_IOTA:
13462f167a42Smrg            buf[0] = 0x49;
13472f167a42Smrg            return True;
13482f167a42Smrg        case XK_Greek_KAPPA:
13492f167a42Smrg            buf[0] = 0x4B;
13502f167a42Smrg            return True;
13512f167a42Smrg        case XK_Greek_LAMDA:
13522f167a42Smrg            buf[0] = 0x4C;
13532f167a42Smrg            return True;
13542f167a42Smrg        case XK_Greek_MU:
13552f167a42Smrg            buf[0] = 0x4D;
13562f167a42Smrg            return True;
13572f167a42Smrg        case XK_Greek_NU:
13582f167a42Smrg            buf[0] = 0x4E;
13592f167a42Smrg            return True;
13602f167a42Smrg        case XK_Greek_OMICRON:
13612f167a42Smrg            buf[0] = 0x4F;
13622f167a42Smrg            return True;
13632f167a42Smrg        case XK_Greek_PI:
13642f167a42Smrg            buf[0] = 0x50;
13652f167a42Smrg            return True;
13662f167a42Smrg        case XK_Greek_THETA:
13672f167a42Smrg            buf[0] = 0x51;
13682f167a42Smrg            return True;
13692f167a42Smrg        case XK_Greek_RHO:
13702f167a42Smrg            buf[0] = 0x52;
13712f167a42Smrg            return True;
13722f167a42Smrg        case XK_Greek_SIGMA:
13732f167a42Smrg            buf[0] = 0x53;
13742f167a42Smrg            return True;
13752f167a42Smrg        case XK_Greek_TAU:
13762f167a42Smrg            buf[0] = 0x54;
13772f167a42Smrg            return True;
13782f167a42Smrg        case XK_Greek_UPSILON:
13792f167a42Smrg            buf[0] = 0x55;
13802f167a42Smrg            return True;
13812f167a42Smrg        case XK_Greek_OMEGA:
13822f167a42Smrg            buf[0] = 0x57;
13832f167a42Smrg            return True;
13842f167a42Smrg        case XK_Greek_XI:
13852f167a42Smrg            buf[0] = 0x58;
13862f167a42Smrg            return True;
13872f167a42Smrg        case XK_Greek_PSI:
13882f167a42Smrg            buf[0] = 0x59;
13892f167a42Smrg            return True;
13902f167a42Smrg        case XK_Greek_ZETA:
13912f167a42Smrg            buf[0] = 0x5A;
13922f167a42Smrg            return True;
13932f167a42Smrg
13942f167a42Smrg        case XK_Greek_alpha:
13952f167a42Smrg            buf[0] = 0x61;
13962f167a42Smrg            return True;
13972f167a42Smrg        case XK_Greek_beta:
13982f167a42Smrg            buf[0] = 0x62;
13992f167a42Smrg            return True;
14002f167a42Smrg        case XK_Greek_chi:
14012f167a42Smrg            buf[0] = 0x63;
14022f167a42Smrg            return True;
14032f167a42Smrg        case XK_Greek_delta:
14042f167a42Smrg            buf[0] = 0x64;
14052f167a42Smrg            return True;
14062f167a42Smrg        case XK_Greek_epsilon:
14072f167a42Smrg            buf[0] = 0x65;
14082f167a42Smrg            return True;
14092f167a42Smrg        case XK_Greek_phi:
14102f167a42Smrg            buf[0] = 0x66;
14112f167a42Smrg            return True;
14122f167a42Smrg        case XK_Greek_gamma:
14132f167a42Smrg            buf[0] = 0x67;
14142f167a42Smrg            return True;
14152f167a42Smrg        case XK_Greek_eta:
14162f167a42Smrg            buf[0] = 0x68;
14172f167a42Smrg            return True;
14182f167a42Smrg        case XK_Greek_iota:
14192f167a42Smrg            buf[0] = 0x69;
14202f167a42Smrg            return True;
14212f167a42Smrg        case XK_Greek_kappa:
14222f167a42Smrg            buf[0] = 0x6B;
14232f167a42Smrg            return True;
14242f167a42Smrg        case XK_Greek_lamda:
14252f167a42Smrg            buf[0] = 0x6C;
14262f167a42Smrg            return True;
14272f167a42Smrg        case XK_Greek_mu:
14282f167a42Smrg            buf[0] = 0x6D;
14292f167a42Smrg            return True;
14302f167a42Smrg        case XK_Greek_nu:
14312f167a42Smrg            buf[0] = 0x6E;
14322f167a42Smrg            return True;
14332f167a42Smrg        case XK_Greek_omicron:
14342f167a42Smrg            buf[0] = 0x6F;
14352f167a42Smrg            return True;
14362f167a42Smrg        case XK_Greek_pi:
14372f167a42Smrg            buf[0] = 0x70;
14382f167a42Smrg            return True;
14392f167a42Smrg        case XK_Greek_theta:
14402f167a42Smrg            buf[0] = 0x71;
14412f167a42Smrg            return True;
14422f167a42Smrg        case XK_Greek_rho:
14432f167a42Smrg            buf[0] = 0x72;
14442f167a42Smrg            return True;
14452f167a42Smrg        case XK_Greek_sigma:
14462f167a42Smrg            buf[0] = 0x73;
14472f167a42Smrg            return True;
14482f167a42Smrg        case XK_Greek_tau:
14492f167a42Smrg            buf[0] = 0x74;
14502f167a42Smrg            return True;
14512f167a42Smrg        case XK_Greek_upsilon:
14522f167a42Smrg            buf[0] = 0x75;
14532f167a42Smrg            return True;
14542f167a42Smrg        case XK_Greek_omega:
14552f167a42Smrg            buf[0] = 0x77;
14562f167a42Smrg            return True;
14572f167a42Smrg        case XK_Greek_xi:
14582f167a42Smrg            buf[0] = 0x78;
14592f167a42Smrg            return True;
14602f167a42Smrg        case XK_Greek_psi:
14612f167a42Smrg            buf[0] = 0x79;
14622f167a42Smrg            return True;
14632f167a42Smrg        case XK_Greek_zeta:
14642f167a42Smrg            buf[0] = 0x7A;
14652f167a42Smrg            return True;
14662f167a42Smrg        }
14670e20ee16Smrg    }
14680e20ee16Smrg    switch (sym) {
14692f167a42Smrg    case XK_leftarrow:
14702f167a42Smrg        buf[0] = 0xAC;
14712f167a42Smrg        return True;
14722f167a42Smrg    case XK_uparrow:
14732f167a42Smrg        buf[0] = 0xAD;
14742f167a42Smrg        return True;
14752f167a42Smrg    case XK_rightarrow:
14762f167a42Smrg        buf[0] = 0xAE;
14772f167a42Smrg        return True;
14782f167a42Smrg    case XK_downarrow:
14792f167a42Smrg        buf[0] = 0xAF;
14802f167a42Smrg        return True;
14812f167a42Smrg    case XK_horizconnector:
14822f167a42Smrg        buf[0] = 0xBE;
14832f167a42Smrg        return True;
14842f167a42Smrg    case XK_trademark:
14852f167a42Smrg        buf[0] = 0xE4;
14862f167a42Smrg        return True;
14870e20ee16Smrg    }
14880e20ee16Smrg    return False;
14890e20ee16Smrg}
14900e20ee16Smrg
14910e20ee16Smrgstatic KeySym
14920e20ee16SmrgCheckSymbolAlias(KeySym sym, PSState *state)
14930e20ee16Smrg{
14940e20ee16Smrg    if (XkbKSIsKeypad(sym)) {
14952f167a42Smrg        if ((sym >= XK_KP_0) && (sym <= XK_KP_9))
14962f167a42Smrg            sym = (sym - XK_KP_0) + XK_0;
14972f167a42Smrg        else
14982f167a42Smrg            switch (sym) {
14992f167a42Smrg            case XK_KP_Space:
15002f167a42Smrg                return XK_space;
15012f167a42Smrg            case XK_KP_Tab:
15022f167a42Smrg                return XK_Tab;
15032f167a42Smrg            case XK_KP_Enter:
15042f167a42Smrg                return XK_Return;
15052f167a42Smrg            case XK_KP_F1:
15062f167a42Smrg                return XK_F1;
15072f167a42Smrg            case XK_KP_F2:
15082f167a42Smrg                return XK_F2;
15092f167a42Smrg            case XK_KP_F3:
15102f167a42Smrg                return XK_F3;
15112f167a42Smrg            case XK_KP_F4:
15122f167a42Smrg                return XK_F4;
15132f167a42Smrg            case XK_KP_Home:
15142f167a42Smrg                return XK_Home;
15152f167a42Smrg            case XK_KP_Left:
15162f167a42Smrg                return XK_Left;
15172f167a42Smrg            case XK_KP_Up:
15182f167a42Smrg                return XK_Up;
15192f167a42Smrg            case XK_KP_Right:
15202f167a42Smrg                return XK_Right;
15212f167a42Smrg            case XK_KP_Down:
15222f167a42Smrg                return XK_Down;
15232f167a42Smrg            case XK_KP_Page_Up:
15242f167a42Smrg                return XK_Page_Up;
15252f167a42Smrg            case XK_KP_Page_Down:
15262f167a42Smrg                return XK_Page_Down;
15272f167a42Smrg            case XK_KP_End:
15282f167a42Smrg                return XK_End;
15292f167a42Smrg            case XK_KP_Begin:
15302f167a42Smrg                return XK_Begin;
15312f167a42Smrg            case XK_KP_Insert:
15322f167a42Smrg                return XK_Insert;
15332f167a42Smrg            case XK_KP_Delete:
15342f167a42Smrg                return XK_Delete;
15352f167a42Smrg            case XK_KP_Equal:
15362f167a42Smrg                return XK_equal;
15372f167a42Smrg            case XK_KP_Multiply:
15382f167a42Smrg                return XK_asterisk;
15392f167a42Smrg            case XK_KP_Add:
15402f167a42Smrg                return XK_plus;
15412f167a42Smrg            case XK_KP_Subtract:
15422f167a42Smrg                return XK_minus;
15432f167a42Smrg            case XK_KP_Divide:
15442f167a42Smrg                return XK_slash;
15452f167a42Smrg            }
15460e20ee16Smrg    }
15470e20ee16Smrg    else if (XkbKSIsDeadKey(sym)) {
15482f167a42Smrg        switch (sym) {
15492f167a42Smrg        case XK_dead_grave:
15502f167a42Smrg            sym = XK_grave;
15512f167a42Smrg            break;
15522f167a42Smrg        case XK_dead_acute:
15532f167a42Smrg            sym = XK_acute;
15542f167a42Smrg            break;
15552f167a42Smrg        case XK_dead_circumflex:
15562f167a42Smrg            sym = XK_asciicircum;
15572f167a42Smrg            break;
15582f167a42Smrg        case XK_dead_tilde:
15592f167a42Smrg            sym = XK_asciitilde;
15602f167a42Smrg            break;
15612f167a42Smrg        case XK_dead_macron:
15622f167a42Smrg            sym = XK_macron;
15632f167a42Smrg            break;
15642f167a42Smrg        case XK_dead_breve:
15652f167a42Smrg            sym = XK_breve;
15662f167a42Smrg            break;
15672f167a42Smrg        case XK_dead_abovedot:
15682f167a42Smrg            sym = XK_abovedot;
15692f167a42Smrg            break;
15702f167a42Smrg        case XK_dead_diaeresis:
15712f167a42Smrg            sym = XK_diaeresis;
15722f167a42Smrg            break;
15732f167a42Smrg        case XK_dead_abovering:
15742f167a42Smrg            sym = XK_degree;
15752f167a42Smrg            break;
15762f167a42Smrg        case XK_dead_doubleacute:
15772f167a42Smrg            sym = XK_doubleacute;
15782f167a42Smrg            break;
15792f167a42Smrg        case XK_dead_caron:
15802f167a42Smrg            sym = XK_caron;
15812f167a42Smrg            break;
15822f167a42Smrg        case XK_dead_cedilla:
15832f167a42Smrg            sym = XK_cedilla;
15842f167a42Smrg            break;
15852f167a42Smrg        case XK_dead_ogonek:
15862f167a42Smrg            sym = XK_ogonek;
15872f167a42Smrg            break;
15882f167a42Smrg        case XK_dead_iota:
15892f167a42Smrg            sym = XK_Greek_iota;
15902f167a42Smrg            break;
15912f167a42Smrg        case XK_dead_voiced_sound:
15922f167a42Smrg            sym = XK_voicedsound;
15932f167a42Smrg            break;
15942f167a42Smrg        case XK_dead_semivoiced_sound:
15952f167a42Smrg            sym = XK_semivoicedsound;
15962f167a42Smrg            break;
15972f167a42Smrg        }
15980e20ee16Smrg    }
15990e20ee16Smrg    return sym;
16000e20ee16Smrg}
16010e20ee16Smrg
16020e20ee16Smrgstatic Bool
16030e20ee16SmrgFindKeysymsByName(XkbDescPtr xkb, char *name, PSState *state, KeyTop *top)
16040e20ee16Smrg{
16052f167a42Smrg    static unsigned char buf[30];
16062f167a42Smrg    int kc;
16072f167a42Smrg    KeySym sym, *syms, topSyms[NLABELS];
16082f167a42Smrg    int level, group;
16092f167a42Smrg    int eG, nG, gI, l, g;
16102f167a42Smrg
16112f167a42Smrg    bzero(top, sizeof(KeyTop));
16122f167a42Smrg    kc = XkbFindKeycodeByName(xkb, name, True);
16132f167a42Smrg    if (state->args != NULL) {
16142f167a42Smrg        level = state->args->labelLevel;
16152f167a42Smrg        group = state->args->baseLabelGroup;
16160e20ee16Smrg    }
16172f167a42Smrg    else
16182f167a42Smrg        level = group = 0;
16192f167a42Smrg    syms = XkbKeySymsPtr(xkb, kc);
16202f167a42Smrg    eG = group;
16212f167a42Smrg    nG = XkbKeyNumGroups(xkb, kc);
16222f167a42Smrg    gI = XkbKeyGroupInfo(xkb, kc);
16232f167a42Smrg    if ((state->args->wantDiffs) && (eG >= XkbKeyNumGroups(xkb, kc)))
16242f167a42Smrg        return False;           /* XXX was a return with no value */
16252f167a42Smrg    if (nG == 0) {
16262f167a42Smrg        return False;
16270e20ee16Smrg    }
16282f167a42Smrg    else if (nG == 1) {
16292f167a42Smrg        eG = 0;
16300e20ee16Smrg    }
16312f167a42Smrg    else if (eG >= XkbKeyNumGroups(xkb, kc)) {
16322f167a42Smrg        switch (XkbOutOfRangeGroupAction(gI)) {
16332f167a42Smrg        default:
16342f167a42Smrg            eG %= nG;
16352f167a42Smrg            break;
16362f167a42Smrg        case XkbClampIntoRange:
16372f167a42Smrg            eG = nG - 1;
16382f167a42Smrg            break;
16392f167a42Smrg        case XkbRedirectIntoRange:
16402f167a42Smrg            eG = XkbOutOfRangeGroupNumber(gI);
16412f167a42Smrg            if (eG >= nG)
16422f167a42Smrg                eG = 0;
16432f167a42Smrg            break;
16442f167a42Smrg        }
16450e20ee16Smrg    }
16462f167a42Smrg    for (g = 0; g < state->args->nLabelGroups; g++) {
16472f167a42Smrg        if ((eG + g) >= nG)
16482f167a42Smrg            continue;
16492f167a42Smrg        for (l = 0; l < 2; l++) {
16502f167a42Smrg            int font, sz;
16512f167a42Smrg
16522f167a42Smrg            if (level + l >= XkbKeyGroupWidth(xkb, kc, (eG + g)))
16532f167a42Smrg                continue;
16542f167a42Smrg            sym = syms[((eG + g) * XkbKeyGroupsWidth(xkb, kc)) + (level + l)];
16552f167a42Smrg
16562f167a42Smrg            if (state->args->wantSymbols != NO_SYMBOLS)
16572f167a42Smrg                sym = CheckSymbolAlias(sym, state);
16582f167a42Smrg            topSyms[(g * 2) + l] = sym;
16592f167a42Smrg
16602f167a42Smrg            if (PSKeycapsSymbol(sym, buf, &font, &sz, state)) {
16612f167a42Smrg                top->font[(g * 2) + l] = font;
16622f167a42Smrg                top->size[(g * 2) + l] = sz;
16632f167a42Smrg            }
16642f167a42Smrg            else if (((sym & (~0xffUL)) == 0) && isprint(sym) && (!isspace(sym))) {
16652f167a42Smrg                if (sym == '(')
16662f167a42Smrg                    snprintf((char *) buf, sizeof(buf), "\\(");
16672f167a42Smrg                else if (sym == ')')
16682f167a42Smrg                    snprintf((char *) buf, sizeof(buf), "\\)");
16692f167a42Smrg                else if (sym == '\\')
16702f167a42Smrg                    snprintf((char *) buf, sizeof(buf), "\\\\");
16712f167a42Smrg                else
16722f167a42Smrg                    snprintf((char *) buf, sizeof(buf), "%c", (char) sym);
16732f167a42Smrg                top->font[(g * 2) + l] = FONT_LATIN1;
16742f167a42Smrg                top->size[(g * 2) + l] = SZ_MEDIUM;
16752f167a42Smrg                switch (buf[0]) {
16762f167a42Smrg                case '.':
16772f167a42Smrg                case ':':
16782f167a42Smrg                case ',':
16792f167a42Smrg                case ';':
16802f167a42Smrg                case '\'':
16812f167a42Smrg                case '"':
16822f167a42Smrg                case '`':
16832f167a42Smrg                case '~':
16842f167a42Smrg                case '^':
16852f167a42Smrg                case 0250:
16862f167a42Smrg                case 0270:
16872f167a42Smrg                case 0267:
16882f167a42Smrg                case 0260:
16892f167a42Smrg                case 0252:
16902f167a42Smrg                case 0272:
16912f167a42Smrg                case 0271:
16922f167a42Smrg                case 0262:
16932f167a42Smrg                case 0263:
16942f167a42Smrg                case 0264:
16952f167a42Smrg                case 0255:
16962f167a42Smrg                case 0254:
16972f167a42Smrg                case 0257:
16982f167a42Smrg                    top->size[(g * 2) + l] = SZ_LARGE;
16992f167a42Smrg                    break;
17002f167a42Smrg                }
17012f167a42Smrg            }
17022f167a42Smrg            else if (PSNonLatin1Symbol(sym, buf, &font, &sz, state)) {
17032f167a42Smrg                top->font[(g * 2) + l] = font;
17042f167a42Smrg                top->size[(g * 2) + l] = sz;
17052f167a42Smrg            }
17062f167a42Smrg            else {
17072f167a42Smrg                char *tmp;
17082f167a42Smrg
17092f167a42Smrg                tmp = XKeysymToString(sym);
17102f167a42Smrg                if (tmp != NULL)
17112f167a42Smrg                    strcpy((char *) buf, tmp);
17122f167a42Smrg                else
17132f167a42Smrg                    snprintf((char *) buf, sizeof(buf), "(%ld)", sym);
17142f167a42Smrg                top->font[(g * 2) + l] = FONT_LATIN1;
17152f167a42Smrg                if (strlen((char *) buf) < 9)
17162f167a42Smrg                    top->size[(g * 2) + l] = SZ_SMALL;
17172f167a42Smrg                else
17182f167a42Smrg                    top->size[(g * 2) + l] = SZ_TINY;
17192f167a42Smrg            }
17202f167a42Smrg            top->present |= (1 << ((g * 2) + l));
17212f167a42Smrg            strncpy(top->label[(g * 2) + l], (char *) buf, LABEL_LEN - 1);
17222f167a42Smrg            top->label[(g * 2) + l][LABEL_LEN - 1] = '\0';
17232f167a42Smrg        }
17242f167a42Smrg        if (((g == 0) && (top->present & G1LX_MASK) == G1LX_MASK) ||
17252f167a42Smrg            ((g == 1) && (top->present & G2LX_MASK) == G2LX_MASK)) {
17262f167a42Smrg            KeySym lower, upper;
17272f167a42Smrg
17282f167a42Smrg            XConvertCase(topSyms[(g * 2)], &lower, &upper);
17292f167a42Smrg            if ((topSyms[(g * 2)] == lower) && (topSyms[(g * 2) + 1] == upper)) {
17302f167a42Smrg                top->alpha[g] = True;
17312f167a42Smrg            }
17322f167a42Smrg        }
17330e20ee16Smrg    }
17340e20ee16Smrg    return True;
17350e20ee16Smrg}
17360e20ee16Smrg
17370e20ee16Smrgstatic void
17382f167a42SmrgPSDrawLabel(FILE *out, const char *label, int x, int y, int w, int h)
17390e20ee16Smrg{
17402f167a42Smrg    fprintf(out, "%d %d (%s) centeroffset\n", w, h, label);
17412f167a42Smrg    fprintf(out, "%d add exch\n", y);
17422f167a42Smrg    fprintf(out, "%d add exch moveto\n", x);
17432f167a42Smrg    fprintf(out, "1 -1 scale (%s) show 1 -1 scale\n", label);
17440e20ee16Smrg    return;
17450e20ee16Smrg}
17460e20ee16Smrg
17470e20ee16Smrg#define	TOP_ROW		0
17480e20ee16Smrg#define	BOTTOM_ROW	1
17490e20ee16Smrg#define	CENTER_ROW	2
17500e20ee16Smrg
17510e20ee16Smrg#define	LEFT_COL	0
17520e20ee16Smrg#define	RIGHT_COL	1
17530e20ee16Smrg#define	CENTER_COL	2
17540e20ee16Smrg
17550e20ee16Smrgstatic void
17560e20ee16SmrgPSLabelKey(FILE *out, PSState *state, KeyTop *top, int x, int y,
17572f167a42Smrg           XkbBoundsPtr bounds, int kc, int btm)
17580e20ee16Smrg{
17592f167a42Smrg    int w, h, i;
17602f167a42Smrg    int row_y[3];
17612f167a42Smrg    int col_x[3];
17622f167a42Smrg    int row_h[3];
17632f167a42Smrg    int col_w[3];
17642f167a42Smrg    Bool present[NLABELS];
17652f167a42Smrg    int sym_row[NLABELS];
17662f167a42Smrg    int sym_col[NLABELS];
17672f167a42Smrg
17682f167a42Smrg    w = XkbBoundsWidth(bounds);
17692f167a42Smrg    h = XkbBoundsHeight(bounds);
17702f167a42Smrg    row_y[TOP_ROW] = y + bounds->y1 + (h / 10);
17712f167a42Smrg    row_y[BOTTOM_ROW] = y + bounds->y1 + (h / 2) + (h / 10);
17722f167a42Smrg    row_y[CENTER_ROW] = y + bounds->y1 + (h / 10);
17732f167a42Smrg    row_h[TOP_ROW] = h / 2;
17742f167a42Smrg    row_h[BOTTOM_ROW] = h / 2;
17752f167a42Smrg    row_h[CENTER_ROW] = h;
17762f167a42Smrg
17772f167a42Smrg    col_x[LEFT_COL] = x + bounds->x1;
17782f167a42Smrg    col_x[RIGHT_COL] = x + bounds->x1 + w / 2;
17792f167a42Smrg    col_x[CENTER_COL] = x + bounds->x1;
17802f167a42Smrg    col_w[LEFT_COL] = w / 2;
17812f167a42Smrg    col_w[RIGHT_COL] = w / 2;
17822f167a42Smrg    col_w[CENTER_COL] = w;
17832f167a42Smrg
17842f167a42Smrg    present[G1L1] = False;
17852f167a42Smrg    sym_row[G1L1] = BOTTOM_ROW;
17862f167a42Smrg    sym_col[G1L1] = LEFT_COL;
17872f167a42Smrg
17882f167a42Smrg    present[G1L2] = False;
17892f167a42Smrg    sym_row[G1L2] = TOP_ROW;
17902f167a42Smrg    sym_col[G1L2] = LEFT_COL;
17912f167a42Smrg
17922f167a42Smrg    present[G2L1] = False;
17932f167a42Smrg    sym_row[G2L1] = BOTTOM_ROW;
17942f167a42Smrg    sym_col[G2L1] = RIGHT_COL;
17952f167a42Smrg
17962f167a42Smrg    present[G2L2] = False;
17972f167a42Smrg    sym_row[G2L2] = TOP_ROW;
17982f167a42Smrg    sym_col[G2L2] = RIGHT_COL;
17992f167a42Smrg
18002f167a42Smrg    present[CENTER] = False;
18012f167a42Smrg    sym_row[CENTER] = CENTER_ROW;
18022f167a42Smrg    sym_col[CENTER] = CENTER_COL;
18032f167a42Smrg
18042f167a42Smrg    if (top->present & CENTER_MASK) {
18052f167a42Smrg        present[CENTER] = True;
18060e20ee16Smrg    }
18072f167a42Smrg    else
18082f167a42Smrg        switch (top->present & GXLX_MASK) {
18092f167a42Smrg        case G1L1_MASK:
18102f167a42Smrg            present[G1L1] = True;
18112f167a42Smrg            sym_row[G1L1] = CENTER_ROW;
18122f167a42Smrg            sym_col[G1L1] = CENTER_COL;
18132f167a42Smrg            break;
18142f167a42Smrg        case G1LX_MASK:
18152f167a42Smrg            present[G1L2] = True;
18162f167a42Smrg            if (!top->alpha[0]) {
18172f167a42Smrg                present[G1L1] = True;
18182f167a42Smrg                if ((strlen(top->label[G1L1]) > 1) &&
18192f167a42Smrg                    (top->label[G1L1][0] != '\\'))
18202f167a42Smrg                    sym_col[G1L1] = CENTER_COL;
18212f167a42Smrg                if ((strlen(top->label[G1L2]) > 1) &&
18222f167a42Smrg                    (top->label[G1L1][0] != '\\'))
18232f167a42Smrg                    sym_col[G1L2] = CENTER_COL;
18242f167a42Smrg            }
18252f167a42Smrg            break;
18262f167a42Smrg        default:
18272f167a42Smrg            if ((top->present & G1LX_MASK) == G1LX_MASK) {
18282f167a42Smrg                present[G1L2] = True;
18292f167a42Smrg                if (!top->alpha[0])
18302f167a42Smrg                    present[G1L1] = True;
18312f167a42Smrg            }
18322f167a42Smrg            else if ((top->present & G1LX_MASK) == G1L1_MASK) {
18332f167a42Smrg                present[G1L1] = True;
18342f167a42Smrg            }
18352f167a42Smrg            else if ((top->present & G1LX_MASK) == G1L2_MASK) {
18362f167a42Smrg                present[G1L2] = True;
18372f167a42Smrg            }
18382f167a42Smrg            if ((top->present & G2LX_MASK) == G2LX_MASK) {
18392f167a42Smrg                present[G2L2] = True;
18402f167a42Smrg                if (!top->alpha[1])
18412f167a42Smrg                    present[G2L1] = True;
18422f167a42Smrg            }
18432f167a42Smrg            else if ((top->present & G2LX_MASK) == G2L1_MASK) {
18442f167a42Smrg                present[G2L1] = True;
18452f167a42Smrg            }
18462f167a42Smrg            else if ((top->present & G2LX_MASK) == G2L2_MASK) {
18472f167a42Smrg                present[G2L2] = True;
18482f167a42Smrg            }
18492f167a42Smrg            break;
18502f167a42Smrg        case 0:
18512f167a42Smrg            return;
18522f167a42Smrg        }
18532f167a42Smrg    for (i = 0; i < NLABELS; i++) {
18542f167a42Smrg        if (present[i]) {
18552f167a42Smrg            int size;
18562f167a42Smrg
18572f167a42Smrg            if (top->size[i] == SZ_AUTO) {
18582f167a42Smrg                size_t len = strlen(top->label[i]);
18592f167a42Smrg                if (len == 1) {
18602f167a42Smrg                    if (top->font[i] == FONT_ISOCAPS)
18612f167a42Smrg                        size = 18;
18622f167a42Smrg                    else
18632f167a42Smrg                        size = 14;
18642f167a42Smrg                }
18652f167a42Smrg                else if (len < 10)
18662f167a42Smrg                    size = 12;
18672f167a42Smrg                else
18682f167a42Smrg                    size = 10;
18692f167a42Smrg            }
18702f167a42Smrg            else if (top->size[i] == SZ_TINY)
18712f167a42Smrg                size = 10;
18722f167a42Smrg            else if (top->size[i] == SZ_SMALL)
18732f167a42Smrg                size = 12;
18742f167a42Smrg            else if (top->size[i] == SZ_LARGE)
18752f167a42Smrg                size = 18;
18762f167a42Smrg            else if (top->size[i] == SZ_XLARGE)
18772f167a42Smrg                size = 24;
18782f167a42Smrg            else
18792f167a42Smrg                size = 14;
18802f167a42Smrg            PSSetFont(out, state, top->font[i], size, True);
18812f167a42Smrg            PSDrawLabel(out, top->label[i], col_x[sym_col[i]],
18822f167a42Smrg                        row_y[sym_row[i]], col_w[sym_col[i]],
18832f167a42Smrg                        row_h[sym_row[i]]);
18842f167a42Smrg        }
18850e20ee16Smrg    }
18860e20ee16Smrg    if (state->args->wantKeycodes) {
18872f167a42Smrg        char keycode[10];
18882f167a42Smrg
18892f167a42Smrg        snprintf(keycode, sizeof(keycode), "%d", kc);
18902f167a42Smrg        PSSetFont(out, state, FONT_LATIN1, 8, True);
18912f167a42Smrg        PSDrawLabel(out, keycode, x + bounds->x1, y + btm - 5, w, 0);
18920e20ee16Smrg    }
18930e20ee16Smrg    return;
18940e20ee16Smrg}
18950e20ee16Smrg
18960e20ee16Smrgstatic void
18970e20ee16SmrgPSSection(FILE *out, PSState *state, XkbSectionPtr section)
18980e20ee16Smrg{
18992f167a42Smrg    int r, offset;
19002f167a42Smrg    XkbRowPtr row;
19012f167a42Smrg    Display *dpy;
19022f167a42Smrg    XkbDescPtr xkb;
19032f167a42Smrg
19042f167a42Smrg    xkb = state->xkb;
19052f167a42Smrg    dpy = xkb->dpy;
19062f167a42Smrg    fprintf(out, "%% Begin Section '%s'\n", (section->name != None ?
19072f167a42Smrg             XkbAtomGetString(dpy, section-> name) : "NoName"));
19082f167a42Smrg    PSGSave(out, state);
19092f167a42Smrg    fprintf(out, "%d %d translate\n", section->left, section->top);
19102f167a42Smrg    if (section->angle != 0)
19112f167a42Smrg        fprintf(out, "%s rotate\n", XkbGeomFPText(section->angle, XkbMessage));
19120e20ee16Smrg    if (section->doodads) {
19132f167a42Smrg        XkbDrawablePtr first, draw;
19142f167a42Smrg
19152f167a42Smrg        first = draw = XkbGetOrderedDrawables(NULL, section);
19162f167a42Smrg        while (draw) {
19172f167a42Smrg            if (draw->type == XkbDW_Section)
19182f167a42Smrg                PSSection(out, state, draw->u.section);
19192f167a42Smrg            else
19202f167a42Smrg                PSDoodad(out, state, draw->u.doodad);
19212f167a42Smrg            draw = draw->next;
19222f167a42Smrg        }
19232f167a42Smrg        XkbFreeOrderedDrawables(first);
19240e20ee16Smrg    }
19252f167a42Smrg    for (r = 0, row = section->rows; r < section->num_rows; r++, row++) {
19262f167a42Smrg        int k;
19272f167a42Smrg        XkbKeyPtr key;
19282f167a42Smrg        XkbShapePtr shape;
19292f167a42Smrg
19302f167a42Smrg        if (row->vertical)
19312f167a42Smrg            offset = row->top;
19322f167a42Smrg        else
19332f167a42Smrg            offset = row->left;
19342f167a42Smrg        fprintf(out, "%% Begin %s %d\n", row->vertical ? "column" : "row",
19352f167a42Smrg                r + 1);
19362f167a42Smrg        for (k = 0, key = row->keys; k < row->num_keys; k++, key++) {
19372f167a42Smrg            shape = XkbKeyShape(xkb->geom, key);
19382f167a42Smrg            offset += key->gap;
19392f167a42Smrg            if (row->vertical) {
19402f167a42Smrg                if (state->args->wantColor) {
19412f167a42Smrg                    if (key->color_ndx != state->white) {
19422f167a42Smrg                        PSSetColor(out, state, key->color_ndx);
19432f167a42Smrg                        fprintf(out, "true 0 %d %d %s %% %s\n",
19442f167a42Smrg                                row->left, offset,
19452f167a42Smrg                                XkbAtomGetString(dpy, shape->name),
19462f167a42Smrg                                XkbKeyNameText(key->name.name, XkbMessage));
19472f167a42Smrg                    }
19482f167a42Smrg                    PSSetColor(out, state, state->black);
19492f167a42Smrg                }
19502f167a42Smrg                fprintf(out, "false 0 %d %d %s %% %s\n", row->left, offset,
19512f167a42Smrg                        XkbAtomGetString(dpy, shape->name),
19522f167a42Smrg                        XkbKeyNameText(key->name.name, XkbMessage));
19532f167a42Smrg                offset += shape->bounds.y2;
19542f167a42Smrg            }
19552f167a42Smrg            else {
19562f167a42Smrg                if (state->args->wantColor) {
19572f167a42Smrg                    if (key->color_ndx != state->white) {
19582f167a42Smrg                        PSSetColor(out, state, key->color_ndx);
19592f167a42Smrg                        fprintf(out, "true 0 %d %d %s %% %s\n", offset,
19602f167a42Smrg                                row->top, XkbAtomGetString(dpy, shape->name),
19612f167a42Smrg                                XkbKeyNameText(key->name.name, XkbMessage));
19622f167a42Smrg                    }
19632f167a42Smrg                    PSSetColor(out, state, state->black);
19642f167a42Smrg                }
19652f167a42Smrg                fprintf(out, "false 0 %d %d %s %% %s\n", offset, row->top,
19662f167a42Smrg                        XkbAtomGetString(dpy, shape->name),
19672f167a42Smrg                        XkbKeyNameText(key->name.name, XkbMessage));
19682f167a42Smrg                offset += shape->bounds.x2;
19692f167a42Smrg            }
19702f167a42Smrg        }
19710e20ee16Smrg    }
19722f167a42Smrg    for (r = 0, row = section->rows; r < section->num_rows; r++, row++) {
19732f167a42Smrg        int k, kc = 0;
19742f167a42Smrg        XkbKeyPtr key;
19752f167a42Smrg        XkbShapePtr shape;
19762f167a42Smrg        XkbBoundsRec bounds;
19772f167a42Smrg
19782f167a42Smrg        if (state->args->label == LABEL_NONE)
19792f167a42Smrg            break;
19802f167a42Smrg        if (row->vertical)
19812f167a42Smrg            offset = row->top;
19822f167a42Smrg        else
19832f167a42Smrg            offset = row->left;
19842f167a42Smrg        fprintf(out, "%% Begin %s %d labels\n",
19852f167a42Smrg                row->vertical ? "column" : "row", r + 1);
19862f167a42Smrg        PSSetColor(out, state, xkb->geom->label_color->pixel);
19872f167a42Smrg        PSSetFont(out, state, FONT_LATIN1, 12, True);
19882f167a42Smrg        for (k = 0, key = row->keys; k < row->num_keys; k++, key++) {
19892f167a42Smrg            char *name, *name2, buf[30], buf2[30];
19902f167a42Smrg            int x, y;
19912f167a42Smrg            KeyTop top;
19922f167a42Smrg
19932f167a42Smrg            shape = XkbKeyShape(xkb->geom, key);
19942f167a42Smrg            XkbComputeShapeTop(shape, &bounds);
19952f167a42Smrg            offset += key->gap;
19962f167a42Smrg            name = name2 = NULL;
19972f167a42Smrg            if (state->args->label == LABEL_SYMBOLS) {
19982f167a42Smrg                if (!FindKeysymsByName(xkb, key->name.name, state, &top)) {
19992f167a42Smrg                    fprintf(out, "%% No label for %s\n",
20002f167a42Smrg                            XkbKeyNameText(key->name.name, XkbMessage));
20012f167a42Smrg                }
20022f167a42Smrg            }
20032f167a42Smrg            else {
20042f167a42Smrg                char *olKey;
20052f167a42Smrg
20062f167a42Smrg                if (section->num_overlays > 0)
20072f167a42Smrg                    olKey = XkbFindOverlayForKey(xkb->geom, section,
20082f167a42Smrg                                                 key->name.name);
20092f167a42Smrg                else
20102f167a42Smrg                    olKey = NULL;
20112f167a42Smrg
20122f167a42Smrg                if (state->args->label == LABEL_KEYNAME) {
20132f167a42Smrg                    name = XkbKeyNameText(key->name.name, XkbMessage);
20142f167a42Smrg                    if (olKey)
20152f167a42Smrg                        name2 = XkbKeyNameText(olKey, XkbMessage);
20162f167a42Smrg                }
20172f167a42Smrg                else if (state->args->label == LABEL_KEYCODE) {
20182f167a42Smrg                    name = buf;
20192f167a42Smrg                    snprintf(name, sizeof(buf), "%d",
20202f167a42Smrg                            XkbFindKeycodeByName(xkb, key->name.name, True));
20212f167a42Smrg                    if (olKey) {
20222f167a42Smrg                        name2 = buf2;
20232f167a42Smrg                        snprintf(name2, sizeof(buf2), "%d",
20242f167a42Smrg                                 XkbFindKeycodeByName(xkb, olKey, True));
20252f167a42Smrg                    }
20262f167a42Smrg                }
20272f167a42Smrg                bzero(&top, sizeof(KeyTop));
20282f167a42Smrg                if (name2 != NULL) {
20292f167a42Smrg                    top.present |= G1LX_MASK;
20302f167a42Smrg                    strncpy(top.label[G1L1], name, LABEL_LEN - 1);
20312f167a42Smrg                    top.label[G1L1][LABEL_LEN - 1] = '\0';
20322f167a42Smrg                    strncpy(top.label[G1L2], name2, LABEL_LEN - 1);
20332f167a42Smrg                    top.label[G1L2][LABEL_LEN - 1] = '\0';
20342f167a42Smrg                }
20352f167a42Smrg                else if (name != NULL) {
20362f167a42Smrg                    top.present |= CENTER_MASK;
20372f167a42Smrg                    strncpy(top.label[CENTER], name, LABEL_LEN - 1);
20382f167a42Smrg                    top.label[CENTER][LABEL_LEN - 1] = '\0';
20392f167a42Smrg                }
20402f167a42Smrg                else {
20412f167a42Smrg                    fprintf(out, "%% No label for %s\n",
20422f167a42Smrg                            XkbKeyNameText(key->name.name, XkbMessage));
20432f167a42Smrg                }
20442f167a42Smrg            }
20452f167a42Smrg            if (row->vertical) {
20462f167a42Smrg                x = row->left;
20472f167a42Smrg                y = offset;
20482f167a42Smrg                offset += shape->bounds.y2;
20492f167a42Smrg            }
20502f167a42Smrg            else {
20512f167a42Smrg                x = offset;
20522f167a42Smrg                y = row->top;
20532f167a42Smrg                offset += shape->bounds.x2;
20542f167a42Smrg            }
20552f167a42Smrg            name = key->name.name;
20562f167a42Smrg            fprintf(out, "%% %s\n", XkbKeyNameText(name, XkbMessage));
20572f167a42Smrg            if (state->args->wantKeycodes)
20582f167a42Smrg                kc = XkbFindKeycodeByName(xkb, key->name.name, True);
20592f167a42Smrg            PSLabelKey(out, state, &top, x, y, &bounds, kc, shape->bounds.y2);
20602f167a42Smrg        }
20610e20ee16Smrg    }
20622f167a42Smrg    PSGRestore(out, state);
20630e20ee16Smrg    return;
20640e20ee16Smrg}
20650e20ee16Smrg
20660e20ee16SmrgBool
20670e20ee16SmrgGeometryToPostScript(FILE *out, XkbFileInfo *pResult, XKBPrintArgs *args)
20680e20ee16Smrg{
20692f167a42Smrg    XkbDrawablePtr first, draw;
20702f167a42Smrg    PSState state;
20712f167a42Smrg    Bool dfltBorder;
20722f167a42Smrg    int i;
20732f167a42Smrg
20742f167a42Smrg    if ((!pResult) || (!pResult->xkb) || (!pResult->xkb->geom))
20752f167a42Smrg        return False;
20762f167a42Smrg    state.xkb = pResult->xkb;
20772f167a42Smrg    state.dpy = pResult->xkb->dpy;
20782f167a42Smrg    state.geom = pResult->xkb->geom;
20792f167a42Smrg    state.color = state.black = state.white = -1;
20802f167a42Smrg    state.font = -1;
20812f167a42Smrg    state.nPages = 0;
20822f167a42Smrg    state.totalKB = 1;
20832f167a42Smrg    state.kbPerPage = 1;
20842f167a42Smrg    state.x1 = state.y1 = state.x2 = state.y2 = 0;
20852f167a42Smrg    state.args = args;
20862f167a42Smrg
20872f167a42Smrg    if ((args->label == LABEL_SYMBOLS) && (pResult->xkb->ctrls)) {
20882f167a42Smrg        if (args->nTotalGroups == 0)
20892f167a42Smrg            state.totalKB =
20902f167a42Smrg                pResult->xkb->ctrls->num_groups / args->nLabelGroups;
20912f167a42Smrg        else
20922f167a42Smrg            state.totalKB = args->nTotalGroups;
20932f167a42Smrg        if (state.totalKB < 1)
20942f167a42Smrg            state.totalKB = 1;
20952f167a42Smrg        else if (state.totalKB > 1)
20962f167a42Smrg            state.kbPerPage = 2;
20970e20ee16Smrg    }
20982f167a42Smrg    if (args->nKBPerPage != 0)
20992f167a42Smrg        state.kbPerPage = args->nKBPerPage;
21002f167a42Smrg
21012f167a42Smrg    PSProlog(out, &state);
21022f167a42Smrg    first = XkbGetOrderedDrawables(state.geom, NULL);
21032f167a42Smrg
21042f167a42Smrg    for (draw = first, dfltBorder = True; draw != NULL; draw = draw->next) {
21052f167a42Smrg        if ((draw->type != XkbDW_Section) &&
21062f167a42Smrg            ((draw->u.doodad->any.type == XkbOutlineDoodad) ||
21072f167a42Smrg             (draw->u.doodad->any.type == XkbSolidDoodad))) {
21082f167a42Smrg            char *name;
21092f167a42Smrg
21102f167a42Smrg            name = XkbAtomGetString(state.dpy, draw->u.doodad->any.name);
21112f167a42Smrg            if ((name != NULL) && (uStrCaseEqual(name, "edges"))) {
21122f167a42Smrg                dfltBorder = False;
21132f167a42Smrg                break;
21142f167a42Smrg            }
21152f167a42Smrg        }
21160e20ee16Smrg    }
21172f167a42Smrg    for (i = 0; i < state.totalKB; i++) {
21182f167a42Smrg        PSPageSetup(out, &state, dfltBorder);
21192f167a42Smrg        for (draw = first; draw != NULL; draw = draw->next) {
21202f167a42Smrg            if (draw->type == XkbDW_Section)
21212f167a42Smrg                PSSection(out, &state, draw->u.section);
21222f167a42Smrg            else {
21232f167a42Smrg                PSDoodad(out, &state, draw->u.doodad);
21242f167a42Smrg            }
21252f167a42Smrg        }
21262f167a42Smrg        PSPageTrailer(out, &state);
21272f167a42Smrg        state.args->baseLabelGroup += state.args->nLabelGroups;
21280e20ee16Smrg    }
21290e20ee16Smrg    XkbFreeOrderedDrawables(first);
21302f167a42Smrg    PSFileTrailer(out, &state);
21310e20ee16Smrg    return True;
21320e20ee16Smrg}
2133