1 #!/usr/bin/env perl !! 1 #!/usr/bin/perl 2 # SPDX-License-Identifier: GPL-2.0 2 # SPDX-License-Identifier: GPL-2.0 3 3 4 use strict; 4 use strict; 5 use Pod::Usage; 5 use Pod::Usage; 6 use Getopt::Long; 6 use Getopt::Long; 7 use File::Find; 7 use File::Find; 8 use Fcntl ':mode'; 8 use Fcntl ':mode'; 9 use Cwd 'abs_path'; 9 use Cwd 'abs_path'; 10 10 11 my $help; 11 my $help; 12 my $man; 12 my $man; 13 my $debug; 13 my $debug; 14 my $arch; 14 my $arch; 15 my $feat; 15 my $feat; 16 my $enable_fname; << 17 16 18 my $basename = abs_path($0); 17 my $basename = abs_path($0); 19 $basename =~ s,/[^/]+$,/,; 18 $basename =~ s,/[^/]+$,/,; 20 19 21 my $prefix=$basename . "../Documentation/featu 20 my $prefix=$basename . "../Documentation/features"; 22 21 23 # Used only at for full features output. The s 22 # Used only at for full features output. The script will auto-adjust 24 # such values for the minimal possible values 23 # such values for the minimal possible values 25 my $status_size = 1; 24 my $status_size = 1; 26 my $description_size = 1; 25 my $description_size = 1; 27 26 28 GetOptions( 27 GetOptions( 29 "debug|d+" => \$debug, 28 "debug|d+" => \$debug, 30 "dir=s" => \$prefix, 29 "dir=s" => \$prefix, 31 'help|?' => \$help, 30 'help|?' => \$help, 32 'arch=s' => \$arch, 31 'arch=s' => \$arch, 33 'feat=s' => \$feat, 32 'feat=s' => \$feat, 34 'feature=s' => \$feat, 33 'feature=s' => \$feat, 35 "enable-fname" => \$enable_fname, << 36 man => \$man 34 man => \$man 37 ) or pod2usage(2); 35 ) or pod2usage(2); 38 36 39 pod2usage(1) if $help; 37 pod2usage(1) if $help; 40 pod2usage(-exitstatus => 0, -verbose => 2) if 38 pod2usage(-exitstatus => 0, -verbose => 2) if $man; 41 39 42 pod2usage(1) if (scalar @ARGV < 1 || @ARGV > 2) 40 pod2usage(1) if (scalar @ARGV < 1 || @ARGV > 2); 43 41 44 my ($cmd, $arg) = @ARGV; 42 my ($cmd, $arg) = @ARGV; 45 43 46 pod2usage(2) if ($cmd ne "current" && $cmd ne 44 pod2usage(2) if ($cmd ne "current" && $cmd ne "rest" && $cmd ne "validate" 47 && $cmd ne "ls" && $cmd ne "li 45 && $cmd ne "ls" && $cmd ne "list"); 48 46 49 require Data::Dumper if ($debug); 47 require Data::Dumper if ($debug); 50 48 51 my %data; 49 my %data; 52 my %archs; 50 my %archs; 53 51 54 # 52 # 55 # Displays an error message, printing file nam 53 # Displays an error message, printing file name and line 56 # 54 # 57 sub parse_error($$$$) { 55 sub parse_error($$$$) { 58 my ($file, $ln, $msg, $data) = @_; 56 my ($file, $ln, $msg, $data) = @_; 59 57 60 $data =~ s/\s+$/\n/; 58 $data =~ s/\s+$/\n/; 61 59 62 print STDERR "Warning: file $file#$ln: 60 print STDERR "Warning: file $file#$ln:\n\t$msg"; 63 61 64 if ($data ne "") { 62 if ($data ne "") { 65 print STDERR ". Line\n\t\t$dat 63 print STDERR ". Line\n\t\t$data"; 66 } else { 64 } else { 67 print STDERR "\n"; 65 print STDERR "\n"; 68 } 66 } 69 } 67 } 70 68 71 # 69 # 72 # Parse a features file, storing its contents 70 # Parse a features file, storing its contents at %data 73 # 71 # 74 72 75 my $h_name = "Feature"; 73 my $h_name = "Feature"; 76 my $h_kconfig = "Kconfig"; 74 my $h_kconfig = "Kconfig"; 77 my $h_description = "Description"; 75 my $h_description = "Description"; 78 my $h_subsys = "Subsystem"; 76 my $h_subsys = "Subsystem"; 79 my $h_status = "Status"; 77 my $h_status = "Status"; 80 my $h_arch = "Architecture"; 78 my $h_arch = "Architecture"; 81 79 82 my $max_size_name = length($h_name); 80 my $max_size_name = length($h_name); 83 my $max_size_kconfig = length($h_kconfig); 81 my $max_size_kconfig = length($h_kconfig); 84 my $max_size_description = length($h_descripti 82 my $max_size_description = length($h_description); 85 my $max_size_subsys = length($h_subsys); 83 my $max_size_subsys = length($h_subsys); 86 my $max_size_status = length($h_status); 84 my $max_size_status = length($h_status); 87 85 88 my $max_size_arch = 0; 86 my $max_size_arch = 0; 89 my $max_size_arch_with_header; 87 my $max_size_arch_with_header; 90 my $max_description_word = 0; 88 my $max_description_word = 0; 91 89 92 sub parse_feat { 90 sub parse_feat { 93 my $file = $File::Find::name; 91 my $file = $File::Find::name; 94 92 95 my $mode = (stat($file))[2]; 93 my $mode = (stat($file))[2]; 96 return if ($mode & S_IFDIR); 94 return if ($mode & S_IFDIR); 97 return if ($file =~ m,($prefix)/arch-s 95 return if ($file =~ m,($prefix)/arch-support.txt,); 98 return if (!($file =~ m,arch-support.t 96 return if (!($file =~ m,arch-support.txt$,)); 99 97 100 if ($enable_fname) { << 101 printf ".. FILE %s\n", abs_pat << 102 } << 103 << 104 my $subsys = ""; 98 my $subsys = ""; 105 $subsys = $2 if ( m,.*($prefix)/([^/]+ 99 $subsys = $2 if ( m,.*($prefix)/([^/]+).*,); 106 100 107 if (length($subsys) > $max_size_subsys 101 if (length($subsys) > $max_size_subsys) { 108 $max_size_subsys = length($sub 102 $max_size_subsys = length($subsys); 109 } 103 } 110 104 111 my $name; 105 my $name; 112 my $kconfig; 106 my $kconfig; 113 my $description; 107 my $description; 114 my $comments = ""; 108 my $comments = ""; 115 my $last_status; 109 my $last_status; 116 my $ln; 110 my $ln; 117 my %arch_table; 111 my %arch_table; 118 112 119 print STDERR "Opening $file\n" if ($de 113 print STDERR "Opening $file\n" if ($debug > 1); 120 open IN, $file; 114 open IN, $file; 121 115 122 while(<IN>) { 116 while(<IN>) { 123 $ln++; 117 $ln++; 124 118 125 if (m/^\#\s+Feature\s+name:\s* 119 if (m/^\#\s+Feature\s+name:\s*(.*\S)/) { 126 $name = $1; 120 $name = $1; 127 if (length($name) > $m 121 if (length($name) > $max_size_name) { 128 $max_size_name 122 $max_size_name = length($name); 129 } 123 } 130 next; 124 next; 131 } 125 } 132 if (m/^\#\s+Kconfig:\s*(.*\S)/ 126 if (m/^\#\s+Kconfig:\s*(.*\S)/) { 133 $kconfig = $1; 127 $kconfig = $1; 134 if (length($kconfig) > 128 if (length($kconfig) > $max_size_kconfig) { 135 $max_size_kcon 129 $max_size_kconfig = length($kconfig); 136 } 130 } 137 next; 131 next; 138 } 132 } 139 if (m/^\#\s+description:\s*(.* 133 if (m/^\#\s+description:\s*(.*\S)/) { 140 $description = $1; 134 $description = $1; 141 if (length($descriptio 135 if (length($description) > $max_size_description) { 142 $max_size_desc 136 $max_size_description = length($description); 143 } 137 } 144 138 145 foreach my $word (spli 139 foreach my $word (split /\s+/, $description) { 146 if (length($wo 140 if (length($word) > $max_description_word) { 147 $max_d 141 $max_description_word = length($word); 148 } 142 } 149 } 143 } 150 144 151 next; 145 next; 152 } 146 } 153 next if (m/^\\s*$/); 147 next if (m/^\\s*$/); 154 next if (m/^\s*\-+\s*$/); 148 next if (m/^\s*\-+\s*$/); 155 next if (m/^\s*\|\s*arch\s*\|\ 149 next if (m/^\s*\|\s*arch\s*\|\s*status\s*\|\s*$/); 156 150 157 if (m/^\#\s*(.*)/) { 151 if (m/^\#\s*(.*)/) { 158 $comments .= "$1\n"; 152 $comments .= "$1\n"; 159 next; 153 next; 160 } 154 } 161 if (m/^\s*\|\s*(\S+):\s*\|\s*( 155 if (m/^\s*\|\s*(\S+):\s*\|\s*(\S+)\s*\|\s*$/) { 162 my $a = $1; 156 my $a = $1; 163 my $status = $2; 157 my $status = $2; 164 158 165 if (length($status) > 159 if (length($status) > $max_size_status) { 166 $max_size_stat 160 $max_size_status = length($status); 167 } 161 } 168 if (length($a) > $max_ 162 if (length($a) > $max_size_arch) { 169 $max_size_arch 163 $max_size_arch = length($a); 170 } 164 } 171 165 172 $status = "---" if ($s 166 $status = "---" if ($status =~ m/^\.\.$/); 173 167 174 $archs{$a} = 1; 168 $archs{$a} = 1; 175 $arch_table{$a} = $sta 169 $arch_table{$a} = $status; 176 next; 170 next; 177 } 171 } 178 172 179 #Everything else is an error 173 #Everything else is an error 180 parse_error($file, $ln, "line 174 parse_error($file, $ln, "line is invalid", $_); 181 } 175 } 182 close IN; 176 close IN; 183 177 184 if (!$name) { 178 if (!$name) { 185 parse_error($file, $ln, "Featu 179 parse_error($file, $ln, "Feature name not found", ""); 186 return; 180 return; 187 } 181 } 188 182 189 parse_error($file, $ln, "Subsystem not 183 parse_error($file, $ln, "Subsystem not found", "") if (!$subsys); 190 parse_error($file, $ln, "Kconfig not f 184 parse_error($file, $ln, "Kconfig not found", "") if (!$kconfig); 191 parse_error($file, $ln, "Description n 185 parse_error($file, $ln, "Description not found", "") if (!$description); 192 186 193 if (!%arch_table) { 187 if (!%arch_table) { 194 parse_error($file, $ln, "Archi 188 parse_error($file, $ln, "Architecture table not found", ""); 195 return; 189 return; 196 } 190 } 197 191 198 $data{$name}->{where} = $file; 192 $data{$name}->{where} = $file; 199 $data{$name}->{subsys} = $subsys; 193 $data{$name}->{subsys} = $subsys; 200 $data{$name}->{kconfig} = $kconfig; 194 $data{$name}->{kconfig} = $kconfig; 201 $data{$name}->{description} = $descrip 195 $data{$name}->{description} = $description; 202 $data{$name}->{comments} = $comments; 196 $data{$name}->{comments} = $comments; 203 $data{$name}->{table} = \%arch_table; 197 $data{$name}->{table} = \%arch_table; 204 198 205 $max_size_arch_with_header = $max_size 199 $max_size_arch_with_header = $max_size_arch + length($h_arch); 206 } 200 } 207 201 208 # 202 # 209 # Output feature(s) for a given architecture 203 # Output feature(s) for a given architecture 210 # 204 # 211 sub output_arch_table { 205 sub output_arch_table { 212 my $title = "Feature status on $arch a 206 my $title = "Feature status on $arch architecture"; 213 207 214 print "=" x length($title) . "\n"; 208 print "=" x length($title) . "\n"; 215 print "$title\n"; 209 print "$title\n"; 216 print "=" x length($title) . "\n\n"; 210 print "=" x length($title) . "\n\n"; 217 211 218 print "=" x $max_size_subsys; 212 print "=" x $max_size_subsys; 219 print " "; 213 print " "; 220 print "=" x $max_size_name; 214 print "=" x $max_size_name; 221 print " "; 215 print " "; 222 print "=" x $max_size_kconfig; 216 print "=" x $max_size_kconfig; 223 print " "; 217 print " "; 224 print "=" x $max_size_status; 218 print "=" x $max_size_status; 225 print " "; 219 print " "; 226 print "=" x $max_size_description; 220 print "=" x $max_size_description; 227 print "\n"; 221 print "\n"; 228 printf "%-${max_size_subsys}s ", $h_s 222 printf "%-${max_size_subsys}s ", $h_subsys; 229 printf "%-${max_size_name}s ", $h_nam 223 printf "%-${max_size_name}s ", $h_name; 230 printf "%-${max_size_kconfig}s ", $h_ 224 printf "%-${max_size_kconfig}s ", $h_kconfig; 231 printf "%-${max_size_status}s ", $h_s 225 printf "%-${max_size_status}s ", $h_status; 232 printf "%-${max_size_description}s\n", 226 printf "%-${max_size_description}s\n", $h_description; 233 print "=" x $max_size_subsys; 227 print "=" x $max_size_subsys; 234 print " "; 228 print " "; 235 print "=" x $max_size_name; 229 print "=" x $max_size_name; 236 print " "; 230 print " "; 237 print "=" x $max_size_kconfig; 231 print "=" x $max_size_kconfig; 238 print " "; 232 print " "; 239 print "=" x $max_size_status; 233 print "=" x $max_size_status; 240 print " "; 234 print " "; 241 print "=" x $max_size_description; 235 print "=" x $max_size_description; 242 print "\n"; 236 print "\n"; 243 237 244 foreach my $name (sort { 238 foreach my $name (sort { 245 ($data{$a}->{s 239 ($data{$a}->{subsys} cmp $data{$b}->{subsys}) || 246 ("\L$a" cmp "\ 240 ("\L$a" cmp "\L$b") 247 } keys %data) { 241 } keys %data) { 248 next if ($feat && $name ne $fe 242 next if ($feat && $name ne $feat); 249 243 250 my %arch_table = %{$data{$name 244 my %arch_table = %{$data{$name}->{table}}; 251 printf "%-${max_size_subsys}s 245 printf "%-${max_size_subsys}s ", $data{$name}->{subsys}; 252 printf "%-${max_size_name}s " 246 printf "%-${max_size_name}s ", $name; 253 printf "%-${max_size_kconfig}s 247 printf "%-${max_size_kconfig}s ", $data{$name}->{kconfig}; 254 printf "%-${max_size_status}s 248 printf "%-${max_size_status}s ", $arch_table{$arch}; 255 printf "%-s\n", $data{$name}-> 249 printf "%-s\n", $data{$name}->{description}; 256 } 250 } 257 251 258 print "=" x $max_size_subsys; 252 print "=" x $max_size_subsys; 259 print " "; 253 print " "; 260 print "=" x $max_size_name; 254 print "=" x $max_size_name; 261 print " "; 255 print " "; 262 print "=" x $max_size_kconfig; 256 print "=" x $max_size_kconfig; 263 print " "; 257 print " "; 264 print "=" x $max_size_status; 258 print "=" x $max_size_status; 265 print " "; 259 print " "; 266 print "=" x $max_size_description; 260 print "=" x $max_size_description; 267 print "\n"; 261 print "\n"; 268 } 262 } 269 263 270 # 264 # 271 # list feature(s) for a given architecture 265 # list feature(s) for a given architecture 272 # 266 # 273 sub list_arch_features { 267 sub list_arch_features { 274 print "#\n# Kernel feature support mat 268 print "#\n# Kernel feature support matrix of the '$arch' architecture:\n#\n"; 275 269 276 foreach my $name (sort { 270 foreach my $name (sort { 277 ($data{$a}->{s 271 ($data{$a}->{subsys} cmp $data{$b}->{subsys}) || 278 ("\L$a" cmp "\ 272 ("\L$a" cmp "\L$b") 279 } keys %data) { 273 } keys %data) { 280 next if ($feat && $name ne $fe 274 next if ($feat && $name ne $feat); 281 275 282 my %arch_table = %{$data{$name 276 my %arch_table = %{$data{$name}->{table}}; 283 277 284 my $status = $arch_table{$arch 278 my $status = $arch_table{$arch}; 285 $status = " " x ((4 - length($ 279 $status = " " x ((4 - length($status)) / 2) . $status; 286 280 287 printf " %${max_size_subsys}s/ 281 printf " %${max_size_subsys}s/ ", $data{$name}->{subsys}; 288 printf "%-${max_size_name}s: " 282 printf "%-${max_size_name}s: ", $name; 289 printf "%-5s| ", $status; 283 printf "%-5s| ", $status; 290 printf "%${max_size_kconfig}s 284 printf "%${max_size_kconfig}s # ", $data{$name}->{kconfig}; 291 printf " %s\n", $data{$name}-> 285 printf " %s\n", $data{$name}->{description}; 292 } 286 } 293 } 287 } 294 288 295 # 289 # 296 # Output a feature on all architectures 290 # Output a feature on all architectures 297 # 291 # 298 sub output_feature { 292 sub output_feature { 299 my $title = "Feature $feat"; 293 my $title = "Feature $feat"; 300 294 301 print "=" x length($title) . "\n"; 295 print "=" x length($title) . "\n"; 302 print "$title\n"; 296 print "$title\n"; 303 print "=" x length($title) . "\n\n"; 297 print "=" x length($title) . "\n\n"; 304 298 305 print ":Subsystem: $data{$feat}->{subs 299 print ":Subsystem: $data{$feat}->{subsys} \n" if ($data{$feat}->{subsys}); 306 print ":Kconfig: $data{$feat}->{kconfi 300 print ":Kconfig: $data{$feat}->{kconfig} \n" if ($data{$feat}->{kconfig}); 307 301 308 my $desc = $data{$feat}->{description} 302 my $desc = $data{$feat}->{description}; 309 $desc =~ s/^([a-z])/\U$1/; 303 $desc =~ s/^([a-z])/\U$1/; 310 $desc =~ s/\.?\s*//; 304 $desc =~ s/\.?\s*//; 311 print "\n$desc.\n\n"; 305 print "\n$desc.\n\n"; 312 306 313 my $com = $data{$feat}->{comments}; 307 my $com = $data{$feat}->{comments}; 314 $com =~ s/^\s+//; 308 $com =~ s/^\s+//; 315 $com =~ s/\s+$//; 309 $com =~ s/\s+$//; 316 if ($com) { 310 if ($com) { 317 print "Comments\n"; 311 print "Comments\n"; 318 print "--------\n\n"; 312 print "--------\n\n"; 319 print "$com\n\n"; 313 print "$com\n\n"; 320 } 314 } 321 315 322 print "=" x $max_size_arch_with_header 316 print "=" x $max_size_arch_with_header; 323 print " "; 317 print " "; 324 print "=" x $max_size_status; 318 print "=" x $max_size_status; 325 print "\n"; 319 print "\n"; 326 320 327 printf "%-${max_size_arch}s ", $h_arc 321 printf "%-${max_size_arch}s ", $h_arch; 328 printf "%-${max_size_status}s", $h_sta 322 printf "%-${max_size_status}s", $h_status . "\n"; 329 323 330 print "=" x $max_size_arch_with_header 324 print "=" x $max_size_arch_with_header; 331 print " "; 325 print " "; 332 print "=" x $max_size_status; 326 print "=" x $max_size_status; 333 print "\n"; 327 print "\n"; 334 328 335 my %arch_table = %{$data{$feat}->{tabl 329 my %arch_table = %{$data{$feat}->{table}}; 336 foreach my $arch (sort keys %arch_tabl 330 foreach my $arch (sort keys %arch_table) { 337 printf "%-${max_size_arch}s " 331 printf "%-${max_size_arch}s ", $arch; 338 printf "%-${max_size_status}s\ 332 printf "%-${max_size_status}s\n", $arch_table{$arch}; 339 } 333 } 340 334 341 print "=" x $max_size_arch_with_header 335 print "=" x $max_size_arch_with_header; 342 print " "; 336 print " "; 343 print "=" x $max_size_status; 337 print "=" x $max_size_status; 344 print "\n"; 338 print "\n"; 345 } 339 } 346 340 347 # 341 # 348 # Output all features for all architectures 342 # Output all features for all architectures 349 # 343 # 350 344 351 sub matrix_lines($$$) { 345 sub matrix_lines($$$) { 352 my $desc_size = shift; 346 my $desc_size = shift; 353 my $status_size = shift; 347 my $status_size = shift; 354 my $header = shift; 348 my $header = shift; 355 my $fill; 349 my $fill; 356 my $ln_marker; 350 my $ln_marker; 357 351 358 if ($header) { 352 if ($header) { 359 $ln_marker = "="; 353 $ln_marker = "="; 360 } else { 354 } else { 361 $ln_marker = "-"; 355 $ln_marker = "-"; 362 } 356 } 363 357 364 $fill = $ln_marker; 358 $fill = $ln_marker; 365 359 366 print "+"; 360 print "+"; 367 print $fill x $max_size_name; 361 print $fill x $max_size_name; 368 print "+"; 362 print "+"; 369 print $fill x $desc_size; 363 print $fill x $desc_size; 370 print "+"; 364 print "+"; 371 print $ln_marker x $status_size; 365 print $ln_marker x $status_size; 372 print "+\n"; 366 print "+\n"; 373 } 367 } 374 368 375 sub output_matrix { 369 sub output_matrix { 376 my $title = "Feature status on all arc 370 my $title = "Feature status on all architectures"; 377 my $notcompat = "Not compatible"; 371 my $notcompat = "Not compatible"; 378 372 379 print "=" x length($title) . "\n"; 373 print "=" x length($title) . "\n"; 380 print "$title\n"; 374 print "$title\n"; 381 print "=" x length($title) . "\n\n"; 375 print "=" x length($title) . "\n\n"; 382 376 383 my $desc_title = "$h_kconfig / $h_desc 377 my $desc_title = "$h_kconfig / $h_description"; 384 378 385 my $desc_size = $max_size_kconfig + 4; 379 my $desc_size = $max_size_kconfig + 4; 386 if (!$description_size) { 380 if (!$description_size) { 387 $desc_size = $max_size_descrip 381 $desc_size = $max_size_description if ($max_size_description > $desc_size); 388 } else { 382 } else { 389 $desc_size = $description_size 383 $desc_size = $description_size if ($description_size > $desc_size); 390 } 384 } 391 $desc_size = $max_description_word if 385 $desc_size = $max_description_word if ($max_description_word > $desc_size); 392 386 393 $desc_size = length($desc_title) if (l 387 $desc_size = length($desc_title) if (length($desc_title) > $desc_size); 394 388 395 $max_size_status = length($notcompat) 389 $max_size_status = length($notcompat) if (length($notcompat) > $max_size_status); 396 390 397 # Ensure that the status will fit 391 # Ensure that the status will fit 398 my $min_status_size = $max_size_status 392 my $min_status_size = $max_size_status + $max_size_arch + 6; 399 $status_size = $min_status_size if ($s 393 $status_size = $min_status_size if ($status_size < $min_status_size); 400 394 401 395 402 my $cur_subsys = ""; 396 my $cur_subsys = ""; 403 foreach my $name (sort { 397 foreach my $name (sort { 404 ($data{$a}->{s 398 ($data{$a}->{subsys} cmp $data{$b}->{subsys}) or 405 ("\L$a" cmp "\ 399 ("\L$a" cmp "\L$b") 406 } keys %data) { 400 } keys %data) { 407 401 408 if ($cur_subsys ne $data{$name 402 if ($cur_subsys ne $data{$name}->{subsys}) { 409 if ($cur_subsys ne "") 403 if ($cur_subsys ne "") { 410 printf "\n"; 404 printf "\n"; 411 } 405 } 412 406 413 $cur_subsys = $data{$n 407 $cur_subsys = $data{$name}->{subsys}; 414 408 415 my $title = "Subsystem 409 my $title = "Subsystem: $cur_subsys"; 416 print "$title\n"; 410 print "$title\n"; 417 print "=" x length($ti 411 print "=" x length($title) . "\n\n"; 418 412 419 413 420 matrix_lines($desc_siz 414 matrix_lines($desc_size, $status_size, 0); 421 415 422 printf "|%-${max_size_ 416 printf "|%-${max_size_name}s", $h_name; 423 printf "|%-${desc_size 417 printf "|%-${desc_size}s", $desc_title; 424 418 425 printf "|%-${status_si 419 printf "|%-${status_size}s|\n", "Status per architecture"; 426 matrix_lines($desc_siz 420 matrix_lines($desc_size, $status_size, 1); 427 } 421 } 428 422 429 my %arch_table = %{$data{$name 423 my %arch_table = %{$data{$name}->{table}}; 430 my $cur_status = ""; 424 my $cur_status = ""; 431 425 432 my (@lines, @descs); 426 my (@lines, @descs); 433 my $line = ""; 427 my $line = ""; 434 foreach my $arch (sort { 428 foreach my $arch (sort { 435 ($arch 429 ($arch_table{$b} cmp $arch_table{$a}) or 436 ("\L$a 430 ("\L$a" cmp "\L$b") 437 } keys 431 } keys %arch_table) { 438 432 439 my $status = $arch_tab 433 my $status = $arch_table{$arch}; 440 434 441 if ($status eq "---") 435 if ($status eq "---") { 442 $status = $not 436 $status = $notcompat; 443 } 437 } 444 438 445 if ($status ne $cur_st 439 if ($status ne $cur_status) { 446 if ($line ne " 440 if ($line ne "") { 447 push @ 441 push @lines, $line; 448 $line 442 $line = ""; 449 } 443 } 450 $line = "- **" 444 $line = "- **" . $status . "**: " . $arch; 451 } elsif (length($line) 445 } elsif (length($line) + length ($arch) + 2 < $status_size) { 452 $line .= ", " 446 $line .= ", " . $arch; 453 } else { 447 } else { 454 push @lines, $ 448 push @lines, $line; 455 $line = " " . 449 $line = " " . $arch; 456 } 450 } 457 $cur_status = $status; 451 $cur_status = $status; 458 } 452 } 459 push @lines, $line if ($line n 453 push @lines, $line if ($line ne ""); 460 454 461 my $description = $data{$name} 455 my $description = $data{$name}->{description}; 462 while (length($description) > 456 while (length($description) > $desc_size) { 463 my $d = substr $descri 457 my $d = substr $description, 0, $desc_size; 464 458 465 # Ensure that it will 459 # Ensure that it will end on a space 466 # if it can't, it mean 460 # if it can't, it means that the size is too small 467 # Instead of aborting 461 # Instead of aborting it, let's print what we have 468 if (!($d =~ s/^(.*)\s+ 462 if (!($d =~ s/^(.*)\s+.*/$1/)) { 469 $d = substr $d 463 $d = substr $d, 0, -1; 470 push @descs, " 464 push @descs, "$d\\"; 471 $description = 465 $description =~ s/^\Q$d\E//; 472 } else { 466 } else { 473 push @descs, $ 467 push @descs, $d; 474 $description = 468 $description =~ s/^\Q$d\E\s+//; 475 } 469 } 476 } 470 } 477 push @descs, $description; 471 push @descs, $description; 478 472 479 # Ensure that the full descrip 473 # Ensure that the full description will be printed 480 push @lines, "" while (scalar( 474 push @lines, "" while (scalar(@lines) < 2 + scalar(@descs)); 481 475 482 my $ln = 0; 476 my $ln = 0; 483 for my $line(@lines) { 477 for my $line(@lines) { 484 if (!$ln) { 478 if (!$ln) { 485 printf "|%-${m 479 printf "|%-${max_size_name}s", $name; 486 printf "|%-${d 480 printf "|%-${desc_size}s", "``" . $data{$name}->{kconfig} . "``"; 487 } elsif ($ln >= 2 && s 481 } elsif ($ln >= 2 && scalar(@descs)) { 488 printf "|%-${m 482 printf "|%-${max_size_name}s", ""; 489 printf "|%-${d 483 printf "|%-${desc_size}s", shift @descs; 490 } else { 484 } else { 491 printf "|%-${m 485 printf "|%-${max_size_name}s", ""; 492 printf "|%-${d 486 printf "|%-${desc_size}s", ""; 493 } 487 } 494 488 495 printf "|%-${status_si 489 printf "|%-${status_size}s|\n", $line; 496 490 497 $ln++; 491 $ln++; 498 } 492 } 499 matrix_lines($desc_size, $stat 493 matrix_lines($desc_size, $status_size, 0); 500 } 494 } 501 } 495 } 502 496 503 497 504 # 498 # 505 # Parses all feature files located at $prefix 499 # Parses all feature files located at $prefix dir 506 # 500 # 507 find({wanted =>\&parse_feat, no_chdir => 1}, $ 501 find({wanted =>\&parse_feat, no_chdir => 1}, $prefix); 508 502 509 print STDERR Data::Dumper->Dump([\%data], [qw( 503 print STDERR Data::Dumper->Dump([\%data], [qw(*data)]) if ($debug); 510 504 511 # 505 # 512 # Handles the command 506 # Handles the command 513 # 507 # 514 if ($cmd eq "current") { 508 if ($cmd eq "current") { 515 $arch = qx(uname -m | sed 's/x86_64/x8 509 $arch = qx(uname -m | sed 's/x86_64/x86/' | sed 's/i386/x86/'); 516 $arch =~s/\s+$//; 510 $arch =~s/\s+$//; 517 } 511 } 518 512 519 if ($cmd eq "ls" or $cmd eq "list") { 513 if ($cmd eq "ls" or $cmd eq "list") { 520 if (!$arch) { 514 if (!$arch) { 521 $arch = qx(uname -m | sed 's/x 515 $arch = qx(uname -m | sed 's/x86_64/x86/' | sed 's/i386/x86/'); 522 $arch =~s/\s+$//; 516 $arch =~s/\s+$//; 523 } 517 } 524 518 525 list_arch_features; 519 list_arch_features; 526 520 527 exit; 521 exit; 528 } 522 } 529 523 530 if ($cmd ne "validate") { 524 if ($cmd ne "validate") { 531 if ($arch) { 525 if ($arch) { 532 output_arch_table; 526 output_arch_table; 533 } elsif ($feat) { 527 } elsif ($feat) { 534 output_feature; 528 output_feature; 535 } else { 529 } else { 536 output_matrix; 530 output_matrix; 537 } 531 } 538 } 532 } 539 533 540 __END__ 534 __END__ 541 535 542 =head1 NAME 536 =head1 NAME 543 537 544 get_feat.pl - parse the Linux Feature files an 538 get_feat.pl - parse the Linux Feature files and produce a ReST book. 545 539 546 =head1 SYNOPSIS 540 =head1 SYNOPSIS 547 541 548 B<get_feat.pl> [--debug] [--man] [--help] [--d 542 B<get_feat.pl> [--debug] [--man] [--help] [--dir=<dir>] [--arch=<arch>] 549 [--feature=<feature>|--feat=<fe 543 [--feature=<feature>|--feat=<feature>] <COMAND> [<ARGUMENT>] 550 544 551 Where <COMMAND> can be: 545 Where <COMMAND> can be: 552 546 553 =over 8 547 =over 8 554 548 555 B<current> - output table in ReS 549 B<current> - output table in ReST compatible ASCII format 556 with features for t 550 with features for this machine's architecture 557 551 558 B<rest> - output table(s) in 552 B<rest> - output table(s) in ReST compatible ASCII format 559 with features in Re 553 with features in ReST markup language. The output 560 is affected by --ar 554 is affected by --arch or --feat/--feature flags. 561 555 562 B<validate> - validate the conten 556 B<validate> - validate the contents of the files under 563 Documentation/featu 557 Documentation/features. 564 558 565 B<ls> or B<list> - list features for t 559 B<ls> or B<list> - list features for this machine's architecture, 566 using an easier to 560 using an easier to parse format. 567 The output is affec 561 The output is affected by --arch flag. 568 562 569 =back 563 =back 570 564 571 =head1 OPTIONS 565 =head1 OPTIONS 572 566 573 =over 8 567 =over 8 574 568 575 =item B<--arch> 569 =item B<--arch> 576 570 577 Output features for an specific architecture, 571 Output features for an specific architecture, optionally filtering for 578 a single specific feature. 572 a single specific feature. 579 573 580 =item B<--feat> or B<--feature> 574 =item B<--feat> or B<--feature> 581 575 582 Output features for a single specific feature. 576 Output features for a single specific feature. 583 577 584 =item B<--dir> 578 =item B<--dir> 585 579 586 Changes the location of the Feature files. By 580 Changes the location of the Feature files. By default, it uses 587 the Documentation/features directory. 581 the Documentation/features directory. 588 << 589 =item B<--enable-fname> << 590 << 591 Prints the file name of the feature files. Thi << 592 track dependencies during documentation build. << 593 582 594 =item B<--debug> 583 =item B<--debug> 595 584 596 Put the script in verbose mode, useful for deb 585 Put the script in verbose mode, useful for debugging. Can be called multiple 597 times, to increase verbosity. 586 times, to increase verbosity. 598 587 599 =item B<--help> 588 =item B<--help> 600 589 601 Prints a brief help message and exits. 590 Prints a brief help message and exits. 602 591 603 =item B<--man> 592 =item B<--man> 604 593 605 Prints the manual page and exits. 594 Prints the manual page and exits. 606 595 607 =back 596 =back 608 597 609 =head1 DESCRIPTION 598 =head1 DESCRIPTION 610 599 611 Parse the Linux feature files from Documentati 600 Parse the Linux feature files from Documentation/features (by default), 612 optionally producing results at ReST format. 601 optionally producing results at ReST format. 613 602 614 It supports output data per architecture, per 603 It supports output data per architecture, per feature or a 615 feature x arch matrix. 604 feature x arch matrix. 616 605 617 When used with B<rest> command, it will use ei 606 When used with B<rest> command, it will use either one of the tree formats: 618 607 619 If neither B<--arch> or B<--feature> arguments 608 If neither B<--arch> or B<--feature> arguments are used, it will output a 620 matrix with features per architecture. 609 matrix with features per architecture. 621 610 622 If B<--arch> argument is used, it will output 611 If B<--arch> argument is used, it will output the features availability for 623 a given architecture. 612 a given architecture. 624 613 625 If B<--feat> argument is used, it will output 614 If B<--feat> argument is used, it will output the content of the feature 626 file using ReStructured Text markup. 615 file using ReStructured Text markup. 627 616 628 =head1 BUGS 617 =head1 BUGS 629 618 630 Report bugs to Mauro Carvalho Chehab <mchehab+s 619 Report bugs to Mauro Carvalho Chehab <mchehab+samsung@kernel.org> 631 620 632 =head1 COPYRIGHT 621 =head1 COPYRIGHT 633 622 634 Copyright (c) 2019 by Mauro Carvalho Chehab <mc 623 Copyright (c) 2019 by Mauro Carvalho Chehab <mchehab+samsung@kernel.org>. 635 624 636 License GPLv2: GNU GPL version 2 <http://gnu.o 625 License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>. 637 626 638 This is free software: you are free to change 627 This is free software: you are free to change and redistribute it. 639 There is NO WARRANTY, to the extent permitted 628 There is NO WARRANTY, to the extent permitted by law. 640 629 641 =cut 630 =cut
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.