1 package Onis::Parser::Persistent;
3 =head1 Parser::Persistent
5 This module provides routines used for ``statefull parsing'' or however
6 you want to call what's going on. It is used to find an absolute time in
7 the logfile and rewind the file or seek further, whichever is neccessary.
11 use Parser::Persistent qw#set_absolute_time add_relative_time get_state
14 set_absolute_time ($year, $month, $day, $hour, $min, $sec);
15 add_relative_time ($hour, $minute);
21 # This module was quite hard to write, so I guess it's hard to understand,
22 # too. I'll try to explain as much as possible, but it twisted my mind
23 # more than once since it actually worked. Good luck :)
28 use vars qw#%MONTHNAMES @MONTHNUMS#;
32 use Onis::Data::Persistent;
34 @Onis::Parser::Persistent::EXPORT_OK = qw/set_absolute_time get_absolute_time add_relative_time get_state newfile %MONTHNAMES @MONTHNUMS/;
35 @Onis::Parser::Persistent::ISA = ('Exporter');
53 @MONTHNUMS = qw/Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec/;
55 our $TimeNewest = Onis::Data::Persistent->new ('TimeNewest', 'inode', 'time');
56 our $AbsoluteTime = 0;
65 my $VERSION = '$Id: Persistent.pm,v 1.7 2004/01/07 20:31:17 octo Exp $';
66 print STDERR $/, __FILE__, ": $VERSION" if ($::DEBUG);
70 =head1 Exported routines
74 This routine decides between four states: ``don't have time'', ``line is
75 old'', ``parse this line'' and ``rewind file and begin again''. The last
76 three imply that the time has been set.
78 B<rewind file and begin again>: The parser should tell the main routine to
79 rewind the file and start reading at the beginning again. This is
80 neccessay if we went past the point where we left off during the last run.
81 In this case zero is returned.
83 B<parse this line>: If the parser should parse the line and call I<store>
84 with the results this routine returns one.
86 B<line is old>: If the parser should simply ignore this line and
87 continue with the next one this routine returns three.
89 B<don't have time>: No time is set. Ignore lines until a date is found.
91 The desire is to pass the return code back to the main routine, unless it
92 is equal to one. The parser should then return one upon success, two upon
100 # 2 == unable to parse
102 # 4 == don't have date
105 my ($newest) = $TimeNewest->get ($CurFile);
108 # We're seeking for an absolute date.
109 if ($TimeData->{'Seeking'})
111 # We're still seeking for a date..
117 # we're seeking past this date
120 # We have a date and it's before the date we're seeking for.
121 # So we continue seeking..
122 if ($AbsoluteTime <= $newest)
126 print STDERR $/, __FILE__, ": Absolute time found. Is earlier than the newest time. Disabling ``NeedsRewind''.";
128 $TimeData->{'NeedsRewind'} = 0;
130 # line old. ignore it
134 # We went too far, so we have to go back.
135 # We substract the duration since the beginning
136 # of the file and tell the main routine to rewind
138 elsif ($TimeData->{'NeedsRewind'})
142 my $diff = $TimeData->{'Duration'};
144 $found = localtime ($AbsoluteTime) if ($::DEBUG & 0x40);
146 $AbsoluteTime -= $diff;
150 $set = localtime ($AbsoluteTime);
151 print STDERR $/, __FILE__, ": Absolute time ``$found'' found. Setting back $diff seconds to ``$set''" if ($::DEBUG & 0x40);
154 $TimeData->{'NeedsRewind'} = 0;
155 delete ($TimeData->{'LastHourSeen'});
156 delete ($TimeData->{'LastMinuteSeen'});
162 # This is the line we were looking for.
163 # It's past $newest, but not the first absolute time found.
166 print STDERR $/, __FILE__, ": Seeking done." if ($::DEBUG & 0x40);
167 $TimeData->{'Seeking'} = 0;
171 # $newest is not set but we have an absolute date.
174 print STDERR $/, __FILE__, ": \$newest not set. Setting it to \$AbsoluteTime." if ($::DEBUG & 0x40);
176 $TimeData->{'Seeking'} = 0;
178 # We had to read some lines to get an absolute date.
180 if ($TimeData->{'Duration'})
182 my $diff = $TimeData->{'Duration'};
185 my $time = localtime ($AbsoluteTime);
186 print STDERR $/, __FILE__, ": AbsolutTime found is ``$time'', but we are $diff seconds into the file.";
189 $AbsoluteTime -= $TimeData->{'Duration'};
193 my $time = localtime ($AbsoluteTime);
194 print STDERR $/, __FILE__, ": Corrected AbsolutTime (set back $diff seconds) is ``$time''";
197 delete ($TimeData->{'LastHourSeen'});
198 delete ($TimeData->{'LastMinuteSeen'});
200 # tell parser to rewind file
204 # We didn't miss anything, so we don't need to rewind the file.
207 $newest = $AbsoluteTime;
208 $TimeNewest->put ($CurFile, $newest);
214 # Ok, we're in the past. Let's skip that line..
215 # This is NOT supposed to happen. If it does, it's a bug!
216 elsif ($AbsoluteTime < $newest)
218 my $now = localtime ($AbsoluteTime);
219 my $then = localtime ($newest);
220 print STDERR $/, __FILE__, ": Absolute time set, but we're in the past. Skipping. ($now < $then)" if ($::DEBUG & 0x40);
224 # We're up to date. $TimeNewest needs to be set accordingly..
225 elsif ($AbsoluteTime != $newest)
229 my $time = localtime ($AbsoluteTime);
230 print STDERR $/, __FILE__, ": Updating. Newest time is now ``$time''";
233 $newest = $AbsoluteTime;
234 $TimeNewest->put ($CurFile, $newest);
240 =head2 add_relative_time ($hour, $min);
242 This routine does two different things, depending on wether or not the
243 absolute time is known.
245 If the absolute time is not known, it will add up the seconds since the
246 start of the file. When we know the absolute time later we can subtract
247 that value to get the absolute time of the beginning of the file.
249 If the absolute time is known it simply adds to it to keep it up to date.
253 sub add_relative_time
255 my $this_hour = shift;
256 my $this_minute = shift;
258 my $this_seconds = ($this_hour * 3600) + ($this_minute * 60);
260 if ((defined ($TimeData->{'LastHourSeen'}))
261 and (defined ($TimeData->{'LastMinuteSeen'})))
264 my $last_hour = $TimeData->{'LastHourSeen'};
265 my $last_minute = $TimeData->{'LastMinuteSeen'};
266 my $last_seconds = ($last_hour * 3600) + ($last_minute * 60);
268 if ($last_seconds > $this_seconds)
270 $this_seconds += 86400; # one day
273 $diff = $this_seconds - $last_seconds;
277 print STDERR $/, __FILE__, ': ';
278 printf STDERR ("diff ('%02u:%02u', '%02u:%02u') = %u seconds",
279 $last_hour, $last_minute,
280 $this_hour, $this_minute,
284 # FIXME needs testing!
287 $TimeData->{'Duration'} += $diff;
291 $AbsoluteTime += $diff;
295 $TimeData->{'LastHourSeen'} = $this_hour;
296 $TimeData->{'LastMinuteSeen'} = $this_minute;
299 =head2 set_absolute_time ($year, $month, $day, $hour, $min, $sec);
301 As the name suggests this routine sets the absolute time.
305 sub set_absolute_time
316 my $time = timelocal ($sec, $min, $hour, $day, $month, $year);
317 print STDERR $/, __FILE__, ": Set absolute time to ", scalar (localtime ($time)) if ($::DEBUG & 0x40);
319 # Add diff if this is the first
322 add_relative_time ($hour, $min);
327 $TimeData->{'LastHourSeen'} = $hour;
328 $TimeData->{'LastMinuteSeen'} = $min;
331 $AbsoluteTime = $time;
334 sub get_absolute_time
336 return ($AbsoluteTime);
341 Resets the internal counters to be ready for another file.
349 my ($time) = $TimeNewest->get ($inode);
351 $TimeNewest->put ($inode, $time);
354 $TimeData->{'Duration'} = 0;
355 $TimeData->{'NeedsRewind'} = 1;
356 $TimeData->{'Seeking'} = 1;
357 delete ($TimeData->{'LastHourSeen'});
358 delete ($TimeData->{'LastMinuteSeen'});