/* $XConsortium: xkmout.c /main/5 1996/01/23 10:11:10 kaleb $ */
/************************************************************
 Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.

 Permission to use, copy, modify, and distribute this
 software and its documentation for any purpose and without
 fee is hereby granted, provided that the above copyright
 notice appear in all copies and that both that copyright
 notice and this permission notice appear in supporting
 documentation, and that the name of Silicon Graphics not be 
 used in advertising or publicity pertaining to distribution 
 of the software without specific prior written permission.
 Silicon Graphics makes no representation about the suitability 
 of this software for any purpose. It is provided "as is"
 without any express or implied warranty.
 
 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 
 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 
 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 
 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 
 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 
 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
 THE USE OR PERFORMANCE OF THIS SOFTWARE.

 ********************************************************/

#include <stdio.h>
#include <ctype.h>
#ifndef X_NOT_STDC_ENV
#include <stdlib.h>
#endif
#include <X11/Xfuncs.h>
#include <X11/Xlib.h>
#include <X11/XKBlib.h>
#include <X11/extensions/XKBgeom.h>

#include "XKMformat.h"
#include "XKBfileInt.h"

typedef struct _XkmInfo {
     unsigned short	bound_vmods;
     unsigned short	named_vmods;
     unsigned char	num_bound;
     unsigned char	group_compat;
     unsigned short	num_group_compat;
     unsigned short	num_leds;
     int		total_vmodmaps;
} XkmInfo;

/***====================================================================***/

#define	xkmPutCARD8(f,v)	(putc(v,f),1)

static int
#if NeedFunctionPrototypes
xkmPutCARD16(FILE *file,unsigned val)
#else
xkmPutCARD16(file,val)
    FILE *		file;
    unsigned		val;
#endif
{
CARD16	tmp= val;

    fwrite(&tmp,2,1,file);
    return 2;
}

static int
#if NeedFunctionPrototypes
xkmPutCARD32(FILE *file,unsigned long val)
#else
xkmPutCARD32(file,val)
    FILE *		file;
    unsigned long	val;
#endif
{
CARD32 tmp= val;

    fwrite(&tmp,4,1,file);
    return 4;
}

static int
#if NeedFunctionPrototypes
xkmPutPadding(FILE *file,unsigned pad)
#else
xkmPutPadding(file,pad)
    FILE *		file;
    unsigned		pad;
#endif
{
int	i;
    for (i=0;i<pad;i++) {
	putc('\0',file);
    }
    return pad;
}

static int
#if NeedFunctionPrototypes
xkmPutCountedBytes(FILE *file,char *ptr,unsigned count)
#else
xkmPutCountedBytes(file,ptr,count)
    FILE *		file;
    char *		ptr;
    unsigned		count;
#endif
{
register int nOut;
register unsigned pad;

    if (count==0)
	return xkmPutCARD32(file,(unsigned long)0);

    xkmPutCARD16(file,count);
    nOut= fwrite(ptr,1,count,file);
    if (nOut<0)
	return 2;
    nOut= count+2;
    pad= XkbPaddedSize(nOut)-nOut;
    if (pad)
	xkmPutPadding(file,pad);
    return nOut+pad;
}

static unsigned
#if NeedFunctionPrototypes
xkmSizeCountedString(char *str)
#else
xkmSizeCountedString(str)
    char *	str;
#endif
{
    if (str==NULL)
	return 4;
    return XkbPaddedSize(strlen(str)+2);
}

static int
#if NeedFunctionPrototypes
xkmPutCountedString(FILE *file,char *str)
#else
xkmPutCountedString(file,str)
    FILE *	file;
    char *	str;
#endif
{
    if (str==NULL)
	 return xkmPutCARD32(file,(unsigned long)0);
    return xkmPutCountedBytes(file,str,strlen(str));
}

#define	xkmSizeCountedAtomString(d,a)	\
	xkmSizeCountedString(XkbAtomGetString((d),(a)))

#define	xkmPutCountedAtomString(d,f,a)	\
	xkmPutCountedString((f),XkbAtomGetString((d),(a)))

/***====================================================================***/

static unsigned
#if NeedFunctionPrototypes
SizeXKMVirtualMods(	XkbFileInfo *		result,
			XkmInfo *		info,
			xkmSectionInfo *	toc,
			int *			offset_inout)
#else
SizeXKMVirtualMods(result,info,toc,offset_inout)
    XkbFileInfo *	result;
    XkmInfo *		info;
    xkmSectionInfo *	toc;
    int *		offset_inout;
#endif
{
Display *	dpy;
XkbDescPtr	xkb;
unsigned	nBound,bound;
unsigned	nNamed,named,szNames;
register unsigned	i,bit;

    xkb= result->xkb;
    dpy= xkb->dpy;
    if ((!xkb)||(!xkb->names)||(!xkb->server)) {
	_XkbLibError(_XkbErrMissingVMods,"SizeXKMVirtualMods",0);
	return 0;
    }
    bound=named=0;
    for (i=nBound=nNamed=szNames=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
	if (xkb->server->vmods[i]!=XkbNoModifierMask) {
	    bound|= bit;
	    nBound++;
	}
	if (xkb->names->vmods[i]!=None) {
	    named|= bit;
	    szNames+= xkmSizeCountedAtomString(dpy,xkb->names->vmods[i]);
	    nNamed++;
	}
    }
    info->num_bound= nBound;
    info->bound_vmods= bound;
    info->named_vmods= named;
    if ((nBound==0)&&(nNamed==0))
	return 0;
    toc->type= 		XkmVirtualModsIndex;
    toc->format= 	MSBFirst;
    toc->size= 		4+XkbPaddedSize(nBound)+szNames+SIZEOF(xkmSectionInfo);
    toc->offset= 	*offset_inout;
    (*offset_inout)+= 	toc->size;
    return 1;
}

static unsigned
#if NeedFunctionPrototypes
WriteXKMVirtualMods(FILE *file,XkbFileInfo *result,XkmInfo *info)
#else
WriteXKMVirtualMods(file,result,info)
    FILE *		file;
    XkbFileInfo *	result;
    XkmInfo *		info;
#endif
{
register unsigned int i,bit;
XkbDescPtr	xkb;
Display *	dpy;
unsigned	size= 0;

    xkb= result->xkb;
    dpy= xkb->dpy;
    size+= xkmPutCARD16(file,info->bound_vmods);
    size+= xkmPutCARD16(file,info->named_vmods);
    for (i=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
	if (info->bound_vmods&bit)
	    size+= xkmPutCARD8(file,xkb->server->vmods[i]);
    }
    if ((i= XkbPaddedSize(info->num_bound)-info->num_bound)>0)
	size+= xkmPutPadding(file,i);
    for (i=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
	if (info->named_vmods&bit) {
	    register char *name;
	    name= XkbAtomGetString(dpy,xkb->names->vmods[i]);
	    size+= xkmPutCountedString(file,name);
	}
    }
    return size;
}

/***====================================================================***/

static unsigned
#if NeedFunctionPrototypes
SizeXKMKeycodes(XkbFileInfo *result,xkmSectionInfo *toc,int *offset_inout)
#else
SizeXKMKeycodes(result,toc,offset_inout)
    XkbFileInfo *	result;
    xkmSectionInfo *	toc;
    int *		offset_inout;
