lilalo
diff l3text @ 156:a0daf0c3fa52
bsd fix
author | Igor Chubin <igor@chub.in> |
---|---|
date | Mon Nov 28 13:15:16 2011 +0200 (2011-11-28) |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/l3text Mon Nov 28 13:15:16 2011 +0200 1.3 @@ -0,0 +1,365 @@ 1.4 +#!/usr/bin/perl -w 1.5 + 1.6 +use POSIX qw(strftime); 1.7 +use lib '/etc/lilalo'; 1.8 +use l3config; 1.9 +use utf8; 1.10 +use DBI; 1.11 +#no warnings; 1.12 + 1.13 +our @Fields=qw/id time prompt cline output err last_command tab diff l3cd/; 1.14 +our $Fields=join(", ",@Fields); 1.15 +our $db; 1.16 + 1.17 +=cut 1.18 +Множество команд, с которыми выполняется операция, 1.19 +определяется текущим контекстом и текущей строкой, 1.20 +а также параметрами: 1.21 + * фильтр; 1.22 + * регулярное выражение; 1.23 + * интервал. 1.24 +=cut 1.25 +our $Filter; 1.26 +our $Grep; 1.27 +our $Interval; 1.28 +our $Command; 1.29 + 1.30 +# Если мы используем режим -f, то в этой переменной запоминается 1.31 +# до какой точки мы дошли 1.32 +our $Follow=0; 1.33 + 1.34 +our $Context; 1.35 + 1.36 +our @Commands = qw/head tail cat history/; 1.37 + 1.38 +sub main(); 1.39 +sub connect_database(); 1.40 + 1.41 +main(); 1.42 + 1.43 +sub main() 1.44 +{ 1.45 + $| = 1; 1.46 + 1.47 + init_config_without_command_line_processing(); 1.48 + $Context=$Config{l3cd}; 1.49 + connect_database(); 1.50 +# Обработка всех grep'ов 1.51 + $Grep=""; 1.52 + my $i=0; 1.53 + my $arg; 1.54 + my @argv=(); 1.55 + while ($i<=$#ARGV) { 1.56 + $arg=$ARGV[$i]; 1.57 + #print "arg=$arg\n"; 1.58 + if ($arg eq "grep") { 1.59 + my $grep_keys=""; 1.60 + my $grep_regexp=""; 1.61 + $i++; 1.62 + while(defined ($ARGV[$i]) and $ARGV[$i] =~ /^-/) { 1.63 + $grep_keys .= " ".$ARGV[$i]; 1.64 + $i++; 1.65 + } 1.66 + if (defined($ARGV[$i])) { 1.67 + $grep_regexp = $ARGV[$i]; 1.68 + $i++; 1.69 + } 1.70 + else { 1.71 + die "ERROR: grep argument is not specified"; 1.72 + } 1.73 + $Grep .= grep_options($grep_regexp,$grep_keys); 1.74 + } 1.75 + else { 1.76 + $i++; 1.77 + push(@new_argv,$arg); 1.78 + } 1.79 + } 1.80 + @argv=@new_argv; 1.81 + 1.82 + if (grep(/^-f$/, @argv)) { 1.83 + $follow=1; 1.84 + } 1.85 + if (grep(/^history$/, @argv)) { 1.86 + my $interval=$argv[0]||"%"; 1.87 + $interval="%" if $interval eq "history"; 1.88 + my $exit=0; 1.89 + while (not $exit) { 1.90 + print_commands(select_interval($interval, $Grep)); 1.91 + if (not $follow) { 1.92 + $exit=1; 1.93 + } else { 1.94 + sleep(1); 1.95 + } 1.96 + } 1.97 + } else { 1.98 + my $exit=0; 1.99 + while (not $exit) { 1.100 + print_all(select_interval($argv[0]||"%", $Grep)); 1.101 + if (not $follow) { 1.102 + $exit=1; 1.103 + } else { 1.104 + sleep(1); 1.105 + } 1.106 + } 1.107 + } 1.108 + #print_all(select_by_cline("*privet*")); 1.109 +} 1.110 + 1.111 +sub connect_database() 1.112 +{ 1.113 + $db = DBI->connect("dbi:SQLite:".$Config{cache_sqlite}, "", "", 1.114 + {RaiseError => 1, AutoCommit => 1}); 1.115 + $db->func('regexp', 2, sub { 1.116 + my ($regex, $string) = @_; 1.117 + return $string =~ /$regex/; 1.118 + }, 'create_function'); 1.119 +} 1.120 + 1.121 +sub select_all() { 1.122 + $l3cd=$Config{l3cd}; 1.123 + return $db->selectall_arrayref("SELECT $Fields FROM commands WHERE l3cd='$l3cd'"); 1.124 +} 1.125 + 1.126 +sub select_last_n($) { 1.127 + my $last=$_[0]; 1.128 + $count = $db->selectall_arrayref("SELECT COUNT(*) FROM commands"); 1.129 + my $offset=$$count[0][0]-$last; 1.130 + return $db->selectall_arrayref("SELECT $Fields FROM commands LIMIT $last OFFSET $offset"); 1.131 +} 1.132 + 1.133 +sub select_interval($) { 1.134 + my $interval = shift; 1.135 + my $grep = shift; 1.136 + 1.137 + my $q; # Рабочая переменная для запросов 1.138 +# % 1.139 + $interval='1,$' if ($interval eq "%"); 1.140 +# return $db->selectall_arrayref( 1.141 +# "SELECT $Fields FROM commands WHERE l3cd='$Context'"); 1.142 + 1.143 +# Вычисляем номера начальной и конечной строки 1.144 +# на основе интервала 1.145 + my ($start,$stop); 1.146 + my ($start_n, $stop_n, $curr_n) = ("","",""); # номера начальной и конечной строк 1.147 + if ($interval =~ /,/) { 1.148 + ($start,$stop) = split(/,/,$interval); 1.149 + } 1.150 + else { 1.151 + $start = $interval; 1.152 + $stop = $interval; 1.153 + } 1.154 + 1.155 + $q = $db->selectall_arrayref("SELECT COUNT(*) FROM commands"); 1.156 + my $count = $$q[0][0]; 1.157 + 1.158 +# Номер текущей строки 1.159 +# По умолчанию текущая строка указывает на последнюю 1.160 + $curr_n = $count; 1.161 + #$curr_n = 2; 1.162 + 1.163 + if ($start =~ /^[0-9]*$/) { $start_n = $start; } 1.164 + if ($stop =~ /^[0-9]*$/) { $stop_n = $stop; } 1.165 + if ($start =~ /^-[0-9]*$/) { $start_n = $curr_n + $start; } 1.166 + if ($stop =~ /^-[0-9]*$/) { $stop_n = $curr_n + $stop; } 1.167 + if ($start =~ /^\+[0-9]*$/) { $start_n = $curr_n + $start; } 1.168 + if ($stop =~ /^\+[0-9]*$/) { $stop_n = $curr_n + $stop; } 1.169 + if ($start eq '.') { $start_n = $curr_n; } 1.170 + if ($stop eq '.') { $stop_n = $curr_n; } 1.171 + if ($start eq '$') { $start_n = $count; } 1.172 + if ($stop eq '$') { $stop_n = $count; } 1.173 + if ($start =~ m@^/(.*)/@ ) { 1.174 + $q = $db->selectall_arrayref( 1.175 + "SELECT id FROM commands WHERE cline REGEXP '$1' LIMIT 1"); 1.176 + $start_n=$$q[0][0]; 1.177 + } 1.178 + if ($stop =~ m@^/(.*)/@ ) { 1.179 + $q = $db->selectall_arrayref( 1.180 + "SELECT id FROM commands 1.181 + WHERE cline REGEXP '$1' 1.182 + AND (id >= $start_n) LIMIT 1"); 1.183 + $stop_n=$$q[0][0]; 1.184 + } 1.185 + if ($start =~ m@^o/(.*)/@ ) { 1.186 + $q = $db->selectall_arrayref( 1.187 + "SELECT id FROM commands WHERE output REGEXP '$1' LIMIT 1"); 1.188 + $start_n=$$q[0][0]; 1.189 + } 1.190 + if ($stop =~ m@^o/(.*)/@ && $start_n) { 1.191 + $q = $db->selectall_arrayref( 1.192 + "SELECT id FROM commands 1.193 + WHERE output REGEXP '$1' AND (id >= $start_n) LIMIT 1"); 1.194 + $stop_n=$$q[0][0]; 1.195 + } 1.196 + 1.197 + if (not $start_n or not $stop_n) {return ""}; 1.198 + 1.199 + $stop_n = $count if $count < $stop_n; 1.200 + $start_n =1 if 1 > $start_n; 1.201 + 1.202 + my $offset=$start_n-1; 1.203 + my $limit = $stop_n - $offset; 1.204 + 1.205 + my $pre_follow=$Follow; 1.206 + $q = $db->selectall_arrayref( 1.207 + "SELECT id FROM commands 1.208 + WHERE ((id>=$start_n AND id<=$stop_n AND id>$pre_follow) $grep) 1.209 + ORDER BY id DESC"); 1.210 + $Follow = $$q[0][0] if $$q[0][0]; 1.211 + return $db->selectall_arrayref( 1.212 + "SELECT $Fields FROM commands 1.213 + WHERE ((id>=$start_n AND id<=$stop_n AND id>$pre_follow) $grep)"); 1.214 +} 1.215 + 1.216 +sub grep_options($$) { 1.217 +=cut 1.218 + -c ищем только в комадной строке # по умолчанию 1.219 + -o ищем только в выводе 1.220 + -f ищем и там, и там 1.221 + -v инверсия 1.222 +=cut 1.223 + my $regexp=shift; return "" if $regexp eq ''; 1.224 + my $options=shift; 1.225 + my @options = split //, $options; 1.226 + my $not = ""; 1.227 + $not = "NOT" if grep(/v/,@options); 1.228 + 1.229 + my $grep =""; 1.230 + if (grep(/f/,@options)) { 1.231 + $grep = "AND $not ((cline REGEXP '$regexp') OR (output REGEXP '$regexp'))"; 1.232 + } 1.233 + elsif (grep(/o/,@options)) { 1.234 + $grep = "AND $not (output REGEXP '$regexp')"; 1.235 + } 1.236 + elsif (1 || grep(/c/,@options)) { 1.237 + $grep = "AND $not (cline REGEXP '$regexp')"; 1.238 + } 1.239 + 1.240 + return $grep; 1.241 +} 1.242 + 1.243 +sub select_by_cline($) { 1.244 + my $cline = $_[0]; 1.245 + return $db->selectall_arrayref("SELECT $Fields FROM commands WHERE cline GLOB '$cline'"); 1.246 +} 1.247 + 1.248 +sub print_commands($) 1.249 +{ 1.250 + my @fields=@Fields; 1.251 + my $fields=join(", ",@fields); 1.252 + my $all=$_[0]; 1.253 + foreach my $row (@$all) { 1.254 + my $cl; #Каждая строка 1.255 + my $i=0; 1.256 + for my $f (@fields) { 1.257 + $cl->{$fields[$i]}=$$row[$i]; 1.258 + $i++; 1.259 + } 1.260 + print $cl->{id}." ".strdequot($cl->{cline})."\n"; 1.261 + } 1.262 +} 1.263 +sub print_all($) { 1.264 + my @fields=@Fields; 1.265 + my $fields=join(", ",@fields); 1.266 + my $all=$_[0]; 1.267 + my $prev_cl; # Предыдущая строка 1.268 + my $tab_seq; # Номер в табуляционной последовательности 1.269 + foreach my $row (@$all) { 1.270 + my $cl; #Каждая строка 1.271 + my @anchor; #Начальная строка, якорь, по которому привязывается команда 1.272 + my $res=""; #Буфер, в который выводится результат вывода каждой строки 1.273 + $i=0; 1.274 + for my $f (@fields) { 1.275 + $cl->{$fields[$i]}=$$row[$i]; 1.276 + $i++; 1.277 + } 1.278 + next if ($Config{"skip_empty"} =~ /^y/i && $cl->{"cline"} =~ /^\s*$/ ) 1.279 + || ($Config{"skip_wrong"} =~ /^y/i && $cl->{"err"} != 0) 1.280 + || ($Config{"skip_interrupted"} =~ /^y/i && $cl->{"err"} == 130); 1.281 + 1.282 + # Время 1.283 + # Добавляем спереди 0 для удобочитаемости 1.284 + my ($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst) = localtime($cl->{time}); 1.285 + $min = "0".$min if $min =~ /^.$/; 1.286 + $hour = "0".$hour if $hour =~ /^.$/; 1.287 + $sec = "0".$sec if $sec =~ /^.$/; 1.288 + 1.289 + if ($Config{"show_time"} =~ /^y/i) { 1.290 + push @anchor,"$hour:$min:$sec "; 1.291 + } 1.292 + 1.293 + if ($cl->{"err"}) { 1.294 + push @anchor, "err=".$cl->{'err'}; 1.295 + } 1.296 + if ($cl->{"tab"}) { 1.297 + push @anchor, "tab=".$cl->{'tab'}; 1.298 + } 1.299 + $res.="#=".join("",@anchor)."\n"; 1.300 + $res.=$cl->{prompt}.strdequot($cl->{cline})."\n"; 1.301 + 1.302 + my $output = ""; # фомируем вывод команды 1.303 + my $last_command = $cl->{"last_command"}; 1.304 + if (!( $Config{"suppress_editors"} =~ /^y/i 1.305 + && grep ($_ eq $last_command, @{$Config{"editors"}}) 1.306 + || $Config{"suppress_pagers"} =~ /^y/i 1.307 + && grep ($_ eq $last_command, @{$Config{"pagers"}}) 1.308 + || $Config{"suppress_terminal"}=~ /^y/i 1.309 + && grep ($_ eq $last_command, @{$Config{"terminal"}}) 1.310 + )) { 1.311 + $output = strdequot($cl->{output}); 1.312 + 1.313 + # Вырезаем слишком длинные выводы 1.314 + my @lines = split '\n', $output; 1.315 + if (!$Config{"command_id"} 1.316 + && ( $Config{"head_lines"} || $Config{"tail_lines"}) 1.317 + && $#lines > $Config{"head_lines"} + $Config{"tail_lines"}) { 1.318 + $output=""; 1.319 + for (my $i=0; $i<= $#lines && $i < $Config{"head_lines"}; $i++) { 1.320 + $output .= $lines[$i]."\n"; 1.321 + } 1.322 + $output .= $Config{"skip_text"}."\n"; 1.323 + 1.324 + my $start_line=$#lines-$Config{"tail_lines"}+1; 1.325 + for (my $i=$start_line; $i<= $#lines; $i++) { 1.326 + $output .= $lines[$i]."\n"; 1.327 + } 1.328 + } 1.329 + } 1.330 + $res.=$output; 1.331 + if ( $Config{"show_diffs"} =~ /^y/i && $cl->{"diff"}) { 1.332 + $res.= $cl->{"diff"} 1.333 + } 1.334 + #open(OUTPUT, '|sendxmpp nata_samoylenko@jabber.ru'); 1.335 + #print OUTPUT $res; 1.336 + #close(OUTPUT); 1.337 + print $res; 1.338 + $res=""; 1.339 + $prev_cl=$cl; 1.340 + } 1.341 +} 1.342 + 1.343 +sub strdequot($) 1.344 +{ 1.345 + my $text = join "", @_; 1.346 + $text =~ s/&/&/g; 1.347 + $text =~ s/</</g; 1.348 + $text =~ s/>/>/g; 1.349 + $text =~ s/"/"/g; 1.350 + return $text; 1.351 +} 1.352 + 1.353 +sub show_usage() 1.354 +{ 1.355 + print <<EOF; 1.356 +Usage: 1.357 + l3 [INTERVAL] [grep [KEYS] REGEXP] [filter [KEYS] FILTER] [COMMAND [KEYS]] 1.358 + 1.359 +Commands: 1.360 + history 1.361 + tail 1.362 + head 1.363 + cat (default) 1.364 + 1.365 + If COMMAND is not specified, cat assumed. 1.366 + 1.367 +EOF 1.368 +}