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