fix-alignment.pl 2.84 KB
Newer Older
1
#!/usr/bin/env perl
2
# Copyright:	2009-2011, Nick Treleaven
3 4 5
# License:		GNU GPL V2 or later, as published by the Free Software Foundation, USA.
# Warranty:		NONE

6 7
# Re-align C source code for Geany.
# Doesn't handle indents/blank lines/anything complicated ;-)
8 9 10 11 12 13 14 15 16 17 18 19 20

use strict;
use warnings;

use Getopt::Std;

my %args = ();
getopts('w', \%args);
my $opt_write = $args{'w'};

my $argc = $#ARGV + 1;
my $scriptname = $0;

21
(($argc == 1) or ($argc >= 1 and $opt_write)) or die <<END;
22 23 24
Usage:
$scriptname sourcefile [>outfile]
  Print formatted output to STDOUT or outfile.
25
  Warning: do not use the same file for outfile.
26

27 28
$scriptname -w sourcefile(s)
  Writes to the file(s) in-place.
29 30 31 32
  Warning: backup your file(s) first or use clean version control files.
END


33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
sub parse($)
{
	my ($infile) = @_;
	my @lines;

	open(INPUT, $infile) or die "Couldn't open $infile for reading: $!\n";

	while (<INPUT>) {
		my $line = $_;	# read a line, including \n char

		# strip trailing space & newline
		$line =~ s/\s+$//g;

		# for now, don't process lines with comments, strings, preproc non-defines, overflowed lines or chars
		# multi-line comment internal lines are skipped only if they start with '* '.
		if (!($line =~ m,/\*|\*/|//|"|\\$|',) and !($line =~ m/^\s*(\*\s|#[^d])/)) {
			# make binary operators have *one* space each side
			# operators must have longer variants first otherwise trailing operators can be broken e.g. "+ ="
			# '*' ignored as could be pointer
			my $ops = '<<=,<<,>>=,>>,<=,>=,<,>,||,|=,|,&&,&=,-=,+=,+,*=,/=,/,==,!=,%=,%,^=,^,=';
			$ops =~ s/([|*+])/\\$1/g; # escape regex chars
			$ops =~ s/,/|/g;
55
			$line =~ s/([\w)\]]) ?($ops) ?([\w(]|$)/$1 $2 $3/g;
56

57 58 59
			# space binary operators that can conflict with unaries with cast and/or 'return -1/&foo'
			# '-' could be unary "(gint)-j"
			# '&' could be address-of "(type*)&foo"
60
			$line =~ s/([\w\]])(-|&) ?([\w(]|$)/$1 $2 $3/g;
61

62
			# space ternary conditional operator
63
			$line =~ s/ ?\? ?(.+?) ?: ?/ ? $1 : /g;
64 65

			# space comma operator (allowing for possible alignment space afterwards)
66
			$line =~ s/ ?,(\S)/, $1/g;
67 68 69 70 71 72 73 74

			# space after statements
			my $statements = 'for|if|while|switch';
			$line =~ s/\b($statements)\b\s*/$1 /g;

			# no space on inside of brackets
			$line =~ s/\(\s+/(/g;
			$line =~ s/(\S)\s+\)/$1)/g;
75 76 77

			# enforce 'fn(void);' in prototypes
			$line =~ s/^(\w.+\w\()\);$/$1void);/;
78 79 80 81
		}
		# strip trailing space again (e.g. a trailing operator now has space afterwards)
		$line =~ s/\s+$//g;

82
		push(@lines, $line);
83 84
	}
	close(INPUT);
Nick Treleaven's avatar
Nick Treleaven committed
85

86 87 88 89 90 91
	my $text = join("\n", @lines);
	undef @lines;	# free memory
	$text .= "\n";

	# 1+ newline -> 2 newlines after function
	$text =~ s/^}\n\n+([^\n])/}\n\n\n$1/gm;
92

93 94 95 96 97 98 99
	if (!$opt_write) {
		print $text;
	}
	else {
		open(OUTPUT, ">$infile") or die "Couldn't open $infile for writing: $!\n";
		print OUTPUT $text;
		close(OUTPUT);
100 101 102 103
	}
}


104
foreach my $infile (@ARGV)
105
{
106
	parse($infile);
107
}
108