#endif
{
XkbDescPtr	xkb;
Atom		kcName;
int		size=0;
Display *	dpy;

    xkb= result->xkb;
    dpy= xkb->dpy;
    if ((!xkb)||(!xkb->names)||(!xkb->names->keys)) {
	_XkbLibError(_XkbErrMissingNames,"SizeXKMKeycodes",0);
	return 0;
    }
    kcName= xkb->names->keycodes;
    size+= 4;	/* min and max keycode */
    size+= xkmSizeCountedAtomString(dpy,kcName);
    size+= XkbNumKeys(xkb)*sizeof(XkbKeyNameRec);
    if (xkb->names->num_key_aliases>0) {
	if (xkb->names->key_aliases!=NULL)
	     size+= xkb->names->num_key_aliases*sizeof(XkbKeyAliasRec);
	else xkb->names->num_key_aliases= 0;
    }
    toc->type= 		XkmKeyNamesIndex;
    toc->format= 	MSBFirst;
    toc->size= 		size+SIZEOF(xkmSectionInfo);
    toc->offset= 	(*offset_inout);
    (*offset_inout)+= 	toc->size;
    return 1;
}

static unsigned
#if NeedFunctionPrototypes
WriteXKMKeycodes(FILE *file,XkbFileInfo *result)
#else
WriteXKMKeycodes(file,result)
    FILE *		file;
    XkbFileInfo *	result;
#endif
{
XkbDescPtr	xkb;
Atom	 	kcName;
char 		*start;
Display *	dpy;
unsigned	tmp,size= 0;

    xkb= result->xkb;
    dpy= xkb->dpy;
    kcName= xkb->names->keycodes;
    start= xkb->names->keys[xkb->min_key_code].name;
    
    size+= xkmPutCountedString(file,XkbAtomGetString(dpy,kcName));
    size+= xkmPutCARD8(file,xkb->min_key_code);
    size+= xkmPutCARD8(file,xkb->max_key_code);
    size+= xkmPutCARD8(file,xkb->names->num_key_aliases);
    size+= xkmPutPadding(file,1);
    tmp= fwrite(start,sizeof(XkbKeyNameRec),XkbNumKeys(xkb),file);
    size+= tmp*sizeof(XkbKeyNameRec);
    if (xkb->names->num_key_aliases>0) {
	tmp= fwrite((char *)xkb->names->key_aliases,
			sizeof(XkbKeyAliasRec),xkb->names->num_key_aliases,
			file);
	size+= tmp*sizeof(XkbKeyAliasRec);
    }
    return size;
}

/***====================================================================***/

static unsigned
#if NeedFunctionPrototypes
SizeXKMKeyTypes(XkbFileInfo *result,xkmSectionInfo *toc,int *offset_inout)
#else
SizeXKMKeyTypes(result,toc,offset_inout)
    XkbFileInfo *	result;
    xkmSectionInfo *	toc;
    int *		offset_inout;
#endif
{
register unsigned	i,n,size;
XkbKeyTypePtr		type;
XkbDescPtr		xkb;
Display *		dpy;
char *			name;

    xkb= result->xkb;
    dpy= xkb->dpy;
    if ((!xkb)||(!xkb->map)||(!xkb->map->types)) {
	_XkbLibError(_XkbErrMissingTypes,"SizeXKBKeyTypes",0);
	return 0;
    }
    if (xkb->map->num_types<XkbNumRequiredTypes) {
	_XkbLibError(_XkbErrMissingReqTypes,"SizeXKBKeyTypes",0);
	return 0;
    }
    if (xkb->names)	name= XkbAtomGetString(dpy,xkb->names->types);
    else		name= NULL;
    size= xkmSizeCountedString(name);
    size+= 4;	/* room for # of key types + padding */
    for (i=0,type=xkb->map->types;i<xkb->map->num_types;i++,type++) {
	size+= SIZEOF(xkmKeyTypeDesc);
	size+= SIZEOF(xkmKTMapEntryDesc)*type->map_count;
	size+= xkmSizeCountedAtomString(dpy,type->name);
	if (type->preserve)
	    size+= SIZEOF(xkmModsDesc)*type->map_count;
	if (type->level_names) {
	    Atom *names;
	    names= type->level_names;
	    for (n=0;n<(unsigned)type->num_levels;n++) {
		size+= xkmSizeCountedAtomString(dpy,names[n]);
	    }
	}
    }
    toc->type= 		XkmTypesIndex;
    toc->format= 	MSBFirst;
    toc->size= 		size+SIZEOF(xkmSectionInfo);
    toc->offset= 	(*offset_inout);
    (*offset_inout)+= 	toc->size;
    return 1;
}

static unsigned
#if NeedFunctionPrototypes
WriteXKMKeyTypes(FILE *file,XkbFileInfo *result)
#else
WriteXKMKeyTypes(file,result)
    FILE *	file;
    XkbFileInfo *	result;
#endif
{
register unsigned	i,n;
XkbDescPtr		xkb;
XkbKeyTypePtr		type;
xkmKeyTypeDesc		wire;
XkbKTMapEntryPtr	entry;
xkmKTMapEntryDesc	wire_entry;
Atom *			names;
Display *		dpy;
unsigned		tmp,size= 0;
char *			name;

    xkb= result->xkb;
    dpy= xkb->dpy;
    if (xkb->names)	name= XkbAtomGetString(dpy,xkb->names->types);
    else		name= NULL;
    size+= xkmPutCountedString(file,name);
    size+= xkmPutCARD16(file,xkb->map->num_types);
    size+= xkmPutPadding(file,2);
    type= xkb->map->types;
    for (i=0;i<xkb->map->num_types;i++,type++) {
	wire.realMods= type->mods.real_mods;
	wire.virtualMods= type->mods.vmods;
	wire.numLevels= type->num_levels;
	wire.nMapEntries= type->map_count;
	wire.preserve= (type->preserve!=NULL);
	if (type->level_names!=NULL)
	     wire.nLevelNames= type->num_levels;
	else wire.nLevelNames= 0;
	tmp= fwrite(&wire,SIZEOF(xkmKeyTypeDesc),1,file);
	size+= tmp*SIZEOF(xkmKeyTypeDesc);
	for (n=0,entry= type->map;n<type->map_count;n++,entry++) {
	    wire_entry.level= entry->level;
	    wire_entry.realMods= entry->mods.real_mods;
	    wire_entry.virtualMods= entry->mods.vmods;
	    tmp= fwrite(&wire_entry,SIZEOF(xkmKTMapEntryDesc),1,file);
	    size+= tmp*SIZEOF(xkmKTMapEntryDesc);
	}
	size+= xkmPutCountedString(file,XkbAtomGetString(dpy,type->name));
	if (type->preserve) {
	    xkmModsDesc	p_entry;
	    XkbModsPtr	pre;
	    for (n=0,pre=type->preserve;n<type->map_count;n++,pre++) {
		p_entry.realMods= pre->real_mods;
		p_entry.virtualMods= pre->vmods;
		tmp= fwrite(&p_entry,SIZEOF(xkmModsDesc),1,file);
		size+= tmp*SIZEOF(xkmModsDesc);
	    }
	}
	if (type->level_names!=NULL) {
	    names= type->level_names;
	    for (n=0;n<wire.nLevelNames;n++) {
		size+= xkmPutCountedString(file,XkbAtomGetString(dpy,names[n]));
	    }
	}
    }
    return size;
}

