lilalo

view 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 source
1 #!/usr/bin/perl -w
3 use POSIX qw(strftime);
4 use lib '/etc/lilalo';
5 use l3config;
6 use utf8;
7 use DBI;
8 #no warnings;
10 our @Fields=qw/id time prompt cline output err last_command tab diff l3cd/;
11 our $Fields=join(", ",@Fields);
12 our $db;
14 =cut
15 Множество команд, с которыми выполняется операция,
16 определяется текущим контекстом и текущей строкой,
17 а также параметрами:
18 * фильтр;
19 * регулярное выражение;
20 * интервал.
21 =cut
22 our $Filter;
23 our $Grep;
24 our $Interval;
25 our $Command;
27 # Если мы используем режим -f, то в этой переменной запоминается
28 # до какой точки мы дошли
29 our $Follow=0;
31 our $Context;
33 our @Commands = qw/head tail cat history/;
35 sub main();
36 sub connect_database();
38 main();
40 sub main()
41 {
42 $| = 1;
44 init_config_without_command_line_processing();
45 $Context=$Config{l3cd};
46 connect_database();
47 # Обработка всех grep'ов
48 $Grep="";
49 my $i=0;
50 my $arg;
51 my @argv=();
52 while ($i<=$#ARGV) {
53 $arg=$ARGV[$i];
54 #print "arg=$arg\n";
55 if ($arg eq "grep") {
56 my $grep_keys="";
57 my $grep_regexp="";
58 $i++;
59 while(defined ($ARGV[$i]) and $ARGV[$i] =~ /^-/) {
60 $grep_keys .= " ".$ARGV[$i];
61 $i++;
62 }
63 if (defined($ARGV[$i])) {
64 $grep_regexp = $ARGV[$i];
65 $i++;
66 }
67 else {
68 die "ERROR: grep argument is not specified";
69 }
70 $Grep .= grep_options($grep_regexp,$grep_keys);
71 }
72 else {
73 $i++;
74 push(@new_argv,$arg);
75 }
76 }
77 @argv=@new_argv;
79 if (grep(/^-f$/, @argv)) {
80 $follow=1;
81 }
82 if (grep(/^history$/, @argv)) {
83 my $interval=$argv[0]||"%";
84 $interval="%" if $interval eq "history";
85 my $exit=0;
86 while (not $exit) {
87 print_commands(select_interval($interval, $Grep));
88 if (not $follow) {
89 $exit=1;
90 } else {
91 sleep(1);
92 }
93 }
94 } else {
95 my $exit=0;
96 while (not $exit) {
97 print_all(select_interval($argv[0]||"%", $Grep));
98 if (not $follow) {
99 $exit=1;
100 } else {
101 sleep(1);
102 }
103 }
104 }
105 #print_all(select_by_cline("*privet*"));
106 }
108 sub connect_database()
109 {
110 $db = DBI->connect("dbi:SQLite:".$Config{cache_sqlite}, "", "",
111 {RaiseError => 1, AutoCommit => 1});
112 $db->func('regexp', 2, sub {
113 my ($regex, $string) = @_;
114 return $string =~ /$regex/;
115 }, 'create_function');
116 }
118 sub select_all() {
119 $l3cd=$Config{l3cd};
120 return $db->selectall_arrayref("SELECT $Fields FROM commands WHERE l3cd='$l3cd'");
121 }
123 sub select_last_n($) {
124 my $last=$_[0];
125 $count = $db->selectall_arrayref("SELECT COUNT(*) FROM commands");
126 my $offset=$$count[0][0]-$last;
127 return $db->selectall_arrayref("SELECT $Fields FROM commands LIMIT $last OFFSET $offset");
128 }
130 sub select_interval($) {
131 my $interval = shift;
132 my $grep = shift;
134 my $q; # Рабочая переменная для запросов
135 # %
136 $interval='1,$' if ($interval eq "%");
137 # return $db->selectall_arrayref(
138 # "SELECT $Fields FROM commands WHERE l3cd='$Context'");
140 # Вычисляем номера начальной и конечной строки
141 # на основе интервала
142 my ($start,$stop);
143 my ($start_n, $stop_n, $curr_n) = ("","",""); # номера начальной и конечной строк
144 if ($interval =~ /,/) {
145 ($start,$stop) = split(/,/,$interval);
146 }
147 else {
148 $start = $interval;
149 $stop = $interval;
150 }
152 $q = $db->selectall_arrayref("SELECT COUNT(*) FROM commands");
153 my $count = $$q[0][0];
155 # Номер текущей строки
156 # По умолчанию текущая строка указывает на последнюю
157 $curr_n = $count;
158 #$curr_n = 2;
160 if ($start =~ /^[0-9]*$/) { $start_n = $start; }
161 if ($stop =~ /^[0-9]*$/) { $stop_n = $stop; }
162 if ($start =~ /^-[0-9]*$/) { $start_n = $curr_n + $start; }
163 if ($stop =~ /^-[0-9]*$/) { $stop_n = $curr_n + $stop; }
164 if ($start =~ /^\+[0-9]*$/) { $start_n = $curr_n + $start; }
165 if ($stop =~ /^\+[0-9]*$/) { $stop_n = $curr_n + $stop; }
166 if ($start eq '.') { $start_n = $curr_n; }
167 if ($stop eq '.') { $stop_n = $curr_n; }
168 if ($start eq '$') { $start_n = $count; }
169 if ($stop eq '$') { $stop_n = $count; }
170 if ($start =~ m@^/(.*)/@ ) {
171 $q = $db->selectall_arrayref(
172 "SELECT id FROM commands WHERE cline REGEXP '$1' LIMIT 1");
173 $start_n=$$q[0][0];
174 }
175 if ($stop =~ m@^/(.*)/@ ) {
176 $q = $db->selectall_arrayref(
177 "SELECT id FROM commands
178 WHERE cline REGEXP '$1'
179 AND (id >= $start_n) LIMIT 1");
180 $stop_n=$$q[0][0];
181 }
182 if ($start =~ m@^o/(.*)/@ ) {
183 $q = $db->selectall_arrayref(
184 "SELECT id FROM commands WHERE output REGEXP '$1' LIMIT 1");
185 $start_n=$$q[0][0];
186 }
187 if ($stop =~ m@^o/(.*)/@ && $start_n) {
188 $q = $db->selectall_arrayref(
189 "SELECT id FROM commands
190 WHERE output REGEXP '$1' AND (id >= $start_n) LIMIT 1");
191 $stop_n=$$q[0][0];
192 }
194 if (not $start_n or not $stop_n) {return ""};
196 $stop_n = $count if $count < $stop_n;
197 $start_n =1 if 1 > $start_n;
199 my $offset=$start_n-1;
200 my $limit = $stop_n - $offset;
202 my $pre_follow=$Follow;
203 $q = $db->selectall_arrayref(
204 "SELECT id FROM commands
205 WHERE ((id>=$start_n AND id<=$stop_n AND id>$pre_follow) $grep)
206 ORDER BY id DESC");
207 $Follow = $$q[0][0] if $$q[0][0];
208 return $db->selectall_arrayref(
209 "SELECT $Fields FROM commands
210 WHERE ((id>=$start_n AND id<=$stop_n AND id>$pre_follow) $grep)");
211 }
213 sub grep_options($$) {
214 =cut
215 -c ищем только в комадной строке # по умолчанию
216 -o ищем только в выводе
217 -f ищем и там, и там
218 -v инверсия
219 =cut
220 my $regexp=shift; return "" if $regexp eq '';
221 my $options=shift;
222 my @options = split //, $options;
223 my $not = "";
224 $not = "NOT" if grep(/v/,@options);
226 my $grep ="";
227 if (grep(/f/,@options)) {
228 $grep = "AND $not ((cline REGEXP '$regexp') OR (output REGEXP '$regexp'))";
229 }
230 elsif (grep(/o/,@options)) {
231 $grep = "AND $not (output REGEXP '$regexp')";
232 }
233 elsif (1 || grep(/c/,@options)) {
234 $grep = "AND $not (cline REGEXP '$regexp')";
235 }
237 return $grep;
238 }
240 sub select_by_cline($) {
241 my $cline = $_[0];
242 return $db->selectall_arrayref("SELECT $Fields FROM commands WHERE cline GLOB '$cline'");
243 }
245 sub print_commands($)
246 {
247 my @fields=@Fields;
248 my $fields=join(", ",@fields);
249 my $all=$_[0];
250 foreach my $row (@$all) {
251 my $cl; #Каждая строка
252 my $i=0;
253 for my $f (@fields) {
254 $cl->{$fields[$i]}=$$row[$i];
255 $i++;
256 }
257 print $cl->{id}." ".strdequot($cl->{cline})."\n";
258 }
259 }
260 sub print_all($) {
261 my @fields=@Fields;
262 my $fields=join(", ",@fields);
263 my $all=$_[0];
264 my $prev_cl; # Предыдущая строка
265 my $tab_seq; # Номер в табуляционной последовательности
266 foreach my $row (@$all) {
267 my $cl; #Каждая строка
268 my @anchor; #Начальная строка, якорь, по которому привязывается команда
269 my $res=""; #Буфер, в который выводится результат вывода каждой строки
270 $i=0;
271 for my $f (@fields) {
272 $cl->{$fields[$i]}=$$row[$i];
273 $i++;
274 }
275 next if ($Config{"skip_empty"} =~ /^y/i && $cl->{"cline"} =~ /^\s*$/ )
276 || ($Config{"skip_wrong"} =~ /^y/i && $cl->{"err"} != 0)
277 || ($Config{"skip_interrupted"} =~ /^y/i && $cl->{"err"} == 130);
279 # Время
280 # Добавляем спереди 0 для удобочитаемости
281 my ($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst) = localtime($cl->{time});
282 $min = "0".$min if $min =~ /^.$/;
283 $hour = "0".$hour if $hour =~ /^.$/;
284 $sec = "0".$sec if $sec =~ /^.$/;
286 if ($Config{"show_time"} =~ /^y/i) {
287 push @anchor,"$hour:$min:$sec ";
288 }
290 if ($cl->{"err"}) {
291 push @anchor, "err=".$cl->{'err'};
292 }
293 if ($cl->{"tab"}) {
294 push @anchor, "tab=".$cl->{'tab'};
295 }
296 $res.="#=".join("",@anchor)."\n";
297 $res.=$cl->{prompt}.strdequot($cl->{cline})."\n";
299 my $output = ""; # фомируем вывод команды
300 my $last_command = $cl->{"last_command"};
301 if (!( $Config{"suppress_editors"} =~ /^y/i
302 && grep ($_ eq $last_command, @{$Config{"editors"}})
303 || $Config{"suppress_pagers"} =~ /^y/i
304 && grep ($_ eq $last_command, @{$Config{"pagers"}})
305 || $Config{"suppress_terminal"}=~ /^y/i
306 && grep ($_ eq $last_command, @{$Config{"terminal"}})
307 )) {
308 $output = strdequot($cl->{output});
310 # Вырезаем слишком длинные выводы
311 my @lines = split '\n', $output;
312 if (!$Config{"command_id"}
313 && ( $Config{"head_lines"} || $Config{"tail_lines"})
314 && $#lines > $Config{"head_lines"} + $Config{"tail_lines"}) {
315 $output="";
316 for (my $i=0; $i<= $#lines && $i < $Config{"head_lines"}; $i++) {
317 $output .= $lines[$i]."\n";
318 }
319 $output .= $Config{"skip_text"}."\n";
321 my $start_line=$#lines-$Config{"tail_lines"}+1;
322 for (my $i=$start_line; $i<= $#lines; $i++) {
323 $output .= $lines[$i]."\n";
324 }
325 }
326 }
327 $res.=$output;
328 if ( $Config{"show_diffs"} =~ /^y/i && $cl->{"diff"}) {
329 $res.= $cl->{"diff"}
330 }
331 #open(OUTPUT, '|sendxmpp nata_samoylenko@jabber.ru');
332 #print OUTPUT $res;
333 #close(OUTPUT);
334 print $res;
335 $res="";
336 $prev_cl=$cl;
337 }
338 }
340 sub strdequot($)
341 {
342 my $text = join "", @_;
343 $text =~ s/&amp;/&/g;
344 $text =~ s/&lt;/</g;
345 $text =~ s/&gt;/>/g;
346 $text =~ s/&quot;/"/g;
347 return $text;
348 }
350 sub show_usage()
351 {
352 print <<EOF;
353 Usage:
354 l3 [INTERVAL] [grep [KEYS] REGEXP] [filter [KEYS] FILTER] [COMMAND [KEYS]]
356 Commands:
357 history
358 tail
359 head
360 cat (default)
362 If COMMAND is not specified, cat assumed.
364 EOF
365 }