#!/usr/bin/perl

#$Date: 2003/04/28 19:10:19 $
#$Revision: 1.4 $
#$Source: /Volumes/Rotor_Data/cvsroot/perl/cvs-util/cvstatus.pl,v $

######## Examples of use ##############################
# 
# this script can be used to display the status of files
# in the checked-out directory:
#
# show all changed, new, or removed files:
#   % cvstatus.pl
#
#
# this script can also be used in 'succinct mode', with the
# -s switch and a modifier that shows only certain files.
# 
# show only files that are unknown:
#   % cvstatus.pl -s un
# 
# show only files that are locally modified:
#   % cvstatus.pl -s lm
# 
# show only files that are locally changed, locally
# removed, or locally added:
#   % cvstatus.pl -s l
# 
# two ways to see all possible options for the -s switch:
#   % cvstatus.pl -h
#   % cvstatus.pl --help
# 
#
# succint mode produces newline-delimited lists suitable
# for use as input to other commands:
#
# remove deleted ('needs checkout') files from repository:
#   % cvs rm "`cvstatus.pl -s nc`"
# 
# add unknown files to repository:
#   % cvs add "`cvstatus.pl -s un`"
#
#######################################################



sub print_help {

	print "options to -s (succint mode):\n";

	print "    all - All\n";
	print "      l - Locally *\n";
	print "     lm - Locally Modified\n";
	print "     la - Locally Added\n";
	print "     lr - Locally Removed\n";
	print "      n - Needs *\n";
	print "     nc - Needs Checkout\n";
	print "     nu - Needs Update\n";
	print "     nm - Needs Merge\n";
	print "     np - Needs Patch\n";
	print "     un - Unknown\n";
		
}



