File Coverage

blib/lib/Config/Model/Backend/Xorg/Read.pm
Criterion Covered Total %
statement 193 203 95.0
branch 60 72 83.3
condition 8 9 88.8
subroutine 18 18 100.0
pod 0 13 0.0
total 279 315 88.5


line stmt bran cond sub pod time code
1             #
2             # This file is part of Config-Model-Xorg
3             #
4             # This software is Copyright (c) 2007-2016 by Dominique Dumont.
5             #
6             # This is free software, licensed under:
7             #
8             # The GNU Lesser General Public License, Version 2.1, February 1999
9             #
10             package Config::Model::Backend::Xorg::Read ;
11             $Config::Model::Backend::Xorg::Read::VERSION = '1.113';
12 1     1   592 use Mouse::Role;
  1         1  
  1         7  
13              
14 1     1   318 use Carp ;
  1         2  
  1         79  
15 1     1   8 use IO::File ;
  1         1  
  1         280  
16 1     1   6 use Log::Log4perl;
  1         1  
  1         8  
17 1     1   39 use Data::Dumper ;
  1         1  
  1         2749  
18              
19             my $logger = Log::Log4perl::get_logger('Backend::Xorg::Read');
20              
21             # return a data structure in the form :
22             # hash_ref->array_ref->hash_ref->array_ref
23             #
24             # { section_name => [
25             # # section_a
26             # { element_name => [ [ value_a ] , [ va, lue, _b ] },
27             # ...
28             # # section_b
29             # ...
30             # ],
31             # },
32             # ...
33             sub parse_raw_xorg {
34 10     10 0 19 my $xorg_lines = shift ;
35              
36 10         21 my %data ;
37              
38 10         34 while (@$xorg_lines) {
39 112         113 my $line_data = shift @$xorg_lines ;
40 112         137 my ($line_nb,$line) = @$line_data ;
41 112         307 my ($raw_key,$value) = split /\s+/,$line,2;
42 112         204 my $key = lc($raw_key) ;
43 112 50       213 if ($key eq 'section') {
44             # Section names are insensitive to '_' and ' '
45 112         371 $value =~ s/["_ ]+//g;
46 112         111 push @{$data{lc($value)}},
  112         375  
47             [ $line_nb, parse_raw_section($xorg_lines) ] ;
48             }
49             }
50              
51 10         34 return \%data ;
52             }
53              
54             sub parse_raw_section {
55 143     143 0 135 my $xorg_lines = shift ;
56              
57 143         123 my %data ;
58 143         435 $logger->debug( "parse_raw_section: called on xorg file $xorg_lines->[0][0]");
59              
60 143         886 while (@$xorg_lines) {
61 791         756 my $line_data = shift @$xorg_lines ;
62 791         941 my ($line_nb,$line) = @$line_data ;
63 791         2142 my ($raw_key,$value) = split /\s+/,$line,2;
64              
65 791         1005 my $key = lc($raw_key) ; # keys are case insensitive
66 791         769 $key =~ s/_+//g; # keys are insensitive to '_'
67              
68 791 100       1722 if ($key =~ /end(sub)?section/) {
    100          
69 143         607 return \%data ;
70             }
71             elsif ($key eq 'subsection') {
72 31         110 $value =~ s/["_ ]//g;
73 31         43 my $store = lc($value) ; # subsection name is case insensitive
74 31         113 $logger->debug("parse_raw_section: SubSection $value $line_nb");
75 31         153 push @{$data{$store}}, [ $line_nb, parse_raw_section($xorg_lines) ];
  31         93  
76             }
77             else {
78 617         761 my @store = ( $line_nb ) ;
79 617         1118 while (length($value)) {
80 1377 100       3458 if ($value =~ /^"([^"]+)"/) {
    50          
81 793         1199 push @store,$1 ;
82 793         3378 $value =~ s/^"[^"]+"\s*//g;
83             }
84             elsif ($value =~ /^([^"\s]+)/) {
85 584         865 push @store,$1 ;
86 584         2463 $value =~ s/^([^"\s]+)\s*//g;
87             }
88             else {
89 0         0 die "parse_raw_section: unexpected value $value";
90             }
91              
92             }
93 617         546 push @{$data{$key}}, \@store ;
  617         2317  
94             }
95             }
96             }
97              
98             # Need to update functions beloow
99             sub parse_all {
100 10     10 0 21 my $xorg_conf = shift;
101 10         13 my $root = shift ;
102 10         113 $logger->debug("parse_all: called on ".join(' ', keys %$xorg_conf));
103              
104             # parse section data according to model elements order
105 10         105 foreach my $section_name ($root->get_element_name) {
106 140         174513 my $lc_section_name = lc($section_name) ;
107              
108 140         338 my $section_data_ref = delete $xorg_conf->{$lc_section_name} ;
109 140 100       387 next unless defined $section_data_ref ;
110              
111 74         239 foreach my $section_data (@$section_data_ref) {
112 112         13013 $logger->debug( "parse_all: section '$section_name'");
113 112         906 parse_section($section_data,$root->fetch_element($section_name)) ;
114             }
115             }
116              
117 10 50       108 if (keys %$xorg_conf) {
118 0         0 die "can't handle section ", join(' ',keys %$xorg_conf),
119             ": Error in input file or Xorg model is incomplete";
120             }
121             }
122              
123             sub parse_option {
124 136     136 0 444 my ($obj, $trash, $line, @args) = @_ ;
125 136         238 my $opt = shift @args;
126 136         652 $logger->debug( "parse_option: called on option $opt $line");
127              
128 136 100 100     2646 if ($obj->config_class_name eq 'Xorg::ServerFlags') {
    100 100        
    100          
    100          
129 6         25 $logger->debug( "parse_option: obj ",$obj->name, " ($line) load option '$opt' ");
130 6         77 my $opt_obj = $obj->fetch_element($opt) ;
131 6 50       365 $opt_obj->store ( @args ? $args[0] : 1 ) ;
132             }
133             elsif ($opt =~ /Core(Keyboard|Pointer)/ ) {
134 14         59 my $id = $obj -> index_value ;
135 14         91 $logger->debug( "parse_option: ($line) Load top level $opt to '$id'");
136 14         161 $obj->load( qq(! $opt="$id") ) ;
137             }
138             elsif ( $obj->config_class_name eq 'Xorg::InputDevice'
139             and $opt eq 'AutoRepeat') {
140 2         9 $logger->debug( "parse_option: obj ",$obj->name, " ($line) load option '$opt' with '",
141             join('+',@args),"' ");
142 2         34 my @v = split / /,$args[0] ;
143 2         14 my $load = sprintf ( "Option AutoRepeat delay=%s rate=%s", @v);
144 2         8 $logger->debug( "parse_option: ",$obj->name," load '$load'");
145 2         21 $obj->load($load) ;
146             }
147             elsif ( $obj->config_class_name eq 'Xorg::InputDevice'
148             and $opt eq 'XkbOptions' ) {
149 2         10 $logger->debug( "parse_option: obj ",$obj->name, " ($line) load option '$opt' with '",
150             join('+',@args),"' ");
151 2         39 my @v = split /:/,$args[0] ;
152 2         16 my $load = sprintf ( "Option XkbOptions %s=%s", @v);
153 2         8 $logger->debug( "parse_option: ",$obj->name," load '$load'");
154 2         29 $obj->load($load) ;
155             }
156             else {
157             # dont' work for ServerFlags
158 112         339 my $opt_p_obj = $obj->fetch_element("Option") ;
159 112         4557 my $opt_obj;
160 112 50       414 if ($opt_p_obj->has_element($opt)) {
    0          
161 112         2806 $logger->debug( "parse_option: obj ",$obj->name, " ($line) load option '$opt' ");
162 112         1441 $opt_obj= $opt_p_obj->fetch_element($opt) ;
163 112 100       131479 $opt_obj->store ( @args ? $args[0] : 1 ) if defined $opt_obj ;
    50          
164             }
165             elsif ($opt_p_obj->instance->get_value_check('fetch_or_store')) {
166 0         0 Config::Model::Exception::UnknownElement
167             -> throw(
168             object => $opt_p_obj,
169             where => $opt_p_obj->location ,
170             element => $opt,
171             );
172             }
173             else {
174 0         0 $logger->warn( "parse_option: obj ",$obj->name, " ($line) option '$opt' is unknown");
175             }
176             }
177             }
178              
179             my %mode_flags = (
180             '+hsync' => "HSyncPolarity=positive",
181             '-hsync' => "HSyncPolarity=negative",
182             '+vsync' => "VSyncPolarity=positive",
183             '-vsync' => "VSyncPolarity=negative",
184             '+csync' => "CSyncPolarity=positive",
185             '-csync' => "CSyncPolarity=negative",
186             );
187              
188             sub parse_mode_line {
189 50     50 0 327 my ($obj, $trash, $line, $mode, @m) = @_ ;
190              
191             # force @v content to be numerical instead of strings
192 50         192 my @v = map { 0 + $_ } splice @m,0,9 ;
  450         991  
193              
194 50         1006 my $load = qq!Mode:"$mode" DotClock=$v[0] !;
195 50         361 $load .= "HTimings disp=$v[1] syncstart=$v[2] syncend=$v[3] total=$v[4] - ";
196 50         265 $load .= "VTimings disp=$v[5] syncstart=$v[6] syncend=$v[7] total=$v[8] - ";
197              
198 50 100       249 $load .= "Flags " . join (' ', map {$mode_flags{lc($_)} || "$_=1" } @m ) . ' - '
  18 100       201  
199             if @m ;
200              
201 50         349 $logger->debug( "parse_mode_line: ($line) load '$load'");
202 50         543 $obj->load($load) ;
203             }
204              
205             sub parse_modes_list {
206 28     28 0 158 my ($obj, $trash, $line_nb, @modes) = @_ ;
207              
208 28         179 my $load = 'Modes="'.join('","',@modes).'"';
209 28         148 $logger->debug( "parse_modes_list: ($line_nb)) load '$load'");
210 28         344 $obj->load($load) ;
211             }
212              
213             # called while parsing ServerLayout or Device
214             # key is always 'Screen'
215             sub parse_layout_screen {
216 20     20 0 81 my ($obj, $key, $line, $value, @args) = @_ ;
217              
218 20         33 my $load;
219              
220 20 100       122 if ($obj->config_class_name eq 'Xorg::Device') {
221 8         23 $load = "Screen=$value";
222             }
223             else {
224 12         36 my ($num, $screen_id);
225 12 100       99 if ($value =~ /^(\d+)$/) {
226 10         21 $num = $value ;
227 10         24 $screen_id = shift @args ;
228             }
229             else {
230 2         6 $num = 0;
231 2         6 $screen_id = $value ;
232             }
233              
234 12         56 $load = "Screen:$num screen_id=\"$screen_id\" ";
235              
236 12         62 $logger->debug( "parse_layout_screen: screen load '$load'");
237              
238 12 100       97 if (@args) {
239             # there's a position information
240 8         10 my ($relative_spec, $pos );
241              
242 8 100       71 if ( $args[0] =~ /^\d+$/ ) {
    100          
    50          
243 3         6 $pos = 'Absolute' ;
244 3         30 $relative_spec = sprintf("x=%s y=%s",@args) ;
245             }
246             elsif ($args[0] eq 'Absolute') {
247 3         36 $pos = shift @args ;
248 3         29 $relative_spec = sprintf("x=%s y=%s",@args) ;
249             }
250             elsif ($args[0] eq 'Relative') {
251 0         0 $pos = shift @args ;
252 0         0 $relative_spec = sprintf("screen_id=\"%s\" x=%s y=%s",@args) ;
253             }
254             else {
255 2         5 $pos = shift @args;
256 2         17 $relative_spec = sprintf("screen_id=\"%s\"",@args) ;
257             }
258 8         37 $load .= "position relative_screen_location=$pos $relative_spec ";
259             }
260 12         60 $logger->debug( "parse_layout_screen: Screen ($line) load '$load' ");
261             }
262              
263 20         169 $logger->debug( "parse_layout_screen:", $obj->config_class_name," load '$load'");
264 20         159 $obj->load($load) ;
265             }
266              
267             # called when parsing section ServerLayout
268             sub parse_input_device {
269 24     24 0 59 my ($obj, $trash, $line ,$id, @opt) = @_ ;
270              
271 24         167 $logger->debug( "$trash id:'$id' option '".join("' '",@opt)."'");
272              
273 24         234 my $dev = $obj->fetch_element('InputDevice') -> fetch_with_id($id) ;
274              
275 24         22119 foreach my $opt (@opt) {
276 3 50       36 if ($opt eq 'SendCoreEvents') {
    50          
277 0         0 $dev->fetch_element($opt)->store(1) ;
278             }
279             elsif ($opt =~ /Core(Keyboard|Pointer)/) {
280 3         19 $logger->debug( "parse_input_device: Load '! $opt=\"$id\"'");
281 3         35 $obj->load("! $opt=\"$id\"") ;
282             }
283             else {
284 0         0 die "parse_input_device ($line): Unexpected ServerLayout->InputDevice ",
285             "option: $opt. Error in input file or Xorg model is incomplete";
286             }
287             }
288             }
289              
290             sub parse_display_size {
291 4     4 0 14 my ($obj, $tag_name, $line ,$w, $h) = @_ ;
292 4         37 $logger->debug( "$tag_name width:'$w' height:$h");
293 4         47 my $load = "DisplaySize width=$w height=$h";
294 4         39 $logger->debug( $obj->config_class_name," load '$load'");
295 4         37 $obj->load($load) ;
296             }
297              
298             sub parse_view_port {
299 2     2 0 7 my ($obj, $tag_name, $line ,$x0, $y0) = @_ ;
300 2         12 $logger->debug( "$tag_name x0:'$x0' y0:$y0");
301 2         13 my $load = "ViewPort x0=$x0 y0=$y0";
302 2         14 $logger->debug( $obj->config_class_name," load '$load'");
303 2         14 $obj->load($load) ;
304             }
305              
306             sub parse_virtual {
307 4     4 0 17 my ($obj, $tag_name, $line ,$xdim, $ydim) = @_ ;
308 4         25 $logger->debug( "$tag_name xdim:'$xdim' ydim:$ydim");
309 4         27 my $load = "Virtual xdim=$xdim ydim=$ydim";
310 4         52 $logger->debug( $obj->config_class_name," load '$load'");
311 4         47 $obj->load($load) ;
312             }
313              
314             sub parse_gamma {
315 4     4 0 14 my ($obj, $tag_name, $line ,@g) = @_ ;
316 4         23 $logger->debug( "$tag_name @g");
317 4 100       30 my $global = @g == 1 ? 1 : 0 ;
318 4         14 my $load = "Gamma use_global_gamma=$global ";
319 4 100       36 $load .= $global ? "gamma=$g[0]"
320             : sprintf("red_gamma=%s green_gamma=%s blue_gamma=%s",@g) ;
321 4         25 $logger->debug( $obj->config_class_name," load '$load'");
322 4         30 $obj->load($load) ;
323             }
324              
325             my %parse_line = (
326             'fontpath' => sub { $_[0]->fetch_element($_[1])->push($_[3]) ;} ,
327             'load' => sub { $_[0]->fetch_element($_[3])->store(1) ;} ,
328             'modeline' => \&parse_mode_line,
329             'option' => \&parse_option ,
330             'modes' => \&parse_modes_list,
331             'screen' => \&parse_layout_screen,
332             'inputdevice' => \&parse_input_device,
333             'displaysize' => \&parse_display_size ,
334             'viewport' => \&parse_view_port ,
335             'virtual' => \&parse_virtual ,
336             'gamma' => \&parse_gamma ,
337             ) ;
338              
339             sub parse_section {
340 143     143 0 6095 my $section_line_data = shift ; # [ line_nb, hash ref ]
341 143         262 my $obj = shift ;
342              
343 143         314 my ($sect_line_nb, $section_data) = @$section_line_data ;
344              
345             # section like InputDevice have an identifier which must be extracted first
346 143         598 my $obj_type = $obj->get_type ;
347 143 100       1534 my $has_id = $obj_type =~ /list|hash/ ? 1 : 0 ;
348 143         215 my $tmp_obj = $obj ;
349              
350 143         741 $logger->debug( "parse_section ($sect_line_nb) called on ",
351             $obj->name," (has_id: $has_id)");
352              
353             # first get the identifier and create the object.
354 143 100       3241 if ($has_id) {
355             my $id_rr = delete $section_data->{identifier}
356 117   66     661 || delete $section_data->{depth} ;
357 117 100       378 if (not defined $id_rr) {
358 1         4 $logger->debug( "parse_section can't find identifier for ",$obj->name );
359 1         16 return ;
360             }
361              
362 116         207 my ($line,$id) = @{$id_rr->[0]} ;
  116         394  
363 116         554 $logger->debug( "parse_section $line: found id '$id' for '",
364             $obj->name,"'");
365 116         1630 $tmp_obj = $obj->fetch_with_id($id) ;
366             }
367              
368             # parse special cases and section data according to model elements order
369             # special case: modeline must be parsed first
370 142         94818 foreach my $elt_name ('modeline',$tmp_obj->get_element_name) {
371 1052         3169086 my $lc_name = lc($elt_name) ;
372 1052         1648 my $a2_r = delete $section_data->{$lc_name}; # array of array ref ;
373              
374 1052 100       2468 next unless defined $a2_r ;
375              
376 226         972 $logger->debug( "parse_section: parse section data key '$lc_name'");
377              
378 226         1583 foreach my $arg (@$a2_r) {
379 338 100       585998 if (defined $parse_line{$lc_name}) {
    100          
380 193         788 $parse_line{$lc_name} -> ($tmp_obj, $elt_name, @$arg) ;
381             }
382             elsif (ref $arg->[1] eq 'HASH') {
383             # we have a subsection
384 31         128 $logger->debug( $tmp_obj->name, " subsection $elt_name ");
385 31         411 parse_section($arg,$tmp_obj->fetch_element($elt_name)) ;
386             }
387             else {
388 114         251 my $line = shift @$arg ;
389 114         393 my $val = "@$arg" ;
390 114         335 $logger->debug( $tmp_obj->name,
391             " ($line) store $elt_name = '$val'");
392 114         1518 $tmp_obj->fetch_element($elt_name)->store($val);
393             }
394             }
395             }
396              
397 142 100       13222 if ( %$section_data ) {
398 45         213 foreach my $lc_name (keys %$section_data) {
399 45 50       202 if (defined $parse_line{$lc_name}) {
400 45         120 my $a2_r = delete $section_data->{$lc_name};
401 45         110 foreach my $arg (@$a2_r) {
402 193         139456 $parse_line{$lc_name} -> ($tmp_obj, $lc_name, @$arg) ;
403             }
404             }
405             else {
406 0           $logger->warn( "parse_section: unexpected '$lc_name' "
407             ."element for ", $tmp_obj->name) ;
408 0           die ;
409             }
410             }
411             }
412             }
413              
414             1;