# convert linux-kernel __section uses from unquoted string to quoted string
# convert __attribute__((section("foo"))) to __section("foo")
# convert __attribute__((foo, section=("bar"), baz))
#      to __section("bar") attribute((foo, baz))
# convert __attribute__

use strict;

# patch compiler_attributes.h to remove quoting of section name

my $result = qx{patch -p1 <<"EOF"
 include/linux/compiler_attributes.h | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/include/linux/compiler_attributes.h b/include/linux/compiler_attributes.h
index 9ca040fa1cc6..88d3eea1cbba 100644
--- a/include/linux/compiler_attributes.h
+++ b/include/linux/compiler_attributes.h
@@ -225,21 +225,11 @@
 #define __pure                          __attribute__((__pure__))
 
 /*
- * Note: Since this macro makes use of the "stringification operator" `#`,
- * a quoted string literal should not be passed to it. eg. prefer:
- *     __section(.foo)
- * to:
- *     __section(".foo")
- * unless the section name is dynamically built up, in which case the
- * verbose __attribute__((__section__(".foo" x))) should be preferred.
- *
- * See also: https://bugs.llvm.org/show_bug.cgi?id=42950
- *
  *   gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-section-function-attribute
  *   gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-section-variable-attribute
  * clang: https://clang.llvm.org/docs/AttributeReference.html#section-declspec-allocate
  */
-#define __section(S)                    __attribute__((__section__(#S)))
+#define __section(section)              __attribute__((__section__(section)))
 
 /*
  *   gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-unused-function-attribute
EOF};

# Get the list of files to modify (contains __section or __attribute__.*section
# (ignore scripts, tools, uapi, and compiler_attributes.h)

my $output = `git grep --name-only -P "(?:\\b__section\\b\|\\b__attribute__\\b.*section)" | grep -vP '^(?:include/linux/compiler_attributes\\.h|scripts/|tools/|/uapi/)'`;
my @files = split("\n", $output);

# Modify each possible file
foreach (@files) {
    chomp;
    my $file = $_;

    # read the original file
    open(FH, '<', $file) or die $!;
    my @lines = <FH>;
    close FH;

    # write the modified file line by line
    open (FH, '>', $file) or die $!;
    foreach my $line (@lines) {
	chomp $line;
	my $newline = $line;

	# Convert __section(foo) to __section("foo")
	# if "foo" uses token pasting, pre and post tokens are also quoted
	if ($line =~ m/\b__section\s*\(\s*(?!")([^\)]+)\)/) {
	    my $oldsection = $1;
	    my $newsection = $1;
	    if ($oldsection =~ /(.*)##(.*)##(.*)/) {
		$newsection = '"' . trim($1) . '" ## ' . trim($2) . ' ## "' . trim($3) . '"';
	    } else {
		$newsection = '"' . trim($oldsection) . '"';
	    }
	    $newline =~ s/__section\s*\(\s*\Q$oldsection\E\s*\)/__section($newsection)/;
	}

	# convert __attribute__((section("foo"))) to __section("foo")
	$newline =~ s/\b__attribute__\s*\(\s*\(\s*_*section_*\s*\(\s*("[^"]+")\s*\)\s*\)\s*\)/__section($1)/;

	# convert __attribute__((foo, section=("bar"), baz))
	# to __section("bar") attribute((foo, baz))
	if ($newline =~ /(\b__attribute__\s*\(\s*\(([^,_]+)?(\s*,?\s*_*section_*\s*\(\s*("[^"]+")\s*\)\s*,?\s*)(.*)\s*\)\s*\))/) {
	    my $section = $3;
	    my $comma = "";
	    $comma = ", " if ($section =~ /^\s*,/ && $section =~ /,\s*$/);
	    $newline =~ s/\Q$section\E/$comma/;
	    $section =~ s/^[^"]*//;
	    $section =~ s/^("[^"]*").*/$1/;
	    $newline =~ s/\b__attribute__/__section($section) __attribute__/;
	}

	# if the line ended with a line continuation \, try to move the
	# continuation to the same location by removing or adding tabs
	if ($line =~ /\\$/) {
	    my $olen = length(expand_tabs($line));
	    my $nlen = length(expand_tabs($newline));
	    if ($newline =~ /\t\\$/) {
		if ($nlen > $olen) {
		    $newline =~ s/\t\\$/\\/;
		} else {
		    while ($nlen < $olen) {
			$newline =~ s/\\$/\t\\/;
			$nlen = length(expand_tabs($newline));
		    }
		}
	    }
	}
	print FH "$newline\n";
    }
    close FH;
}

# And git commit the changes
$result = qx{git commit -a --author='Joe Perches <joe\@perches.com>' -F- <<"EOF"
treewide: Convert macro and uses of __section(foo) to __section("foo")

Use a more generic form for __section that requires quotes to avoid
complications with clang and gcc differences.

Remove the quote operator # from compiler_attributes.h __section macro.

Convert all unquoted __section(foo) uses to quoted __section("foo").
Also convert __attribute__((section("foo"))) uses to __section("foo")
even if the __attribute__ has multiple list entry forms.

Signed-off-by: Joe Perches <joe\@perches.com>
EOF
};

# utility subroutines
sub trim {
    my ($string) = @_;
    $string =~ s/^\s+|\s+$//g;
    return $string;
}

sub expand_tabs {
    my ($str) = @_;

    my $res = '';
    my $n = 0;
    for my $c (split(//, $str)) {
	if ($c eq "\t") {
	    $res .= ' ';
	    $n++;
	    for (; ($n % 8) != 0; $n++) {
		$res .= ' ';
	    }
	    next;
	}
	$res .= $c;
	$n++;
    }

    return $res;
}