/***====================================================================***/

static unsigned
#if NeedFunctionPrototypes
SizeXKMCompatMap(	XkbFileInfo *		result,
			XkmInfo *		info,
			xkmSectionInfo *	toc,
			int *			offset_inout)
#else
SizeXKMCompatMap(result,info,toc,offset_inout)
    XkbFileInfo *	result;
    XkmInfo *		info;
    xkmSectionInfo *	toc;
    int *		offset_inout;
#endif
{
XkbDescPtr	xkb;
char *		name;
int		size;
register int	i;
unsigned 	groups,nGroups;
Display *	dpy;

    xkb= result->xkb;
    dpy= xkb->dpy;
    if ((!xkb)||(!xkb->compat)||(!xkb->compat->sym_interpret)) {
	_XkbLibError(_XkbErrMissingCompatMap,"SizeXKMCompatMap",0);
	return 0;
    }
    if (xkb->names)	name= XkbAtomGetString(dpy,xkb->names->compat);
    else		name= NULL;

    for (i=groups=nGroups=0;i<XkbNumKbdGroups;i++) {
	if ((xkb->compat->groups[i].real_mods!=0)||
			(xkb->compat->groups[i].vmods!=0)) {
	    groups|= (1<<i);
	    nGroups++;
	}
    }
    info->group_compat= groups;
    info->num_group_compat= nGroups;
    size= 4; /* room for num_si and group_compat mask */
    size+= xkmSizeCountedString(name);
    size+= (SIZEOF(xkmSymInterpretDesc)*xkb->compat->num_si);
    size+= (SIZEOF(xkmModsDesc)*nGroups);
    toc->type= 		XkmCompatMapIndex;
    toc->format= 	MSBFirst;
    toc->size= 		size+SIZEOF(xkmSectionInfo);
    toc->offset= 	(*offset_inout);
    (*offset_inout)+= 	toc->size;
    return 1;
}

static unsigned
#if NeedFunctionPrototypes
WriteXKMCompatMap(FILE *file,XkbFileInfo *result,XkmInfo *info)
#else
WriteXKMCompatMap(file,result,info)
    FILE *	file;
    XkbFileInfo *	result;
    XkmInfo *	info;
#endif
{
register unsigned	i;
char *			name;
XkbDescPtr		xkb;
XkbSymInterpretPtr	interp;
xkmSymInterpretDesc	wire;
Display *		dpy;
unsigned		tmp,size=0;

    xkb= result->xkb;
    dpy= xkb->dpy;
    if (xkb->names)	name= XkbAtomGetString(dpy,xkb->names->compat);
    else		name= NULL;
    size+= xkmPutCountedString(file,name);
    size+= xkmPutCARD16(file,xkb->compat->num_si);
    size+= xkmPutCARD8(file,info->group_compat);
    size+= xkmPutPadding(file,1);
    interp= xkb->compat->sym_interpret;
    for (i=0;i<xkb->compat->num_si;i++,interp++) {
	wire.sym= interp->sym;
	wire.mods= interp->mods;
	wire.match= interp->match;
	wire.virtualMod= interp->virtual_mod;
	wire.flags= interp->flags;
	wire.actionType= interp->act.type;
	wire.actionData[0]= interp->act.data[0];
	wire.actionData[1]= interp->act.data[1];
	wire.actionData[2]= interp->act.data[2];
	wire.actionData[3]= interp->act.data[3];
	wire.actionData[4]= interp->act.data[4];
	wire.actionData[5]= interp->act.data[5];
	wire.actionData[6]= interp->act.data[6];
	tmp= fwrite(&wire,SIZEOF(xkmSymInterpretDesc),1,file);
	size+= tmp*SIZEOF(xkmSymInterpretDesc);
    }
    if (info->group_compat) {
	register unsigned 	bit;
	xkmModsDesc 		modsWire;
	for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) {
	    if (info->group_compat&bit) {
		modsWire.realMods= xkb->compat->groups[i].real_mods;
		modsWire.virtualMods= xkb->compat->groups[i].vmods;
		fwrite(&modsWire,SIZEOF(xkmModsDesc),1,file);
		size+= SIZEOF(xkmModsDesc);
	    }
	}
    }
    return size;
}

/***====================================================================***/

static unsigned
#if NeedFunctionPrototypes
SizeXKMSymbols(	XkbFileInfo *		result,
		XkmInfo *		info,
		xkmSectionInfo *	toc,
		int *			offset_inout)
#else
SizeXKMSymbols(result,info,toc,offset_inout)
    XkbFileInfo *	result;
    XkmInfo *		info;
    xkmSectionInfo *	toc;
    int *		offset_inout;
#endif
{
Display *	dpy;
XkbDescPtr	xkb;
unsigned 	size;
register int	i,nSyms;
char *		name;

    xkb= result->xkb;
    dpy= xkb->dpy;
    if ((!xkb)||(!xkb->map)||((!xkb->map->syms))) {
	_XkbLibError(_XkbErrMissingSymbols,"SizeXKMSymbols",0);
	return 0;
    }
    if (xkb->names && (xkb->names->symbols!=None))
	 name= XkbAtomGetString(dpy,xkb->names->symbols);
    else name= NULL;
    size= xkmSizeCountedString(name);
    size+= 4;	/* min and max keycode, group names mask */
    for (i=0;i<XkbNumKbdGroups;i++) {
	if (xkb->names->groups[i]!=None)
	    size+= xkmSizeCountedAtomString(dpy,xkb->names->groups[i]);
    }
    info->total_vmodmaps= 0;
    for (i=xkb->min_key_code;i<=(int)xkb->max_key_code;i++) {
	nSyms= XkbKeyNumSyms(xkb,i);
	size+= SIZEOF(xkmKeySymMapDesc)+(nSyms*4);
	if (xkb->server) {
	    if (xkb->server->explicit[i]&XkbExplicitKeyTypesMask) {
		register int g;
		for (g=XkbKeyNumGroups(xkb,i)-1;g>=0;g--) {
		    if (xkb->server->explicit[i]&(1<<g)) {
			XkbKeyTypePtr	type;
			char *		name;
			type= XkbKeyKeyType(xkb,i,g);
			name= XkbAtomGetString(dpy,type->name);
			if (name!=NULL)
			    size+= xkmSizeCountedString(name);
		    }
		}
	    }
	    if (XkbKeyHasActions(xkb,i))
		size+= nSyms*SIZEOF(xkmActionDesc);
	    if (xkb->server->behaviors[i].type!=XkbKB_Default)
		size+= SIZEOF(xkmBehaviorDesc);
	    if (xkb->server->vmodmap && (xkb->server->vmodmap[i]!=0))
		info->total_vmodmaps++;
	}
    }
    size+= info->total_vmodmaps*SIZEOF(xkmVModMapDesc);
    toc->type= 		XkmSymbolsIndex;
    toc->format= 	MSBFirst;
    toc->size= 		size+SIZEOF(xkmSectionInfo);
    toc->offset= 	(*offset_inout);
    (*offset_inout)+= 	toc->size;
    return 1;
}

static unsigned
#if NeedFunctionPrototypes
WriteXKMSymbols(FILE *file,XkbFileInfo *result,XkmInfo *info)
#else
WriteXKMSymbols(file,result,info)
    FILE *		file;
    XkbFileInfo *	result;
    XkmInfo *		info;
