162306a36Sopenharmony_ci#!/usr/bin/env perl
262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
362306a36Sopenharmony_ci
462306a36Sopenharmony_ciuse strict;
562306a36Sopenharmony_ciuse Pod::Usage;
662306a36Sopenharmony_ciuse Getopt::Long;
762306a36Sopenharmony_ciuse File::Find;
862306a36Sopenharmony_ciuse Fcntl ':mode';
962306a36Sopenharmony_ciuse Cwd 'abs_path';
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_cimy $help;
1262306a36Sopenharmony_cimy $man;
1362306a36Sopenharmony_cimy $debug;
1462306a36Sopenharmony_cimy $arch;
1562306a36Sopenharmony_cimy $feat;
1662306a36Sopenharmony_cimy $enable_fname;
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cimy $basename = abs_path($0);
1962306a36Sopenharmony_ci$basename =~ s,/[^/]+$,/,;
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cimy $prefix=$basename . "../Documentation/features";
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci# Used only at for full features output. The script will auto-adjust
2462306a36Sopenharmony_ci# such values for the minimal possible values
2562306a36Sopenharmony_cimy $status_size = 1;
2662306a36Sopenharmony_cimy $description_size = 1;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ciGetOptions(
2962306a36Sopenharmony_ci	"debug|d+" => \$debug,
3062306a36Sopenharmony_ci	"dir=s" => \$prefix,
3162306a36Sopenharmony_ci	'help|?' => \$help,
3262306a36Sopenharmony_ci	'arch=s' => \$arch,
3362306a36Sopenharmony_ci	'feat=s' => \$feat,
3462306a36Sopenharmony_ci	'feature=s' => \$feat,
3562306a36Sopenharmony_ci	"enable-fname" => \$enable_fname,
3662306a36Sopenharmony_ci	man => \$man
3762306a36Sopenharmony_ci) or pod2usage(2);
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cipod2usage(1) if $help;
4062306a36Sopenharmony_cipod2usage(-exitstatus => 0, -verbose => 2) if $man;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cipod2usage(1) if (scalar @ARGV < 1 || @ARGV > 2);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cimy ($cmd, $arg) = @ARGV;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cipod2usage(2) if ($cmd ne "current" && $cmd ne "rest" && $cmd ne "validate"
4762306a36Sopenharmony_ci		&& $cmd ne "ls" && $cmd ne "list");
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cirequire Data::Dumper if ($debug);
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cimy %data;
5262306a36Sopenharmony_cimy %archs;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#
5562306a36Sopenharmony_ci# Displays an error message, printing file name and line
5662306a36Sopenharmony_ci#
5762306a36Sopenharmony_cisub parse_error($$$$) {
5862306a36Sopenharmony_ci	my ($file, $ln, $msg, $data) = @_;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	$data =~ s/\s+$/\n/;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	print STDERR "Warning: file $file#$ln:\n\t$msg";
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	if ($data ne "") {
6562306a36Sopenharmony_ci		print STDERR ". Line\n\t\t$data";
6662306a36Sopenharmony_ci	} else {
6762306a36Sopenharmony_ci	    print STDERR "\n";
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#
7262306a36Sopenharmony_ci# Parse a features file, storing its contents at %data
7362306a36Sopenharmony_ci#
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cimy $h_name = "Feature";
7662306a36Sopenharmony_cimy $h_kconfig = "Kconfig";
7762306a36Sopenharmony_cimy $h_description = "Description";
7862306a36Sopenharmony_cimy $h_subsys = "Subsystem";
7962306a36Sopenharmony_cimy $h_status = "Status";
8062306a36Sopenharmony_cimy $h_arch = "Architecture";
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cimy $max_size_name = length($h_name);
8362306a36Sopenharmony_cimy $max_size_kconfig = length($h_kconfig);
8462306a36Sopenharmony_cimy $max_size_description = length($h_description);
8562306a36Sopenharmony_cimy $max_size_subsys = length($h_subsys);
8662306a36Sopenharmony_cimy $max_size_status = length($h_status);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cimy $max_size_arch = 0;
8962306a36Sopenharmony_cimy $max_size_arch_with_header;
9062306a36Sopenharmony_cimy $max_description_word = 0;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cisub parse_feat {
9362306a36Sopenharmony_ci	my $file = $File::Find::name;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	my $mode = (stat($file))[2];
9662306a36Sopenharmony_ci	return if ($mode & S_IFDIR);
9762306a36Sopenharmony_ci	return if ($file =~ m,($prefix)/arch-support.txt,);
9862306a36Sopenharmony_ci	return if (!($file =~ m,arch-support.txt$,));
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	if ($enable_fname) {
10162306a36Sopenharmony_ci		printf ".. FILE %s\n", abs_path($file);
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	my $subsys = "";
10562306a36Sopenharmony_ci	$subsys = $2 if ( m,.*($prefix)/([^/]+).*,);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	if (length($subsys) > $max_size_subsys) {
10862306a36Sopenharmony_ci		$max_size_subsys = length($subsys);
10962306a36Sopenharmony_ci	}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	my $name;
11262306a36Sopenharmony_ci	my $kconfig;
11362306a36Sopenharmony_ci	my $description;
11462306a36Sopenharmony_ci	my $comments = "";
11562306a36Sopenharmony_ci	my $last_status;
11662306a36Sopenharmony_ci	my $ln;
11762306a36Sopenharmony_ci	my %arch_table;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	print STDERR "Opening $file\n" if ($debug > 1);
12062306a36Sopenharmony_ci	open IN, $file;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	while(<IN>) {
12362306a36Sopenharmony_ci		$ln++;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci		if (m/^\#\s+Feature\s+name:\s*(.*\S)/) {
12662306a36Sopenharmony_ci			$name = $1;
12762306a36Sopenharmony_ci			if (length($name) > $max_size_name) {
12862306a36Sopenharmony_ci				$max_size_name = length($name);
12962306a36Sopenharmony_ci			}
13062306a36Sopenharmony_ci			next;
13162306a36Sopenharmony_ci		}
13262306a36Sopenharmony_ci		if (m/^\#\s+Kconfig:\s*(.*\S)/) {
13362306a36Sopenharmony_ci			$kconfig = $1;
13462306a36Sopenharmony_ci			if (length($kconfig) > $max_size_kconfig) {
13562306a36Sopenharmony_ci				$max_size_kconfig = length($kconfig);
13662306a36Sopenharmony_ci			}
13762306a36Sopenharmony_ci			next;
13862306a36Sopenharmony_ci		}
13962306a36Sopenharmony_ci		if (m/^\#\s+description:\s*(.*\S)/) {
14062306a36Sopenharmony_ci			$description = $1;
14162306a36Sopenharmony_ci			if (length($description) > $max_size_description) {
14262306a36Sopenharmony_ci				$max_size_description = length($description);
14362306a36Sopenharmony_ci			}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci			foreach my $word (split /\s+/, $description) {
14662306a36Sopenharmony_ci				if (length($word) > $max_description_word) {
14762306a36Sopenharmony_ci					$max_description_word = length($word);
14862306a36Sopenharmony_ci				}
14962306a36Sopenharmony_ci			}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci			next;
15262306a36Sopenharmony_ci		}
15362306a36Sopenharmony_ci		next if (m/^\\s*$/);
15462306a36Sopenharmony_ci		next if (m/^\s*\-+\s*$/);
15562306a36Sopenharmony_ci		next if (m/^\s*\|\s*arch\s*\|\s*status\s*\|\s*$/);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci		if (m/^\#\s*(.*)/) {
15862306a36Sopenharmony_ci			$comments .= "$1\n";
15962306a36Sopenharmony_ci			next;
16062306a36Sopenharmony_ci		}
16162306a36Sopenharmony_ci		if (m/^\s*\|\s*(\S+):\s*\|\s*(\S+)\s*\|\s*$/) {
16262306a36Sopenharmony_ci			my $a = $1;
16362306a36Sopenharmony_ci			my $status = $2;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci			if (length($status) > $max_size_status) {
16662306a36Sopenharmony_ci				$max_size_status = length($status);
16762306a36Sopenharmony_ci			}
16862306a36Sopenharmony_ci			if (length($a) > $max_size_arch) {
16962306a36Sopenharmony_ci				$max_size_arch = length($a);
17062306a36Sopenharmony_ci			}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci			$status = "---" if ($status =~ m/^\.\.$/);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci			$archs{$a} = 1;
17562306a36Sopenharmony_ci			$arch_table{$a} = $status;
17662306a36Sopenharmony_ci			next;
17762306a36Sopenharmony_ci		}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci		#Everything else is an error
18062306a36Sopenharmony_ci		parse_error($file, $ln, "line is invalid", $_);
18162306a36Sopenharmony_ci	}
18262306a36Sopenharmony_ci	close IN;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	if (!$name) {
18562306a36Sopenharmony_ci		parse_error($file, $ln, "Feature name not found", "");
18662306a36Sopenharmony_ci		return;
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	parse_error($file, $ln, "Subsystem not found", "") if (!$subsys);
19062306a36Sopenharmony_ci	parse_error($file, $ln, "Kconfig not found", "") if (!$kconfig);
19162306a36Sopenharmony_ci	parse_error($file, $ln, "Description not found", "") if (!$description);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	if (!%arch_table) {
19462306a36Sopenharmony_ci		parse_error($file, $ln, "Architecture table not found", "");
19562306a36Sopenharmony_ci		return;
19662306a36Sopenharmony_ci	}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	$data{$name}->{where} = $file;
19962306a36Sopenharmony_ci	$data{$name}->{subsys} = $subsys;
20062306a36Sopenharmony_ci	$data{$name}->{kconfig} = $kconfig;
20162306a36Sopenharmony_ci	$data{$name}->{description} = $description;
20262306a36Sopenharmony_ci	$data{$name}->{comments} = $comments;
20362306a36Sopenharmony_ci	$data{$name}->{table} = \%arch_table;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	$max_size_arch_with_header = $max_size_arch + length($h_arch);
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci#
20962306a36Sopenharmony_ci# Output feature(s) for a given architecture
21062306a36Sopenharmony_ci#
21162306a36Sopenharmony_cisub output_arch_table {
21262306a36Sopenharmony_ci	my $title = "Feature status on $arch architecture";
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	print "=" x length($title) . "\n";
21562306a36Sopenharmony_ci	print "$title\n";
21662306a36Sopenharmony_ci	print "=" x length($title) . "\n\n";
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	print "=" x $max_size_subsys;
21962306a36Sopenharmony_ci	print "  ";
22062306a36Sopenharmony_ci	print "=" x $max_size_name;
22162306a36Sopenharmony_ci	print "  ";
22262306a36Sopenharmony_ci	print "=" x $max_size_kconfig;
22362306a36Sopenharmony_ci	print "  ";
22462306a36Sopenharmony_ci	print "=" x $max_size_status;
22562306a36Sopenharmony_ci	print "  ";
22662306a36Sopenharmony_ci	print "=" x $max_size_description;
22762306a36Sopenharmony_ci	print "\n";
22862306a36Sopenharmony_ci	printf "%-${max_size_subsys}s  ", $h_subsys;
22962306a36Sopenharmony_ci	printf "%-${max_size_name}s  ", $h_name;
23062306a36Sopenharmony_ci	printf "%-${max_size_kconfig}s  ", $h_kconfig;
23162306a36Sopenharmony_ci	printf "%-${max_size_status}s  ", $h_status;
23262306a36Sopenharmony_ci	printf "%-${max_size_description}s\n", $h_description;
23362306a36Sopenharmony_ci	print "=" x $max_size_subsys;
23462306a36Sopenharmony_ci	print "  ";
23562306a36Sopenharmony_ci	print "=" x $max_size_name;
23662306a36Sopenharmony_ci	print "  ";
23762306a36Sopenharmony_ci	print "=" x $max_size_kconfig;
23862306a36Sopenharmony_ci	print "  ";
23962306a36Sopenharmony_ci	print "=" x $max_size_status;
24062306a36Sopenharmony_ci	print "  ";
24162306a36Sopenharmony_ci	print "=" x $max_size_description;
24262306a36Sopenharmony_ci	print "\n";
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	foreach my $name (sort {
24562306a36Sopenharmony_ci				($data{$a}->{subsys} cmp $data{$b}->{subsys}) ||
24662306a36Sopenharmony_ci				("\L$a" cmp "\L$b")
24762306a36Sopenharmony_ci			       } keys %data) {
24862306a36Sopenharmony_ci		next if ($feat && $name ne $feat);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci		my %arch_table = %{$data{$name}->{table}};
25162306a36Sopenharmony_ci		printf "%-${max_size_subsys}s  ", $data{$name}->{subsys};
25262306a36Sopenharmony_ci		printf "%-${max_size_name}s  ", $name;
25362306a36Sopenharmony_ci		printf "%-${max_size_kconfig}s  ", $data{$name}->{kconfig};
25462306a36Sopenharmony_ci		printf "%-${max_size_status}s  ", $arch_table{$arch};
25562306a36Sopenharmony_ci		printf "%-s\n", $data{$name}->{description};
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	print "=" x $max_size_subsys;
25962306a36Sopenharmony_ci	print "  ";
26062306a36Sopenharmony_ci	print "=" x $max_size_name;
26162306a36Sopenharmony_ci	print "  ";
26262306a36Sopenharmony_ci	print "=" x $max_size_kconfig;
26362306a36Sopenharmony_ci	print "  ";
26462306a36Sopenharmony_ci	print "=" x $max_size_status;
26562306a36Sopenharmony_ci	print "  ";
26662306a36Sopenharmony_ci	print "=" x $max_size_description;
26762306a36Sopenharmony_ci	print "\n";
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci#
27162306a36Sopenharmony_ci# list feature(s) for a given architecture
27262306a36Sopenharmony_ci#
27362306a36Sopenharmony_cisub list_arch_features {
27462306a36Sopenharmony_ci	print "#\n# Kernel feature support matrix of the '$arch' architecture:\n#\n";
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	foreach my $name (sort {
27762306a36Sopenharmony_ci				($data{$a}->{subsys} cmp $data{$b}->{subsys}) ||
27862306a36Sopenharmony_ci				("\L$a" cmp "\L$b")
27962306a36Sopenharmony_ci			       } keys %data) {
28062306a36Sopenharmony_ci		next if ($feat && $name ne $feat);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci		my %arch_table = %{$data{$name}->{table}};
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci		my $status = $arch_table{$arch};
28562306a36Sopenharmony_ci		$status = " " x ((4 - length($status)) / 2) . $status;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci		printf " %${max_size_subsys}s/ ", $data{$name}->{subsys};
28862306a36Sopenharmony_ci		printf "%-${max_size_name}s: ", $name;
28962306a36Sopenharmony_ci		printf "%-5s|   ", $status;
29062306a36Sopenharmony_ci		printf "%${max_size_kconfig}s # ", $data{$name}->{kconfig};
29162306a36Sopenharmony_ci		printf " %s\n", $data{$name}->{description};
29262306a36Sopenharmony_ci	}
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci#
29662306a36Sopenharmony_ci# Output a feature on all architectures
29762306a36Sopenharmony_ci#
29862306a36Sopenharmony_cisub output_feature {
29962306a36Sopenharmony_ci	my $title = "Feature $feat";
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	print "=" x length($title) . "\n";
30262306a36Sopenharmony_ci	print "$title\n";
30362306a36Sopenharmony_ci	print "=" x length($title) . "\n\n";
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	print ":Subsystem: $data{$feat}->{subsys} \n" if ($data{$feat}->{subsys});
30662306a36Sopenharmony_ci	print ":Kconfig: $data{$feat}->{kconfig} \n" if ($data{$feat}->{kconfig});
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	my $desc = $data{$feat}->{description};
30962306a36Sopenharmony_ci	$desc =~ s/^([a-z])/\U$1/;
31062306a36Sopenharmony_ci	$desc =~ s/\.?\s*//;
31162306a36Sopenharmony_ci	print "\n$desc.\n\n";
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	my $com = $data{$feat}->{comments};
31462306a36Sopenharmony_ci	$com =~ s/^\s+//;
31562306a36Sopenharmony_ci	$com =~ s/\s+$//;
31662306a36Sopenharmony_ci	if ($com) {
31762306a36Sopenharmony_ci		print "Comments\n";
31862306a36Sopenharmony_ci		print "--------\n\n";
31962306a36Sopenharmony_ci		print "$com\n\n";
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	print "=" x $max_size_arch_with_header;
32362306a36Sopenharmony_ci	print "  ";
32462306a36Sopenharmony_ci	print "=" x $max_size_status;
32562306a36Sopenharmony_ci	print "\n";
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	printf "%-${max_size_arch}s  ", $h_arch;
32862306a36Sopenharmony_ci	printf "%-${max_size_status}s", $h_status . "\n";
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	print "=" x $max_size_arch_with_header;
33162306a36Sopenharmony_ci	print "  ";
33262306a36Sopenharmony_ci	print "=" x $max_size_status;
33362306a36Sopenharmony_ci	print "\n";
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	my %arch_table = %{$data{$feat}->{table}};
33662306a36Sopenharmony_ci	foreach my $arch (sort keys %arch_table) {
33762306a36Sopenharmony_ci		printf "%-${max_size_arch}s  ", $arch;
33862306a36Sopenharmony_ci		printf "%-${max_size_status}s\n", $arch_table{$arch};
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	print "=" x $max_size_arch_with_header;
34262306a36Sopenharmony_ci	print "  ";
34362306a36Sopenharmony_ci	print "=" x $max_size_status;
34462306a36Sopenharmony_ci	print "\n";
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci#
34862306a36Sopenharmony_ci# Output all features for all architectures
34962306a36Sopenharmony_ci#
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cisub matrix_lines($$$) {
35262306a36Sopenharmony_ci	my $desc_size = shift;
35362306a36Sopenharmony_ci	my $status_size = shift;
35462306a36Sopenharmony_ci	my $header = shift;
35562306a36Sopenharmony_ci	my $fill;
35662306a36Sopenharmony_ci	my $ln_marker;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	if ($header) {
35962306a36Sopenharmony_ci		$ln_marker = "=";
36062306a36Sopenharmony_ci	} else {
36162306a36Sopenharmony_ci		$ln_marker = "-";
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	$fill = $ln_marker;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	print "+";
36762306a36Sopenharmony_ci	print $fill x $max_size_name;
36862306a36Sopenharmony_ci	print "+";
36962306a36Sopenharmony_ci	print $fill x $desc_size;
37062306a36Sopenharmony_ci	print "+";
37162306a36Sopenharmony_ci	print $ln_marker x $status_size;
37262306a36Sopenharmony_ci	print "+\n";
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_cisub output_matrix {
37662306a36Sopenharmony_ci	my $title = "Feature status on all architectures";
37762306a36Sopenharmony_ci	my $notcompat = "Not compatible";
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	print "=" x length($title) . "\n";
38062306a36Sopenharmony_ci	print "$title\n";
38162306a36Sopenharmony_ci	print "=" x length($title) . "\n\n";
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	my $desc_title = "$h_kconfig / $h_description";
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	my $desc_size = $max_size_kconfig + 4;
38662306a36Sopenharmony_ci	if (!$description_size) {
38762306a36Sopenharmony_ci		$desc_size = $max_size_description if ($max_size_description > $desc_size);
38862306a36Sopenharmony_ci	} else {
38962306a36Sopenharmony_ci		$desc_size = $description_size if ($description_size > $desc_size);
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci	$desc_size = $max_description_word if ($max_description_word > $desc_size);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	$desc_size = length($desc_title) if (length($desc_title) > $desc_size);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	$max_size_status = length($notcompat) if (length($notcompat) > $max_size_status);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	# Ensure that the status will fit
39862306a36Sopenharmony_ci	my $min_status_size = $max_size_status + $max_size_arch + 6;
39962306a36Sopenharmony_ci	$status_size = $min_status_size if ($status_size < $min_status_size);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	my $cur_subsys = "";
40362306a36Sopenharmony_ci	foreach my $name (sort {
40462306a36Sopenharmony_ci				($data{$a}->{subsys} cmp $data{$b}->{subsys}) or
40562306a36Sopenharmony_ci				("\L$a" cmp "\L$b")
40662306a36Sopenharmony_ci			       } keys %data) {
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci		if ($cur_subsys ne $data{$name}->{subsys}) {
40962306a36Sopenharmony_ci			if ($cur_subsys ne "") {
41062306a36Sopenharmony_ci				printf "\n";
41162306a36Sopenharmony_ci			}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci			$cur_subsys = $data{$name}->{subsys};
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci			my $title = "Subsystem: $cur_subsys";
41662306a36Sopenharmony_ci			print "$title\n";
41762306a36Sopenharmony_ci			print "=" x length($title) . "\n\n";
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci			matrix_lines($desc_size, $status_size, 0);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci			printf "|%-${max_size_name}s", $h_name;
42362306a36Sopenharmony_ci			printf "|%-${desc_size}s", $desc_title;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci			printf "|%-${status_size}s|\n", "Status per architecture";
42662306a36Sopenharmony_ci			matrix_lines($desc_size, $status_size, 1);
42762306a36Sopenharmony_ci		}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci		my %arch_table = %{$data{$name}->{table}};
43062306a36Sopenharmony_ci		my $cur_status = "";
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci		my (@lines, @descs);
43362306a36Sopenharmony_ci		my $line = "";
43462306a36Sopenharmony_ci		foreach my $arch (sort {
43562306a36Sopenharmony_ci					($arch_table{$b} cmp $arch_table{$a}) or
43662306a36Sopenharmony_ci					("\L$a" cmp "\L$b")
43762306a36Sopenharmony_ci				       } keys %arch_table) {
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci			my $status = $arch_table{$arch};
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci			if ($status eq "---") {
44262306a36Sopenharmony_ci				$status = $notcompat;
44362306a36Sopenharmony_ci			}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci			if ($status ne $cur_status) {
44662306a36Sopenharmony_ci				if ($line ne "") {
44762306a36Sopenharmony_ci					push @lines, $line;
44862306a36Sopenharmony_ci					$line = "";
44962306a36Sopenharmony_ci				}
45062306a36Sopenharmony_ci				$line = "- **" . $status . "**: " . $arch;
45162306a36Sopenharmony_ci			} elsif (length($line) + length ($arch) + 2 < $status_size) {
45262306a36Sopenharmony_ci				$line .= ", " . $arch;
45362306a36Sopenharmony_ci			} else {
45462306a36Sopenharmony_ci				push @lines, $line;
45562306a36Sopenharmony_ci				$line = "  " . $arch;
45662306a36Sopenharmony_ci			}
45762306a36Sopenharmony_ci			$cur_status = $status;
45862306a36Sopenharmony_ci		}
45962306a36Sopenharmony_ci		push @lines, $line if ($line ne "");
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci		my $description = $data{$name}->{description};
46262306a36Sopenharmony_ci		while (length($description) > $desc_size) {
46362306a36Sopenharmony_ci			my $d = substr $description, 0, $desc_size;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci			# Ensure that it will end on a space
46662306a36Sopenharmony_ci			# if it can't, it means that the size is too small
46762306a36Sopenharmony_ci			# Instead of aborting it, let's print what we have
46862306a36Sopenharmony_ci			if (!($d =~ s/^(.*)\s+.*/$1/)) {
46962306a36Sopenharmony_ci				$d = substr $d, 0, -1;
47062306a36Sopenharmony_ci				push @descs, "$d\\";
47162306a36Sopenharmony_ci				$description =~ s/^\Q$d\E//;
47262306a36Sopenharmony_ci			} else {
47362306a36Sopenharmony_ci				push @descs, $d;
47462306a36Sopenharmony_ci				$description =~ s/^\Q$d\E\s+//;
47562306a36Sopenharmony_ci			}
47662306a36Sopenharmony_ci		}
47762306a36Sopenharmony_ci		push @descs, $description;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci		# Ensure that the full description will be printed
48062306a36Sopenharmony_ci		push @lines, "" while (scalar(@lines) < 2 + scalar(@descs));
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci		my $ln = 0;
48362306a36Sopenharmony_ci		for my $line(@lines) {
48462306a36Sopenharmony_ci			if (!$ln) {
48562306a36Sopenharmony_ci				printf "|%-${max_size_name}s", $name;
48662306a36Sopenharmony_ci				printf "|%-${desc_size}s", "``" . $data{$name}->{kconfig} . "``";
48762306a36Sopenharmony_ci			} elsif ($ln >= 2 && scalar(@descs)) {
48862306a36Sopenharmony_ci				printf "|%-${max_size_name}s", "";
48962306a36Sopenharmony_ci				printf "|%-${desc_size}s", shift @descs;
49062306a36Sopenharmony_ci			} else {
49162306a36Sopenharmony_ci				printf "|%-${max_size_name}s", "";
49262306a36Sopenharmony_ci				printf "|%-${desc_size}s", "";
49362306a36Sopenharmony_ci			}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci			printf "|%-${status_size}s|\n", $line;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci			$ln++;
49862306a36Sopenharmony_ci		}
49962306a36Sopenharmony_ci		matrix_lines($desc_size, $status_size, 0);
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci#
50562306a36Sopenharmony_ci# Parses all feature files located at $prefix dir
50662306a36Sopenharmony_ci#
50762306a36Sopenharmony_cifind({wanted =>\&parse_feat, no_chdir => 1}, $prefix);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ciprint STDERR Data::Dumper->Dump([\%data], [qw(*data)]) if ($debug);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci#
51262306a36Sopenharmony_ci# Handles the command
51362306a36Sopenharmony_ci#
51462306a36Sopenharmony_ciif ($cmd eq "current") {
51562306a36Sopenharmony_ci	$arch = qx(uname -m | sed 's/x86_64/x86/' | sed 's/i386/x86/');
51662306a36Sopenharmony_ci	$arch =~s/\s+$//;
51762306a36Sopenharmony_ci}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ciif ($cmd eq "ls" or $cmd eq "list") {
52062306a36Sopenharmony_ci	if (!$arch) {
52162306a36Sopenharmony_ci		$arch = qx(uname -m | sed 's/x86_64/x86/' | sed 's/i386/x86/');
52262306a36Sopenharmony_ci		$arch =~s/\s+$//;
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	list_arch_features;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	exit;
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ciif ($cmd ne "validate") {
53162306a36Sopenharmony_ci	if ($arch) {
53262306a36Sopenharmony_ci		output_arch_table;
53362306a36Sopenharmony_ci	} elsif ($feat) {
53462306a36Sopenharmony_ci		output_feature;
53562306a36Sopenharmony_ci	} else {
53662306a36Sopenharmony_ci		output_matrix;
53762306a36Sopenharmony_ci	}
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci__END__
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci=head1 NAME
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ciget_feat.pl - parse the Linux Feature files and produce a ReST book.
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci=head1 SYNOPSIS
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ciB<get_feat.pl> [--debug] [--man] [--help] [--dir=<dir>] [--arch=<arch>]
54962306a36Sopenharmony_ci	       [--feature=<feature>|--feat=<feature>] <COMAND> [<ARGUMENT>]
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ciWhere <COMMAND> can be:
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci=over 8
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ciB<current>               - output table in ReST compatible ASCII format
55662306a36Sopenharmony_ci			   with features for this machine's architecture
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ciB<rest>                  - output table(s)  in ReST compatible ASCII format
55962306a36Sopenharmony_ci			   with features in ReST markup language. The output
56062306a36Sopenharmony_ci			   is affected by --arch or --feat/--feature flags.
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ciB<validate>              - validate the contents of the files under
56362306a36Sopenharmony_ci			   Documentation/features.
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ciB<ls> or B<list>         - list features for this machine's architecture,
56662306a36Sopenharmony_ci			   using an easier to parse format.
56762306a36Sopenharmony_ci			   The output is affected by --arch flag.
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci=back
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci=head1 OPTIONS
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci=over 8
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci=item B<--arch>
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ciOutput features for an specific architecture, optionally filtering for
57862306a36Sopenharmony_cia single specific feature.
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci=item B<--feat> or B<--feature>
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ciOutput features for a single specific feature.
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci=item B<--dir>
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ciChanges the location of the Feature files. By default, it uses
58762306a36Sopenharmony_cithe Documentation/features directory.
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci=item B<--enable-fname>
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ciPrints the file name of the feature files. This can be used in order to
59262306a36Sopenharmony_citrack dependencies during documentation build.
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci=item B<--debug>
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ciPut the script in verbose mode, useful for debugging. Can be called multiple
59762306a36Sopenharmony_citimes, to increase verbosity.
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci=item B<--help>
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ciPrints a brief help message and exits.
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci=item B<--man>
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ciPrints the manual page and exits.
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci=back
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci=head1 DESCRIPTION
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ciParse the Linux feature files from Documentation/features (by default),
61262306a36Sopenharmony_cioptionally producing results at ReST format.
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ciIt supports output data per architecture, per feature or a
61562306a36Sopenharmony_cifeature x arch matrix.
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ciWhen used with B<rest> command, it will use either one of the tree formats:
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ciIf neither B<--arch> or B<--feature> arguments are used, it will output a
62062306a36Sopenharmony_cimatrix with features per architecture.
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ciIf B<--arch> argument is used, it will output the features availability for
62362306a36Sopenharmony_cia given architecture.
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ciIf B<--feat> argument is used, it will output the content of the feature
62662306a36Sopenharmony_cifile using ReStructured Text markup.
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci=head1 BUGS
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ciReport bugs to Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci=head1 COPYRIGHT
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ciCopyright (c) 2019 by Mauro Carvalho Chehab <mchehab+samsung@kernel.org>.
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ciLicense GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>.
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ciThis is free software: you are free to change and redistribute it.
63962306a36Sopenharmony_ciThere is NO WARRANTY, to the extent permitted by law.
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci=cut
642