sub succint_args {
	
	$succint = 0;
		
	if( $ARGV[0] eq '-s' ) {
		
		$succint = 1;
		
		$_ = $ARGV[1];
		
		STATUS_FILTER: {
		
			( $#ARGV <= 0 )
				&& ( ( $status_filter = "All" )
					&& ( $do_status = 1 )
					&& ( $do_update = 1 ) );
			
			/^l$/
				&& ( ( $status_filter = "Locally" )
					&& ( $do_status = 1 )
					&& ( $do_update = 1 ) );
			
			/^lm/
				&& ( ( $status_filter = "Locally Modified" )
					&& ( $do_status = 1 ) );
			
			/^la/
				&& ( ( $status_filter = "Locally Added" )
					&& ( $do_update = 1 ) );
			
			/^lr/
				&& ( ( $status_filter = "Locally Removed" )
					&& ( $do_status = 1 ) );
			
			/^n$/
				&& ( ( $status_filter = "Needs" )
					&& ( $do_status = 1 ) );
			
			/^nc/
				&& ( ( $status_filter = "Needs Checkout" )
					&& ( $do_status = 1 ) );
			
			/^nu/
				&& ( ( $status_filter = "Needs Update" )
					&& ( $do_status = 1 ) );
			
			/^nm/
				&& ( ( $status_filter = "Needs Merge" )
					&& ( $do_status = 1 ) );
			
			/^np/
				&& ( ( $status_filter = "Needs Patch" )
					&& ( $do_status = 1 ) );
			
			/^un/
				&& ( ( $status_filter = "Unknown" )
					&& ( $do_update = 1 ) );
			
			/^all$/
				&& ( ( $status_filter = "All" )
					&& ( $do_status = 1 )
					&& ( $do_update = 1 ) );
			
		}
	
	} else {
	
		$do_status = 1;
		$do_update = 1;
	
	}

	!$succint
		&& ( $output = "\n\ncvs status thingie-\n" );

	open( CVS_DIR, "cat CVS/Repository $err_away |" );
	chomp( my( @cvs_dir_out ) = <CVS_DIR> );
	close CVS_DIR;

	!$succint
		&& ( $output .= "        repository: ${cvs_dir_out[0]}\n" );

	open( CVS_DIR, "cat CVS/Root $err_away |" );
	chomp( my( @cvs_dir_out ) = <CVS_DIR> );
	close CVS_DIR;

	!$succint
		&& ( $output .= "              root: ${cvs_dir_out[0]}\n\n" );

}



sub check_status {



	$err_away = '2>&1';

	open( CVS_REP, "cat CVS/Repository $err_away |" );
	my( @cvs_rep_out ) = <CVS_REP>;
	close CVS_REP;
	
	chomp( my $repository = $cvs_rep_out[0] );

	my $found_flag = 0;



	if( $do_status ) {
	
		open( CVS_ST, "cvs st $err_away |" );
		my( @cvs_st_out ) = <CVS_ST>;
		close CVS_ST;
		
		foreach $cvs_st_out_line ( @cvs_st_out ) {
		
			$_ = $cvs_st_out_line;
			
			if( /^File:\s+(.*\S)\s+Status:\s+((\S+).+)$/ || /^File:\s+no file\s+(.*\S)\s+Status:\s+((\S+).+)$/ ) {
			
				$status_all = $2;
				$status_head = $3;
			
				$_ = $2;
				
				if( !/Up-to-date/ ) {
				
					$found_flag = 1;
					my $status_id = "      ?";
				
					STATUS_ID: {
							
						/^Locally Modified/
							&& ( $status_id = "loc mod" );
						
						/^Locally Added/
							&& ( $found_flag = 0 );
						
						/^Locally Removed/
							&& ( $status_id = "loc rem" );
						
						/^Needs Checkout/
							&& ( $status_id = "need co" );
						
						/^Needs Update/
							&& ( $status_id = "need up" );
						
						/^Needs Merge/
							&& ( $status_id = "need mr" );
						
						/^Needs Patch/
							&& ( $status_id = "need pa" );
						
					}
					
					!$succint
						&& ( $found_flag )
						&& ( $output .= "$status_id: " );
				
				}
				
			}
		
			$_ = $cvs_st_out_line;
			
			use bytes;
			if( $found_flag && /^\s*Repository revision:\s+\S+\s+.*$repository\/((\S+).+),v$/ ) {
	
				$_ = $1;
				s/Attic\///;
				
				!$succint
					&& ( $output .= "$_\n" );

				( $succint
					&& ( ( $status_all eq $status_filter )
							|| ( $status_head eq $status_filter )
							|| ( $status_filter eq 'All' ) ) )
					&& ( $output .= "$_\n" );

				$found_flag = 0;
	
			}
			
		}
		
	}



	if( $do_update ) {
	
		open( CVS_UP, "cvs -n up $err_away |" );
		my( @cvs_up_out ) = <CVS_UP>;
		close CVS_UP;
		
		foreach $cvs_up_out_line ( @cvs_up_out ) {
		
			$_ = $cvs_up_out_line;
			
			if( /^\?\s+(\S.+)$/ && !/\.AppleDouble/ ) {
	
				$_ = $1;
				s/Attic\///;
				
				!$succint
					&& ( $output .= "unknown: $_\n" );

				( $succint
					&& ( ( $status_filter eq 'Unknown' )
							|| ( $status_filter eq 'All' ) ) )
					&& ( $output .= "$_\n" );
	
			}
		
			if( /^A\s+(\S.+)$/ ) {
	
				$_ = $1;
				s/Attic\///;
				
				!$succint
					&& ( $output .= "loc add: $_\n" );

				( $succint
					&& ( ( $status_filter eq 'Locally Added' )
							|| ( $status_filter eq 'Locally' )
							|| ( $status_filter eq 'All' ) ) )
					&& ( $output .= "$_\n" );
	
			}
		
		}
		
	}



}






if(($ARGV[0] eq '-h') || ($ARGV[0] eq '--help')) {

	print_help();
		
} else {

	succint_args();

	check_status();
	
	print "\n$output\n\n";
	
	
	
}