#endif
{
Display *		dpy;
XkbDescPtr		xkb;
register int		i,n;
xkmKeySymMapDesc 	wireMap;
char *			name;
unsigned		tmp,size= 0;

    xkb= result->xkb;
    dpy= xkb->dpy;
    if (xkb->names && (xkb->names->symbols!=None))
	 name= XkbAtomGetString(dpy,xkb->names->symbols);
    else name= NULL;
    size+= xkmPutCountedString(file,name);
    for (tmp=i=0;i<XkbNumKbdGroups;i++) {
	if (xkb->names->groups[i]!=None)
	    tmp|= (1<<i);
    }
    size+= xkmPutCARD8(file,xkb->min_key_code);
    size+= xkmPutCARD8(file,xkb->max_key_code);
    size+= xkmPutCARD8(file,tmp);
    size+= xkmPutCARD8(file,info->total_vmodmaps);
    for (i=0,n=1;i<XkbNumKbdGroups;i++,n<<=1) {
	if ((tmp&n)==0)
	    continue;
	size+= xkmPutCountedAtomString(dpy,file,xkb->names->groups[i]);
    }
    for (i=xkb->min_key_code;i<=(int)xkb->max_key_code;i++)  {
	char *typeName[XkbNumKbdGroups];
	wireMap.width= XkbKeyGroupsWidth(xkb,i);
	wireMap.num_groups= XkbKeyNumGroups(xkb,i);
	if (xkb->map && xkb->map->modmap)
	     wireMap.modifier_map= xkb->map->modmap[i];
	else wireMap.modifier_map= 0;
	wireMap.flags= 0;
	bzero((char *)typeName,XkbNumKbdGroups*sizeof(char *));
	if (xkb->server) {
	    if (xkb->server->explicit[i]&XkbExplicitKeyTypesMask) {
		register int g;
		for (g=0;g<XkbKeyNumGroups(xkb,i);g++) {
		    if (xkb->server->explicit[i]&(1<<g)) {
			XkbKeyTypePtr	type;
			type= XkbKeyKeyType(xkb,i,g);
			typeName[g]= XkbAtomGetString(dpy,type->name);
			if (typeName[g]!=NULL)
			    wireMap.flags|= (1<<g);
		    }
		}
	    }
	    if (XkbKeyHasActions(xkb,i))
		wireMap.flags|= XkmKeyHasActions;
	    if (xkb->server->behaviors[i].type!=XkbKB_Default)
		wireMap.flags|= XkmKeyHasBehavior;
	    if ((xkb->server->explicit[i]&XkbExplicitAutoRepeatMask)&&
		(xkb->ctrls!=NULL)) {
		if (xkb->ctrls->per_key_repeat[(i/8)]&(1<<(i%8)))
		     wireMap.flags|= XkmRepeatingKey;
		else wireMap.flags|= XkmNonRepeatingKey;
	    }
	}
	tmp= fwrite(&wireMap,SIZEOF(xkmKeySymMapDesc),1,file);
	size+= tmp*SIZEOF(xkmKeySymMapDesc);
	if (xkb->server->explicit[i]&XkbExplicitKeyTypesMask) {
	    register int g;
	    for (g=0;g<XkbNumKbdGroups;g++) {
		if (typeName[g]!=NULL)
		    size+= xkmPutCountedString(file,typeName[g]);
	    }
	}
	if (wireMap.num_groups>0) {
	    KeySym	*sym;
	    sym= XkbKeySymsPtr(xkb,i);
	    for (n=XkbKeyNumSyms(xkb,i);n>0;n--,sym++) {
		size+= xkmPutCARD32(file,(CARD32)*sym);
	    }
	    if (wireMap.flags&XkmKeyHasActions) {
		XkbAction *	act;
		act= XkbKeyActionsPtr(xkb,i);
		for (n=XkbKeyNumActions(xkb,i);n>0;n--,act++) {
		    tmp= fwrite(act,SIZEOF(xkmActionDesc),1,file);
		    size+= tmp*SIZEOF(xkmActionDesc);
		}
	    }
	}
	if (wireMap.flags&XkmKeyHasBehavior) {
	    xkmBehaviorDesc	b;
	    b.type= xkb->server->behaviors[i].type;
	    b.data= xkb->server->behaviors[i].data;
	    tmp= fwrite(&b,SIZEOF(xkmBehaviorDesc),1,file);
	    size+= tmp*SIZEOF(xkmBehaviorDesc);
	}
    }
    if (info->total_vmodmaps>0) {
	xkmVModMapDesc	v;
	for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
	    if (xkb->server->vmodmap[i]!=0) {
		v.key= i;
		v.vmods= xkb->server->vmodmap[i];
		tmp= fwrite(&v,SIZEOF(xkmVModMapDesc),1,file);
		size+= tmp*SIZEOF(xkmVModMapDesc);
	    }
	}
    }
    return size;
}

/***====================================================================***/

static unsigned
#if NeedFunctionPrototypes
SizeXKMIndicators(XkbFileInfo *result,XkmInfo *info,xkmSectionInfo *toc,
							int *offset_inout)
#else
SizeXKMIndicators(result,info,toc,offset_inout)
    XkbFileInfo *	result;
    XkmInfo *		info;
    xkmSectionInfo *	toc;
    int *		offset_inout;
#endif
{
Display *		dpy;
XkbDescPtr		xkb;
unsigned 		size;
register unsigned	i,nLEDs;

    xkb= result->xkb;
    dpy= xkb->dpy;
    if ((xkb==NULL)||(xkb->indicators==NULL)) {
/*	_XkbLibError(_XkbErrMissingIndicators,"SizeXKMIndicators",0);*/
	return 0;
    }
    nLEDs=0;
    size= 8;	/* number of indicator maps/physical indicators */
    if (xkb->indicators!=NULL) {
	for (i=0;i<XkbNumIndicators;i++) {
	    XkbIndicatorMapPtr map= &xkb->indicators->maps[i];
	    if ((map->flags!=0)||(map->which_groups!=0)||(map->groups!=0)||
		(map->which_mods!=0)||
		(map->mods.real_mods!=0)||(map->mods.vmods!=0)||
		(map->ctrls!=0) || 
		(xkb->names && (xkb->names->indicators[i]!=None))) {
		char *name;
		if (xkb->names && xkb->names->indicators[i]!=None) {
		     name= XkbAtomGetString(dpy,xkb->names->indicators[i]);
		}
		else name= NULL;
		size+= xkmSizeCountedString(name);
		size+= SIZEOF(xkmIndicatorMapDesc);
		nLEDs++;
	    }
	}
    }
    info->num_leds= nLEDs;
    toc->type= 		XkmIndicatorsIndex;
    toc->format= 	MSBFirst;
    toc->size= 		size+SIZEOF(xkmSectionInfo);
    toc->offset= 	(*offset_inout);
    (*offset_inout)+= 	toc->size;
    return 1;
}

static unsigned
#if NeedFunctionPrototypes
WriteXKMIndicators(FILE *file,XkbFileInfo *result,XkmInfo *info)
#else
WriteXKMIndicators(file,result,info)
    FILE *		file;
    XkbFileInfo *	result;
    XkmInfo *		info;
