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