Still more memory leak fixes
[platform/upstream/libxkbcommon.git] / src / xkbcomp / geometry.c
1 /************************************************************
2  Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3
4  Permission to use, copy, modify, and distribute this
5  software and its documentation for any purpose and without
6  fee is hereby granted, provided that the above copyright
7  notice appear in all copies and that both that copyright
8  notice and this permission notice appear in supporting
9  documentation, and that the name of Silicon Graphics not be
10  used in advertising or publicity pertaining to distribution
11  of the software without specific prior written permission.
12  Silicon Graphics makes no representation about the suitability
13  of this software for any purpose. It is provided "as is"
14  without any express or implied warranty.
15
16  SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17  SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18  AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19  GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20  DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21  DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22  OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23  THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25  ********************************************************/
26
27 #include "xkbcomp.h"
28 #include "xkballoc.h"
29 #include "xkbgeom.h"
30 #include "xkbmisc.h"
31 #include "tokens.h"
32 #include "expr.h"
33 #include "vmod.h"
34 #include "misc.h"
35 #include "indicators.h"
36 #include "action.h"
37 #include "keycodes.h"
38 #include "alias.h"
39
40 #define DFLT_FONT       "helvetica"
41 #define DFLT_SLANT      "r"
42 #define DFLT_WEIGHT     "medium"
43 #define DFLT_SET_WIDTH  "normal"
44 #define DFLT_VARIANT    ""
45 #define DFLT_ENCODING   "iso8859-1"
46 #define DFLT_SIZE       120
47
48 typedef struct _PropertyInfo
49 {
50     CommonInfo defs;
51     char *name;
52     char *value;
53 } PropertyInfo;
54
55 #define _GSh_Outlines   (1<<1)
56 #define _GSh_Approx     (1<<2)
57 #define _GSh_Primary    (1<<3)
58 typedef struct _ShapeInfo
59 {
60     CommonInfo defs;
61     uint32_t name;
62     short index;
63     unsigned short nOutlines;
64     unsigned short szOutlines;
65     struct xkb_outline * outlines;
66     struct xkb_outline * approx;
67     struct xkb_outline * primary;
68     int dfltCornerRadius;
69 } ShapeInfo;
70
71 #define shText(s) \
72     ((s) ? XkbcAtomText((s)->name) : "default shape")
73
74 #define _GD_Priority    (1<<0)
75 #define _GD_Top         (1<<1)
76 #define _GD_Left        (1<<2)
77 #define _GD_Angle       (1<<3)
78 #define _GD_Shape       (1<<4)
79 #define _GD_FontVariant (1<<4)  /* CHEATING */
80 #define _GD_Corner      (1<<5)
81 #define _GD_Width       (1<<5)  /* CHEATING */
82 #define _GD_Color       (1<<6)
83 #define _GD_OffColor    (1<<7)
84 #define _GD_Height      (1<<7)  /* CHEATING */
85 #define _GD_Text        (1<<8)
86 #define _GD_Font        (1<<9)
87 #define _GD_FontSlant   (1<<10)
88 #define _GD_FontWeight  (1<<11)
89 #define _GD_FontSetWidth (1<<12)
90 #define _GD_FontSize    (1<<13)
91 #define _GD_FontEncoding (1<<14)
92 #define _GD_FontSpec    (1<<15)
93
94
95 #define _GD_FontParts   (_GD_Font|_GD_FontSlant|_GD_FontWeight|_GD_FontSetWidth|_GD_FontSize|_GD_FontEncoding|_GD_FontVariant)
96
97 typedef struct _DoodadInfo
98 {
99     CommonInfo defs;
100     uint32_t name;
101     unsigned char type;
102     unsigned char priority;
103     short top;
104     short left;
105     short angle;
106     unsigned short corner;
107     unsigned short width;
108     unsigned short height;
109     uint32_t shape;
110     uint32_t color;
111     uint32_t offColor;
112     uint32_t text;
113     uint32_t font;
114     uint32_t fontSlant;
115     uint32_t fontWeight;
116     uint32_t fontSetWidth;
117     uint32_t fontVariant;
118     unsigned short fontSize;
119     uint32_t fontEncoding;
120     uint32_t fontSpec;
121     char *logoName;
122     struct _SectionInfo *section;
123 } DoodadInfo;
124
125 #define Yes             1
126 #define No              0
127 #define Undefined       -1
128
129 #define _GK_Default     (1<<0)
130 #define _GK_Name        (1<<1)
131 #define _GK_Gap         (1<<2)
132 #define _GK_Shape       (1<<3)
133 #define _GK_Color       (1<<4)
134 typedef struct _KeyInfo
135 {
136     CommonInfo defs;
137     char name[8];
138     short gap;
139     short index;
140     uint32_t shape;
141     uint32_t color;
142     struct _RowInfo *row;
143 } KeyInfo;
144 #define keyText(k)      ((k)&&(k)->name[0]?(k)->name:"default")
145
146 #define _GR_Default     (1<<0)
147 #define _GR_Vertical    (1<<1)
148 #define _GR_Top         (1<<2)
149 #define _GR_Left        (1<<3)
150 typedef struct _RowInfo
151 {
152     CommonInfo defs;
153     unsigned short top;
154     unsigned short left;
155     short index;
156     Bool vertical;
157     unsigned short nKeys;
158     KeyInfo *keys;
159     KeyInfo dfltKey;
160     struct _SectionInfo *section;
161 } RowInfo;
162 #define rowText(r) \
163     ((r) ? XkbcAtomText((r)->section->name) : "default")
164
165 #define _GOK_UnknownRow -1
166 typedef struct _OverlayKeyInfo
167 {
168     CommonInfo defs;
169     short sectionRow;
170     short overlayRow;
171     char over[XkbKeyNameLength + 1];
172     char under[XkbKeyNameLength + 1];
173 } OverlayKeyInfo;
174
175 typedef struct _OverlayInfo
176 {
177     CommonInfo defs;
178     uint32_t name;
179     unsigned short nRows;
180     unsigned short nKeys;
181     OverlayKeyInfo *keys;
182 } OverlayInfo;
183 #define oiText(o) \
184     ((o) ? XkbcAtomText((o)->name) : "default")
185
186
187 #define _GS_Default     (1<<0)
188 #define _GS_Name        (1<<1)
189 #define _GS_Top         (1<<2)
190 #define _GS_Left        (1<<3)
191 #define _GS_Width       (1<<4)
192 #define _GS_Height      (1<<5)
193 #define _GS_Angle       (1<<6)
194 #define _GS_Priority    (1<<7)
195 typedef struct _SectionInfo
196 {
197     CommonInfo defs;
198     uint32_t name;
199     unsigned short top;
200     unsigned short left;
201     unsigned short width;
202     unsigned short height;
203     unsigned short angle;
204     unsigned short nRows;
205     unsigned short nDoodads;
206     unsigned short nOverlays;
207     unsigned char priority;
208     unsigned char nextDoodadPriority;
209     RowInfo *rows;
210     DoodadInfo *doodads;
211     RowInfo dfltRow;
212     DoodadInfo *dfltDoodads;
213     OverlayInfo *overlays;
214     struct _GeometryInfo *geometry;
215 } SectionInfo;
216 #define scText(s) \
217     ((s) ? XkbcAtomText((s)->name) : "default")
218
219 typedef struct _GeometryInfo
220 {
221     char *name;
222     unsigned fileID;
223     unsigned merge;
224     int errorCount;
225     unsigned nextPriority;
226     int nProps;
227     int nShapes;
228     int nSections;
229     int nDoodads;
230     PropertyInfo *props;
231     ShapeInfo *shapes;
232     SectionInfo *sections;
233     DoodadInfo *doodads;
234     int widthMM;
235     int heightMM;
236     uint32_t font;
237     uint32_t fontSlant;
238     uint32_t fontWeight;
239     uint32_t fontSetWidth;
240     uint32_t fontVariant;
241     unsigned fontSize;
242     uint32_t fontEncoding;
243     uint32_t fontSpec;
244     uint32_t baseColor;
245     uint32_t labelColor;
246     int dfltCornerRadius;
247     SectionInfo dfltSection;
248     DoodadInfo *dfltDoodads;
249     AliasInfo *aliases;
250 } GeometryInfo;
251
252 static const char *
253 ddText(DoodadInfo * di)
254 {
255     static char buf[64];
256
257     if (di == NULL)
258     {
259         strcpy(buf, "default");
260         return buf;
261     }
262     if (di->section)
263     {
264         sprintf(buf, "%s in section %s",
265                 XkbcAtomText(di->name), scText(di->section));
266         return buf;
267     }
268     return XkbcAtomText(di->name);
269 }
270
271 /***====================================================================***/
272
273 static void
274 InitPropertyInfo(PropertyInfo * pi, GeometryInfo * info)
275 {
276     pi->defs.defined = 0;
277     pi->defs.fileID = info->fileID;
278     pi->defs.merge = info->merge;
279     pi->name = pi->value = NULL;
280     return;
281 }
282
283 static void
284 FreeProperties(PropertyInfo * pi, GeometryInfo * info)
285 {
286     PropertyInfo *tmp;
287     PropertyInfo *next;
288
289     if (info->props == pi)
290     {
291         info->props = NULL;
292         info->nProps = 0;
293     }
294     for (tmp = pi; tmp != NULL; tmp = next)
295     {
296         if (tmp->name)
297             free(tmp->name);
298         if (tmp->value)
299             free(tmp->value);
300         tmp->name = tmp->value = NULL;
301         next = (PropertyInfo *) tmp->defs.next;
302         free(tmp);
303     }
304     return;
305 }
306
307 static void
308 InitKeyInfo(KeyInfo * key, RowInfo * row, GeometryInfo * info)
309 {
310
311     if (key != &row->dfltKey)
312     {
313         *key = row->dfltKey;
314         strcpy(key->name, "unknown");
315         key->defs.defined &= ~_GK_Default;
316     }
317     else
318     {
319         bzero(key, sizeof(KeyInfo));
320         strcpy(key->name, "default");
321         key->defs.defined = _GK_Default;
322         key->defs.fileID = info->fileID;
323         key->defs.merge = info->merge;
324         key->defs.next = NULL;
325         key->row = row;
326     }
327     return;
328 }
329
330 static void
331 ClearKeyInfo(KeyInfo * key)
332 {
333     key->defs.defined &= ~_GK_Default;
334     strcpy(key->name, "default");
335     key->gap = 0;
336     key->shape = None;
337     key->color = None;
338     return;
339 }
340
341 static void
342 FreeKeys(KeyInfo * key, RowInfo * row, GeometryInfo * info)
343 {
344     KeyInfo *tmp;
345     KeyInfo *next;
346
347     if (row->keys == key)
348     {
349         row->nKeys = 0;
350         row->keys = NULL;
351     }
352     for (tmp = key; tmp != NULL; tmp = next)
353     {
354         ClearKeyInfo(tmp);
355         next = (KeyInfo *) tmp->defs.next;
356         free(tmp);
357     }
358     return;
359 }
360
361 static void
362 InitRowInfo(RowInfo * row, SectionInfo * section, GeometryInfo * info)
363 {
364     if (row != &section->dfltRow)
365     {
366         *row = section->dfltRow;
367         row->defs.defined &= ~_GR_Default;
368     }
369     else
370     {
371         bzero(row, sizeof(RowInfo *));
372         row->defs.defined = _GR_Default;
373         row->defs.fileID = info->fileID;
374         row->defs.merge = info->merge;
375         row->defs.next = NULL;
376         row->section = section;
377         row->nKeys = 0;
378         row->keys = NULL;
379         InitKeyInfo(&row->dfltKey, row, info);
380     }
381     return;
382 }
383
384 static void
385 ClearRowInfo(RowInfo * row, GeometryInfo * info)
386 {
387     row->defs.defined &= ~_GR_Default;
388     row->top = row->left = 0;
389     row->vertical = False;
390     row->nKeys = 0;
391     if (row->keys)
392         FreeKeys(row->keys, row, info);
393     ClearKeyInfo(&row->dfltKey);
394     row->dfltKey.defs.defined |= _GK_Default;
395     return;
396 }
397
398 static void
399 FreeRows(RowInfo * row, SectionInfo * section, GeometryInfo * info)
400 {
401     RowInfo *next;
402     RowInfo *tmp;
403
404     if (row == section->rows)
405     {
406         section->nRows = 0;
407         section->rows = NULL;
408     }
409     for (tmp = row; tmp != NULL; tmp = next)
410     {
411         ClearRowInfo(tmp, info);
412         next = (RowInfo *) tmp->defs.next;
413         free(tmp);
414     }
415     return;
416 }
417
418 static DoodadInfo *
419 FindDoodadByType(DoodadInfo * di, unsigned type)
420 {
421     while (di)
422     {
423         if (di->type == type)
424             return di;
425         di = (DoodadInfo *) di->defs.next;
426     }
427     return NULL;
428 }
429
430 static DoodadInfo *
431 FindDoodadByName(DoodadInfo * di, uint32_t name)
432 {
433     while (di)
434     {
435         if (di->name == name)
436             return di;
437         di = (DoodadInfo *) di->defs.next;
438     }
439     return NULL;
440 }
441
442 static void
443 InitDoodadInfo(DoodadInfo * di, unsigned type, SectionInfo * si,
444                GeometryInfo * info)
445 {
446     DoodadInfo *dflt;
447
448     dflt = NULL;
449     if (si && si->dfltDoodads)
450         dflt = FindDoodadByType(si->dfltDoodads, type);
451     if ((dflt == NULL) && (info->dfltDoodads))
452         dflt = FindDoodadByType(info->dfltDoodads, type);
453     if (dflt != NULL)
454     {
455         *di = *dflt;
456         di->defs.next = NULL;
457     }
458     else
459     {
460         bzero(di, sizeof(DoodadInfo));
461         di->defs.fileID = info->fileID;
462         di->type = type;
463     }
464     di->section = si;
465     if (si != NULL)
466     {
467         di->priority = si->nextDoodadPriority++;
468 #if XkbGeomMaxPriority < 255
469         if (si->nextDoodadPriority > XkbGeomMaxPriority)
470             si->nextDoodadPriority = XkbGeomMaxPriority;
471 #endif
472     }
473     else
474     {
475         di->priority = info->nextPriority++;
476         if (info->nextPriority > XkbGeomMaxPriority)
477             info->nextPriority = XkbGeomMaxPriority;
478     }
479     return;
480 }
481
482 static void
483 ClearDoodadInfo(DoodadInfo * di)
484 {
485     CommonInfo defs;
486
487     defs = di->defs;
488     bzero(di, sizeof(DoodadInfo));
489     di->defs = defs;
490     di->defs.defined = 0;
491     return;
492 }
493
494 static void
495 ClearOverlayInfo(OverlayInfo * ol)
496 {
497     if (ol && ol->keys)
498     {
499         ol->keys = (OverlayKeyInfo *) ClearCommonInfo(&ol->keys->defs);
500         ol->nKeys = 0;
501     }
502     return;
503 }
504
505 static void
506 FreeDoodads(DoodadInfo * di, SectionInfo * si, GeometryInfo * info)
507 {
508     DoodadInfo *tmp;
509     DoodadInfo *next;
510
511     if (si)
512     {
513         if (si->doodads == di)
514         {
515             si->doodads = NULL;
516             si->nDoodads = 0;
517         }
518         if (si->dfltDoodads == di)
519             si->dfltDoodads = NULL;
520     }
521     if (info->doodads == di)
522     {
523         info->doodads = NULL;
524         info->nDoodads = 0;
525     }
526     if (info->dfltDoodads == di)
527         info->dfltDoodads = NULL;
528     for (tmp = di; tmp != NULL; tmp = next)
529     {
530         next = (DoodadInfo *) tmp->defs.next;
531         ClearDoodadInfo(tmp);
532         free(tmp);
533     }
534     return;
535 }
536
537 static void
538 InitSectionInfo(SectionInfo * si, GeometryInfo * info)
539 {
540     if (si != &info->dfltSection)
541     {
542         *si = info->dfltSection;
543         si->defs.defined &= ~_GS_Default;
544         si->name = xkb_intern_atom("unknown");
545         si->priority = info->nextPriority++;
546         if (info->nextPriority > XkbGeomMaxPriority)
547             info->nextPriority = XkbGeomMaxPriority;
548     }
549     else
550     {
551         bzero(si, sizeof(SectionInfo));
552         si->defs.fileID = info->fileID;
553         si->defs.merge = info->merge;
554         si->defs.next = NULL;
555         si->geometry = info;
556         si->name = xkb_intern_atom("default");
557         InitRowInfo(&si->dfltRow, si, info);
558     }
559     return;
560 }
561
562 static void
563 DupSectionInfo(SectionInfo * into, SectionInfo * from, GeometryInfo * info)
564 {
565     CommonInfo defs;
566
567     defs = into->defs;
568     *into = *from;
569     into->defs.fileID = defs.fileID;
570     into->defs.merge = defs.merge;
571     into->defs.next = NULL;
572     into->dfltRow.defs.fileID = defs.fileID;
573     into->dfltRow.defs.merge = defs.merge;
574     into->dfltRow.defs.next = NULL;
575     into->dfltRow.section = into;
576     into->dfltRow.dfltKey.defs.fileID = defs.fileID;
577     into->dfltRow.dfltKey.defs.merge = defs.merge;
578     into->dfltRow.dfltKey.defs.next = NULL;
579     into->dfltRow.dfltKey.row = &into->dfltRow;
580     return;
581 }
582
583 static void
584 ClearSectionInfo(SectionInfo * si, GeometryInfo * info)
585 {
586
587     si->defs.defined &= ~_GS_Default;
588     si->name = xkb_intern_atom("default");
589     si->top = si->left = 0;
590     si->width = si->height = 0;
591     si->angle = 0;
592     if (si->rows)
593     {
594         FreeRows(si->rows, si, info);
595         si->rows = NULL;
596     }
597     ClearRowInfo(&si->dfltRow, info);
598     if (si->doodads)
599     {
600         FreeDoodads(si->doodads, si, info);
601         si->doodads = NULL;
602     }
603     si->dfltRow.defs.defined = _GR_Default;
604     return;
605 }
606
607 static void
608 FreeSections(SectionInfo * si, GeometryInfo * info)
609 {
610     SectionInfo *tmp;
611     SectionInfo *next;
612
613     if (si == info->sections)
614     {
615         info->nSections = 0;
616         info->sections = NULL;
617     }
618     for (tmp = si; tmp != NULL; tmp = next)
619     {
620         ClearSectionInfo(tmp, info);
621         next = (SectionInfo *) tmp->defs.next;
622         free(tmp);
623     }
624     return;
625 }
626
627 static void
628 FreeShapes(ShapeInfo * si, GeometryInfo * info)
629 {
630     ShapeInfo *tmp;
631     ShapeInfo *next;
632
633     if (si == info->shapes)
634     {
635         info->nShapes = 0;
636         info->shapes = NULL;
637     }
638     for (tmp = si; tmp != NULL; tmp = next)
639     {
640         if (tmp->outlines)
641         {
642             register int i;
643             for (i = 0; i < tmp->nOutlines; i++)
644             {
645                 if (tmp->outlines[i].points != NULL)
646                 {
647                     free(tmp->outlines[i].points);
648                     tmp->outlines[i].num_points = 0;
649                     tmp->outlines[i].points = NULL;
650                 }
651             }
652             free(tmp->outlines);
653             tmp->szOutlines = 0;
654             tmp->nOutlines = 0;
655             tmp->outlines = NULL;
656             tmp->primary = tmp->approx = NULL;
657         }
658         next = (ShapeInfo *) tmp->defs.next;
659         free(tmp);
660     }
661     return;
662 }
663
664 /***====================================================================***/
665
666 static void
667 InitGeometryInfo(GeometryInfo * info, unsigned fileID, unsigned merge)
668 {
669     bzero(info, sizeof(GeometryInfo));
670     info->fileID = fileID;
671     info->merge = merge;
672     InitSectionInfo(&info->dfltSection, info);
673     info->dfltSection.defs.defined = _GS_Default;
674     return;
675 }
676
677 static void
678 ClearGeometryInfo(GeometryInfo * info)
679 {
680     if (info->name)
681         free(info->name);
682     info->name = NULL;
683     if (info->props)
684         FreeProperties(info->props, info);
685     if (info->shapes)
686         FreeShapes(info->shapes, info);
687     if (info->sections)
688         FreeSections(info->sections, info);
689     info->widthMM = 0;
690     info->heightMM = 0;
691     info->dfltCornerRadius = 0;
692     ClearSectionInfo(&info->dfltSection, info);
693     info->dfltSection.defs.defined = _GS_Default;
694     if (info->aliases)
695         ClearAliases(&info->aliases);
696     return;
697 }
698
699 /***====================================================================***/
700
701 static PropertyInfo *
702 NextProperty(GeometryInfo * info)
703 {
704     PropertyInfo *pi;
705
706     pi = uTypedAlloc(PropertyInfo);
707     if (pi)
708     {
709         bzero((char *) pi, sizeof(PropertyInfo));
710         info->props = (PropertyInfo *) AddCommonInfo(&info->props->defs,
711                                                      (CommonInfo *) pi);
712         info->nProps++;
713     }
714     return pi;
715 }
716
717 static PropertyInfo *
718 FindProperty(GeometryInfo * info, char *name)
719 {
720     PropertyInfo *old;
721
722     if (!name)
723         return NULL;
724     for (old = info->props; old != NULL;
725          old = (PropertyInfo *) old->defs.next)
726     {
727         if ((old->name) && (uStringEqual(name, old->name)))
728             return old;
729     }
730     return NULL;
731 }
732
733 static Bool
734 AddProperty(GeometryInfo * info, PropertyInfo * new)
735 {
736     PropertyInfo *old;
737
738     if ((!new) || (!new->value) || (!new->name))
739         return False;
740     old = FindProperty(info, new->name);
741     if (old != NULL)
742     {
743         if ((new->defs.merge == MergeReplace)
744             || (new->defs.merge == MergeOverride))
745         {
746             if (((old->defs.fileID == new->defs.fileID)
747                  && (warningLevel > 0)) || (warningLevel > 9))
748             {
749                 WARN("Multiple definitions for the \"%s\" property\n",
750                       new->name);
751                 ACTION("Ignoring \"%s\", using \"%s\"\n", old->value,
752                         new->value);
753             }
754             if (old->value)
755                 free(old->value);
756             old->value = _XkbDupString(new->value);
757             return True;
758         }
759         if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
760             || (warningLevel > 9))
761         {
762             WARN("Multiple definitions for \"%s\" property\n", new->name);
763             ACTION("Using \"%s\", ignoring \"%s\" \n", old->value,
764                     new->value);
765         }
766         return True;
767     }
768     old = new;
769     if ((new = NextProperty(info)) == NULL)
770         return False;
771     new->defs.next = NULL;
772     new->name = _XkbDupString(old->name);
773     new->value = _XkbDupString(old->value);
774     return True;
775 }
776
777 /***====================================================================***/
778
779 static ShapeInfo *
780 NextShape(GeometryInfo * info)
781 {
782     ShapeInfo *si;
783
784     si = uTypedAlloc(ShapeInfo);
785     if (si)
786     {
787         bzero((char *) si, sizeof(ShapeInfo));
788         info->shapes = (ShapeInfo *) AddCommonInfo(&info->shapes->defs,
789                                                    (CommonInfo *) si);
790         info->nShapes++;
791         si->dfltCornerRadius = info->dfltCornerRadius;
792     }
793     return si;
794 }
795
796 static ShapeInfo *
797 FindShape(GeometryInfo * info, uint32_t name, const char *type, const char *which)
798 {
799     ShapeInfo *old;
800
801     for (old = info->shapes; old != NULL; old = (ShapeInfo *) old->defs.next)
802     {
803         if (name == old->name)
804             return old;
805     }
806     if (type != NULL)
807     {
808         old = info->shapes;
809         WARN("Unknown shape \"%s\" for %s %s\n",
810               XkbcAtomText(name), type, which);
811         if (old)
812         {
813             ACTION("Using default shape %s instead\n", shText(old));
814             return old;
815         }
816         ACTION("No default shape; definition ignored\n");
817         return NULL;
818     }
819     return NULL;
820 }
821
822 static Bool
823 AddShape(GeometryInfo * info, ShapeInfo * new)
824 {
825     ShapeInfo *old;
826
827     old = FindShape(info, new->name, NULL, NULL);
828     if (old != NULL)
829     {
830         if ((new->defs.merge == MergeReplace)
831             || (new->defs.merge == MergeOverride))
832         {
833             ShapeInfo *next = (ShapeInfo *) old->defs.next;
834             if (((old->defs.fileID == new->defs.fileID)
835                  && (warningLevel > 0)) || (warningLevel > 9))
836             {
837                 WARN("Duplicate shape name \"%s\"\n", shText(old));
838                 ACTION("Using last definition\n");
839             }
840             *old = *new;
841             old->defs.next = &next->defs;
842             return True;
843         }
844         if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
845             || (warningLevel > 9))
846         {
847             WARN("Multiple shapes named \"%s\"\n", shText(old));
848             ACTION("Using first definition\n");
849         }
850         return True;
851     }
852     old = new;
853     if ((new = NextShape(info)) == NULL)
854         return False;
855     *new = *old;
856     new->defs.next = NULL;
857     old->szOutlines = old->nOutlines = 0;
858     old->outlines = NULL;
859     old->approx = NULL;
860     old->primary = NULL;
861     return True;
862 }
863
864 /***====================================================================***/
865
866 static void
867 ReplaceDoodad(DoodadInfo * into, DoodadInfo * from)
868 {
869     CommonInfo *next;
870
871     next = into->defs.next;
872     ClearDoodadInfo(into);
873     *into = *from;
874     into->defs.next = next;
875     next = from->defs.next;
876     ClearDoodadInfo(from);
877     from->defs.next = next;
878     return;
879 }
880
881 static DoodadInfo *
882 NextDfltDoodad(SectionInfo * si, GeometryInfo * info)
883 {
884     DoodadInfo *di;
885
886     di = uTypedCalloc(1, DoodadInfo);
887     if (!di)
888         return NULL;
889     if (si)
890     {
891         si->dfltDoodads =
892             (DoodadInfo *) AddCommonInfo(&si->dfltDoodads->defs,
893                                          (CommonInfo *) di);
894     }
895     else
896     {
897         info->dfltDoodads =
898             (DoodadInfo *) AddCommonInfo(&info->dfltDoodads->defs,
899                                          (CommonInfo *) di);
900     }
901     return di;
902 }
903
904 static DoodadInfo *
905 NextDoodad(SectionInfo * si, GeometryInfo * info)
906 {
907     DoodadInfo *di;
908
909     di = uTypedCalloc(1, DoodadInfo);
910     if (di)
911     {
912         if (si)
913         {
914             si->doodads = (DoodadInfo *) AddCommonInfo(&si->doodads->defs,
915                                                        (CommonInfo *) di);
916             si->nDoodads++;
917         }
918         else
919         {
920             info->doodads =
921                 (DoodadInfo *) AddCommonInfo(&info->doodads->defs,
922                                              (CommonInfo *) di);
923             info->nDoodads++;
924         }
925     }
926     return di;
927 }
928
929 static Bool
930 AddDoodad(SectionInfo * si, GeometryInfo * info, DoodadInfo * new)
931 {
932     DoodadInfo *old;
933
934     old = FindDoodadByName((si ? si->doodads : info->doodads), new->name);
935     if (old != NULL)
936     {
937         if ((new->defs.merge == MergeReplace)
938             || (new->defs.merge == MergeOverride))
939         {
940             if (((old->defs.fileID == new->defs.fileID)
941                  && (warningLevel > 0)) || (warningLevel > 9))
942             {
943                 WARN("Multiple doodads named \"%s\"\n",
944                       XkbcAtomText(old->name));
945                 ACTION("Using last definition\n");
946             }
947             ReplaceDoodad(old, new);
948             old->section = si;
949             return True;
950         }
951         if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
952             || (warningLevel > 9))
953         {
954             WARN("Multiple doodads named \"%s\"\n",
955                   XkbcAtomText(old->name));
956             ACTION("Using first definition\n");
957         }
958         return True;
959     }
960     old = new;
961     if ((new = NextDoodad(si, info)) == NULL)
962         return False;
963     ReplaceDoodad(new, old);
964     new->section = si;
965     new->defs.next = NULL;
966     return True;
967 }
968
969 static DoodadInfo *
970 FindDfltDoodadByTypeName(char *name, SectionInfo * si, GeometryInfo * info)
971 {
972     DoodadInfo *dflt = NULL;
973     unsigned type;
974
975     if (uStrCaseCmp(name, "outline") == 0)
976         type = XkbOutlineDoodad;
977     else if (uStrCaseCmp(name, "solid") == 0)
978         type = XkbSolidDoodad;
979     else if (uStrCaseCmp(name, "text") == 0)
980         type = XkbTextDoodad;
981     else if (uStrCaseCmp(name, "indicator") == 0)
982         type = XkbIndicatorDoodad;
983     else if (uStrCaseCmp(name, "logo") == 0)
984         type = XkbLogoDoodad;
985     else
986         return NULL;
987     if ((si) && (si->dfltDoodads))
988         dflt = FindDoodadByType(si->dfltDoodads, type);
989     if ((!dflt) && (info->dfltDoodads))
990         dflt = FindDoodadByType(info->dfltDoodads, type);
991     if (dflt == NULL)
992     {
993         dflt = NextDfltDoodad(si, info);
994         if (dflt != NULL)
995         {
996             dflt->name = None;
997             dflt->type = type;
998         }
999     }
1000     return dflt;
1001 }
1002
1003 /***====================================================================***/
1004
1005 static Bool
1006 AddOverlay(SectionInfo * si, GeometryInfo * info, OverlayInfo * new)
1007 {
1008     OverlayInfo *old;
1009
1010     for (old = si->overlays; old != NULL;
1011          old = (OverlayInfo *) old->defs.next)
1012     {
1013         if (old->name == new->name)
1014             break;
1015     }
1016     if (old != NULL)
1017     {
1018         if ((new->defs.merge == MergeReplace)
1019             || (new->defs.merge == MergeOverride))
1020         {
1021             if (((old->defs.fileID == new->defs.fileID)
1022                  && (warningLevel > 0)) || (warningLevel > 9))
1023             {
1024                 WARN
1025                     ("Multiple overlays named \"%s\" for section \"%s\"\n",
1026                      XkbcAtomText(old->name), XkbcAtomText(si->name));
1027                 ACTION("Using last definition\n");
1028             }
1029             ClearOverlayInfo(old);
1030             old->nKeys = new->nKeys;
1031             old->keys = new->keys;
1032             new->nKeys = 0;
1033             new->keys = NULL;
1034             return True;
1035         }
1036         if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
1037             || (warningLevel > 9))
1038         {
1039             WARN("Multiple doodads named \"%s\" in section \"%s\"\n",
1040                   XkbcAtomText(old->name), XkbcAtomText(si->name));
1041             ACTION("Using first definition\n");
1042         }
1043         return True;
1044     }
1045     old = new;
1046     new = uTypedCalloc(1, OverlayInfo);
1047     if (!new)
1048     {
1049         if (warningLevel > 0)
1050         {
1051             WSGO("Couldn't allocate a new OverlayInfo\n");
1052             ACTION
1053                 ("Overlay \"%s\" in section \"%s\" will be incomplete\n",
1054                  XkbcAtomText(old->name), XkbcAtomText(si->name));
1055         }
1056         return False;
1057     }
1058     *new = *old;
1059     old->nKeys = 0;
1060     old->keys = NULL;
1061     si->overlays = (OverlayInfo *) AddCommonInfo(&si->overlays->defs,
1062                                                  (CommonInfo *) new);
1063     si->nOverlays++;
1064     return True;
1065 }
1066
1067 /***====================================================================***/
1068
1069 static SectionInfo *
1070 NextSection(GeometryInfo * info)
1071 {
1072     SectionInfo *si;
1073
1074     si = uTypedAlloc(SectionInfo);
1075     if (si)
1076     {
1077         *si = info->dfltSection;
1078         si->defs.defined &= ~_GS_Default;
1079         si->defs.next = NULL;
1080         si->nRows = 0;
1081         si->rows = NULL;
1082         info->sections =
1083             (SectionInfo *) AddCommonInfo(&info->sections->defs,
1084                                           (CommonInfo *) si);
1085         info->nSections++;
1086     }
1087     return si;
1088 }
1089
1090 static SectionInfo *
1091 FindMatchingSection(GeometryInfo * info, SectionInfo * new)
1092 {
1093     SectionInfo *old;
1094
1095     for (old = info->sections; old != NULL;
1096          old = (SectionInfo *) old->defs.next)
1097     {
1098         if (new->name == old->name)
1099             return old;
1100     }
1101     return NULL;
1102 }
1103
1104 static Bool
1105 AddSection(GeometryInfo * info, SectionInfo * new)
1106 {
1107     SectionInfo *old;
1108
1109     old = FindMatchingSection(info, new);
1110     if (old != NULL)
1111     {
1112 #ifdef NOTDEF
1113         if ((new->defs.merge == MergeReplace)
1114             || (new->defs.merge == MergeOverride))
1115         {
1116             SectionInfo *next = (SectionInfo *) old->defs.next;
1117             if (((old->defs.fileID == new->defs.fileID)
1118                  && (warningLevel > 0)) || (warningLevel > 9))
1119             {
1120                 WARN("Duplicate shape name \"%s\"\n", shText(old));
1121                 ACTION("Using last definition\n");
1122             }
1123             *old = *new;
1124             old->defs.next = &next->defs;
1125             return True;
1126         }
1127         if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
1128             || (warningLevel > 9))
1129         {
1130             WARN("Multiple shapes named \"%s\"\n", shText(old));
1131             ACTION("Using first definition\n");
1132         }
1133         return True;
1134 #else
1135         WARN("Don't know how to merge sections yet\n");
1136 #endif
1137     }
1138     old = new;
1139     if ((new = NextSection(info)) == NULL)
1140         return False;
1141     *new = *old;
1142     new->defs.next = NULL;
1143     old->nRows = old->nDoodads = old->nOverlays = 0;
1144     old->rows = NULL;
1145     old->doodads = NULL;
1146     old->overlays = NULL;
1147     if (new->doodads)
1148     {
1149         DoodadInfo *di;
1150         for (di = new->doodads; di; di = (DoodadInfo *) di->defs.next)
1151         {
1152             di->section = new;
1153         }
1154     }
1155     return True;
1156 }
1157
1158 /***====================================================================***/
1159
1160 static RowInfo *
1161 NextRow(SectionInfo * si)
1162 {
1163     RowInfo *row;
1164
1165     row = uTypedAlloc(RowInfo);
1166     if (row)
1167     {
1168         *row = si->dfltRow;
1169         row->defs.defined &= ~_GR_Default;
1170         row->defs.next = NULL;
1171         row->nKeys = 0;
1172         row->keys = NULL;
1173         si->rows =
1174             (RowInfo *) AddCommonInfo(&si->rows->defs, (CommonInfo *) row);
1175         row->index = si->nRows++;
1176     }
1177     return row;
1178 }
1179
1180 static Bool
1181 AddRow(SectionInfo * si, RowInfo * new)
1182 {
1183     RowInfo *old;
1184
1185     old = new;
1186     if ((new = NextRow(si)) == NULL)
1187         return False;
1188     *new = *old;
1189     new->defs.next = NULL;
1190     old->nKeys = 0;
1191     old->keys = NULL;
1192     return True;
1193 }
1194
1195 /***====================================================================***/
1196
1197 static KeyInfo *
1198 NextKey(RowInfo * row)
1199 {
1200     KeyInfo *key;
1201
1202     key = uTypedAlloc(KeyInfo);
1203     if (key)
1204     {
1205         *key = row->dfltKey;
1206         key->defs.defined &= ~_GK_Default;
1207         key->defs.next = NULL;
1208         key->index = row->nKeys++;
1209     }
1210     return key;
1211 }
1212
1213 static Bool
1214 AddKey(RowInfo * row, KeyInfo * new)
1215 {
1216     KeyInfo *old;
1217
1218     old = new;
1219     if ((new = NextKey(row)) == NULL)
1220         return False;
1221     *new = *old;
1222     new->defs.next = NULL;
1223     row->keys =
1224         (KeyInfo *) AddCommonInfo(&row->keys->defs, (CommonInfo *) new);
1225     return True;
1226 }
1227
1228 /***====================================================================***/
1229
1230 static void
1231 MergeIncludedGeometry(GeometryInfo * into, GeometryInfo * from,
1232                       unsigned merge)
1233 {
1234     Bool clobber;
1235
1236     if (from->errorCount > 0)
1237     {
1238         into->errorCount += from->errorCount;
1239         return;
1240     }
1241     clobber = (merge == MergeOverride) || (merge == MergeReplace);
1242     if (into->name == NULL)
1243     {
1244         into->name = from->name;
1245         from->name = NULL;
1246     }
1247     if ((into->widthMM == 0) || ((from->widthMM != 0) && clobber))
1248         into->widthMM = from->widthMM;
1249     if ((into->heightMM == 0) || ((from->heightMM != 0) && clobber))
1250         into->heightMM = from->heightMM;
1251     if ((into->font == None) || ((from->font != None) && clobber))
1252         into->font = from->font;
1253     if ((into->fontSlant == None) || ((from->fontSlant != None) && clobber))
1254         into->fontSlant = from->fontSlant;
1255     if ((into->fontWeight == None) || ((from->fontWeight != None) && clobber))
1256         into->fontWeight = from->fontWeight;
1257     if ((into->fontSetWidth == None)
1258         || ((from->fontSetWidth != None) && clobber))
1259         into->fontSetWidth = from->fontSetWidth;
1260     if ((into->fontVariant == None)
1261         || ((from->fontVariant != None) && clobber))
1262         into->fontVariant = from->fontVariant;
1263     if ((into->fontSize == 0) || ((from->fontSize != 0) && clobber))
1264         into->fontSize = from->fontSize;
1265     if ((into->fontEncoding == None)
1266         || ((from->fontEncoding != None) && clobber))
1267         into->fontEncoding = from->fontEncoding;
1268     if ((into->fontSpec == None) || ((from->fontSpec != None) && clobber))
1269         into->fontSpec = from->fontSpec;
1270     if ((into->baseColor == None) || ((from->baseColor != None) && clobber))
1271         into->baseColor = from->baseColor;
1272     if ((into->labelColor == None) || ((from->labelColor != None) && clobber))
1273         into->labelColor = from->labelColor;
1274     into->nextPriority = from->nextPriority;
1275     if (from->props != NULL)
1276     {
1277         PropertyInfo *pi;
1278         for (pi = from->props; pi; pi = (PropertyInfo *) pi->defs.next)
1279         {
1280             if (!AddProperty(into, pi))
1281                 into->errorCount++;
1282         }
1283     }
1284     if (from->shapes != NULL)
1285     {
1286         ShapeInfo *si;
1287
1288         for (si = from->shapes; si; si = (ShapeInfo *) si->defs.next)
1289         {
1290             if (!AddShape(into, si))
1291                 into->errorCount++;
1292         }
1293     }
1294     if (from->sections != NULL)
1295     {
1296         SectionInfo *si;
1297
1298         for (si = from->sections; si; si = (SectionInfo *) si->defs.next)
1299         {
1300             if (!AddSection(into, si))
1301                 into->errorCount++;
1302         }
1303     }
1304     if (from->doodads != NULL)
1305     {
1306         DoodadInfo *di;
1307
1308         for (di = from->doodads; di; di = (DoodadInfo *) di->defs.next)
1309         {
1310             if (!AddDoodad(NULL, into, di))
1311                 into->errorCount++;
1312         }
1313     }
1314     if (!MergeAliases(&into->aliases, &from->aliases, merge))
1315         into->errorCount++;
1316     return;
1317 }
1318
1319 typedef void (*FileHandler) (XkbFile * /* file */ ,
1320                              struct xkb_desc * /* xkb */ ,
1321                              unsigned /* merge */ ,
1322                              GeometryInfo *     /* info */
1323     );
1324
1325 static Bool
1326 HandleIncludeGeometry(IncludeStmt * stmt, struct xkb_desc * xkb, GeometryInfo * info,
1327                       FileHandler hndlr)
1328 {
1329     unsigned newMerge;
1330     XkbFile *rtrn;
1331     GeometryInfo included;
1332     Bool haveSelf;
1333
1334     haveSelf = False;
1335     if ((stmt->file == NULL) && (stmt->map == NULL))
1336     {
1337         haveSelf = True;
1338         included = *info;
1339         bzero(info, sizeof(GeometryInfo));
1340     }
1341     else if (ProcessIncludeFile(stmt, XkmGeometryIndex, &rtrn, &newMerge))
1342     {
1343         InitGeometryInfo(&included, rtrn->id, newMerge);
1344         included.nextPriority = info->nextPriority;
1345         included.dfltCornerRadius = info->dfltCornerRadius;
1346         DupSectionInfo(&included.dfltSection, &info->dfltSection, info);
1347         (*hndlr) (rtrn, xkb, MergeOverride, &included);
1348         if (stmt->stmt != NULL)
1349         {
1350             if (included.name != NULL)
1351                 free(included.name);
1352             included.name = stmt->stmt;
1353             stmt->stmt = NULL;
1354         }
1355     }
1356     else
1357     {
1358         info->errorCount += 10;
1359         return False;
1360     }
1361     if ((stmt->next != NULL) && (included.errorCount < 1))
1362     {
1363         IncludeStmt *next;
1364         unsigned op;
1365         GeometryInfo next_incl;
1366
1367         for (next = stmt->next; next != NULL; next = next->next)
1368         {
1369             if ((next->file == NULL) && (next->map == NULL))
1370             {
1371                 haveSelf = True;
1372                 MergeIncludedGeometry(&included, info, next->merge);
1373                 ClearGeometryInfo(info);
1374             }
1375             else if (ProcessIncludeFile(next, XkmGeometryIndex, &rtrn, &op))
1376             {
1377                 InitGeometryInfo(&next_incl, rtrn->id, op);
1378                 next_incl.nextPriority = included.nextPriority;
1379                 next_incl.dfltCornerRadius = included.dfltCornerRadius;
1380                 DupSectionInfo(&next_incl.dfltSection,
1381                                &included.dfltSection, &included);
1382                 (*hndlr) (rtrn, xkb, MergeOverride, &next_incl);
1383                 MergeIncludedGeometry(&included, &next_incl, op);
1384                 ClearGeometryInfo(&next_incl);
1385             }
1386             else
1387             {
1388                 info->errorCount += 10;
1389                 return False;
1390             }
1391         }
1392     }
1393     if (haveSelf)
1394         *info = included;
1395     else
1396     {
1397         MergeIncludedGeometry(info, &included, newMerge);
1398         ClearGeometryInfo(&included);
1399     }
1400     return (info->errorCount == 0);
1401 }
1402
1403 static int
1404 SetShapeField(ShapeInfo * si,
1405               const char *field,
1406               ExprDef * arrayNdx, ExprDef * value, GeometryInfo * info)
1407 {
1408     ExprResult tmp;
1409
1410     if ((uStrCaseCmp(field, "radius") == 0)
1411         || (uStrCaseCmp(field, "corner") == 0)
1412         || (uStrCaseCmp(field, "cornerradius") == 0))
1413     {
1414         if (arrayNdx != NULL)
1415         {
1416             info->errorCount++;
1417             return ReportNotArray("key shape", field, shText(si));
1418         }
1419         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1420         {
1421             info->errorCount++;
1422             return ReportBadType("key shape", field, shText(si), "number");
1423         }
1424         if (si)
1425             si->dfltCornerRadius = tmp.ival;
1426         else
1427             info->dfltCornerRadius = tmp.ival;
1428         return True;
1429     }
1430     info->errorCount++;
1431     return ReportBadField("key shape", field, shText(si));
1432 }
1433
1434 static int
1435 SetShapeDoodadField(DoodadInfo * di,
1436                     char *field,
1437                     ExprDef * arrayNdx,
1438                     ExprDef * value, SectionInfo * si, GeometryInfo * info)
1439 {
1440     ExprResult tmp;
1441     const char *typeName;
1442
1443     typeName =
1444         (di->type == XkbSolidDoodad ? "solid doodad" : "outline doodad");
1445     if ((!uStrCaseCmp(field, "corner"))
1446         || (!uStrCaseCmp(field, "cornerradius")))
1447     {
1448         if (arrayNdx != NULL)
1449         {
1450             info->errorCount++;
1451             return ReportNotArray(typeName, field, ddText(di));
1452         }
1453         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1454         {
1455             info->errorCount++;
1456             return ReportBadType(typeName, field, ddText(di), "number");
1457         }
1458         di->defs.defined |= _GD_Corner;
1459         di->corner = tmp.ival;
1460         return True;
1461     }
1462     else if (uStrCaseCmp(field, "angle") == 0)
1463     {
1464         if (arrayNdx != NULL)
1465         {
1466             info->errorCount++;
1467             return ReportNotArray(typeName, field, ddText(di));
1468         }
1469         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1470         {
1471             info->errorCount++;
1472             return ReportBadType(typeName, field, ddText(di), "number");
1473         }
1474         di->defs.defined |= _GD_Angle;
1475         di->angle = tmp.ival;
1476         return True;
1477     }
1478     else if (uStrCaseCmp(field, "shape") == 0)
1479     {
1480         if (arrayNdx != NULL)
1481         {
1482             info->errorCount++;
1483             return ReportNotArray(typeName, field, ddText(di));
1484         }
1485         if (!ExprResolveString(value, &tmp, NULL, NULL))
1486         {
1487             info->errorCount++;
1488             return ReportBadType(typeName, field, ddText(di), "string");
1489         }
1490         di->shape = xkb_intern_atom(tmp.str);
1491         di->defs.defined |= _GD_Shape;
1492         free(tmp.str);
1493         return True;
1494     }
1495     return ReportBadField(typeName, field, ddText(di));
1496 }
1497
1498 #define FIELD_STRING    0
1499 #define FIELD_SHORT     1
1500 #define FIELD_USHORT    2
1501
1502 static int
1503 SetTextDoodadField(DoodadInfo * di,
1504                    char *field,
1505                    ExprDef * arrayNdx,
1506                    ExprDef * value, SectionInfo * si, GeometryInfo * info)
1507 {
1508     ExprResult tmp;
1509     unsigned def;
1510     unsigned type;
1511     char *typeName = "text doodad";
1512     union
1513     {
1514         uint32_t *str;
1515         short *ival;
1516         unsigned short *uval;
1517     } pField;
1518
1519     if (uStrCaseCmp(field, "angle") == 0)
1520     {
1521         if (arrayNdx != NULL)
1522         {
1523             info->errorCount++;
1524             return ReportNotArray(typeName, field, ddText(di));
1525         }
1526         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1527         {
1528             info->errorCount++;
1529             return ReportBadType(typeName, field, ddText(di), "number");
1530         }
1531         di->defs.defined |= _GD_Angle;
1532         di->angle = tmp.ival;
1533         return True;
1534     }
1535     if (uStrCaseCmp(field, "width") == 0)
1536     {
1537         type = FIELD_USHORT;
1538         pField.uval = &di->width;
1539         def = _GD_Width;
1540     }
1541     else if (uStrCaseCmp(field, "height") == 0)
1542     {
1543         type = FIELD_USHORT;
1544         pField.uval = &di->height;
1545         def = _GD_Height;
1546     }
1547     else if (uStrCaseCmp(field, "text") == 0)
1548     {
1549         type = FIELD_STRING;
1550         pField.str = &di->text;
1551         def = _GD_Text;
1552     }
1553     else if (uStrCaseCmp(field, "font") == 0)
1554     {
1555         type = FIELD_STRING;
1556         pField.str = &di->font;
1557         def = _GD_Font;
1558     }
1559     else if ((uStrCaseCmp(field, "fontslant") == 0) ||
1560              (uStrCaseCmp(field, "slant") == 0))
1561     {
1562         type = FIELD_STRING;
1563         pField.str = &di->fontSlant;
1564         def = _GD_FontSlant;
1565     }
1566     else if ((uStrCaseCmp(field, "fontweight") == 0) ||
1567              (uStrCaseCmp(field, "weight") == 0))
1568     {
1569         type = FIELD_STRING;
1570         pField.str = &di->fontWeight;
1571         def = _GD_FontWeight;
1572     }
1573     else if ((uStrCaseCmp(field, "fontwidth") == 0) ||
1574              (uStrCaseCmp(field, "setwidth") == 0))
1575     {
1576         type = FIELD_STRING;
1577         pField.str = &di->fontSetWidth;
1578         def = _GD_FontSetWidth;
1579     }
1580     else if ((uStrCaseCmp(field, "fontvariant") == 0) ||
1581              (uStrCaseCmp(field, "variant") == 0))
1582     {
1583         type = FIELD_STRING;
1584         pField.str = &di->fontVariant;
1585         def = _GD_FontVariant;
1586     }
1587     else if ((uStrCaseCmp(field, "fontencoding") == 0) ||
1588              (uStrCaseCmp(field, "encoding") == 0))
1589     {
1590         type = FIELD_STRING;
1591         pField.str = &di->fontEncoding;
1592         def = _GD_FontEncoding;
1593     }
1594     else if ((uStrCaseCmp(field, "xfont") == 0) ||
1595              (uStrCaseCmp(field, "xfontname") == 0))
1596     {
1597         type = FIELD_STRING;
1598         pField.str = &di->fontSpec;
1599         def = _GD_FontSpec;
1600     }
1601     else if (uStrCaseCmp(field, "fontsize") == 0)
1602     {
1603         type = FIELD_USHORT;
1604         pField.uval = &di->fontSize;
1605         def = _GD_FontSize;
1606     }
1607     else
1608     {
1609         return ReportBadField(typeName, field, ddText(di));
1610     }
1611     if (arrayNdx != NULL)
1612     {
1613         info->errorCount++;
1614         return ReportNotArray(typeName, field, ddText(di));
1615     }
1616     if (type == FIELD_STRING)
1617     {
1618         if (!ExprResolveString(value, &tmp, NULL, NULL))
1619         {
1620             info->errorCount++;
1621             return ReportBadType(typeName, field, ddText(di), "string");
1622         }
1623         di->defs.defined |= def;
1624         *pField.str = xkb_intern_atom(tmp.str);
1625         free(tmp.str);
1626     }
1627     else
1628     {
1629         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1630         {
1631             info->errorCount++;
1632             return ReportBadType(typeName, field, ddText(di), "number");
1633         }
1634         if ((type == FIELD_USHORT) && (tmp.ival < 0))
1635         {
1636             info->errorCount++;
1637             return
1638                 ReportBadType(typeName, field, ddText(di), "unsigned");
1639         }
1640         di->defs.defined |= def;
1641         if (type == FIELD_USHORT)
1642             *pField.uval = tmp.uval;
1643         else
1644             *pField.ival = tmp.ival;
1645     }
1646     return True;
1647 }
1648
1649 static int
1650 SetIndicatorDoodadField(DoodadInfo * di,
1651                         char *field,
1652                         ExprDef * arrayNdx,
1653                         ExprDef * value,
1654                         SectionInfo * si, GeometryInfo * info)
1655 {
1656     ExprResult tmp;
1657
1658     if ((uStrCaseCmp(field, "oncolor") == 0)
1659         || (uStrCaseCmp(field, "offcolor") == 0)
1660         || (uStrCaseCmp(field, "shape") == 0))
1661     {
1662         if (arrayNdx != NULL)
1663         {
1664             info->errorCount++;
1665             return ReportNotArray("indicator doodad", field, ddText(di));
1666         }
1667         if (!ExprResolveString(value, &tmp, NULL, NULL))
1668         {
1669             info->errorCount++;
1670             return ReportBadType("indicator doodad", field,
1671                                  ddText(di), "string");
1672         }
1673         if (uStrCaseCmp(field, "oncolor") == 0)
1674         {
1675             di->defs.defined |= _GD_Color;
1676             di->color = xkb_intern_atom(tmp.str);
1677         }
1678         else if (uStrCaseCmp(field, "offcolor") == 0)
1679         {
1680             di->defs.defined |= _GD_OffColor;
1681             di->offColor = xkb_intern_atom(tmp.str);
1682         }
1683         else if (uStrCaseCmp(field, "shape") == 0)
1684         {
1685             di->defs.defined |= _GD_Shape;
1686             di->shape = xkb_intern_atom(tmp.str);
1687         }
1688         free(tmp.str);
1689         return True;
1690     }
1691     return ReportBadField("indicator doodad", field, ddText(di));
1692 }
1693
1694 static int
1695 SetLogoDoodadField(DoodadInfo * di,
1696                    char *field,
1697                    ExprDef * arrayNdx,
1698                    ExprDef * value, SectionInfo * si, GeometryInfo * info)
1699 {
1700     ExprResult tmp;
1701     char *typeName = "logo doodad";
1702
1703     if ((!uStrCaseCmp(field, "corner"))
1704         || (!uStrCaseCmp(field, "cornerradius")))
1705     {
1706         if (arrayNdx != NULL)
1707         {
1708             info->errorCount++;
1709             return ReportNotArray(typeName, field, ddText(di));
1710         }
1711         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1712         {
1713             info->errorCount++;
1714             return ReportBadType(typeName, field, ddText(di), "number");
1715         }
1716         di->defs.defined |= _GD_Corner;
1717         di->corner = tmp.ival;
1718         return True;
1719     }
1720     else if (uStrCaseCmp(field, "angle") == 0)
1721     {
1722         if (arrayNdx != NULL)
1723         {
1724             info->errorCount++;
1725             return ReportNotArray(typeName, field, ddText(di));
1726         }
1727         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1728         {
1729             info->errorCount++;
1730             return ReportBadType(typeName, field, ddText(di), "number");
1731         }
1732         di->defs.defined |= _GD_Angle;
1733         di->angle = tmp.ival;
1734         return True;
1735     }
1736     else if (uStrCaseCmp(field, "shape") == 0)
1737     {
1738         if (arrayNdx != NULL)
1739         {
1740             info->errorCount++;
1741             return ReportNotArray(typeName, field, ddText(di));
1742         }
1743         if (!ExprResolveString(value, &tmp, NULL, NULL))
1744         {
1745             info->errorCount++;
1746             return ReportBadType(typeName, field, ddText(di), "string");
1747         }
1748         di->shape = xkb_intern_atom(tmp.str);
1749         free(tmp.str);
1750         di->defs.defined |= _GD_Shape;
1751         return True;
1752     }
1753     else if ((!uStrCaseCmp(field, "logoname"))
1754              || (!uStrCaseCmp(field, "name")))
1755     {
1756         if (arrayNdx != NULL)
1757         {
1758             info->errorCount++;
1759             return ReportNotArray(typeName, field, ddText(di));
1760         }
1761         if (!ExprResolveString(value, &tmp, NULL, NULL))
1762         {
1763             info->errorCount++;
1764             return ReportBadType(typeName, field, ddText(di),
1765                                  "string");
1766         }
1767         di->logoName = _XkbDupString(tmp.str);
1768         free(tmp.str);
1769         return True;
1770     }
1771     return ReportBadField(typeName, field, ddText(di));
1772 }
1773
1774 static int
1775 SetDoodadField(DoodadInfo * di,
1776                char *field,
1777                ExprDef * arrayNdx,
1778                ExprDef * value, SectionInfo * si, GeometryInfo * info)
1779 {
1780     ExprResult tmp;
1781
1782     if (uStrCaseCmp(field, "priority") == 0)
1783     {
1784         if (arrayNdx != NULL)
1785         {
1786             info->errorCount++;
1787             return ReportNotArray("doodad", field, ddText(di));
1788         }
1789         if (!ExprResolveInteger(value, &tmp, NULL, NULL))
1790         {
1791             info->errorCount++;
1792             return ReportBadType("doodad", field, ddText(di), "integer");
1793         }
1794         if ((tmp.ival < 0) || (tmp.ival > XkbGeomMaxPriority))
1795         {
1796             info->errorCount++;
1797             ERROR("Doodad priority %d out of range (must be 0..%d)\n",
1798                    tmp.ival, XkbGeomMaxPriority);
1799             ACTION("Priority for doodad %s not changed", ddText(di));
1800             return False;
1801         }
1802         di->defs.defined |= _GD_Priority;
1803         di->priority = tmp.ival;
1804         return True;
1805     }
1806     else if (uStrCaseCmp(field, "left") == 0)
1807     {
1808         if (arrayNdx != NULL)
1809         {
1810             info->errorCount++;
1811             return ReportNotArray("doodad", field, ddText(di));
1812         }
1813         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1814         {
1815             info->errorCount++;
1816             return ReportBadType("doodad", field, ddText(di), "number");
1817         }
1818         di->defs.defined |= _GD_Left;
1819         di->left = tmp.ival;
1820         return True;
1821     }
1822     else if (uStrCaseCmp(field, "top") == 0)
1823     {
1824         if (arrayNdx != NULL)
1825         {
1826             info->errorCount++;
1827             return ReportNotArray("doodad", field, ddText(di));
1828         }
1829         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1830         {
1831             info->errorCount++;
1832             return ReportBadType("doodad", field, ddText(di), "number");
1833         }
1834         di->defs.defined |= _GD_Top;
1835         di->top = tmp.ival;
1836         return True;
1837     }
1838     else if (uStrCaseCmp(field, "color") == 0)
1839     {
1840         if (arrayNdx != NULL)
1841         {
1842             info->errorCount++;
1843             return ReportNotArray("doodad", field, ddText(di));
1844         }
1845         if (!ExprResolveString(value, &tmp, NULL, NULL))
1846         {
1847             info->errorCount++;
1848             return ReportBadType("doodad", field, ddText(di), "string");
1849         }
1850         di->defs.defined |= _GD_Color;
1851         di->color = xkb_intern_atom(tmp.str);
1852         free(tmp.str);
1853         return True;
1854     }
1855     switch (di->type)
1856     {
1857     case XkbOutlineDoodad:
1858     case XkbSolidDoodad:
1859         return SetShapeDoodadField(di, field, arrayNdx, value, si, info);
1860     case XkbTextDoodad:
1861         return SetTextDoodadField(di, field, arrayNdx, value, si, info);
1862     case XkbIndicatorDoodad:
1863         return SetIndicatorDoodadField(di, field, arrayNdx, value, si, info);
1864     case XkbLogoDoodad:
1865         return SetLogoDoodadField(di, field, arrayNdx, value, si, info);
1866     }
1867     WSGO("Unknown doodad type %d in SetDoodadField\n",
1868           (unsigned int) di->type);
1869     ACTION("Definition of %s in %s ignored\n", field, ddText(di));
1870     return False;
1871 }
1872
1873 static int
1874 SetSectionField(SectionInfo * si,
1875                 char *field,
1876                 ExprDef * arrayNdx, ExprDef * value, GeometryInfo * info)
1877 {
1878     unsigned short *pField;
1879     unsigned def;
1880     ExprResult tmp;
1881
1882     pField = NULL;
1883     def = 0;
1884     if (uStrCaseCmp(field, "priority") == 0)
1885     {
1886         if (arrayNdx != NULL)
1887         {
1888             info->errorCount++;
1889             return ReportNotArray("keyboard section", field, scText(si));
1890         }
1891         if (!ExprResolveInteger(value, &tmp, NULL, NULL))
1892         {
1893             info->errorCount++;
1894             ReportBadType("keyboard section", field, scText(si), "integer");
1895             return False;
1896         }
1897         if ((tmp.ival < 0) || (tmp.ival > XkbGeomMaxPriority))
1898         {
1899             info->errorCount++;
1900             ERROR("Section priority %d out of range (must be 0..%d)\n",
1901                    tmp.ival, XkbGeomMaxPriority);
1902             ACTION("Priority for section %s not changed", scText(si));
1903             return False;
1904         }
1905         si->priority = tmp.ival;
1906         si->defs.defined |= _GS_Priority;
1907         return True;
1908     }
1909     else if (uStrCaseCmp(field, "top") == 0)
1910     {
1911         pField = &si->top;
1912         def = _GS_Top;
1913     }
1914     else if (uStrCaseCmp(field, "left") == 0)
1915     {
1916         pField = &si->left;
1917         def = _GS_Left;
1918     }
1919     else if (uStrCaseCmp(field, "width") == 0)
1920     {
1921         pField = &si->width;
1922         def = _GS_Width;
1923     }
1924     else if (uStrCaseCmp(field, "height") == 0)
1925     {
1926         pField = &si->height;
1927         def = _GS_Height;
1928     }
1929     else if (uStrCaseCmp(field, "angle") == 0)
1930     {
1931         pField = &si->angle;
1932         def = _GS_Angle;
1933     }
1934     else
1935     {
1936         info->errorCount++;
1937         return ReportBadField("keyboard section", field, scText(si));
1938     }
1939     if (arrayNdx != NULL)
1940     {
1941         info->errorCount++;
1942         return ReportNotArray("keyboard section", field, scText(si));
1943     }
1944     if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1945     {
1946         info->errorCount++;
1947         ReportBadType("keyboard section", field, scText(si), "number");
1948         return False;
1949     }
1950     si->defs.defined |= def;
1951     *pField = tmp.uval;
1952     return True;
1953 }
1954
1955 static int
1956 SetRowField(RowInfo * row,
1957             char *field,
1958             ExprDef * arrayNdx, ExprDef * value, GeometryInfo * info)
1959 {
1960     ExprResult tmp;
1961
1962     if (uStrCaseCmp(field, "top") == 0)
1963     {
1964         if (arrayNdx != NULL)
1965         {
1966             info->errorCount++;
1967             return ReportNotArray("keyboard row", field, rowText(row));
1968         }
1969         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1970         {
1971             info->errorCount++;
1972             return ReportBadType("keyboard row", field, rowText(row),
1973                                  "number");
1974         }
1975         row->defs.defined |= _GR_Top;
1976         row->top = tmp.uval;
1977     }
1978     else if (uStrCaseCmp(field, "left") == 0)
1979     {
1980         if (arrayNdx != NULL)
1981         {
1982             info->errorCount++;
1983             return ReportNotArray("keyboard row", field, rowText(row));
1984         }
1985         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
1986         {
1987             info->errorCount++;
1988             return ReportBadType("keyboard row", field, rowText(row),
1989                                  "number");
1990         }
1991         row->defs.defined |= _GR_Left;
1992         row->left = tmp.uval;
1993     }
1994     else if (uStrCaseCmp(field, "vertical") == 0)
1995     {
1996         if (arrayNdx != NULL)
1997         {
1998             info->errorCount++;
1999             return ReportNotArray("keyboard row", field, rowText(row));
2000         }
2001         if (!ExprResolveBoolean(value, &tmp, NULL, NULL))
2002         {
2003             info->errorCount++;
2004             return ReportBadType("keyboard row", field, rowText(row),
2005                                  "boolean");
2006         }
2007         row->defs.defined |= _GR_Vertical;
2008         row->vertical = tmp.uval;
2009     }
2010     else
2011     {
2012         info->errorCount++;
2013         return ReportBadField("keyboard row", field, rowText(row));
2014     }
2015     return True;
2016 }
2017
2018 static int
2019 SetKeyField(KeyInfo * key,
2020             const char *field,
2021             ExprDef * arrayNdx, ExprDef * value, GeometryInfo * info)
2022 {
2023     ExprResult tmp;
2024
2025     if (uStrCaseCmp(field, "gap") == 0)
2026     {
2027         if (arrayNdx != NULL)
2028         {
2029             info->errorCount++;
2030             return ReportNotArray("key", field, keyText(key));
2031         }
2032         if (!ExprResolveFloat(value, &tmp, NULL, NULL))
2033         {
2034             info->errorCount++;
2035             return ReportBadType("key", field, keyText(key), "number");
2036         }
2037         key->defs.defined |= _GK_Gap;
2038         key->gap = tmp.ival;
2039     }
2040     else if (uStrCaseCmp(field, "shape") == 0)
2041     {
2042         if (arrayNdx != NULL)
2043         {
2044             info->errorCount++;
2045             return ReportNotArray("key", field, keyText(key));
2046         }
2047         if (!ExprResolveString(value, &tmp, NULL, NULL))
2048         {
2049             info->errorCount++;
2050             return ReportBadType("key", field, keyText(key), "string");
2051         }
2052         key->defs.defined |= _GK_Shape;
2053         key->shape = xkb_intern_atom(tmp.str);
2054         free(tmp.str);
2055     }
2056     else if ((uStrCaseCmp(field, "color") == 0) ||
2057              (uStrCaseCmp(field, "keycolor") == 0))
2058     {
2059         if (arrayNdx != NULL)
2060         {
2061             info->errorCount++;
2062             return ReportNotArray("key", field, keyText(key));
2063         }
2064         if (!ExprResolveString(value, &tmp, NULL, NULL))
2065         {
2066             info->errorCount++;
2067             return ReportBadType("key", field, keyText(key), "string");
2068         }
2069         key->defs.defined |= _GK_Color;
2070         key->color = xkb_intern_atom(tmp.str);
2071         free(tmp.str);
2072     }
2073     else if ((uStrCaseCmp(field, "name") == 0)
2074              || (uStrCaseCmp(field, "keyname") == 0))
2075     {
2076         if (arrayNdx != NULL)
2077         {
2078             info->errorCount++;
2079             return ReportNotArray("key", field, keyText(key));
2080         }
2081         if (!ExprResolveKeyName(value, &tmp, NULL, NULL))
2082         {
2083             info->errorCount++;
2084             return ReportBadType("key", field, keyText(key), "key name");
2085         }
2086         key->defs.defined |= _GK_Name;
2087         bzero(key->name, XkbKeyNameLength + 1);
2088         strncpy(key->name, tmp.keyName.name, XkbKeyNameLength);
2089     }
2090     else
2091     {
2092         info->errorCount++;
2093         return ReportBadField("key", field, keyText(key));
2094     }
2095     return True;
2096 }
2097
2098 static int
2099 SetGeometryProperty(GeometryInfo * info, char *property, ExprDef * value)
2100 {
2101     PropertyInfo pi;
2102     ExprResult result;
2103     int ret;
2104
2105     InitPropertyInfo(&pi, info);
2106     pi.name = property;
2107     if (!ExprResolveString(value, &result, NULL, NULL))
2108     {
2109         info->errorCount++;
2110         ERROR("Property values must be type string\n");
2111         ACTION("Ignoring illegal definition of \"%s\" property\n", property);
2112         return False;
2113     }
2114     pi.value = result.str;
2115     ret = AddProperty(info, &pi);
2116     free(pi.value);
2117     return ret;
2118 }
2119
2120 static int
2121 HandleGeometryVar(VarDef * stmt, struct xkb_desc * xkb, GeometryInfo * info)
2122 {
2123     ExprResult elem, field, tmp;
2124     ExprDef *ndx;
2125     DoodadInfo *di;
2126     uint32_t *pField = NULL;
2127     int ret = True; /* default to no error */
2128
2129     if (ExprResolveLhs(stmt->name, &elem, &field, &ndx) == 0)
2130         return 0;               /* internal error, already reported */
2131
2132     if (elem.str) {
2133         if (uStrCaseCmp(elem.str, "shape") == 0)
2134             ret = SetShapeField(NULL, field.str, ndx, stmt->value, info);
2135         else if (uStrCaseCmp(elem.str, "key") == 0)
2136             ret = SetKeyField(&info->dfltSection.dfltRow.dfltKey,
2137                                field.str, ndx, stmt->value, info);
2138         else if (uStrCaseCmp(elem.str, "row") == 0)
2139             ret = SetRowField(&info->dfltSection.dfltRow, field.str, ndx,
2140                                stmt->value, info);
2141         else if (uStrCaseCmp(elem.str, "section") == 0)
2142             ret = SetSectionField(&info->dfltSection, field.str, ndx,
2143                                    stmt->value, info);
2144         else if (uStrCaseCmp(elem.str, "property") == 0)
2145         {
2146             if (ndx != NULL)
2147             {
2148                 info->errorCount++;
2149                 ERROR("The %s geometry property is not an array\n", field.str);
2150                 ACTION("Ignoring illegal property definition\n");
2151                 ret = False;
2152             }
2153             else {
2154                 ret = SetGeometryProperty(info, field.str, stmt->value);
2155             }
2156         }
2157         else if ((di = FindDfltDoodadByTypeName(elem.str, NULL, info)) != NULL)
2158             ret = SetDoodadField(di, field.str, ndx, stmt->value, NULL, info);
2159         else if (uStrCaseCmp(elem.str, "solid") == 0)
2160         {
2161             DoodadInfo *dflt;
2162             dflt = FindDoodadByType(info->dfltDoodads, XkbSolidDoodad);
2163             if (dflt == NULL)
2164                 dflt = NextDfltDoodad(NULL, info);
2165             ret = SetDoodadField(dflt, field.str, ndx, stmt->value, NULL, info);
2166         }
2167         else if (uStrCaseCmp(elem.str, "outline") == 0)
2168         {
2169             DoodadInfo *dflt;
2170             dflt = FindDoodadByType(info->dfltDoodads, XkbOutlineDoodad);
2171             if (dflt == NULL)
2172                 dflt = NextDfltDoodad(NULL, info);
2173             ret = SetDoodadField(dflt, field.str, ndx, stmt->value, NULL, info);
2174         }
2175         else if (uStrCaseCmp(elem.str, "text") == 0)
2176         {
2177             DoodadInfo *dflt;
2178             dflt = FindDoodadByType(info->dfltDoodads, XkbTextDoodad);
2179             if (dflt == NULL)
2180                 dflt = NextDfltDoodad(NULL, info);
2181             ret = SetDoodadField(dflt, field.str, ndx, stmt->value, NULL, info);
2182         }
2183         else if (uStrCaseCmp(elem.str, "indicator") == 0)
2184         {
2185             DoodadInfo *dflt;
2186             dflt = FindDoodadByType(info->dfltDoodads, XkbIndicatorDoodad);
2187             if (dflt == NULL)
2188                 dflt = NextDfltDoodad(NULL, info);
2189             ret = SetDoodadField(dflt, field.str, ndx, stmt->value, NULL, info);
2190         }
2191         else if (uStrCaseCmp(elem.str, "logo") == 0)
2192         {
2193             DoodadInfo *dflt;
2194             dflt = FindDoodadByType(info->dfltDoodads, XkbLogoDoodad);
2195             if (dflt == NULL)
2196                 dflt = NextDfltDoodad(NULL, info);
2197             ret = SetDoodadField(dflt, field.str, ndx, stmt->value, NULL, info);
2198         }
2199         else
2200         {
2201             WARN("Assignment to field of unknown element\n");
2202             ACTION("No value assigned to %s.%s\n", elem.str, field.str);
2203             ret = False;
2204         }
2205         free(elem.str);
2206         free(field.str);
2207         return ret;
2208     }
2209
2210     if ((uStrCaseCmp(field.str, "width") == 0) ||
2211         (uStrCaseCmp(field.str, "widthmm") == 0))
2212     {
2213         if (ndx != NULL)
2214         {
2215             info->errorCount++;
2216             ret = ReportNotArray("keyboard", field.str, "geometry");
2217         }
2218         else if (!ExprResolveFloat(stmt->value, &tmp, NULL, NULL))
2219         {
2220             info->errorCount++;
2221             ret = ReportBadType("keyboard", field.str, "geometry", "number");
2222         }
2223         else if (tmp.ival < 1)
2224         {
2225             WARN("Keyboard width must be positive\n");
2226             ACTION("Ignoring illegal keyboard width %s\n",
2227                     XkbcGeomFPText(tmp.ival));
2228             ret = True;
2229         }
2230         else {
2231             if (info->widthMM != 0)
2232             {
2233                 WARN("Keyboard width multiply defined\n");
2234                 ACTION("Using last definition (%s),", XkbcGeomFPText(tmp.ival));
2235                 INFO(" ignoring first (%s)\n", XkbcGeomFPText(info->widthMM));
2236             }
2237             info->widthMM = tmp.ival;
2238             ret = True;
2239         }
2240         free(field.str);
2241         return ret;
2242     }
2243     else if ((uStrCaseCmp(field.str, "height") == 0) ||
2244              (uStrCaseCmp(field.str, "heightmm") == 0))
2245     {
2246         if (ndx != NULL)
2247         {
2248             info->errorCount++;
2249             ret = ReportNotArray("keyboard", field.str, "geometry");
2250         }
2251         if (!ExprResolveFloat(stmt->value, &tmp, NULL, NULL))
2252         {
2253             info->errorCount++;
2254             ret = ReportBadType("keyboard", field.str, "geometry", "number");
2255         }
2256         if (tmp.ival < 1)
2257         {
2258             WARN("Keyboard height must be positive\n");
2259             ACTION("Ignoring illegal keyboard height %s\n",
2260                     XkbcGeomFPText(tmp.ival));
2261             ret = True;
2262         }
2263         else {
2264             if (info->heightMM != 0)
2265             {
2266                 WARN("Keyboard height multiply defined\n");
2267                 ACTION("Using last definition (%s),", XkbcGeomFPText(tmp.ival));
2268                 INFO(" ignoring first (%s)\n", XkbcGeomFPText(info->heightMM));
2269             }
2270             info->heightMM = tmp.ival;
2271             ret = True;
2272         }
2273         free(field.str);
2274         return ret;
2275     }
2276     else if (uStrCaseCmp(field.str, "fontsize") == 0)
2277     {
2278         if (ndx != NULL)
2279         {
2280             info->errorCount++;
2281             ret = ReportNotArray("keyboard", field.str, "geometry");
2282         }
2283         else if (!ExprResolveFloat(stmt->value, &tmp, NULL, NULL))
2284         {
2285             info->errorCount++;
2286             ret = ReportBadType("keyboard", field.str, "geometry", "number");
2287         }
2288         else if ((tmp.ival < 40) || (tmp.ival > 2550))
2289         {
2290             info->errorCount++;
2291             ERROR("Illegal font size %d (must be 4..255)\n", tmp.ival);
2292             ACTION("Ignoring font size in keyboard geometry\n");
2293             ret = False;
2294         }
2295         else {
2296             info->fontSize = tmp.ival;
2297             ret = True;
2298         }
2299         free(field.str);
2300         return ret;
2301     }
2302     else if ((uStrCaseCmp(field.str, "color") == 0) ||
2303              (uStrCaseCmp(field.str, "basecolor") == 0))
2304     {
2305         if (ndx != NULL)
2306         {
2307             info->errorCount++;
2308             ret = ReportNotArray("keyboard", field.str, "geometry");
2309         }
2310         if (!ExprResolveString(stmt->value, &tmp, NULL, NULL))
2311         {
2312             info->errorCount++;
2313             ret = ReportBadType("keyboard", field.str, "geometry", "string");
2314         }
2315         else {
2316             info->baseColor = xkb_intern_atom(tmp.str);
2317             free(tmp.str);
2318             ret = True;
2319         }
2320         free(field.str);
2321         return ret;
2322     }
2323     else if (uStrCaseCmp(field.str, "labelcolor") == 0)
2324     {
2325         if (ndx != NULL)
2326         {
2327             info->errorCount++;
2328             ret = ReportNotArray("keyboard", field.str, "geometry");
2329         }
2330         if (!ExprResolveString(stmt->value, &tmp, NULL, NULL))
2331         {
2332             info->errorCount++;
2333             ret = ReportBadType("keyboard", field.str, "geometry", "string");
2334         }
2335         else {
2336             info->labelColor = xkb_intern_atom(tmp.str);
2337             free(tmp.str);
2338             ret = True;
2339         }
2340         free(field.str);
2341         return ret;
2342     }
2343     else if (uStrCaseCmp(field.str, "font") == 0)
2344     {
2345         pField = &info->font;
2346     }
2347     else if ((uStrCaseCmp(field.str, "fontslant") == 0) ||
2348              (uStrCaseCmp(field.str, "slant") == 0))
2349     {
2350         pField = &info->fontSlant;
2351     }
2352     else if ((uStrCaseCmp(field.str, "fontweight") == 0) ||
2353              (uStrCaseCmp(field.str, "weight") == 0))
2354     {
2355         pField = &info->fontWeight;
2356     }
2357     else if ((uStrCaseCmp(field.str, "fontwidth") == 0) ||
2358              (uStrCaseCmp(field.str, "setwidth") == 0))
2359     {
2360         pField = &info->fontWeight;
2361     }
2362     else if ((uStrCaseCmp(field.str, "fontencoding") == 0) ||
2363              (uStrCaseCmp(field.str, "encoding") == 0))
2364     {
2365         pField = &info->fontEncoding;
2366     }
2367     else if ((uStrCaseCmp(field.str, "xfont") == 0) ||
2368              (uStrCaseCmp(field.str, "xfontname") == 0))
2369     {
2370         pField = &info->fontSpec;
2371     }
2372     else
2373     {
2374         ret = SetGeometryProperty(info, field.str, stmt->value);
2375         free(field.str);
2376         return ret;
2377     }
2378
2379     /* fallthrough for the cases that set pField */
2380     if (ndx != NULL)
2381     {
2382         info->errorCount++;
2383         ret = ReportNotArray("keyboard", field.str, "geometry");
2384     }
2385     else if (!ExprResolveString(stmt->value, &tmp, NULL, NULL))
2386     {
2387         info->errorCount++;
2388         ret = ReportBadType("keyboard", field.str, "geometry", "string");
2389     }
2390     else {
2391         *pField = xkb_intern_atom(tmp.str);
2392         free(tmp.str);
2393     }
2394     free(field.str);
2395     return ret;
2396 }
2397
2398 /***====================================================================***/
2399
2400 static Bool
2401 HandleShapeBody(ShapeDef * def, ShapeInfo * si, unsigned merge,
2402                 GeometryInfo * info)
2403 {
2404     OutlineDef *ol;
2405     int nOut, nPt;
2406     struct xkb_outline * outline;
2407     ExprDef *pt;
2408
2409     if (def->nOutlines < 1)
2410     {
2411         WARN("Shape \"%s\" has no outlines\n", shText(si));
2412         ACTION("Definition ignored\n");
2413         return True;
2414     }
2415     si->nOutlines = def->nOutlines;
2416     si->outlines = uTypedCalloc(def->nOutlines, struct xkb_outline);
2417     if (!si->outlines)
2418     {
2419         ERROR("Couldn't allocate outlines for \"%s\"\n", shText(si));
2420         ACTION("Definition ignored\n");
2421         info->errorCount++;
2422         return False;
2423     }
2424     for (nOut = 0, ol = def->outlines; ol != NULL;
2425          ol = (OutlineDef *) ol->common.next)
2426     {
2427         if (ol->nPoints < 1)
2428         {
2429             SetShapeField(si, XkbcAtomText(ol->field), NULL, ol->points, info);
2430             continue;
2431         }
2432         outline = NULL;
2433         outline = &si->outlines[nOut++];
2434         outline->num_points = ol->nPoints;
2435         outline->corner_radius = si->dfltCornerRadius;
2436         outline->points = uTypedCalloc(ol->nPoints, struct xkb_point);
2437         if (!outline->points)
2438         {
2439             ERROR("Can't allocate points for \"%s\"\n", shText(si));
2440             ACTION("Definition ignored\n");
2441             /* XXX leaks */
2442             info->errorCount++;
2443             return False;
2444         }
2445         for (nPt = 0, pt = ol->points; pt != NULL;
2446              pt = (ExprDef *) pt->common.next)
2447         {
2448             outline->points[nPt].x = pt->value.coord.x;
2449             outline->points[nPt].y = pt->value.coord.y;
2450             nPt++;
2451         }
2452         if (ol->field != None)
2453         {
2454             const char *str = XkbcAtomText(ol->field);
2455             if ((uStrCaseCmp(str, "approximation") == 0) ||
2456                 (uStrCaseCmp(str, "approx") == 0))
2457             {
2458                 if (si->approx == NULL)
2459                     si->approx = outline;
2460                 else
2461                 {
2462                     WARN("Multiple approximations for \"%s\"\n",
2463                           shText(si));
2464                     ACTION("Treating all but the first as normal outlines\n");
2465                 }
2466             }
2467             else if (uStrCaseCmp(str, "primary") == 0)
2468             {
2469                 if (si->primary == NULL)
2470                     si->primary = outline;
2471                 else
2472                 {
2473                     WARN("Multiple primary outlines for \"%s\"\n",
2474                           shText(si));
2475                     ACTION("Treating all but the first as normal outlines\n");
2476                 }
2477             }
2478             else
2479             {
2480                 WARN("Unknown outline type %s for \"%s\"\n", str,
2481                       shText(si));
2482                 ACTION("Treated as a normal outline\n");
2483             }
2484         }
2485     }
2486     if (nOut != si->nOutlines)
2487     {
2488         WSGO("Expected %d outlines, got %d\n",
2489               (unsigned int) si->nOutlines, nOut);
2490         si->nOutlines = nOut;
2491     }
2492     return True;
2493 }
2494
2495 static int
2496 HandleShapeDef(ShapeDef * def, struct xkb_desc * xkb, unsigned merge,
2497                GeometryInfo * info)
2498 {
2499     ShapeInfo si;
2500
2501     if (def->merge != MergeDefault)
2502         merge = def->merge;
2503
2504     bzero(&si, sizeof(ShapeInfo));
2505     si.defs.merge = merge;
2506     si.name = def->name;
2507     si.dfltCornerRadius = info->dfltCornerRadius;
2508     if (!HandleShapeBody(def, &si, merge, info))
2509         return False;
2510     if (!AddShape(info, &si))
2511         return False;
2512     return True;
2513 }
2514
2515 /***====================================================================***/
2516
2517 static int
2518 HandleDoodadDef(DoodadDef * def,
2519                 unsigned merge, SectionInfo * si, GeometryInfo * info)
2520 {
2521     ExprResult elem, field;
2522     ExprDef *ndx;
2523     DoodadInfo new;
2524     VarDef *var;
2525
2526     if (def->common.stmtType == StmtIndicatorMapDef)
2527     {
2528         def->common.stmtType = StmtDoodadDef;
2529         def->type = XkbIndicatorDoodad;
2530     }
2531     InitDoodadInfo(&new, def->type, si, info);
2532     new.name = def->name;
2533     for (var = def->body; var != NULL; var = (VarDef *) var->common.next)
2534     {
2535         if (ExprResolveLhs(var->name, &elem, &field, &ndx) == 0)
2536             return 0;           /* internal error, already reported */
2537         if (elem.str != NULL)
2538         {
2539             WARN("Assignment to field of unknown element in doodad %s\n",
2540                   ddText(&new));
2541             ACTION("No value assigned to %s.%s\n", elem.str, field.str);
2542             free(elem.str);
2543         }
2544         else if (!SetDoodadField(&new, field.str, ndx, var->value, si, info)) {
2545             free(field.str);
2546             return False;
2547         }
2548         free(field.str);
2549     }
2550     if (!AddDoodad(si, info, &new))
2551         return False;
2552     ClearDoodadInfo(&new);
2553     return True;
2554 }
2555
2556 /***====================================================================***/
2557
2558 static int
2559 HandleOverlayDef(OverlayDef * def,
2560                  unsigned merge, SectionInfo * si, GeometryInfo * info)
2561 {
2562     OverlayKeyDef *keyDef;
2563     OverlayKeyInfo *key;
2564     OverlayInfo ol;
2565
2566     if ((def->nKeys < 1) && (warningLevel > 3))
2567     {
2568         WARN("Overlay \"%s\" in section \"%s\" has no keys\n",
2569               XkbcAtomText(def->name), scText(si));
2570         ACTION("Overlay ignored\n");
2571         return True;
2572     }
2573     bzero(&ol, sizeof(OverlayInfo));
2574     ol.name = def->name;
2575     for (keyDef = def->keys; keyDef;
2576          keyDef = (OverlayKeyDef *) keyDef->common.next)
2577     {
2578         key = uTypedCalloc(1, OverlayKeyInfo);
2579         if ((!key) && warningLevel > 0)
2580         {
2581             WSGO("Couldn't allocate OverlayKeyInfo\n");
2582             ACTION("Overlay %s for section %s will be incomplete\n",
2583                     XkbcAtomText(ol.name), scText(si));
2584             return False;
2585         }
2586         strncpy(key->over, keyDef->over, XkbKeyNameLength);
2587         strncpy(key->under, keyDef->under, XkbKeyNameLength);
2588         key->sectionRow = _GOK_UnknownRow;
2589         key->overlayRow = _GOK_UnknownRow;
2590         ol.keys = (OverlayKeyInfo *) AddCommonInfo(&ol.keys->defs,
2591                                                    (CommonInfo *) key);
2592         ol.nKeys++;
2593     }
2594     if (!AddOverlay(si, info, &ol))
2595         return False;
2596     ClearOverlayInfo(&ol);
2597     return True;
2598 }
2599
2600 /***====================================================================***/
2601
2602 static Bool
2603 HandleComplexKey(KeyDef * def, KeyInfo * key, GeometryInfo * info)
2604 {
2605     RowInfo *row;
2606     ExprDef *expr;
2607
2608     row = key->row;
2609     for (expr = def->expr; expr != NULL; expr = (ExprDef *) expr->common.next)
2610     {
2611         if (expr->op == OpAssign)
2612         {
2613             ExprResult elem, f;
2614             ExprDef *ndx;
2615             if (ExprResolveLhs(expr->value.binary.left, &elem, &f, &ndx) == 0)
2616                 return False;   /* internal error, already reported */
2617             if ((elem.str == NULL) || (uStrCaseCmp(elem.str, "key") == 0))
2618             {
2619                 if (!SetKeyField
2620                     (key, f.str, ndx, expr->value.binary.right, info))
2621                 {
2622                     free(elem.str);
2623                     free(f.str);
2624                     return False;
2625                 }
2626                 free(elem.str);
2627                 free(f.str);
2628             }
2629             else
2630             {
2631                 ERROR("Illegal element used in a key definition\n");
2632                 ACTION("Assignment to %s.%s ignored\n", elem.str, f.str);
2633                 free(elem.str);
2634                 free(f.str);
2635                 return False;
2636             }
2637         }
2638         else
2639         {
2640             switch (expr->type)
2641             {
2642             case TypeInt:
2643             case TypeFloat:
2644                 if (!SetKeyField(key, "gap", NULL, expr, info))
2645                     return False;
2646                 break;
2647             case TypeString:
2648                 if (!SetKeyField(key, "shape", NULL, expr, info))
2649                     return False;
2650                 break;
2651             case TypeKeyName:
2652                 if (!SetKeyField(key, "name", NULL, expr, info))
2653                     return False;
2654                 break;
2655             default:
2656                 ERROR("Cannot determine field for unnamed expression\n");
2657                 ACTION("Ignoring key %d in row %d of section %s\n",
2658                         row->nKeys + 1, row->section->nRows + 1,
2659                         rowText(row));
2660                 return False;
2661             }
2662         }
2663     }
2664     return True;
2665 }
2666
2667 static Bool
2668 HandleRowBody(RowDef * def, RowInfo * row, unsigned merge,
2669               GeometryInfo * info)
2670 {
2671     KeyDef *keyDef;
2672
2673     if ((def->nKeys < 1) && (warningLevel > 3))
2674     {
2675         ERROR("Row in section %s has no keys\n", rowText(row));
2676         ACTION("Section ignored\n");
2677         return True;
2678     }
2679     for (keyDef = def->keys; keyDef != NULL;
2680          keyDef = (KeyDef *) keyDef->common.next)
2681     {
2682         if (keyDef->common.stmtType == StmtVarDef)
2683         {
2684             VarDef *var = (VarDef *) keyDef;
2685             ExprResult elem, field;
2686             ExprDef *ndx;
2687             if (ExprResolveLhs(var->name, &elem, &field, &ndx) == 0)
2688                 return 0;       /* internal error, already reported */
2689             if ((elem.str == NULL) || (uStrCaseCmp(elem.str, "row") == 0))
2690             {
2691                 if (!SetRowField(row, field.str, ndx, var->value, info))
2692                     return False;
2693             }
2694             else if (uStrCaseCmp(elem.str, "key") == 0)
2695             {
2696                 if (!SetKeyField
2697                     (&row->dfltKey, field.str, ndx, var->value, info))
2698                     return False;
2699             }
2700             else
2701             {
2702                 WARN("Assignment to field of unknown element in row\n");
2703                 ACTION("No value assigned to %s.%s\n", elem.str, field.str);
2704             }
2705             free(elem.str);
2706             free(field.str);
2707         }
2708         else if (keyDef->common.stmtType == StmtKeyDef)
2709         {
2710             KeyInfo key;
2711             InitKeyInfo(&key, row, info);
2712             if (keyDef->name != NULL)
2713             {
2714                 int len = strlen(keyDef->name);
2715                 if ((len < 1) || (len > XkbKeyNameLength))
2716                 {
2717                     ERROR("Illegal name %s for key in section %s\n",
2718                            keyDef->name, rowText(row));
2719                     ACTION("Section not compiled\n");
2720                     return False;
2721                 }
2722                 bzero(key.name, XkbKeyNameLength + 1);
2723                 strncpy(key.name, keyDef->name, XkbKeyNameLength);
2724                 key.defs.defined |= _GK_Name;
2725             }
2726             else if (!HandleComplexKey(keyDef, &key, info))
2727                 return False;
2728             if (!AddKey(row, &key))
2729                 return False;
2730         }
2731         else
2732         {
2733             WSGO("Unexpected statement (type %d) in row body\n",
2734                   keyDef->common.stmtType);
2735             return False;
2736         }
2737     }
2738     return True;
2739 }
2740
2741 static Bool
2742 HandleSectionBody(SectionDef * def,
2743                   SectionInfo * si, unsigned merge, GeometryInfo * info)
2744 {
2745     RowDef *rowDef;
2746     DoodadInfo *di;
2747
2748     for (rowDef = def->rows; rowDef != NULL;
2749          rowDef = (RowDef *) rowDef->common.next)
2750     {
2751         if (rowDef->common.stmtType == StmtVarDef)
2752         {
2753             VarDef *var = (VarDef *) rowDef;
2754             ExprResult elem, field;
2755             ExprDef *ndx;
2756             if (ExprResolveLhs(var->name, &elem, &field, &ndx) == 0)
2757                 return 0;       /* internal error, already reported */
2758             if ((elem.str == NULL) || (uStrCaseCmp(elem.str, "section") == 0))
2759             {
2760                 if (!SetSectionField(si, field.str, ndx, var->value, info))
2761                 {
2762                     free(field.str);
2763                     return False;
2764                 }
2765             }
2766             else if (uStrCaseCmp(elem.str, "row") == 0)
2767             {
2768                 if (!SetRowField
2769                     (&si->dfltRow, field.str, ndx, var->value, info))
2770                 {
2771                     free(field.str);
2772                     return False;
2773                 }
2774             }
2775             else if (uStrCaseCmp(elem.str, "key") == 0)
2776             {
2777                 if (!SetKeyField(&si->dfltRow.dfltKey, field.str, ndx,
2778                                  var->value, info))
2779                 {
2780                     free(field.str);
2781                     return False;
2782                 }
2783             }
2784             else if ((di =
2785                       FindDfltDoodadByTypeName(elem.str, si, info)) != NULL)
2786             {
2787                 if (!SetDoodadField(di, field.str, ndx, var->value, si, info))
2788                 {
2789                     free(field.str);
2790                     return False;
2791                 }
2792             }
2793             else
2794             {
2795                 WARN("Assignment to field of unknown element in section\n");
2796                 ACTION("No value assigned to %s.%s\n", elem.str, field.str);
2797             }
2798             free(field.str);
2799             free(elem.str);
2800         }
2801         else if (rowDef->common.stmtType == StmtRowDef)
2802         {
2803             RowInfo row;
2804             InitRowInfo(&row, si, info);
2805             if (!HandleRowBody(rowDef, &row, merge, info))
2806                 return False;
2807             if (!AddRow(si, &row))
2808                 return False;
2809 /*          ClearRowInfo(&row,info);*/
2810         }
2811         else if ((rowDef->common.stmtType == StmtDoodadDef) ||
2812                  (rowDef->common.stmtType == StmtIndicatorMapDef))
2813         {
2814             if (!HandleDoodadDef((DoodadDef *) rowDef, merge, si, info))
2815                 return False;
2816         }
2817         else if (rowDef->common.stmtType == StmtOverlayDef)
2818         {
2819             if (!HandleOverlayDef((OverlayDef *) rowDef, merge, si, info))
2820                 return False;
2821         }
2822         else
2823         {
2824             WSGO("Unexpected statement (type %d) in section body\n",
2825                   rowDef->common.stmtType);
2826             return False;
2827         }
2828     }
2829     if (si->nRows != def->nRows)
2830     {
2831         WSGO("Expected %d rows, found %d\n", (unsigned int) def->nRows,
2832               (unsigned int) si->nRows);
2833         ACTION("Definition of section %s might be incorrect\n", scText(si));
2834     }
2835     return True;
2836 }
2837
2838 static int
2839 HandleSectionDef(SectionDef * def,
2840                  struct xkb_desc * xkb, unsigned merge, GeometryInfo * info)
2841 {
2842     SectionInfo si;
2843
2844     if (def->merge != MergeDefault)
2845         merge = def->merge;
2846     InitSectionInfo(&si, info);
2847     si.defs.merge = merge;
2848     si.name = def->name;
2849     if (!HandleSectionBody(def, &si, merge, info))
2850         return False;
2851     if (!AddSection(info, &si))
2852         return False;
2853     return True;
2854 }
2855
2856 /***====================================================================***/
2857
2858 static void
2859 HandleGeometryFile(XkbFile * file,
2860                    struct xkb_desc * xkb, unsigned merge, GeometryInfo * info)
2861 {
2862     ParseCommon *stmt;
2863     char *failWhat;
2864
2865     if (merge == MergeDefault)
2866         merge = MergeAugment;
2867     info->name = _XkbDupString(file->name);
2868     stmt = file->defs;
2869     while (stmt)
2870     {
2871         failWhat = NULL;
2872         switch (stmt->stmtType)
2873         {
2874         case StmtInclude:
2875             if (!HandleIncludeGeometry((IncludeStmt *) stmt, xkb, info,
2876                                        HandleGeometryFile))
2877                 info->errorCount++;
2878             break;
2879         case StmtKeyAliasDef:
2880             if (!HandleAliasDef((KeyAliasDef *) stmt,
2881                                 merge, info->fileID, &info->aliases))
2882             {
2883                 info->errorCount++;
2884             }
2885             break;
2886         case StmtVarDef:
2887             if (!HandleGeometryVar((VarDef *) stmt, xkb, info))
2888                 info->errorCount++;
2889             break;
2890         case StmtShapeDef:
2891             if (!HandleShapeDef((ShapeDef *) stmt, xkb, merge, info))
2892                 info->errorCount++;
2893             break;
2894         case StmtSectionDef:
2895             if (!HandleSectionDef((SectionDef *) stmt, xkb, merge, info))
2896                 info->errorCount++;
2897             break;
2898         case StmtIndicatorMapDef:
2899         case StmtDoodadDef:
2900             if (!HandleDoodadDef((DoodadDef *) stmt, merge, NULL, info))
2901                 info->errorCount++;
2902             break;
2903         case StmtVModDef:
2904             if (!failWhat)
2905                 failWhat = "virtual modfier";
2906         case StmtInterpDef:
2907             if (!failWhat)
2908                 failWhat = "symbol interpretation";
2909         case StmtGroupCompatDef:
2910             if (!failWhat)
2911                 failWhat = "group compatibility map";
2912         case StmtKeycodeDef:
2913             if (!failWhat)
2914                 failWhat = "key name";
2915             ERROR("Interpretation files may not include other types\n");
2916             ACTION("Ignoring %s definition.\n", failWhat);
2917             info->errorCount++;
2918             break;
2919         default:
2920             WSGO("Unexpected statement type %d in HandleGeometryFile\n",
2921                   stmt->stmtType);
2922             break;
2923         }
2924         stmt = stmt->next;
2925         if (info->errorCount > 10)
2926         {
2927 #ifdef NOISY
2928             ERROR("Too many errors\n");
2929 #endif
2930             ACTION("Abandoning geometry file \"%s\"\n", file->topName);
2931             break;
2932         }
2933     }
2934     return;
2935 }
2936
2937 /***====================================================================***/
2938
2939 static Bool
2940 CopyShapeDef(struct xkb_geometry * geom, ShapeInfo * si)
2941 {
2942     register int i, n;
2943     struct xkb_shape * shape;
2944     struct xkb_outline *old_outline, *outline;
2945     uint32_t name;
2946
2947     si->index = geom->num_shapes;
2948     name = si->name;
2949     shape = XkbcAddGeomShape(geom, name, si->nOutlines);
2950     if (!shape)
2951     {
2952         WSGO("Couldn't allocate shape in geometry\n");
2953         ACTION("Shape %s not compiled\n", shText(si));
2954         return False;
2955     }
2956     old_outline = si->outlines;
2957     for (i = 0; i < si->nOutlines; i++, old_outline++)
2958     {
2959         outline = XkbcAddGeomOutline(shape, old_outline->num_points);
2960         if (!outline)
2961         {
2962             WSGO("Couldn't allocate outline in shape\n");
2963             ACTION("Shape %s is incomplete\n", shText(si));
2964             return False;
2965         }
2966         n = old_outline->num_points;
2967         memcpy(outline->points, old_outline->points, n * sizeof(struct xkb_point));
2968         outline->num_points = old_outline->num_points;
2969         outline->corner_radius = old_outline->corner_radius;
2970     }
2971     if (si->approx)
2972     {
2973         n = (si->approx - si->outlines);
2974         shape->approx = &shape->outlines[n];
2975     }
2976     if (si->primary)
2977     {
2978         n = (si->primary - si->outlines);
2979         shape->primary = &shape->outlines[n];
2980     }
2981     XkbcComputeShapeBounds(shape);
2982     return True;
2983 }
2984
2985 static Bool
2986 VerifyDoodadInfo(DoodadInfo * di, GeometryInfo * info)
2987 {
2988     if ((di->defs.defined & (_GD_Top | _GD_Left)) != (_GD_Top | _GD_Left))
2989     {
2990         if (warningLevel < 9)
2991         {
2992             ERROR("No position defined for doodad %s\n",
2993                    ddText(di));
2994             ACTION("Illegal doodad ignored\n");
2995             return False;
2996         }
2997     }
2998     if ((di->defs.defined & _GD_Priority) == 0)
2999     {
3000         /* calculate priority -- should be just above previous doodad/row */
3001     }
3002     switch (di->type)
3003     {
3004     case XkbOutlineDoodad:
3005     case XkbSolidDoodad:
3006         if ((di->defs.defined & _GD_Shape) == 0)
3007         {
3008             ERROR("No shape defined for %s doodad %s\n",
3009                    (di->type == XkbOutlineDoodad ? "outline" : "filled"),
3010                    ddText(di));
3011             ACTION("Incomplete definition ignored\n");
3012             return False;
3013         }
3014         else
3015         {
3016             ShapeInfo *si;
3017             si = FindShape(info, di->shape,
3018                            (di->type ==
3019                             XkbOutlineDoodad ? "outline doodad" :
3020                             "solid doodad"), ddText(di));
3021             if (si)
3022                 di->shape = si->name;
3023             else
3024             {
3025                 ERROR("No legal shape for %s\n", ddText(di));
3026                 ACTION("Incomplete definition ignored\n");
3027                 return False;
3028             }
3029         }
3030         if ((di->defs.defined & _GD_Color) == 0)
3031         {
3032             if (warningLevel > 5)
3033             {
3034                 WARN("No color for doodad %s\n", ddText(di));
3035                 ACTION("Using black\n");
3036             }
3037             di->color = xkb_intern_atom("black");
3038         }
3039         break;
3040     case XkbTextDoodad:
3041         if ((di->defs.defined & _GD_Text) == 0)
3042         {
3043             ERROR("No text specified for text doodad %s\n", ddText(di));
3044             ACTION("Illegal doodad definition ignored\n");
3045             return False;
3046         }
3047         if ((di->defs.defined & _GD_Angle) == 0)
3048             di->angle = 0;
3049         if ((di->defs.defined & _GD_Color) == 0)
3050         {
3051             if (warningLevel > 5)
3052             {
3053                 WARN("No color specified for doodad %s\n", ddText(di));
3054                 ACTION("Using black\n");
3055             }
3056             di->color = xkb_intern_atom("black");
3057         }
3058         if ((di->defs.defined & _GD_FontSpec) != 0)
3059         {
3060             if ((di->defs.defined & _GD_FontParts) == 0)
3061                 return True;
3062             if (warningLevel < 9)
3063             {
3064                 WARN
3065                     ("Text doodad %s has full and partial font definition\n",
3066                      ddText(di));
3067                 ACTION("Full specification ignored\n");
3068             }
3069             di->defs.defined &= ~_GD_FontSpec;
3070             di->fontSpec = None;
3071         }
3072         if ((di->defs.defined & _GD_Font) == 0)
3073         {
3074             if (warningLevel > 5)
3075             {
3076                 WARN("No font specified for doodad %s\n", ddText(di));
3077                 ACTION("Using \"%s\"\n", DFLT_FONT);
3078             }
3079             di->font = xkb_intern_atom(DFLT_FONT);
3080         }
3081         if ((di->defs.defined & _GD_FontSlant) == 0)
3082         {
3083             if (warningLevel > 7)
3084             {
3085                 WARN("No font slant for text doodad %s\n", ddText(di));
3086                 ACTION("Using \"%s\"\n", DFLT_SLANT);
3087             }
3088             di->fontSlant = xkb_intern_atom(DFLT_SLANT);
3089         }
3090         if ((di->defs.defined & _GD_FontWeight) == 0)
3091         {
3092             if (warningLevel > 7)
3093             {
3094                 WARN("No font weight for text doodad %s\n", ddText(di));
3095                 ACTION("Using \"%s\"\n", DFLT_WEIGHT);
3096             }
3097             di->fontWeight = xkb_intern_atom(DFLT_WEIGHT);
3098         }
3099         if ((di->defs.defined & _GD_FontSetWidth) == 0)
3100         {
3101             if (warningLevel > 9)
3102             {
3103                 WARN("No font set width for text doodad %s\n", ddText(di));
3104                 ACTION("Using \"%s\"\n", DFLT_SET_WIDTH);
3105             }
3106             di->fontSetWidth = xkb_intern_atom(DFLT_SET_WIDTH);
3107         }
3108         if ((di->defs.defined & _GD_FontVariant) == 0)
3109         {
3110             if (warningLevel > 9)
3111             {
3112                 WARN("No font variant for text doodad %s\n", ddText(di));
3113                 ACTION("Using \"%s\"\n", DFLT_VARIANT);
3114             }
3115             di->fontVariant = xkb_intern_atom(DFLT_VARIANT);
3116         }
3117         if ((di->defs.defined & _GD_FontEncoding) == 0)
3118         {
3119             if (warningLevel > 7)
3120             {
3121                 WARN("No font encoding for doodad %s\n", ddText(di));
3122                 ACTION("Using \"%s\"\n", DFLT_ENCODING);
3123             }
3124             di->fontEncoding = xkb_intern_atom(DFLT_ENCODING);
3125         }
3126         if ((di->defs.defined & _GD_FontSize) == 0)
3127         {
3128             if (warningLevel > 7)
3129             {
3130                 WARN("No font size for text doodad %s\n", ddText(di));
3131                 ACTION("Using %s point text\n", XkbcGeomFPText(DFLT_SIZE));
3132             }
3133             di->fontSize = DFLT_SIZE;
3134         }
3135         if ((di->defs.defined & _GD_Height) == 0)
3136         {
3137             unsigned size, nLines;
3138             const char *tmp;
3139             size = (di->fontSize * 120) / 100;
3140             size = (size * 254) / 720;  /* convert to mm/10 */
3141             for (nLines = 1, tmp = XkbcAtomText(di->text); *tmp; tmp++)
3142             {
3143                 if (*tmp == '\n')
3144                     nLines++;
3145             }
3146             size *= nLines;
3147             if (warningLevel > 5)
3148             {
3149                 WARN("No height for text doodad %s\n", ddText(di));
3150                 ACTION("Using calculated height %s millimeters\n",
3151                         XkbcGeomFPText(size));
3152             }
3153             di->height = size;
3154         }
3155         if ((di->defs.defined & _GD_Width) == 0)
3156         {
3157             unsigned width, tmp;
3158             const char *str;
3159             width = tmp = 0;
3160             for (str = XkbcAtomText(di->text); *str; str++)
3161             {
3162                 if (*str != '\n')
3163                     tmp++;
3164                 else
3165                 {
3166                     if (tmp > width)
3167                         width = tmp;
3168                     tmp = 1;
3169                 }
3170             }
3171             if (width == 0)
3172                 width = tmp;
3173             width *= (di->height * 2) / 3;
3174             if (warningLevel > 5)
3175             {
3176                 WARN("No width for text doodad %s\n", ddText(di));
3177                 ACTION("Using calculated width %s millimeters\n",
3178                         XkbcGeomFPText(width));
3179             }
3180             di->width = width;
3181         }
3182         break;
3183     case XkbIndicatorDoodad:
3184         if ((di->defs.defined & _GD_Shape) == 0)
3185         {
3186             ERROR("No shape defined for indicator doodad %s\n", ddText(di));
3187             ACTION("Incomplete definition ignored\n");
3188             return False;
3189         }
3190         else
3191         {
3192             ShapeInfo *si;
3193             si = FindShape(info, di->shape, "indicator doodad", ddText(di));
3194             if (si)
3195                 di->shape = si->name;
3196             else
3197             {
3198                 ERROR("No legal shape for doodad %s\n", ddText(di));
3199                 ACTION("Incomplete definition ignored\n");
3200                 return False;
3201             }
3202         }
3203         if ((di->defs.defined & _GD_Color) == 0)
3204         {
3205             if (warningLevel > 5)
3206             {
3207                 WARN("No \"on\" color for indicator doodad %s\n",
3208                       ddText(di));
3209                 ACTION("Using green\n");
3210             }
3211             di->color = xkb_intern_atom("green");
3212         }
3213         if ((di->defs.defined & _GD_OffColor) == 0)
3214         {
3215             if (warningLevel > 5)
3216             {
3217                 WARN("No \"off\" color for indicator doodad %s\n",
3218                       ddText(di));
3219                 ACTION("Using black\n");
3220             }
3221             di->offColor = xkb_intern_atom("black");
3222         }
3223         break;
3224     case XkbLogoDoodad:
3225         if (di->logoName == NULL)
3226         {
3227             ERROR("No logo name defined for logo doodad %s\n", ddText(di));
3228             ACTION("Incomplete definition ignored\n");
3229             return False;
3230         }
3231         if ((di->defs.defined & _GD_Shape) == 0)
3232         {
3233             ERROR("No shape defined for logo doodad %s\n", ddText(di));
3234             ACTION("Incomplete definition ignored\n");
3235             return False;
3236         }
3237         else
3238         {
3239             ShapeInfo *si;
3240             si = FindShape(info, di->shape, "logo doodad",
3241                            ddText(di));
3242             if (si)
3243                 di->shape = si->name;
3244             else
3245             {
3246                 ERROR("No legal shape for %s\n", ddText(di));
3247                 ACTION("Incomplete definition ignored\n");
3248                 return False;
3249             }
3250         }
3251         if ((di->defs.defined & _GD_Color) == 0)
3252         {
3253             if (warningLevel > 5)
3254             {
3255                 WARN("No color for doodad %s\n", ddText(di));
3256                 ACTION("Using black\n");
3257             }
3258             di->color = xkb_intern_atom("black");
3259         }
3260         break;
3261     default:
3262         WSGO("Uknown doodad type %d in VerifyDoodad\n",
3263               (unsigned int) di->type);
3264         return False;
3265     }
3266     return True;
3267 }
3268
3269 #define FONT_TEMPLATE   "-*-%s-%s-%s-%s-%s-*-%d-*-*-*-*-%s"
3270
3271 static char *
3272 FontFromParts(uint32_t fontTok,
3273               uint32_t weightTok,
3274               uint32_t slantTok,
3275               uint32_t setWidthTok, uint32_t varTok, int size, uint32_t encodingTok)
3276 {
3277     int totalSize;
3278     const char *font, *weight, *slant, *setWidth, *variant, *encoding;
3279     char *rtrn;
3280
3281     font = (fontTok != None ? XkbcAtomText(fontTok) : DFLT_FONT);
3282     weight = (weightTok != None ? XkbcAtomText(weightTok) : DFLT_WEIGHT);
3283     slant = (slantTok != None ? XkbcAtomText(slantTok) : DFLT_SLANT);
3284     setWidth =
3285         (setWidthTok != None ? XkbcAtomText(setWidthTok) : DFLT_SET_WIDTH);
3286     variant = (varTok != None ? XkbcAtomText(varTok) : DFLT_VARIANT);
3287     encoding =
3288         (encodingTok != None ? XkbcAtomText(encodingTok) : DFLT_ENCODING);
3289     if (size == 0)
3290         size = DFLT_SIZE;
3291     totalSize =
3292         strlen(FONT_TEMPLATE) + strlen(font) + strlen(weight) + strlen(slant);
3293     totalSize += strlen(setWidth) + strlen(variant) + strlen(encoding);
3294     rtrn = calloc(totalSize, 1);
3295     if (rtrn)
3296         sprintf(rtrn, FONT_TEMPLATE, font, weight, slant, setWidth, variant,
3297                 size, encoding);
3298     return rtrn;
3299 }
3300
3301 static Bool
3302 CopyDoodadDef(struct xkb_geometry * geom,
3303               struct xkb_section * section, DoodadInfo * di, GeometryInfo * info)
3304 {
3305     uint32_t name;
3306     union xkb_doodad * doodad;
3307     struct xkb_color * color;
3308     struct xkb_shape * shape;
3309     ShapeInfo *si;
3310
3311     if (!VerifyDoodadInfo(di, info))
3312         return False;
3313     name = di->name;
3314     doodad = XkbcAddGeomDoodad(geom, section, name);
3315     if (!doodad)
3316     {
3317         WSGO("Couldn't allocate doodad in %s\n",
3318               (section ? "section" : "geometry"));
3319         ACTION("Cannot copy doodad %s\n", ddText(di));
3320         return False;
3321     }
3322     doodad->any.type = di->type;
3323     doodad->any.priority = di->priority;
3324     doodad->any.top = di->top;
3325     doodad->any.left = di->left;
3326     switch (di->type)
3327     {
3328     case XkbOutlineDoodad:
3329     case XkbSolidDoodad:
3330         si = FindShape(info, di->shape, NULL, NULL);
3331         if (!si)
3332             return False;
3333         doodad->shape.angle = di->angle;
3334         color = XkbcAddGeomColor(geom, XkbcAtomText(di->color),
3335                                  geom->num_colors);
3336         shape = &geom->shapes[si->index];
3337         XkbSetShapeDoodadColor(geom, &doodad->shape, color);
3338         XkbSetShapeDoodadShape(geom, &doodad->shape, shape);
3339         break;
3340     case XkbTextDoodad:
3341         doodad->text.angle = di->angle;
3342         doodad->text.width = di->width;
3343         doodad->text.height = di->height;
3344         if (di->fontSpec == None)
3345             doodad->text.font = FontFromParts(di->font, di->fontWeight,
3346                                               di->fontSlant,
3347                                               di->fontSetWidth,
3348                                               di->fontVariant, di->fontSize,
3349                                               di->fontEncoding);
3350         else
3351             doodad->text.font = XkbcAtomGetString(di->fontSpec);
3352         doodad->text.text = XkbcAtomGetString(di->text);
3353         color = XkbcAddGeomColor(geom, XkbcAtomText(di->color),
3354                                  geom->num_colors);
3355         XkbSetTextDoodadColor(geom, &doodad->text, color);
3356         break;
3357     case XkbIndicatorDoodad:
3358         si = FindShape(info, di->shape, NULL, NULL);
3359         if (!si)
3360             return False;
3361         shape = &geom->shapes[si->index];
3362         color = XkbcAddGeomColor(geom, XkbcAtomText(di->color),
3363                                  geom->num_colors);
3364         XkbSetIndicatorDoodadShape(geom, &doodad->indicator, shape);
3365         XkbSetIndicatorDoodadOnColor(geom, &doodad->indicator, color);
3366         color = XkbcAddGeomColor(geom, XkbcAtomText(di->offColor),
3367                                  geom->num_colors);
3368         XkbSetIndicatorDoodadOffColor(geom, &doodad->indicator, color);
3369         break;
3370     case XkbLogoDoodad:
3371         si = FindShape(info, di->shape, NULL, NULL);
3372         if (!si)
3373             return False;
3374         doodad->logo.angle = di->angle;
3375         color = XkbcAddGeomColor(geom, XkbcAtomText(di->color),
3376                                  geom->num_colors);
3377         shape = &geom->shapes[si->index];
3378         XkbSetLogoDoodadColor(geom, &doodad->logo, color);
3379         XkbSetLogoDoodadShape(geom, &doodad->logo, shape);
3380         doodad->logo.logo_name = di->logoName;
3381         di->logoName = NULL;
3382         break;
3383     }
3384     return True;
3385 }
3386
3387 /***====================================================================***/
3388
3389 static Bool
3390 VerifyOverlayInfo(struct xkb_geometry * geom,
3391                   struct xkb_section * section,
3392                   OverlayInfo * oi,
3393                   GeometryInfo * info, short rowMap[256], short rowSize[256])
3394 {
3395     register OverlayKeyInfo *ki, *next;
3396     unsigned long oKey, uKey, sKey;
3397     struct xkb_row * row;
3398     struct xkb_key * key;
3399     int r, k;
3400
3401     /* find out which row each key is in */
3402     for (ki = oi->keys; ki != NULL; ki = (OverlayKeyInfo *) ki->defs.next)
3403     {
3404         oKey = KeyNameToLong(ki->over);
3405         uKey = KeyNameToLong(ki->under);
3406         for (r = 0, row = section->rows; (r < section->num_rows) && oKey;
3407              r++, row++)
3408         {
3409             for (k = 0, key = row->keys; (k < row->num_keys) && oKey;
3410                  k++, key++)
3411             {
3412                 sKey = KeyNameToLong(key->name.name);
3413                 if (sKey == oKey)
3414                 {
3415                     if (warningLevel > 0)
3416                     {
3417                         WARN
3418                             ("Key %s in section \"%s\" and overlay \"%s\"\n",
3419                              XkbcKeyNameText(key->name.name),
3420                              XkbcAtomText(section->name),
3421                              XkbcAtomText(oi->name));
3422                         ACTION("Overlay definition ignored\n");
3423                     }
3424                     oKey = 0;
3425                 }
3426                 else if (sKey == uKey)
3427                 {
3428                     ki->sectionRow = r;
3429                     oKey = 0;
3430                 }
3431             }
3432         }
3433         if ((ki->sectionRow == _GOK_UnknownRow) && (warningLevel > 0))
3434         {
3435             WARN
3436                 ("Key %s not in \"%s\", but has an overlay key in \"%s\"\n",
3437                  XkbcKeyNameText(ki->under),
3438                  XkbcAtomText(section->name),
3439                  XkbcAtomText(oi->name));
3440             ACTION("Definition ignored\n");
3441         }
3442     }
3443     /* now prune out keys that aren't in the section */
3444     while ((oi->keys != NULL) && (oi->keys->sectionRow == _GOK_UnknownRow))
3445     {
3446         next = (OverlayKeyInfo *) oi->keys->defs.next;
3447         free(oi->keys);
3448         oi->keys = next;
3449         oi->nKeys--;
3450     }
3451     for (ki = oi->keys; (ki != NULL) && (ki->defs.next != NULL); ki = next)
3452     {
3453         next = (OverlayKeyInfo *) ki->defs.next;
3454         if (next->sectionRow == _GOK_UnknownRow)
3455         {
3456             ki->defs.next = next->defs.next;
3457             oi->nKeys--;
3458             free(next);
3459             next = (OverlayKeyInfo *) ki->defs.next;
3460         }
3461     }
3462     if (oi->nKeys < 1)
3463     {
3464         ERROR("Overlay \"%s\" for section \"%s\" has no legal keys\n",
3465                XkbcAtomText(oi->name), XkbcAtomText(section->name));
3466         ACTION("Overlay definition ignored\n");
3467         return False;
3468     }
3469     /* now figure out how many rows are defined for the overlay */
3470     bzero(rowSize, sizeof(short) * 256);
3471     for (k = 0; k < 256; k++)
3472     {
3473         rowMap[k] = -1;
3474     }
3475     oi->nRows = 0;
3476     for (ki = oi->keys; ki != NULL; ki = (OverlayKeyInfo *) ki->defs.next)
3477     {
3478         if (rowMap[ki->sectionRow] == -1)
3479             rowMap[ki->sectionRow] = oi->nRows++;
3480         ki->overlayRow = rowMap[ki->sectionRow];
3481         rowSize[ki->overlayRow]++;
3482     }
3483     return True;
3484 }
3485
3486 static Bool
3487 CopyOverlayDef(struct xkb_geometry * geom,
3488                struct xkb_section * section, OverlayInfo * oi, GeometryInfo * info)
3489 {
3490     uint32_t name;
3491     struct xkb_overlay * ol;
3492     struct xkb_overlay_row * row;
3493     struct xkb_overlay_key * key;
3494     OverlayKeyInfo *ki;
3495     short rowMap[256], rowSize[256];
3496     int i;
3497
3498     if (!VerifyOverlayInfo(geom, section, oi, info, rowMap, rowSize))
3499         return False;
3500     name = oi->name;
3501     ol = XkbcAddGeomOverlay(section, name, oi->nRows);
3502     if (!ol)
3503     {
3504         WSGO("Couldn't add overlay \"%s\" to section \"%s\"\n",
3505               XkbcAtomText(name), XkbcAtomText(section->name));
3506         return False;
3507     }
3508     for (i = 0; i < oi->nRows; i++)
3509     {
3510         int tmp, row_under;
3511         for (tmp = 0, row_under = -1;
3512              (tmp < section->num_rows) && (row_under < 0); tmp++)
3513         {
3514             if (rowMap[tmp] == i)
3515                 row_under = tmp;
3516         }
3517         if (!XkbcAddGeomOverlayRow(ol, row_under, rowSize[i]))
3518         {
3519             WSGO
3520                 ("Can't add row %d to overlay \"%s\" of section \"%s\"\n",
3521                  i, XkbcAtomText(name), XkbcAtomText(section->name));
3522             return False;
3523         }
3524     }
3525     for (ki = oi->keys; ki != NULL; ki = (OverlayKeyInfo *) ki->defs.next)
3526     {
3527         row = &ol->rows[ki->overlayRow];
3528         key = &row->keys[row->num_keys++];
3529         bzero(key, sizeof(struct xkb_overlay_key));
3530         strncpy(key->over.name, ki->over, XkbKeyNameLength);
3531         strncpy(key->under.name, ki->under, XkbKeyNameLength);
3532     }
3533     return True;
3534 }
3535
3536 /***====================================================================***/
3537
3538 static Bool
3539 CopySectionDef(struct xkb_geometry * geom, SectionInfo * si, GeometryInfo * info)
3540 {
3541     struct xkb_section * section;
3542     struct xkb_row * row;
3543     struct xkb_key * key;
3544     KeyInfo *ki;
3545     RowInfo *ri;
3546
3547     section = XkbcAddGeomSection(geom, si->name, si->nRows, si->nDoodads,
3548                                  si->nOverlays);
3549     if (section == NULL)
3550     {
3551         WSGO("Couldn't allocate section in geometry\n");
3552         ACTION("Section %s not compiled\n", scText(si));
3553         return False;
3554     }
3555     section->top = si->top;
3556     section->left = si->left;
3557     section->width = si->width;
3558     section->height = si->height;
3559     section->angle = si->angle;
3560     section->priority = si->priority;
3561     for (ri = si->rows; ri != NULL; ri = (RowInfo *) ri->defs.next)
3562     {
3563         row = XkbcAddGeomRow(section, ri->nKeys);
3564         if (row == NULL)
3565         {
3566             WSGO("Couldn't allocate row in section\n");
3567             ACTION("Section %s is incomplete\n", scText(si));
3568             return False;
3569         }
3570         row->top = ri->top;
3571         row->left = ri->left;
3572         row->vertical = ri->vertical;
3573         for (ki = ri->keys; ki != NULL; ki = (KeyInfo *) ki->defs.next)
3574         {
3575             struct xkb_color * color;
3576             if ((ki->defs.defined & _GK_Name) == 0)
3577             {
3578                 ERROR("Key %d of row %d in section %s has no name\n",
3579                        (int) ki->index, (int) ri->index, scText(si));
3580                 ACTION("Section %s ignored\n", scText(si));
3581                 return False;
3582             }
3583             key = XkbcAddGeomKey(row);
3584             if (key == NULL)
3585             {
3586                 WSGO("Couldn't allocate key in row\n");
3587                 ACTION("Section %s is incomplete\n", scText(si));
3588                 return False;
3589             }
3590             memcpy(key->name.name, ki->name, XkbKeyNameLength);
3591             key->gap = ki->gap;
3592             if (ki->shape == None)
3593                 key->shape_ndx = 0;
3594             else
3595             {
3596                 ShapeInfo *si;
3597                 si = FindShape(info, ki->shape, "key", keyText(ki));
3598                 if (!si)
3599                     return False;
3600                 key->shape_ndx = si->index;
3601             }
3602             if (ki->color != None)
3603                 color =
3604                     XkbcAddGeomColor(geom, XkbcAtomText(ki->color),
3605                                      geom->num_colors);
3606             else
3607                 color = XkbcAddGeomColor(geom, "white", geom->num_colors);
3608             XkbSetKeyColor(geom, key, color);
3609         }
3610     }
3611     if (si->doodads != NULL)
3612     {
3613         DoodadInfo *di;
3614         for (di = si->doodads; di != NULL; di = (DoodadInfo *) di->defs.next)
3615         {
3616             CopyDoodadDef(geom, section, di, info);
3617         }
3618     }
3619     if (si->overlays != NULL)
3620     {
3621         OverlayInfo *oi;
3622         for (oi = si->overlays; oi != NULL;
3623              oi = (OverlayInfo *) oi->defs.next)
3624         {
3625             CopyOverlayDef(geom, section, oi, info);
3626         }
3627     }
3628     if (XkbcComputeSectionBounds(geom, section))
3629     {
3630         /* 7/6/94 (ef) --  check for negative origin and translate */
3631         if ((si->defs.defined & _GS_Width) == 0)
3632             section->width = section->bounds.x2;
3633         if ((si->defs.defined & _GS_Height) == 0)
3634             section->height = section->bounds.y2;
3635     }
3636     return True;
3637 }
3638
3639 /***====================================================================***/
3640
3641 Bool
3642 CompileGeometry(XkbFile *file, struct xkb_desc * xkb, unsigned merge)
3643 {
3644     GeometryInfo info;
3645
3646     InitGeometryInfo(&info, file->id, merge);
3647     HandleGeometryFile(file, xkb, merge, &info);
3648
3649     if (info.errorCount == 0)
3650     {
3651         struct xkb_geometry * geom;
3652         struct xkb_geometry_sizes sizes;
3653         bzero(&sizes, sizeof(sizes));
3654         sizes.which = XkbGeomAllMask;
3655         sizes.num_properties = info.nProps;
3656         sizes.num_colors = 8;
3657         sizes.num_shapes = info.nShapes;
3658         sizes.num_sections = info.nSections;
3659         sizes.num_doodads = info.nDoodads;
3660         if (XkbcAllocGeometry(xkb, &sizes) != Success)
3661         {
3662             WSGO("Couldn't allocate GeometryRec\n");
3663             ACTION("Geometry not compiled\n");
3664             return False;
3665         }
3666         geom = xkb->geom;
3667
3668         geom->width_mm = info.widthMM;
3669         geom->height_mm = info.heightMM;
3670         if (info.name != NULL)
3671         {
3672             geom->name = xkb_intern_atom(info.name);
3673             if (XkbcAllocNames(xkb, XkbGeometryNameMask, 0, 0) == Success)
3674                 xkb->names->geometry = geom->name;
3675         }
3676         if (info.fontSpec != None)
3677             geom->label_font = XkbcAtomGetString(info.fontSpec);
3678         else
3679             geom->label_font = FontFromParts(info.font, info.fontWeight,
3680                                              info.fontSlant,
3681                                              info.fontSetWidth,
3682                                              info.fontVariant,
3683                                              info.fontSize,
3684                                              info.fontEncoding);
3685         XkbcAddGeomColor(geom, "black", geom->num_colors);
3686         XkbcAddGeomColor(geom, "white", geom->num_colors);
3687
3688         if (info.baseColor == None)
3689             info.baseColor = xkb_intern_atom("white");
3690         if (info.labelColor == None)
3691             info.labelColor = xkb_intern_atom("black");
3692         geom->base_color =
3693             XkbcAddGeomColor(geom, XkbcAtomText(info.baseColor),
3694                              geom->num_colors);
3695         geom->label_color =
3696             XkbcAddGeomColor(geom, XkbcAtomText(info.labelColor),
3697                              geom->num_colors);
3698
3699         if (info.props)
3700         {
3701             PropertyInfo *pi;
3702             for (pi = info.props; pi != NULL;
3703                  pi = (PropertyInfo *) pi->defs.next)
3704             {
3705                 if (!XkbcAddGeomProperty(geom, pi->name, pi->value))
3706                     return False;
3707             }
3708         }
3709         if (info.shapes)
3710         {
3711             ShapeInfo *si;
3712             for (si = info.shapes; si != NULL;
3713                  si = (ShapeInfo *) si->defs.next)
3714             {
3715                 if (!CopyShapeDef(geom, si))
3716                     return False;
3717             }
3718         }
3719         if (info.sections)
3720         {
3721             SectionInfo *si;
3722             for (si = info.sections; si != NULL;
3723                  si = (SectionInfo *) si->defs.next)
3724             {
3725                 if (!CopySectionDef(geom, si, &info))
3726                     return False;
3727             }
3728         }
3729         if (info.doodads)
3730         {
3731             DoodadInfo *di;
3732             for (di = info.doodads; di != NULL;
3733                  di = (DoodadInfo *) di->defs.next)
3734             {
3735                 if (!CopyDoodadDef(geom, NULL, di, &info))
3736                     return False;
3737             }
3738         }
3739         if (info.aliases)
3740             ApplyAliases(xkb, True, &info.aliases);
3741         ClearGeometryInfo(&info);
3742         return True;
3743     }
3744     return False;
3745 }