#!/usr/bin/perl -w use POSIX qw(strftime); use lib '/etc/lilalo'; use l3config; use utf8; use DBI; #no warnings; our @Fields=qw/id time prompt cline output err last_command tab diff l3cd/; our $Fields=join(", ",@Fields); our $db; =cut Множество команд, с которыми выполняется операция, определяется текущим контекстом и текущей строкой, а также параметрами: * фильтр; * регулярное выражение; * интервал. =cut our $Filter; our $Grep; our $Interval; our $Command; # Если мы используем режим -f, то в этой переменной запоминается # до какой точки мы дошли our $Follow=0; our $Context; our @Commands = qw/head tail cat history/; sub main(); sub connect_database(); main(); sub main() { $| = 1; init_config_without_command_line_processing(); $Context=$Config{l3cd}; connect_database(); # Обработка всех grep'ов $Grep=""; my $i=0; my $arg; my @argv=(); while ($i<=$#ARGV) { $arg=$ARGV[$i]; #print "arg=$arg\n"; if ($arg eq "grep") { my $grep_keys=""; my $grep_regexp=""; $i++; while(defined ($ARGV[$i]) and $ARGV[$i] =~ /^-/) { $grep_keys .= " ".$ARGV[$i]; $i++; } if (defined($ARGV[$i])) { $grep_regexp = $ARGV[$i]; $i++; } else { die "ERROR: grep argument is not specified"; } $Grep .= grep_options($grep_regexp,$grep_keys); } else { $i++; push(@new_argv,$arg); } } @argv=@new_argv; if (grep(/^-f$/, @argv)) { $follow=1; } if (grep(/^history$/, @argv)) { my $interval=$argv[0]||"%"; $interval="%" if $interval eq "history"; my $exit=0; while (not $exit) { print_commands(select_interval($interval, $Grep)); if (not $follow) { $exit=1; } else { sleep(1); } } } else { my $exit=0; while (not $exit) { print_all(select_interval($argv[0]||"%", $Grep)); if (not $follow) { $exit=1; } else { sleep(1); } } } #print_all(select_by_cline("*privet*")); } sub connect_database() { $db = DBI->connect("dbi:SQLite:".$Config{cache_sqlite}, "", "", {RaiseError => 1, AutoCommit => 1}); $db->func('regexp', 2, sub { my ($regex, $string) = @_; return $string =~ /$regex/; }, 'create_function'); } sub select_all() { $l3cd=$Config{l3cd}; return $db->selectall_arrayref("SELECT $Fields FROM commands WHERE l3cd='$l3cd'"); } sub select_last_n($) { my $last=$_[0]; $count = $db->selectall_arrayref("SELECT COUNT(*) FROM commands"); my $offset=$$count[0][0]-$last; return $db->selectall_arrayref("SELECT $Fields FROM commands LIMIT $last OFFSET $offset"); } sub select_interval($) { my $interval = shift; my $grep = shift; my $q; # Рабочая переменная для запросов # % $interval='1,$' if ($interval eq "%"); # return $db->selectall_arrayref( # "SELECT $Fields FROM commands WHERE l3cd='$Context'"); # Вычисляем номера начальной и конечной строки # на основе интервала my ($start,$stop); my ($start_n, $stop_n, $curr_n) = ("","",""); # номера начальной и конечной строк if ($interval =~ /,/) { ($start,$stop) = split(/,/,$interval); } else { $start = $interval; $stop = $interval; } $q = $db->selectall_arrayref("SELECT COUNT(*) FROM commands"); my $count = $$q[0][0]; # Номер текущей строки # По умолчанию текущая строка указывает на последнюю $curr_n = $count; #$curr_n = 2; if ($start =~ /^[0-9]*$/) { $start_n = $start; } if ($stop =~ /^[0-9]*$/) { $stop_n = $stop; } if ($start =~ /^-[0-9]*$/) { $start_n = $curr_n + $start; } if ($stop =~ /^-[0-9]*$/) { $stop_n = $curr_n + $stop; } if ($start =~ /^\+[0-9]*$/) { $start_n = $curr_n + $start; } if ($stop =~ /^\+[0-9]*$/) { $stop_n = $curr_n + $stop; } if ($start eq '.') { $start_n = $curr_n; } if ($stop eq '.') { $stop_n = $curr_n; } if ($start eq '$') { $start_n = $count; } if ($stop eq '$') { $stop_n = $count; } if ($start =~ m@^/(.*)/@ ) { $q = $db->selectall_arrayref( "SELECT id FROM commands WHERE cline REGEXP '$1' LIMIT 1"); $start_n=$$q[0][0]; } if ($stop =~ m@^/(.*)/@ ) { $q = $db->selectall_arrayref( "SELECT id FROM commands WHERE cline REGEXP '$1' AND (id >= $start_n) LIMIT 1"); $stop_n=$$q[0][0]; } if ($start =~ m@^o/(.*)/@ ) { $q = $db->selectall_arrayref( "SELECT id FROM commands WHERE output REGEXP '$1' LIMIT 1"); $start_n=$$q[0][0]; } if ($stop =~ m@^o/(.*)/@ && $start_n) { $q = $db->selectall_arrayref( "SELECT id FROM commands WHERE output REGEXP '$1' AND (id >= $start_n) LIMIT 1"); $stop_n=$$q[0][0]; } if (not $start_n or not $stop_n) {return ""}; $stop_n = $count if $count < $stop_n; $start_n =1 if 1 > $start_n; my $offset=$start_n-1; my $limit = $stop_n - $offset; my $pre_follow=$Follow; $q = $db->selectall_arrayref( "SELECT id FROM commands WHERE ((id>=$start_n AND id<=$stop_n AND id>$pre_follow) $grep) ORDER BY id DESC"); $Follow = $$q[0][0] if $$q[0][0]; return $db->selectall_arrayref( "SELECT $Fields FROM commands WHERE ((id>=$start_n AND id<=$stop_n AND id>$pre_follow) $grep)"); } sub grep_options($$) { =cut -c ищем только в комадной строке # по умолчанию -o ищем только в выводе -f ищем и там, и там -v инверсия =cut my $regexp=shift; return "" if $regexp eq ''; my $options=shift; my @options = split //, $options; my $not = ""; $not = "NOT" if grep(/v/,@options); my $grep =""; if (grep(/f/,@options)) { $grep = "AND $not ((cline REGEXP '$regexp') OR (output REGEXP '$regexp'))"; } elsif (grep(/o/,@options)) { $grep = "AND $not (output REGEXP '$regexp')"; } elsif (1 || grep(/c/,@options)) { $grep = "AND $not (cline REGEXP '$regexp')"; } return $grep; } sub select_by_cline($) { my $cline = $_[0]; return $db->selectall_arrayref("SELECT $Fields FROM commands WHERE cline GLOB '$cline'"); } sub print_commands($) { my @fields=@Fields; my $fields=join(", ",@fields); my $all=$_[0]; foreach my $row (@$all) { my $cl; #Каждая строка my $i=0; for my $f (@fields) { $cl->{$fields[$i]}=$$row[$i]; $i++; } print $cl->{id}." ".strdequot($cl->{cline})."\n"; } } sub print_all($) { my @fields=@Fields; my $fields=join(", ",@fields); my $all=$_[0]; my $prev_cl; # Предыдущая строка my $tab_seq; # Номер в табуляционной последовательности foreach my $row (@$all) { my $cl; #Каждая строка my @anchor; #Начальная строка, якорь, по которому привязывается команда my $res=""; #Буфер, в который выводится результат вывода каждой строки $i=0; for my $f (@fields) { $cl->{$fields[$i]}=$$row[$i]; $i++; } next if ($Config{"skip_empty"} =~ /^y/i && $cl->{"cline"} =~ /^\s*$/ ) || ($Config{"skip_wrong"} =~ /^y/i && $cl->{"err"} != 0) || ($Config{"skip_interrupted"} =~ /^y/i && $cl->{"err"} == 130); # Время # Добавляем спереди 0 для удобочитаемости my ($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst) = localtime($cl->{time}); $min = "0".$min if $min =~ /^.$/; $hour = "0".$hour if $hour =~ /^.$/; $sec = "0".$sec if $sec =~ /^.$/; if ($Config{"show_time"} =~ /^y/i) { push @anchor,"$hour:$min:$sec "; } if ($cl->{"err"}) { push @anchor, "err=".$cl->{'err'}; } if ($cl->{"tab"}) { push @anchor, "tab=".$cl->{'tab'}; } $res.="#=".join("",@anchor)."\n"; $res.=$cl->{prompt}.strdequot($cl->{cline})."\n"; my $output = ""; # фомируем вывод команды my $last_command = $cl->{"last_command"}; if (!( $Config{"suppress_editors"} =~ /^y/i && grep ($_ eq $last_command, @{$Config{"editors"}}) || $Config{"suppress_pagers"} =~ /^y/i && grep ($_ eq $last_command, @{$Config{"pagers"}}) || $Config{"suppress_terminal"}=~ /^y/i && grep ($_ eq $last_command, @{$Config{"terminal"}}) )) { $output = strdequot($cl->{output}); # Вырезаем слишком длинные выводы my @lines = split '\n', $output; if (!$Config{"command_id"} && ( $Config{"head_lines"} || $Config{"tail_lines"}) && $#lines > $Config{"head_lines"} + $Config{"tail_lines"}) { $output=""; for (my $i=0; $i<= $#lines && $i < $Config{"head_lines"}; $i++) { $output .= $lines[$i]."\n"; } $output .= $Config{"skip_text"}."\n"; my $start_line=$#lines-$Config{"tail_lines"}+1; for (my $i=$start_line; $i<= $#lines; $i++) { $output .= $lines[$i]."\n"; } } } $res.=$output; if ( $Config{"show_diffs"} =~ /^y/i && $cl->{"diff"}) { $res.= $cl->{"diff"} } #open(OUTPUT, '|sendxmpp nata_samoylenko@jabber.ru'); #print OUTPUT $res; #close(OUTPUT); print $res; $res=""; $prev_cl=$cl; } } sub strdequot($) { my $text = join "", @_; $text =~ s/&/&/g; $text =~ s/<//g; $text =~ s/"/"/g; return $text; } sub show_usage() { print <