#endif
{
Display *		dpy;
XkbDescPtr		xkb;
register unsigned	i;
xkmIndicatorMapDesc	wire;
unsigned		tmp,size= 0;

    xkb= result->xkb;
    dpy= xkb->dpy;
    size+= xkmPutCARD8(file,info->num_leds);
    size+= xkmPutPadding(file,3);
    size+= xkmPutCARD32(file,xkb->indicators->phys_indicators);
    if (xkb->indicators!=NULL) {
	for (i=0;i<XkbNumIndicators;i++) {
	    XkbIndicatorMapPtr map= &xkb->indicators->maps[i];
	    if ((map->flags!=0)||(map->which_groups!=0)||(map->groups!=0)||
		(map->which_mods!=0)||
		(map->mods.real_mods!=0)||(map->mods.vmods!=0)||
		(map->ctrls!=0) ||
		(xkb->names && (xkb->names->indicators[i]!=None))) {
		char *name;
		if (xkb->names && xkb->names->indicators[i]!=None) {
		     name= XkbAtomGetString(dpy,xkb->names->indicators[i]);
		}
		else name= NULL;
		size+= xkmPutCountedString(file,name);
		wire.indicator= i+1;
		wire.flags= map->flags;
		wire.which_mods= map->which_mods;
		wire.real_mods= map->mods.real_mods;
		wire.vmods= map->mods.vmods;
		wire.which_groups= map->which_groups;
		wire.groups= map->groups;
		wire.ctrls= map->ctrls;
		tmp= fwrite(&wire,SIZEOF(xkmIndicatorMapDesc),1,file);
		size+= tmp*SIZEOF(xkmIndicatorMapDesc);
	    }
	}
    }
    return size;
}

/***====================================================================***/

static unsigned
#if NeedFunctionPrototypes
SizeXKMGeomDoodad(XkbFileInfo *result,XkbDoodadPtr doodad)
#else
SizeXKMGeomDoodad(result,doodad)
    XkbFileInfo *	result;
    XkbDoodadPtr	doodad;
#endif
{
unsigned	size;

    size= SIZEOF(xkmAnyDoodadDesc);
    size+= xkmSizeCountedAtomString(result->xkb->dpy,doodad->any.name);
    if (doodad->any.type==XkbTextDoodad) {
	size+= xkmSizeCountedString(doodad->text.text);
	size+= xkmSizeCountedString(doodad->text.font);
    }
    else if (doodad->any.type==XkbLogoDoodad) {
	size+= xkmSizeCountedString(doodad->logo.logo_name);
    }
    return size;
}

static unsigned
#if NeedFunctionPrototypes
SizeXKMGeomSection(XkbFileInfo *result,XkbSectionPtr section)
#else
SizeXKMGeomSection(result,section)
    XkbFileInfo *	result;
    XkbSectionPtr	section;
#endif
{
register int i;
unsigned size;

    size= SIZEOF(xkmSectionDesc);
    size+= xkmSizeCountedAtomString(result->xkb->dpy,section->name);
    if (section->rows) {
	XkbRowPtr	row;
	for (row=section->rows,i=0;i<section->num_rows;i++,row++) {
	    size+= SIZEOF(xkmRowDesc);
	    size+= row->num_keys*SIZEOF(xkmKeyDesc);
	}
    }
    if (section->doodads) {
	XkbDoodadPtr	doodad;
	for (doodad=section->doodads,i=0;i<section->num_doodads;i++,doodad++) {
	    size+= SizeXKMGeomDoodad(result,doodad);
	}
    }
    if (section->overlays) {
	XkbOverlayPtr	ol;
	for (ol=section->overlays,i=0;i<section->num_overlays;i++,ol++) {
	    register int r;
	    XkbOverlayRowPtr	row;
	    size+= xkmSizeCountedAtomString(result->xkb->dpy,ol->name);
	    size+= SIZEOF(xkmOverlayDesc);
	    for (r=0,row=ol->rows;r<ol->num_rows;r++,row++) {
		size+= SIZEOF(xkmOverlayRowDesc);
		size+= row->num_keys*SIZEOF(xkmOverlayKeyDesc);
	    }
	}
    }
    return size;
}

static unsigned
#if NeedFunctionPrototypes
SizeXKMGeometry(XkbFileInfo *result,xkmSectionInfo *toc,int *offset_inout)
#else
SizeXKMGeometry(result,toc,offset_inout)
    XkbFileInfo *	result;
    xkmSectionInfo *	toc;
    int *		offset_inout;
#endif
{
register int	i;
Display *	dpy;
XkbDescPtr	xkb;
XkbGeometryPtr	geom;
unsigned	size;

    xkb= result->xkb;
    dpy= xkb->dpy;
    if ((!xkb)||(!xkb->geom))
	return 0;
    geom= xkb->geom;
    size= xkmSizeCountedAtomString(dpy,geom->name);
    size+= SIZEOF(xkmGeometryDesc);
    size+= xkmSizeCountedString(geom->label_font);
    if (geom->properties) {
	XkbPropertyPtr	prop;
	for (i=0,prop=geom->properties;i<geom->num_properties;i++,prop++) {
	    size+= xkmSizeCountedString(prop->name);
	    size+= xkmSizeCountedString(prop->value);
	}
    }
    if (geom->colors) {
	XkbColorPtr	color;
	for (i=0,color=geom->colors;i<geom->num_colors;i++,color++) {
	    size+= xkmSizeCountedString(color->spec);
	}
    }
    if (geom->shapes) {
	XkbShapePtr	shape;
	for (i=0,shape=geom->shapes;i<geom->num_shapes;i++,shape++) {
	    register int n;
	    register XkbOutlinePtr	ol;
	    size+= xkmSizeCountedAtomString(dpy,shape->name);
	    size+= SIZEOF(xkmShapeDesc);
	    for (n=0,ol=shape->outlines;n<shape->num_outlines;n++,ol++) {
		size+= SIZEOF(xkmOutlineDesc);
		size+= ol->num_points*SIZEOF(xkmPointDesc);
	    }
	}
    }
    if (geom->sections) {
	XkbSectionPtr	section;
	for (i=0,section=geom->sections;i<geom->num_sections;i++,section++) {
	    size+= SizeXKMGeomSection(result,section);
	}
    }
    if  (geom->doodads) {
	XkbDoodadPtr	doodad;
	for (i=0,doodad=geom->doodads;i<geom->num_doodads;i++,doodad++) {
	    size+= SizeXKMGeomDoodad(result,doodad);
	}
    }
    if (geom->key_aliases) {
	size+= geom->num_key_aliases*(XkbKeyNameLength*2);
    }
    toc->type= 		XkmGeometryIndex;
    toc->format= 	MSBFirst;
    toc->size= 		size+SIZEOF(xkmSectionInfo);
    toc->offset= 	(*offset_inout);
    (*offset_inout)+= 	toc->size;
    return 1;
}

static unsigned
#if NeedFunctionPrototypes
WriteXKMGeomDoodad(FILE *file,XkbFileInfo *result,XkbDoodadPtr doodad)
#else
WriteXKMGeomDoodad(file,result,doodad)
    FILE *		file;
    XkbFileInfo *	result;
    XkbDoodadPtr	doodad;
