#!/usr/bin/perl #! code perl # justify all the lines to a predefined width (default 80) # usage: # as with any other Perl script you can either # $ perl justifier.pl -wW [file]... # or change the above line /usr/bin/perl to your local Perl binary # and: # # $ chmod +x justifier.pl # $ ./justifier.pl -wW [file]... # # where file is one or several filenames. If no filename is given, # standard input is used. # -wW is the line width, which is 80 by default. # # There are several options (some of them even useful), type # # $ ./justifier.pl -h # # to see them. # # Notice that this program is none of either: # a) the simplest one # b) the fastest one # c) the cleanest one # but I did it quickly and it does the job for me. Want more? Pay. # http://pfortuny.sdf-eu.org # use strict ; use warnings ; # "Global" variables. my ($COL_WIDTH, $RANDOM_SPACE, $LEFTWARD_SPACE, $IGNORE_LOOSE, $LOOSE) = (0) x 5; my ($IGNORE_REGEXP, $PREPEND, ) = ("", "", ) ; my $IGNORE_STOPS = 0 ; # Parameter processing while(@ARGV and $ARGV[0] =~ /^-/) { $_ = shift @ARGV; last if /^--$/; if (/^-w(\d+)$/) {$COL_WIDTH = $1 ;} elsif (/^-sr$/) {$RANDOM_SPACE = 1 ;} elsif (/^-sl$/) {$LEFTWARD_SPACE = 1 ;} elsif (/^-il(\d*)$/) {$IGNORE_LOOSE = 1 ; $LOOSE = $1} elsif (/^-I(.*)$/) {$IGNORE_REGEXP = eval {qr/$1/} or die "BOGUS -I option: $1" ;} elsif (/^-is$/) {$IGNORE_STOPS = 1 ;} elsif (/^-p(.*)/) {$PREPEND = $1} else { error_exit() ;} } $IGNORE_STOPS = qr"[]})\.:?!{([]$" if $IGNORE_STOPS; # " for fancy highlighting $COL_WIDTH ||= 80 ; $COL_WIDTH -= length $PREPEND ; $LOOSE ||= $COL_WIDTH * $IGNORE_LOOSE ; my $line = "" ; # main loop. LINE: while(<>){ # do not chomp if we simply need to copy my $start = 1; if($IGNORE_REGEXP) { if (/$IGNORE_REGEXP/o ){ print $_ ; next LINE; } } my $output = ""; # Text from Mac won't work in this system... # We probabaly want something like this s/\r?\n// ; # But also probably do not. chomp ; $line .= $_ ; ($output, $line) = justify($start, $line); $start = 0 if $line ; while($line) { #was $line print $output ; print $PREPEND ; ($output, $line) = justify($start, $line); } # chomp the last part of the line and process it again, otherwise, # loose lines were always printed verbatim (which is not necessarily # desired) chomp $output ; ($output, $line) = justify($start, $output ) ; print $output ; } # main subroutine: # justify($start, $line): # # INPUT: # $start: a boolean indicating whether the line is the start of a paragraph # ($start = 1) or not. # $line: a "line", which contains a string. # # OUTPUT: ($output, $overfull) # # $output: a string of length less than or equal to $COL_WIDTH containing # a trimmed version of $line but for the added/removed spaces and # possibly some prepended text $PREPEND. # $overfull: the rest of $line, once $output has been taken away from it. # sub justify { my $start = shift @_ ; my $local_line = shift @_ || "" ; my ($output, $overfull, $space) = ("", "", "") ; my %spaces = ("", "") ; my @last_space = ("", ) ; my $col_width = $COL_WIDTH; # adjust column width for starting lines (which are not prepended by # anything) $col_width += length $PREPEND if $start ; if($IGNORE_LOOSE and length($local_line) <= $LOOSE) { return( $local_line . "\n", ""); } # kill trailing and starting spaces $local_line = join(" ", my @words = split(/\s+/,$local_line)) ; while($#words and length ("@words") > $col_width) { $overfull = (pop @words) . " " . $overfull ; } # now @words contains what is being output: if (($start and $IGNORE_STOPS) and "@words" =~ $IGNORE_STOPS) { return ("@words\n", $overfull) ; } if ($#words) { my $free_space = $col_width - length(join ("", @words)) ; $space = " " x int($free_space / $#words) ; @last_space = (" ") x ($free_space % $#words) ; %spaces = (); for(my $i = 0; $i <= $#last_space; $i++) { CHOOSE_J: my $j = $i ; if ($RANDOM_SPACE) { $j = int rand ($#words); if($spaces{$j}) {goto CHOOSE_J ;} } if ($LEFTWARD_SPACE) { $j = $#words - $i ; } $spaces{$j} = " "; } my $i = 0 ; foreach my $word (0..$#words - 1){ $output .= $words[$word] . $space ; $output .= ($spaces{$i} ? pop @last_space : "" ) ; $i++ ; } } @words = ("") unless @words ; # avoid nasty "uninitialized..." warnings $output .= ($output ? "@last_space" . pop (@words) : pop (@words) ) . "\n" ; return ($output, $overfull) ; } # # exit subroutine which prints usage information. # #! end perl sub error_exit { (my $error = <