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