#endif
{
Display *	dpy;
XkbDescPtr	xkb;
xkmDoodadDesc	doodadWire;
unsigned	tmp,size= 0;

    xkb= result->xkb;
    dpy= xkb->dpy;
    bzero((char *)&doodadWire,sizeof(doodadWire));
    doodadWire.any.type= doodad->any.type;
    doodadWire.any.priority= doodad->any.priority;
    doodadWire.any.top= doodad->any.top;
    doodadWire.any.left= doodad->any.left;
    switch (doodad->any.type) {
	case XkbOutlineDoodad:
	case XkbSolidDoodad:
	    doodadWire.shape.angle= doodad->shape.angle;
	    doodadWire.shape.color_ndx= doodad->shape.color_ndx;
	    doodadWire.shape.shape_ndx= doodad->shape.shape_ndx;
	    break;
	case XkbTextDoodad:
	    doodadWire.text.angle= doodad->text.angle;
	    doodadWire.text.width= doodad->text.width;
	    doodadWire.text.height= doodad->text.height;
	    doodadWire.text.color_ndx= doodad->text.color_ndx;
	    break;
	case XkbIndicatorDoodad:
	    doodadWire.indicator.shape_ndx= doodad->indicator.shape_ndx;
	    doodadWire.indicator.on_color_ndx= doodad->indicator.on_color_ndx;
	    doodadWire.indicator.off_color_ndx= doodad->indicator.off_color_ndx;
	    break;
	case XkbLogoDoodad:
	    doodadWire.logo.angle= doodad->logo.angle;
	    doodadWire.logo.color_ndx= doodad->logo.color_ndx;
	    doodadWire.logo.shape_ndx= doodad->logo.shape_ndx;
	    break;
	default:
	    _XkbLibError(_XkbErrIllegalDoodad,"WriteXKMGeomDoodad",
	    						doodad->any.type);
	    return 0;
    }
    size+= xkmPutCountedAtomString(dpy,file,doodad->any.name);
    tmp= fwrite(&doodadWire,SIZEOF(xkmDoodadDesc),1,file);
    size+= tmp*SIZEOF(xkmDoodadDesc);
    if (doodad->any.type==XkbTextDoodad) {
	size+= xkmPutCountedString(file,doodad->text.text);
	size+= xkmPutCountedString(file,doodad->text.font);
    }
    else if (doodad->any.type==XkbLogoDoodad) {
	size+= xkmPutCountedString(file,doodad->logo.logo_name);
    }
    return size;
}

static unsigned
#if NeedFunctionPrototypes
WriteXKMGeomOverlay(FILE *file,XkbFileInfo *result,XkbOverlayPtr ol)
#else
WriteXKMGeomOverlay(file,result,ol)
    FILE *		file;
    XkbFileInfo *	result;
    XkbOverlayPtr	ol;
#endif
{
register int		r,k;
Display *		dpy;
XkbDescPtr		xkb;
XkbOverlayRowPtr	row;
xkmOverlayDesc		olWire;
xkmOverlayRowDesc	rowWire;
xkmOverlayKeyDesc	keyWire;
unsigned		tmp,size= 0;

    xkb= result->xkb;
    dpy= xkb->dpy;
    bzero((char *)&olWire,sizeof(olWire));
    bzero((char *)&rowWire,sizeof(rowWire));
    bzero((char *)&keyWire,sizeof(keyWire));
    size+= xkmPutCountedAtomString(dpy,file,ol->name);
    olWire.num_rows= ol->num_rows;
    tmp= fwrite(&olWire,SIZEOF(xkmOverlayDesc),1,file);
    size+= tmp*SIZEOF(xkmOverlayDesc);
    for (r=0,row=ol->rows;r<ol->num_rows;r++,row++) {
	XkbOverlayKeyPtr	key;
	rowWire.row_under= row->row_under;
	rowWire.num_keys= row->num_keys;
	tmp= fwrite(&rowWire,SIZEOF(xkmOverlayRowDesc),1,file);
	size+= tmp*SIZEOF(xkmOverlayRowDesc);
	for (k=0,key=row->keys;k<row->num_keys;k++,key++) {
	    memcpy(keyWire.over,key->over.name,XkbKeyNameLength);
	    memcpy(keyWire.under,key->under.name,XkbKeyNameLength);
	    tmp= fwrite(&keyWire,SIZEOF(xkmOverlayKeyDesc),1,file);
	    size+= tmp*SIZEOF(xkmOverlayKeyDesc);
	}
    }
    return size;    
}

static unsigned
#if NeedFunctionPrototypes
WriteXKMGeomSection(FILE *file,XkbFileInfo *result,XkbSectionPtr section)
#else
WriteXKMGeomSection(file,result,section)
    FILE *		file;
    XkbFileInfo *	result;
    XkbSectionPtr	section;
#endif
{
register int	i;
Display *	dpy;
XkbDescPtr	xkb;
xkmSectionDesc	sectionWire;
unsigned	tmp,size= 0;

    xkb= result->xkb;
    dpy= xkb->dpy;
    size+= xkmPutCountedAtomString(dpy,file,section->name);
    sectionWire.top= section->top;
    sectionWire.left= section->left;
    sectionWire.width= section->width;
    sectionWire.height= section->height;
    sectionWire.angle= section->angle;
    sectionWire.priority= section->priority;
    sectionWire.num_rows= section->num_rows;
    sectionWire.num_doodads= section->num_doodads;
    sectionWire.num_overlays= section->num_overlays;
    tmp= fwrite(&sectionWire,SIZEOF(xkmSectionDesc),1,file);
    size+= tmp*SIZEOF(xkmSectionDesc);
    if (section->rows) {
	register unsigned k;
	XkbRowPtr	row;
	xkmRowDesc	rowWire;
	XkbKeyPtr	key;
	xkmKeyDesc	keyWire;
	for (i=0,row=section->rows;i<section->num_rows;i++,row++) {
	    rowWire.top= row->top;
	    rowWire.left= row->left;
	    rowWire.num_keys= row->num_keys;
	    rowWire.vertical= row->vertical;
	    tmp= fwrite(&rowWire,SIZEOF(xkmRowDesc),1,file);
	    size+= tmp*SIZEOF(xkmRowDesc);
	    for (k=0,key=row->keys;k<row->num_keys;k++,key++) {
		memcpy(keyWire.name,key->name.name,XkbKeyNameLength);
		keyWire.gap= key->gap;
		keyWire.shape_ndx= key->shape_ndx;
		keyWire.color_ndx= key->color_ndx;
		tmp= fwrite(&keyWire,SIZEOF(xkmKeyDesc),1,file);
		size+= tmp*SIZEOF(xkmKeyDesc);
	    }
	}
    }
    if (section->doodads) {
	XkbDoodadPtr	doodad;
	for (i=0,doodad=section->doodads;i<section->num_doodads;i++,doodad++) {
	    size+= WriteXKMGeomDoodad(file,result,doodad);
	}
    }
    if (section->overlays) {
	XkbOverlayPtr	ol;
	for (i=0,ol=section->overlays;i<section->num_overlays;i++,ol++) {
	    size+= WriteXKMGeomOverlay(file,result,ol);
	}
    }
    return size;
}

static unsigned
#if NeedFunctionPrototypes
WriteXKMGeometry(FILE *file,XkbFileInfo *result)
#else
WriteXKMGeometry(file,result)
    FILE *		file;
    XkbFileInfo *	result;
