=head1 NAME C - a command line historian... =head1 DESCRIPTION A 'history' script for the Windows command line. While Unix shells allow quite flexible history calling: grepping for patterns etc., Windows only allows you to either tab up and down using the arrow cursors, or use F7 and F9 to select (and execute) an entry from a list or recall a numbered entry (and edit/execute). C offers this additional facility of being able to grep for commands fitting a particular pattern. It is basically a wrapper around the standard C command in Win32, using Aldo Calpini's Win32::Console to generate the selective command history. =head1 SYNOPSIS h shows history of commands h dir shows history of all commands matching 'dir' h /jpe?g/ regular expression on history The list of all matching commands will be returned: you are prompted with the most recent command, for example: Re-run (ESC to cancel)> perldoc h.pl The last of the matching commands will be automatically placed into your command prompt and you can edit and run as normal. Using the UP and DOWN arrow keys will tab through the selected list. =cut use strict; use warnings; use Win32::Console; my $cons=Win32::Console->new(STD_INPUT_HANDLE); # Help: currently invoked using Perldoc - could change to Pod::Usage I suppose if (defined $ARGV[0] && $ARGV[0]=~/^[\/-][hH?]/) { close BAT; system "perldoc $0"; exit; } my $OPT=$ENV{HIST_OPT} || ''; # I'm being lazy (and probably inefficient) by # just parsing the options when needed using a regexp. # (and by not accepting switches on the command line) =head1 OPTIONS The environment variable HIST_OPT can be set to a string containing various options. OPTIONS /v Verbose /limit=10 Show only 10 most recent options /nodup Ignore duplicates. (Alternatively you may prefer to set this on a Shell basis (Alt-Space - Properties - Options - "Discard Old Duplicates" for example (from the commandline) set hist_opt=/verbose /nodup =cut my @hist=split /\n/, `doskey /history`; # latest last. @hist=grep (!/^h\b/i, @hist); # remove any references to hist itself # I used to have an option to do this # but reckon it's a sensible default! if ($OPT=~/[\/-]nodup/i) { my %seen; @hist = reverse grep (! $seen{$_}++ , reverse @hist); # I'm reversing the list so that if there are duplicates, we see the # most recent time only } if ($OPT=~/[\/-]limit=(\d+)/i) { @hist=@hist[-$1..-1]; } if (! @ARGV) { show_hist('ALL', @hist); } else { my $grep=''; if ($ARGV[0]=~m{^/(.*?)/?$}) { $grep=qr{$1}; } else { $grep=$ARGV[0]; } my @grep = grep (/$grep/, @hist); show_hist($grep, @grep); } close BAT; ############### sub show_hist { my ($what, @hist)=@_; print "Options: $OPT\nHistory: $what\n==============\n" if $OPT=~/[-\/][vV]/; my $line=0; my $dummy; if (@hist) { for (@hist) { # write each line of the history to STDIN, followed by # a NEWLINE chr(13) (except for the last one). # The $dummy variable reads what we've written... but # the option is still preserved in doskeys's command # history so you can tab up and down the list with UP # and DOWN arrows if ($line) { write_input(chr(13)); $dummy=; } print ++$line.": "; write_input($_); } print $hist[-1]; } else { print "-- no commands --\n"; } print "\n"; } sub write_input { my $string=shift; for (split //, $string) { # This doesn't quite seem to be the format listed in Win32::Console # documentation at all: it is supposed to take the same format # as the return value of Input, which doesn't work! # 1 = Keyboard input # 1 = keydown, 0 = keyup (if we miss the second event, we won't # push multiples of the same character...) # 1 = Repeat count # Virtual Key code } Doesn't appear to matter what # Virtual Scan code } goes in these ! # Char } # Control Key State - this is the parameter that I am passing # the ASCII code for the character with. $cons->WriteInput(1,1,1,1,1,1,ord($_)); $cons->WriteInput(1,0,1,1,1,1,ord($_)); } } =head1 AUTHOR, VERSION, COPYRIGHT, WARNING hakim@earthling.net version 0.04 This is TEST CODE. No warranty is implied. Use at your own risk. Please contact me for any comments or questions, I will try to help, however I cannot guarantee any particular support. =head1 BUGS and CHANGES =over 4 =item 1 (2001-11-10) FIXED: No means of editing the command line (apart from copying and pasting it). My copy of Term::ReadLine doesn't support the 'addhistory' option which would have been ideal... (2001-11-11) used Win32::Console's WriteInput method. Maybe Term::Readline could be patched to use a similar method to implement this for Windows? =item 2 (2001-11-11) FIXED: (see item 5) If the command history is edited it isn't itself propagated to doskey /history (because it's run from a batch file...) so it won't be visible to later hist calls. This also means that rerunning a command will not make it appear later in the history list. =item 3 (2001-11-11) CHANGED: Renamed from C to C as hist is too much typing... =item 4 (2001-11-11) OPEN: Has only been tested on Win2K so far. =item 5 (2001-11-11) CHANGED: Got rid of the whole batch wrapper concept: realised that as the history is passed back into STDIN, I no longer need to input the command myself! =item 6 (2001-11-11) OPEN: Because I'm adding things into STDIN, the order of the history appears to be messed up. Fine if you're grepping for specifics but annoying if you wanted a chronological view. =back =cut