#!/usr/local/bin/perl -w
use strict;
use Getopt::Std;
use vars qw($opt_n $opt_w $opt_h $opt_p $opt_P $opt_c $line_a $line_b $context $currline $FORMAT_NORMAL $FORMAT_SINGLE);

use constant DEFAULT_CONTEXT => 4;

getopts("pPhn:w:c:");
usage() if ($opt_h);

# set prettyprinting on by default, turn off under some circumstances
my $prettyon = 1;

if ($^O eq 'MSWin32') {
	$prettyon = 0;
} elsif ($^O eq 'MacOS') {
	$prettyon = 0;
} elsif (! -t STDOUT) {
	$prettyon = 0;
}

# command line overrides
if ($opt_p) {
	$prettyon = 0;
} elsif ($opt_P) {
	$prettyon = 1;
}

if ($prettyon) {
	my $col = '32';
	if ($opt_c) { $col = $opt_c; }
	$FORMAT_NORMAL = qq{\033[${col}m%6u-\033[m %s};
	$FORMAT_SINGLE = qq{\033[${col}m\033[1m%6u>\033[m \033[1m%s\033[m};
} else {
	$FORMAT_NORMAL = q{%6u- %s};
	$FORMAT_SINGLE = q{%6u> %s};
}

my $filename;
if (@ARGV == 2) {
	($filename, $opt_n) = @ARGV;
} else {
	$filename = shift;
}

# Line number settings
if ($opt_n) {	# are we told to look at a certain line?
	$opt_n = int($opt_n);
	if ($opt_n < 1) {
		warn('The -n option must be a number greater than 0');
		$opt_n = 1;
	}

	if (defined $opt_w && $opt_w >= 0) {	# alteration of the amount of context?
		$opt_w = int($opt_w);
		$context = $opt_w;
	} elsif (defined $opt_w && $opt_w < 0) {
		warn("The -w option must be 0 or greater");
		$context = DEFAULT_CONTEXT;
	} else {
		$context = DEFAULT_CONTEXT;
	}

	# find out the range of lines we need to show
	$line_a = $opt_n - $context;
	if ($line_a < 1) {$line_a = 1};
	$line_b = $opt_n + $context;
} elsif ($opt_w) {
	warn('Useless use of the -w switch: you need -n too');
}

# File settings
if ($filename) {
	open(FH, '<'.$filename) or die("Can't open $filename : $!");
} else {
	open(FH, '-') or die("Can't open STDIN apparently : $!");
}

# Loop over input stream
while (<FH>) {
	++$currline;

	if ($opt_n) {
		next if ($currline < $line_a);
		if ($opt_n == $currline) {
			printf($FORMAT_SINGLE, $currline, $_);
			next;
		}
		last if ($currline > $line_b);
	}
	printf($FORMAT_NORMAL, $currline, $_);
}
if ($opt_n && $currline < $opt_n) {
	warn("Requested line $opt_n never reached!");
}

#### SUBROUTINES ################

sub TRACE {
	print STDERR "linenum.pl - " . shift() . "\n";
}

sub usage {
	require Pod::Usage;
	Pod::Usage::pod2usage( '-verbose' => 2 );
}

=pod

=head1 NAME

linenum.pl - a flexible tool for numbering lines in a file, or viewing a part of a file, with optional colouring

=head1 SYNOPSIS

	linenum.pl [ -h ] [ -p | -P ] [ -c COLOURCODE ] [ -n LINE [ -w NUM ]] [ filename ]
	linenum.pl filename number

	-h : Display this help
	-p : force no prettyprinting, no colour or bold - e.g. use for piping to a file
	-P : force prettyprinting (i.e. colouring and bold) to be on
	-c nn : the VT100 colour code that you want special chars to come out as [31..37] - defaults to green, 32
	-n : Which line do you want to look at. Give you 4 lines before and after as 
	     context by default.
	-w : Adjusts the amount of context as NUM lines before and NUM after.
	filename : the file you want to inspect, STDIN is used otherwise.

If invoked with exactly 2 arguments the first is taken to be the filename and the second the line number, to
make easier the very common usage of examining a particular line in a file (e.g. when given an error message
such as that produced by die() or the C preprocessor)

=head1 DESCRIPTION

Prepends line numbers to each line in the input text stream.
If the -n option is used only a portion of the text is displayed, centred
on the line number stated. The -w adjusts the number of lines of context
also displayed before and after the line of interest.

The program attempts to work out whether prettyprinting should be on or off
by default - use -p or -P to tell it explicitly.

=head1 EXAMPLE OUTPUT

In the following the line numbers appeared in green on my terminal, and in addition the line of interest, line 7,
was boldened.

	$ ./linenum.pl -n 7 -w 5 linenum.pl 
	     2- use strict;
	     3- use Getopt::Std;
	     4- use vars qw($opt_n $opt_w $opt_h $opt_p $opt_P $filename $line_a);
	     5- 
	     6- use constant DEFAULT_CONTEXT => 3;
	     7> #use constant FORMAT_NORMAL => '%6u: %s';
	     8- #use constant FORMAT_SINGLE => '%6u> %s';
	     9- 
	    10- getopts("pPhn:w:");
	    11- usage() if ($opt_h);
	    12- 

=head1 PREREQUISITES

Getopt::Std, Pod::Usage (for the usage/help message only) - or just put this
file through perldoc or whatever POD viewer you like.

=head1 COREQUISITES

None.

=begin comment

=pod OSNAMES

any

=pod SCRIPT CATEGORIES

UNIX/System_administration

=pod README

A flexible tool for numbering lines in a file, or viewing a part of a file - choose
the line number and how much context you want. Also uses pretty-printing where possible
to make the output clearer.

=end comment

=head1 VERSION

$Revision: 1.3 $

=cut