#endif
{
register int	i;
Display *	dpy;
XkbDescPtr	xkb;
XkbGeometryPtr	geom;
xkmGeometryDesc	wire;
unsigned	tmp,size= 0;

    xkb= result->xkb;
    dpy= xkb->dpy;
    if ((!xkb)||(!xkb->geom))
	return 0;
    geom= xkb->geom;
    wire.width_mm= geom->width_mm;
    wire.height_mm= geom->height_mm;
    wire.base_color_ndx= XkbGeomColorIndex(geom,geom->base_color);
    wire.label_color_ndx= XkbGeomColorIndex(geom,geom->label_color);
    wire.num_properties= geom->num_properties;
    wire.num_colors= geom->num_colors;
    wire.num_shapes= geom->num_shapes;
    wire.num_sections= geom->num_sections;
    wire.num_doodads= geom->num_doodads;
    wire.num_key_aliases= geom->num_key_aliases;
    size+= xkmPutCountedAtomString(dpy,file,geom->name);
    tmp= fwrite(&wire,SIZEOF(xkmGeometryDesc),1,file);
    size+= tmp*SIZEOF(xkmGeometryDesc);
    size+= xkmPutCountedString(file,geom->label_font);
    if (geom->properties) {
	XkbPropertyPtr	prop;
	for (i=0,prop=geom->properties;i<geom->num_properties;i++,prop++) {
	    size+= xkmPutCountedString(file,prop->name);
	    size+= xkmPutCountedString(file,prop->value);
	}
    }
    if (geom->colors) {
	XkbColorPtr	color;
	for (i=0,color=geom->colors;i<geom->num_colors;i++,color++) {
	    size+= xkmPutCountedString(file,color->spec);
	}
    }
    if (geom->shapes) {
	XkbShapePtr	shape;
	xkmShapeDesc	shapeWire;

	for (i=0,shape=geom->shapes;i<geom->num_shapes;i++,shape++) {
	    register int 	n;
	    XkbOutlinePtr	ol;
	    xkmOutlineDesc	olWire;
	    bzero((char *)&shapeWire,sizeof(xkmShapeDesc));
	    size+= xkmPutCountedAtomString(dpy,file,shape->name);
	    shapeWire.num_outlines= shape->num_outlines;
	    if (shape->primary!=NULL)
		 shapeWire.primary_ndx= XkbOutlineIndex(shape,shape->primary);
	    else shapeWire.primary_ndx= XkbNoShape;
	    if (shape->approx!=NULL)
		 shapeWire.approx_ndx= XkbOutlineIndex(shape,shape->approx);
	    else shapeWire.approx_ndx= XkbNoShape;
	    tmp= fwrite(&shapeWire,SIZEOF(xkmShapeDesc),1,file);
	    size+= tmp*SIZEOF(xkmShapeDesc);
	    for (n=0,ol=shape->outlines;n<shape->num_outlines;n++,ol++) {
		register int	p;
		XkbPointPtr	pt;
		xkmPointDesc	ptWire;
		olWire.num_points= ol->num_points;
		olWire.corner_radius= ol->corner_radius;
		tmp= fwrite(&olWire,SIZEOF(xkmOutlineDesc),1,file);
		size+= tmp*SIZEOF(xkmOutlineDesc);
		for (p=0,pt=ol->points;p<ol->num_points;p++,pt++) {
		    ptWire.x= pt->x;
		    ptWire.y= pt->y;
		    tmp= fwrite(&ptWire,SIZEOF(xkmPointDesc),1,file);
		    size+= tmp*SIZEOF(xkmPointDesc);
		}
	    }
	}
    }
    if (geom->sections) {
	XkbSectionPtr	section;
	for (i=0,section=geom->sections;i<geom->num_sections;i++,section++) {
	    size+= WriteXKMGeomSection(file,result,section);
	}
    }
    if (geom->doodads) {
	XkbDoodadPtr	doodad;
	for (i=0,doodad=geom->doodads;i<geom->num_doodads;i++,doodad++) {
	    size+= WriteXKMGeomDoodad(file,result,doodad);
	}
    }
    if (geom->key_aliases) {
	tmp= fwrite(geom->key_aliases,2*XkbKeyNameLength,geom->num_key_aliases,
									file);
	size+= tmp*(2*XkbKeyNameLength);
    }
    return size;
}

/***====================================================================***/

/*ARGSUSED*/
static int
#if NeedFunctionPrototypes
GetXKMKeyNamesTOC(	XkbFileInfo *	result,
			XkmInfo *	info,
			int		max_toc,
			xkmSectionInfo *toc_rtrn)
#else
GetXKMKeyNamesTOC(result,info,max_toc,toc_rtrn)
    XkbFileInfo *	result;
    XkmInfo *		info;
    int			max_toc;
    xkmSectionInfo *	toc_rtrn;
