192ddea16Smrg#!/usr/bin/env perl
2154daed1Smrg
3154daed1Smrg# converts the <rules>.xml file to the old format <rules>.lst file
4154daed1Smrg#
5154daed1Smrg# Usage:
6154daed1Smrg#
7bfd7cbc1Smrg# perl xml2lst.pl < filename.xml > filename.lst
8154daed1Smrg#
9154daed1Smrg# author Ivan Pascal
10154daed1Smrg
11154daed1Smrg$doc = new_document( 0, '');
12154daed1Smrgparse('', $doc);
13154daed1Smrg
14154daed1Smrg($reg)   = node_by_name($doc, '/xkbConfigRegistry');
15154daed1Smrg@models  = node_by_name($reg, 'modelList/model/configItem');
16154daed1Smrg@layouts = node_by_name($reg, 'layoutList/layout/configItem');
17154daed1Smrg@options = node_by_name($reg, 'optionList/group/configItem');
18154daed1Smrg
19154daed1Smrgprint "! model\n";
20154daed1Smrgfor $i (@models) {
21154daed1Smrg   ($name) = node_by_name($i, 'name');
22bfd7cbc1Smrg   ($descr) = node_by_name($i, 'description');
23154daed1Smrg    printf("  %-15s %s\n", text_child($name), text_child($descr));
24154daed1Smrg}
25154daed1Smrg
26154daed1Smrgprint "\n! layout\n";
27154daed1Smrgfor $i (@layouts) {
28154daed1Smrg   ($name) = node_by_name($i, 'name');
29bfd7cbc1Smrg   ($descr) = node_by_name($i, 'description');
30154daed1Smrg    printf("  %-15s %s\n", text_child($name), text_child($descr));
31154daed1Smrg}
32154daed1Smrg
33154daed1Smrgprint "\n! variant\n";
34154daed1Smrgfor $l (@layouts) {
35154daed1Smrg   ($lname) = node_by_name($l, 'name');
36154daed1Smrg    @variants = node_by_name($l, '../variantList/variant/configItem');
37154daed1Smrg    for $v (@variants) {
38154daed1Smrg      ($name) = node_by_name($v, 'name');
39bfd7cbc1Smrg      ($descr) = node_by_name($v, 'description');
40154daed1Smrg       printf("  %-15s %s: %s\n",
41154daed1Smrg               text_child($name), text_child($lname), text_child($descr));
42154daed1Smrg    }
43154daed1Smrg}
44154daed1Smrg
45154daed1Smrgprint "\n! option\n";
46154daed1Smrgfor $g (@options) {
47154daed1Smrg   ($name) = node_by_name($g, 'name');
48bfd7cbc1Smrg   ($descr) = node_by_name($g, 'description');
49154daed1Smrg    printf("  %-20s %s\n", text_child($name), text_child($descr));
50154daed1Smrg
51154daed1Smrg    @opts = node_by_name($g, '../option/configItem');
52154daed1Smrg    for $o (@opts) {
53154daed1Smrg      ($name) = node_by_name($o, 'name');
54bfd7cbc1Smrg      ($descr) = node_by_name($o, 'description');
55154daed1Smrg       printf("  %-20s %s\n",
56154daed1Smrg               text_child($name), text_child($descr));
57154daed1Smrg    }
58154daed1Smrg}
59154daed1Smrg
60154daed1Smrgsub with_attribute {
61154daed1Smrg    local ($nodelist, $attrexpr) = @_;
62154daed1Smrg    local ($attr, $value) = split (/=/, $attrexpr);
63154daed1Smrg    local ($node, $attrvalue);
64154daed1Smrg    if (defined $value && $value ne '') {
65154daed1Smrg        $value =~ s/"//g;
66154daed1Smrg        foreach $node (@{$nodelist}) {
67154daed1Smrg           $attrvalue = node_attribute($node, $attr);
68154daed1Smrg           if (defined $attrvalue && $attrvalue eq $value) {
69154daed1Smrg               return $node;
70154daed1Smrg           }
71154daed1Smrg        }
72154daed1Smrg    } else {
73154daed1Smrg        foreach $node (@{$nodelist}) {
74154daed1Smrg           if (! defined node_attribute($node, $attr)) {
75154daed1Smrg               return $node;
76154daed1Smrg           }
77154daed1Smrg        }
78154daed1Smrg    }
79154daed1Smrg    undef;
80154daed1Smrg}
81154daed1Smrg
82154daed1Smrg# Subroutines
83154daed1Smrg
84154daed1Smrgsub parse {
85154daed1Smrg   local $intag = 0;
86154daed1Smrg   my (@node_stack, $parent);
87154daed1Smrg   $parent = @_[1];
88154daed1Smrg   local ($tag, $text);
89154daed1Smrg
90154daed1Smrg   while (<>) {
91154daed1Smrg      chomp;
92154daed1Smrg      @str = split /([<>])/;
93154daed1Smrg      shift @str if ($str[0] eq '' || $str[0] =~ /^[ \t]*$/);
94154daed1Smrg
95154daed1Smrg      while (scalar @str) {
96154daed1Smrg         $token = shift @str;
97154daed1Smrg         if ($token eq '<') {
98154daed1Smrg            $intag = 1;
99154daed1Smrg            if (defined $text) {
100154daed1Smrg               add_text_node($parent, $text);
101154daed1Smrg               undef $text;
102154daed1Smrg            }
103154daed1Smrg         } elsif ($token eq '>') {
104154daed1Smrg            $intag = 0;
105154daed1Smrg            if ($tag =~ /^\/(.*)/) { # close tag
106154daed1Smrg               $parent = pop @node_stack;
107154daed1Smrg            } elsif ($tag =~ /^([^\/]*)\/$/) {
108154daed1Smrg               empty_tag($parent, $1);
109154daed1Smrg            } else {
110154daed1Smrg               if (defined ($node = open_tag($parent, $tag))) {
111154daed1Smrg                  push @node_stack, $parent;
112154daed1Smrg                  $parent = $node;
113154daed1Smrg               }
114154daed1Smrg            }
115154daed1Smrg            undef $tag;
116154daed1Smrg         } else {
117154daed1Smrg            if ($intag == 1) {
118154daed1Smrg               if (defined $tag) {
119154daed1Smrg                  $tag .= ' '. $token;
120154daed1Smrg               } else {
121154daed1Smrg                  $tag = $token;
122154daed1Smrg               }
123154daed1Smrg            } else {
124154daed1Smrg               if (defined $text) {
125154daed1Smrg                  $text .= "\n" . $token;
126154daed1Smrg               } else {
127154daed1Smrg                  $text = $token;
128154daed1Smrg               }
129154daed1Smrg            }
130154daed1Smrg         }
131154daed1Smrg      }
132154daed1Smrg   }
133154daed1Smrg}
134154daed1Smrg
135154daed1Smrgsub new_document {
136154daed1Smrg   $doc = new_node( 0, '', 'DOCUMENT');
137154daed1Smrg   $doc->{CHILDREN} = [];
138154daed1Smrg   return $doc;
139154daed1Smrg}
140154daed1Smrg
141154daed1Smrgsub new_node {
142154daed1Smrg  local ($parent_node, $tag, $type) = @_;
143154daed1Smrg
144154daed1Smrg  my %node;
145154daed1Smrg  $node{PARENT} = $parent_node;
146154daed1Smrg  $node{TYPE} = $type;
147154daed1Smrg
148154daed1Smrg  if ($type eq 'COMMENT' || $type eq 'TEXT') {
149154daed1Smrg     $node{TEXT} = $tag;
150154daed1Smrg     $node{NAME} = $type;
151154daed1Smrg     return \%node;
152154daed1Smrg  }
153154daed1Smrg
154154daed1Smrg  local ($tname, $attr) = split(' ', $tag, 2);
155154daed1Smrg  $node{NAME} = $tname;
156154daed1Smrg
157154daed1Smrg  if (defined $attr && $attr ne '') {
158154daed1Smrg     my %attr_table;
159154daed1Smrg     local @attr_list = split ( /"/, $attr);
160154daed1Smrg     local ($name, $value);
161154daed1Smrg     while (scalar @attr_list) {
162154daed1Smrg        $name = shift @attr_list;
163154daed1Smrg        $name =~ s/[ =]//g;
164154daed1Smrg        next if ($name eq '');
165154daed1Smrg        $value =  shift @attr_list;
166154daed1Smrg        $attr_table{$name} =$value;
167154daed1Smrg     }
168154daed1Smrg     $node{ATTRIBUTES} = \%attr_table;
169154daed1Smrg  }
170154daed1Smrg  return \%node;
171154daed1Smrg}
172154daed1Smrg
173154daed1Smrgsub add_node {
174154daed1Smrg  local ($parent_node, $node) = @_;
175154daed1Smrg  push @{$parent_node->{CHILDREN}}, $node;
176154daed1Smrg
177154daed1Smrg  local $tname = $node->{NAME};
178154daed1Smrg  if (defined $parent_node->{$tname}) {
179154daed1Smrg      push @{$parent_node->{$tname}}, $node
180154daed1Smrg  } else {
181154daed1Smrg      $parent_node->{$tname} = [ $node ];
182154daed1Smrg  }
183154daed1Smrg}
184154daed1Smrg
185154daed1Smrgsub empty_tag {
186154daed1Smrg   local ($parent_node, $tag) = @_;
187154daed1Smrg   local $node = new_node($parent_node, $tag, 'EMPTY');
188154daed1Smrg   add_node($parent_node, $node);
189154daed1Smrg}
190154daed1Smrg
191154daed1Smrgsub open_tag {
192154daed1Smrg   local ($parent_node, $tag) = @_;
193154daed1Smrg   local $node;
194154daed1Smrg
195154daed1Smrg   if ($tag =~ /^\?.*/ || $tag =~ /^\!.*/) {
196154daed1Smrg      $node = new_node($parent_node, $tag, 'COMMENT');
197154daed1Smrg      add_node($parent_node, $node);
198154daed1Smrg      undef; return;
199154daed1Smrg   } else {
200154daed1Smrg      $node = new_node($parent_node, $tag, 'NODE');
201154daed1Smrg      $node->{CHILDREN} = [];
202154daed1Smrg      add_node($parent_node, $node);
203154daed1Smrg      return $node;
204154daed1Smrg   }
205154daed1Smrg}
206154daed1Smrg
207154daed1Smrgsub add_text_node {
208154daed1Smrg   local ($parent_node, $text) = @_;
209154daed1Smrg   local $node = new_node($parent_node, $text, 'TEXT');
210154daed1Smrg   add_node($parent_node, $node);
211154daed1Smrg}
212154daed1Smrg
213154daed1Smrgsub node_by_name {
214154daed1Smrg   local ($node, $name) = @_;
215154daed1Smrg   local ($tagname, $path) = split(/\//, $name, 2);
216154daed1Smrg
217154daed1Smrg   my @nodelist;
218154daed1Smrg
219154daed1Smrg   if ($tagname eq '') {
220154daed1Smrg      while ($node->{PARENT} != 0) {
221154daed1Smrg         $node = $node->{PARENT};
222154daed1Smrg      }
223154daed1Smrg      sublist_by_name($node, $path, \@nodelist);
224154daed1Smrg   } else {
225154daed1Smrg      sublist_by_name($node, $name, \@nodelist);
226154daed1Smrg   }
227154daed1Smrg   return @nodelist;
228154daed1Smrg}
229154daed1Smrg
230154daed1Smrgsub sublist_by_name {
231154daed1Smrg   local ($node, $name, $res) = @_;
232154daed1Smrg   local ($tagname, $path) = split(/\//, $name, 2);
233154daed1Smrg
234154daed1Smrg   if (! defined $path) {
235154daed1Smrg       push @{$res}, (@{$node->{$tagname}});
236154daed1Smrg       return;
237154daed1Smrg   }
238154daed1Smrg
239154daed1Smrg   if ($tagname eq '..' && $node->{PARENT} != 0) {
240154daed1Smrg      $node = $node->{PARENT};
241154daed1Smrg      sublist_by_name($node, $path, $res);
242154daed1Smrg   } else {
243154daed1Smrg      local $n;
244154daed1Smrg      for $n (@{$node->{$tagname}}) {
245154daed1Smrg         sublist_by_name($n, $path, $res);
246154daed1Smrg      }
247154daed1Smrg   }
248154daed1Smrg}
249154daed1Smrg
250154daed1Smrgsub node_attribute {
251154daed1Smrg    local $node = @_[0];
252154daed1Smrg    if (defined $node->{ATTRIBUTES}) {
253154daed1Smrg       return $node->{ATTRIBUTES}{@_[1]};
254154daed1Smrg    }
255154daed1Smrg    undef;
256154daed1Smrg}
257154daed1Smrg
258154daed1Smrgsub text_child {
259154daed1Smrg    local ($node) = @_;
260154daed1Smrg    local ($child) = node_by_name($node, 'TEXT');
261154daed1Smrg    return $child->{TEXT};
262154daed1Smrg}
263