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