#endif
{
int	num_toc;
int	total_size;

    total_size= num_toc=0;
    if (SizeXKMKeycodes(result,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    if (SizeXKMIndicators(result,info,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    return num_toc;
}

/*ARGSUSED*/
static int
#if NeedFunctionPrototypes
GetXKMTypesTOC(	XkbFileInfo *	result,
		XkmInfo *	info,
		int		max_toc,
		xkmSectionInfo *toc_rtrn)
#else
GetXKMTypesTOC(result,info,max_toc,toc_rtrn)
    XkbFileInfo *	result;
    XkmInfo *		info;
    int			max_toc;
    xkmSectionInfo *	toc_rtrn;
#endif
{
int	num_toc;
int	total_size;

    total_size= num_toc=0;
    if (SizeXKMVirtualMods(result,info,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    if (SizeXKMKeyTypes(result,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    return num_toc;
}

/*ARGSUSED*/
static int
#if NeedFunctionPrototypes
GetXKMCompatMapTOC(	XkbFileInfo *	result,
			XkmInfo *	info,
			int		max_toc,
			xkmSectionInfo *toc_rtrn)
#else
GetXKMCompatMapTOC(result,info,max_toc,toc_rtrn)
    XkbFileInfo *	result;
    XkmInfo *		info;
    int			max_toc;
    xkmSectionInfo *	toc_rtrn;
#endif
{
int	num_toc;
int	total_size;

    total_size= num_toc=0;
    if (SizeXKMVirtualMods(result,info,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    if (SizeXKMCompatMap(result,info,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    if (SizeXKMIndicators(result,info,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    return num_toc;
}

/*ARGSUSED*/
static int
#if NeedFunctionPrototypes
GetXKMSemanticsTOC(	XkbFileInfo *	result,
			XkmInfo *	info,
			int		max_toc,
			xkmSectionInfo *toc_rtrn)
#else
GetXKMSemanticsTOC(result,info,max_toc,toc_rtrn)
    XkbFileInfo *	result;
    XkmInfo *		info;
    int			max_toc;
    xkmSectionInfo *	toc_rtrn;
#endif
{
int	num_toc;
int	total_size;

    total_size= num_toc=0;
    if (SizeXKMVirtualMods(result,info,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    if (SizeXKMKeyTypes(result,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    if (SizeXKMCompatMap(result,info,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    if (SizeXKMIndicators(result,info,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    return num_toc;
}

/*ARGSUSED*/
static int
#if NeedFunctionPrototypes
GetXKMLayoutTOC(	XkbFileInfo *	result,
			XkmInfo *	info,
			int		max_toc,
			xkmSectionInfo *toc_rtrn)
#else
GetXKMLayoutTOC(result,info,max_toc,toc_rtrn)
    XkbFileInfo *	result;
    XkmInfo *		info;
    int			max_toc;
    xkmSectionInfo *	toc_rtrn;
#endif
{
int	num_toc;
int	total_size;

    total_size= num_toc=0;
    if (SizeXKMVirtualMods(result,info,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    if (SizeXKMKeycodes(result,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    if (SizeXKMKeyTypes(result,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    if (SizeXKMSymbols(result,info,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    if (SizeXKMIndicators(result,info,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    if (SizeXKMGeometry(result,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    return num_toc;
}

/*ARGSUSED*/
static int
#if NeedFunctionPrototypes
GetXKMKeymapTOC(	XkbFileInfo *	result,
			XkmInfo *	info,
			int		max_toc,
			xkmSectionInfo *toc_rtrn)
#else
GetXKMKeymapTOC(result,info,max_toc,toc_rtrn)
    XkbFileInfo *	result;
    XkmInfo *		info;
    int			max_toc;
    xkmSectionInfo *	toc_rtrn;
#endif
{
int	num_toc;
int	total_size;

    total_size= num_toc=0;
    if (SizeXKMVirtualMods(result,info,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    if (SizeXKMKeycodes(result,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    if (SizeXKMKeyTypes(result,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    if (SizeXKMCompatMap(result,info,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    if (SizeXKMSymbols(result,info,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    if (SizeXKMIndicators(result,info,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    if (SizeXKMGeometry(result,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    return num_toc;
}

/*ARGSUSED*/
static int
#if NeedFunctionPrototypes
GetXKMGeometryTOC(	XkbFileInfo *	result,
			XkmInfo *	info,
			int		max_toc,
			xkmSectionInfo *toc_rtrn)
#else
GetXKMGeometryTOC(result,info,max_toc,toc_rtrn)
    XkbFileInfo *	result;
    XkmInfo *		info;
    int			max_toc;
    xkmSectionInfo *	toc_rtrn;
#endif
{
int	num_toc;
int	total_size;

    total_size= num_toc=0;
    if (SizeXKMGeometry(result,&toc_rtrn[num_toc],&total_size))
	num_toc++;
    return num_toc;
}

static Bool
#if NeedFunctionPrototypes
WriteXKMFile(	FILE *		file,
		XkbFileInfo *	result,
		int		num_toc,
		xkmSectionInfo *toc,
		XkmInfo *	info)
#else
WriteXKMFile(file,result,num_toc,toc,info)
    FILE *		file;
    XkbFileInfo *	result;
    int			num_toc;
    xkmSectionInfo *	toc;
    XkmInfo *		info;
#endif
{
register int 	i;
unsigned	tmp,size,total= 0;
    
    for (i=0;i<num_toc;i++) {
	tmp= fwrite(&toc[i],SIZEOF(xkmSectionInfo),1,file);
	total+= tmp*SIZEOF(xkmSectionInfo);
	switch (toc[i].type) {
	    case XkmTypesIndex:
		size= WriteXKMKeyTypes(file,result);
		break;
	    case XkmCompatMapIndex:
		size= WriteXKMCompatMap(file,result,info);
		break;
	    case XkmSymbolsIndex:
		size= WriteXKMSymbols(file,result,info);
		break;
	    case XkmIndicatorsIndex:
		size= WriteXKMIndicators(file,result,info);
		break;
	    case XkmKeyNamesIndex:
		size= WriteXKMKeycodes(file,result);
		break;
	    case XkmGeometryIndex:
		size= WriteXKMGeometry(file,result);
		break;
	    case XkmVirtualModsIndex:
		size= WriteXKMVirtualMods(file,result,info);
		break;
	    default:
		_XkbLibError(_XkbErrIllegalTOCType,"WriteXKMFile",toc[i].type);
		return False;
	}
	size+= SIZEOF(xkmSectionInfo);
	if (size!=toc[i].size) {
	    _XkbLibError(_XkbErrBadLength,XkbConfigText(toc[i].type,XkbMessage),
	    						size-toc[i].size);
	    return False;
	}
    }
    return True;
}


#define	MAX_TOC	16

Bool
#if NeedFunctionPrototypes
XkbWriteXKMFile(FILE *out,XkbFileInfo *result)
#else
XkbWriteXKMFile(out,result)
    FILE *		out;
    XkbFileInfo *	result;
#endif
{
Bool	 		ok;
XkbDescPtr		xkb;
XkmInfo			info;
int			size_toc,i;
unsigned		hdr,present;
xkmFileInfo		fileInfo;
xkmSectionInfo		toc[MAX_TOC];
int			(*getTOC)(
#if NeedFunctionPrototypes
	XkbFileInfo *	/* result */,
	XkmInfo *	/* info */,
	int		/* max_to */,
	xkmSectionInfo */* toc_rtrn */
#endif
);

    switch (result->type) {
	case XkmKeyNamesIndex:
	    getTOC= GetXKMKeyNamesTOC;
	    break;
	case XkmTypesIndex:
	    getTOC= GetXKMTypesTOC;
	    break;
	case XkmCompatMapIndex:
	    getTOC= GetXKMCompatMapTOC;
	    break;
	case XkmSemanticsFile:
	    getTOC= GetXKMSemanticsTOC;
	    break;
	case XkmLayoutFile:
	    getTOC= GetXKMLayoutTOC;
	    break;
	case XkmKeymapFile:
	    getTOC= GetXKMKeymapTOC;
	    break;
	case XkmGeometryFile:
	case XkmGeometryIndex:
	    getTOC= GetXKMGeometryTOC;
	    break;
	default:
	    _XkbLibError(_XkbErrIllegalContents,
	    			XkbConfigText(result->type,XkbMessage),0);
	    return False;
    }
    xkb= result->xkb;

    bzero((char *)&info,sizeof(XkmInfo));
    size_toc= (*getTOC)(result,&info,MAX_TOC,toc);
    if (size_toc<1) {
	_XkbLibError(_XkbErrEmptyFile,"XkbWriteXKMFile",0);
	return False;
    }
    if (out==NULL) {
	_XkbLibError(_XkbErrFileCannotOpen,"XkbWriteXKMFile",0);
	return False;
    }
    for (i=present=0;i<size_toc;i++) {
	toc[i].offset+= 4+SIZEOF(xkmFileInfo);
	toc[i].offset+= (size_toc*SIZEOF(xkmSectionInfo));
	if (toc[i].type<=XkmLastIndex) {
	    present|= (1<<toc[i].type);
	}
#ifdef DEBUG
	else {
	    fprintf(stderr,"Illegal section type %d\n",toc[i].type);
	    fprintf(stderr,"Ignored\n");
	}
#endif
    }
    hdr= (('x'<<24)|('k'<<16)|('m'<<8)|XkmFileVersion);
    xkmPutCARD32(out,(unsigned long)hdr);
    fileInfo.type= result->type;
    fileInfo.min_kc= xkb->min_key_code;
    fileInfo.max_kc= xkb->max_key_code;
    fileInfo.num_toc= size_toc;
    fileInfo.present= present;
    fileInfo.pad= 0;
    fwrite(&fileInfo,SIZEOF(xkmFileInfo),1,out);
    fwrite(toc,SIZEOF(xkmSectionInfo),size_toc,out);
    ok= WriteXKMFile(out,result,size_toc,toc,&info);
    return ok;
}
