line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Mozilla::Mork; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
#use 5.008004; |
4
|
|
|
|
|
|
|
#use strict; |
5
|
1
|
|
|
1
|
|
21376
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2297
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
require Exporter; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
# Items to export into callers namespace by default. Note: do not export |
12
|
|
|
|
|
|
|
# names by default without a very good reason. Use EXPORT_OK instead. |
13
|
|
|
|
|
|
|
# Do not simply export all your public functions/methods/constants. |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
# This allows declaration use Mozilla::Mork ':all'; |
16
|
|
|
|
|
|
|
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK |
17
|
|
|
|
|
|
|
# will save memory. |
18
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( 'all' => [ qw( |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
) ] ); |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
our @EXPORT = qw( |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
); |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
our $VERSION = '0.01'; |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# Preloaded methods go here. |
32
|
|
|
|
|
|
|
#TODO make private classes of mork munging routines |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
#package mork; |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
##declare variables |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
my ($verbose, $reference, $file); |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
my (%key_table, %val_table, %row_hash); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
my ($total, $skipped) = (0, 0); |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
##initialise variables |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
#set to 0 if you dont want status reports |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
$verbose++; |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
sub new { |
52
|
0
|
|
|
0
|
0
|
|
my $class = shift; # works on @_ by default |
53
|
0
|
|
|
|
|
|
my $file = shift; # If an file has been given to start with |
54
|
0
|
|
|
|
|
|
my $MorkFileInfo = {}; #create a blank hash |
55
|
|
|
|
|
|
|
|
56
|
0
|
|
|
|
|
|
bless $MorkFileInfo, $class; |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
#test that we got the file to parse |
59
|
0
|
0
|
|
|
|
|
unless ($file) { return 0; } |
|
0
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
#set the file name in the hash |
61
|
0
|
|
|
|
|
|
$MorkFileInfo->{'file'} = $file; |
62
|
|
|
|
|
|
|
#get a reference to an array of hash's |
63
|
|
|
|
|
|
|
|
64
|
0
|
|
|
|
|
|
$MorkFileInfo->{'results'} = mork_parse_file($file); |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
|
68
|
0
|
|
|
|
|
|
return $MorkFileInfo; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
################## |
72
|
|
|
|
|
|
|
# ReturnReferenceStructure |
73
|
|
|
|
|
|
|
# returns the reference to the array containing the hash's of the data |
74
|
|
|
|
|
|
|
################## |
75
|
|
|
|
|
|
|
sub ReturnReferenceStructure { |
76
|
|
|
|
|
|
|
#get the ojbect refernce to the instance thats calling us |
77
|
0
|
|
|
0
|
0
|
|
my ($obj) = shift; |
78
|
|
|
|
|
|
|
#return the details as requested above |
79
|
0
|
|
|
|
|
|
return $obj->{'results'}; |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
################################ |
83
|
|
|
|
|
|
|
#address book specific test |
84
|
|
|
|
|
|
|
# probably a better way of doing this is writing a package that inherits |
85
|
|
|
|
|
|
|
# the Mork class and then does this, but for now.. |
86
|
|
|
|
|
|
|
#TODO AddressBookTestPrint probably doen't work - test and fix |
87
|
|
|
|
|
|
|
#TODO implement AddressBookTestPrint as a inherited module from Morkto Mork::AddressBook |
88
|
|
|
|
|
|
|
################################ |
89
|
|
|
|
|
|
|
sub AddressBookTestPrint { |
90
|
0
|
|
|
0
|
0
|
|
my ($obj) = shift; |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
#get the first hash of results from the parse |
93
|
0
|
|
0
|
|
|
|
my %array = %{ $obj->{'results'}->[0] } |
94
|
|
|
|
|
|
|
|| die "constructor not initialised in Mork.pm. Did you call mork->new()?\n"; |
95
|
|
|
|
|
|
|
#construct an array of just the keys of the hash |
96
|
|
|
|
|
|
|
|
97
|
0
|
|
|
|
|
|
my @field_names = sort(keys(%array)); |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
#print each of the field headers |
100
|
0
|
|
|
|
|
|
map { print "Field Names: $_\n"; } @field_names; |
|
0
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
#test print a couple of values |
103
|
0
|
|
|
|
|
|
print "Record Number 0's First Name is: $array{\"FirstName\"}\n"; |
104
|
0
|
|
|
|
|
|
print "Record Number 0's Email is: $array{\"PrimaryEmail\"}\n"; |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
########################## |
108
|
|
|
|
|
|
|
# dumps the record headers |
109
|
|
|
|
|
|
|
# returns an array of the record headers |
110
|
|
|
|
|
|
|
# assumes that the first record contains all the headers |
111
|
|
|
|
|
|
|
# so far this assumption has proved true |
112
|
|
|
|
|
|
|
########################## |
113
|
|
|
|
|
|
|
sub ListHeaders |
114
|
|
|
|
|
|
|
{ |
115
|
0
|
|
|
0
|
0
|
|
my ($obj) = shift; |
116
|
|
|
|
|
|
|
#get the first hash of results from the parse |
117
|
|
|
|
|
|
|
#having problems with dereferncing, so.. |
118
|
0
|
|
0
|
|
|
|
my $results = $obj->{'results'} |
119
|
|
|
|
|
|
|
|| die "constructor not initialised in Mork.pm. Did you call mork->new()?\n"; |
120
|
|
|
|
|
|
|
|
121
|
0
|
|
|
|
|
|
my @field_names = sort(keys( %{$results->[0]} )); |
|
0
|
|
|
|
|
|
|
122
|
0
|
|
|
|
|
|
return @field_names; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
########################## |
126
|
|
|
|
|
|
|
# Returns a reference to an array of hashes, the contents of the mork file. |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
# expects filename to process ($file) |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
########################## |
131
|
|
|
|
|
|
|
sub mork_parse_file |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
{ |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
#my ($obj) = shift; #dont need to do this for internal (private class methods) |
136
|
|
|
|
|
|
|
#get the filename |
137
|
|
|
|
|
|
|
|
138
|
0
|
|
|
0
|
0
|
|
my ($file) = shift; |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
#stream the file (gulp all in one go, not iterate over each line) |
141
|
|
|
|
|
|
|
|
142
|
0
|
|
|
|
|
|
local $/ = undef; |
143
|
|
|
|
|
|
|
|
144
|
0
|
|
|
|
|
|
local *IN; |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
########################################################################## |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
# Define the messy regexen up here |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
########################################################################## |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
|
156
|
0
|
|
|
|
|
|
my $top_level_comment = qr@//.*\n@; |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
|
160
|
0
|
|
|
|
|
|
my $key_table_re = qr/ < \s* < # "< <" |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
\( a=c \) > # "(a=c)>" |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
(?> ([^>]*) ) > \s* # Grab anything that's not ">" |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
/sx; |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
|
170
|
0
|
|
|
|
|
|
my $value_table_re = qr/ < ( .*?\) )> \s* /sx; |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
|
174
|
0
|
|
|
|
|
|
my $table_re = qr/ \{ -? # "{" or "{-" |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
[\da-f]+ : # hex, ":" |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
(?> .*?\{ ) # Eat up to a {... |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
((?> .*?\} ) # and then the closing }... |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
(?> .*?\} )) # Finally, grab the table section |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
\s* /six; |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
|
188
|
0
|
|
|
|
|
|
my $row_re = qr/ ( (?> \[ [^]]* \] # "["..."]" |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
\s*)+ ) # Perhaps repeated many times |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
/sx; |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
|
196
|
0
|
|
|
|
|
|
my $section_begin_re = qr/ \@\$\$\{ # "@$${" |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
([\dA-F]+) # hex |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
\{\@ \s* # "{@" |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
/six; |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
|
206
|
0
|
|
|
|
|
|
my $section_end_re = undef; |
207
|
|
|
|
|
|
|
|
208
|
0
|
|
|
|
|
|
my $section = "top level"; |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
########################################################################## |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
# Read in the file. |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
########################################################################## |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
#open (IN, "<$file") || error ("$file: $!") || die "Cannot open $file: $!\n"; |
219
|
|
|
|
|
|
|
|
220
|
0
|
0
|
|
|
|
|
open (IN, "<$file") || die "Cannot open $file: $!\n"; |
221
|
0
|
0
|
|
|
|
|
print STDERR "$0: reading $file...\n" if ($verbose); |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
|
225
|
0
|
|
|
|
|
|
my $body = ; |
226
|
|
|
|
|
|
|
|
227
|
0
|
|
|
|
|
|
close IN; |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
|
231
|
0
|
|
|
|
|
|
$body =~ s/\r\n/\n/gs; # Windows Mozilla uses \r\n |
232
|
|
|
|
|
|
|
|
233
|
0
|
|
|
|
|
|
$body =~ s/\r/\n/gs; # Presumably Mac Mozilla is similarly dumb |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
|
237
|
0
|
|
|
|
|
|
$body =~ s/\\\\/\$5C/gs; # Sometimes backslash is quoted with a |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
# backslash; convert to hex. |
240
|
|
|
|
|
|
|
|
241
|
0
|
|
|
|
|
|
$body =~ s/\\\)/\$29/gs; # close-paren is quoted with a backslash; |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
# convert to hex. |
244
|
|
|
|
|
|
|
|
245
|
0
|
|
|
|
|
|
$body =~ s/\\\n//gs; # backslash at end of line is continuation. |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
########################################################################## |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
# Figure out what we're looking at, and parse it. |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
########################################################################## |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
|
257
|
0
|
0
|
|
|
|
|
print STDERR "$0: $file: parsing...\n" if ($verbose); |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
|
261
|
0
|
|
|
|
|
|
pos($body) = 0; |
262
|
|
|
|
|
|
|
|
263
|
0
|
|
|
|
|
|
my $length = length($body); |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
|
267
|
0
|
|
|
|
|
|
while( pos($body) < $length ) |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
{ |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
# Key table |
274
|
|
|
|
|
|
|
|
275
|
0
|
0
|
0
|
|
|
|
if ( $body =~ m/\G$key_table_re/gc ) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
{ |
278
|
|
|
|
|
|
|
|
279
|
0
|
|
|
|
|
|
mork_parse_key_table($file, $section, $1); |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
# Values |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
} elsif ( $body =~ m/\G$value_table_re/gco ) |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
{ |
288
|
|
|
|
|
|
|
|
289
|
0
|
|
|
|
|
|
mork_parse_value_table($file, $section, $1); |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
# Table |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
} elsif ( $body =~ m/\G$table_re/gco ) |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
{ |
298
|
|
|
|
|
|
|
|
299
|
0
|
|
|
|
|
|
mork_parse_table($file, $section, $age, $since, $1); |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
# Rows (-> table) |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
} elsif ( $body =~ m/\G$row_re/gco ) |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
{ |
308
|
|
|
|
|
|
|
|
309
|
0
|
|
|
|
|
|
mork_parse_table($file, $section, $age, $since, $1); |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
# Section begin |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
} elsif ( $body =~ m/\G$section_begin_re/gco ) |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
{ |
318
|
|
|
|
|
|
|
|
319
|
0
|
|
|
|
|
|
$section = $1; |
320
|
|
|
|
|
|
|
|
321
|
0
|
|
|
|
|
|
$section_end_re = qr/\@\$\$\}$section\}\@\s*/s; |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
# Section end |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
} elsif ( $section_end_re && $body =~ m/\G$section_end_re/gc ) |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
{ |
330
|
|
|
|
|
|
|
|
331
|
0
|
|
|
|
|
|
$section_end_re = undef; |
332
|
|
|
|
|
|
|
|
333
|
0
|
|
|
|
|
|
$section = "top level"; |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
# Comment |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
} elsif ( $body =~ m/\G$top_level_comment/gco ) |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
{ |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
#no-op |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
else |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
{ |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
#$body =~ m/\G (.{0,300}) /gcsx; print "<$1>\n"; |
352
|
|
|
|
|
|
|
|
353
|
0
|
|
|
|
|
|
print("$file: $section: Cannot parse"); |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
}#end of while loop |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
|
361
|
0
|
0
|
|
|
|
|
if($section_end_re) |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
{ |
364
|
|
|
|
|
|
|
|
365
|
0
|
|
|
|
|
|
print("$file: Unterminated section $section"); |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
|
373
|
0
|
0
|
|
|
|
|
print STDERR "$0: $file: sorting...\n" if ($verbose); |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
# my @entries = sort { $b->{LastVisitDate} <=> |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
# $a->{LastVisitDate} } values(%row_hash); |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
|
383
|
0
|
|
|
|
|
|
my @entries = values(%row_hash); |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
|
387
|
0
|
0
|
|
|
|
|
print STDERR |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
"$0: $file: done! ($total total, $skipped skipped)\n" |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
if ($verbose); |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
#reset all variables in the left parenthesis |
396
|
|
|
|
|
|
|
|
397
|
0
|
|
|
|
|
|
(%key_table, %val_table, %row_hash, $total, $skipped) = (); |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
#send a reference to the @entries array back to the calling routine |
402
|
|
|
|
|
|
|
|
403
|
0
|
|
|
|
|
|
return \@entries; |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
} # end of mork_parse_file |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
########################################################################## |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
# parse a row and column table |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
########################################################################## |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
sub mork_parse_table { |
416
|
|
|
|
|
|
|
#my ($obj) = shift; |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
#get the variables from the calling script |
419
|
|
|
|
|
|
|
|
420
|
0
|
|
|
0
|
0
|
|
my($file, $section, $age, $since, $table_part) = (@_); |
421
|
|
|
|
|
|
|
|
422
|
0
|
0
|
|
|
|
|
print STDERR "\n" if ($verbose); |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
# Assumption: no relevant spaces in values in this section |
427
|
|
|
|
|
|
|
|
428
|
0
|
|
|
|
|
|
$table_part =~ s/\s+//g; |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
# print $table_part; #exit(0); |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
#Grab each complete [...] block |
437
|
|
|
|
|
|
|
|
438
|
0
|
|
|
|
|
|
while( $table_part =~ m/\G [^[]* \[ # find a "[" |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
( [^]]+ ) \] # capture up to "]" |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
/gcx ) |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
{ |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
#set $_ to the result of the regex (each complete [...] block) |
447
|
|
|
|
|
|
|
|
448
|
0
|
|
|
|
|
|
$_ = $1; |
449
|
|
|
|
|
|
|
|
450
|
0
|
|
|
|
|
|
my %hash; |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
#break up the table - each line cosists of a $id and the rest are records |
453
|
|
|
|
|
|
|
|
454
|
0
|
|
|
|
|
|
my ($id, @cells) = split (m/[()]+/s); |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
#a long way of saying skip the line if there are no records |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
#in the @cells array |
461
|
|
|
|
|
|
|
|
462
|
0
|
0
|
|
|
|
|
next unless scalar(@cells); |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
# Trim junk |
467
|
|
|
|
|
|
|
|
468
|
0
|
|
|
|
|
|
$id =~ s/^-//; |
469
|
|
|
|
|
|
|
|
470
|
0
|
|
|
|
|
|
$id =~ s/:.*//; |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
#check that the $id number we've been given corresponds |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
# to one we pulled out from the key_table index |
477
|
|
|
|
|
|
|
|
478
|
0
|
0
|
|
|
|
|
if($row_hash{$id}) |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
{ |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
#set %hash to the contents of the anonymous |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
# hash that holds the hash $id |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
# uniquely identifies within %row_hash |
487
|
|
|
|
|
|
|
|
488
|
0
|
|
|
|
|
|
%hash = ( %{$row_hash{$id}} ); |
|
0
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
} #else |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
#{ |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
# the code below is for the history mdb hash, |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
# and not what we want to do here, so I've |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
# shamefully just ommitted it. |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
# %hash = ( 'ID' => $id, |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
#'LastVisitDate' => 0 ); |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
#} |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
#TODO write some code that inserts a default value if there isn't one already |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
#having sorted out the right %hash according to the $id which was the |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
#first record of the line, we now interate through all the others |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
# on the line |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
#another bit of Deep Magic which sorts out the cell, |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
# includes some error checking |
519
|
|
|
|
|
|
|
|
520
|
0
|
|
|
|
|
|
foreach (@cells) |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
{ |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
#if the record is empty, skip |
525
|
|
|
|
|
|
|
|
526
|
0
|
0
|
|
|
|
|
next unless $_; |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
# extract $keyi, $which, $vali from the result of the regexp |
529
|
|
|
|
|
|
|
|
530
|
0
|
|
|
|
|
|
my ($keyi, $which, $vali) = |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
m/^\^ ([-\dA-F]+) |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
([\^=]) |
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
(.*) |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
$/xi; |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
|
542
|
0
|
0
|
|
|
|
|
print ("$file: unparsable cell: $_\n") unless defined ($vali); |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
# If the key isn't in the key table, ignore it |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
# |
549
|
|
|
|
|
|
|
|
550
|
0
|
|
|
|
|
|
my $key = $key_table{$keyi}; |
551
|
|
|
|
|
|
|
|
552
|
0
|
0
|
|
|
|
|
next unless defined($key); |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
#IIRC this is the precurser to map() in perl 5. |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
# perl wizards feel free to correct me.. |
559
|
|
|
|
|
|
|
|
560
|
0
|
0
|
|
|
|
|
my $val = ($which eq '=' |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
? $vali |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
: $val_table{$vali}); |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
#if ($key eq 'LastVisitDate' || $key eq 'FirstVisitDate') |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
#{ |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
#$val = int ($val / 1000000); # we don't need milliseconds.. |
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
#} |
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
#add a hash value of the $val we extracted from the table, |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
# relating to the key $key |
581
|
|
|
|
|
|
|
|
582
|
0
|
|
|
|
|
|
$hash{$key} = $val; |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
#print "$id: $key -> $val\n"; |
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
} |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
# if ($age && ($hash{LastVisitDate} || $since) < $since) |
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
# { |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
# print STDERR "$0: $file: skipping old: " . |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
# # "$hash{LastVisitDate} $hash{URL}\n" |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
# if ($verbose); |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
# |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
# $skipped++; |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
# next; |
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
# } |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
#showing a blatant disregard for preserving the my of |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
#$total, we treat it as an our() |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
#increment the $total counter so that mork_parse_file() |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
#can print its stats of how many |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
# lines its processed |
621
|
|
|
|
|
|
|
|
622
|
0
|
|
|
|
|
|
$total++; |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
#add a reference to the %hash table we just constructed |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
#of the values in this line |
627
|
|
|
|
|
|
|
|
628
|
0
|
|
|
|
|
|
$row_hash{$id} = \%hash; |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
} |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
} |
633
|
|
|
|
|
|
|
#end of mork_parse_tabl() |
634
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
########################################################################## |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
# parse a values table |
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
########################################################################## |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
sub mork_parse_value_table { |
645
|
|
|
|
|
|
|
#my ($obj) = shift; |
646
|
|
|
|
|
|
|
|
647
|
0
|
|
|
0
|
0
|
|
my($file, $section, $val_part) = (@_); |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
|
651
|
0
|
0
|
|
|
|
|
return unless $val_part; |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
|
655
|
0
|
|
|
|
|
|
my @pairs = split (m/\(([^\)]+)\)/, $val_part); |
656
|
|
|
|
|
|
|
|
657
|
0
|
|
|
|
|
|
$val_part = undef; |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
|
661
|
0
|
0
|
|
|
|
|
print STDERR "\n" if ($verbose > 3); |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
|
665
|
0
|
|
|
|
|
|
foreach (@pairs) { |
666
|
|
|
|
|
|
|
|
667
|
0
|
0
|
|
|
|
|
next unless (m/[^\s]/s); |
668
|
|
|
|
|
|
|
|
669
|
0
|
|
|
|
|
|
my ($key, $val) = m/([\dA-F]*)[\t\n ]*=[\t\n ]*(.*)/i; |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
|
673
|
0
|
0
|
|
|
|
|
if (! defined ($val)) { |
674
|
|
|
|
|
|
|
|
675
|
0
|
|
|
|
|
|
print STDERR "$0: $file: $section: unparsable val: $_\n"; |
676
|
|
|
|
|
|
|
|
677
|
0
|
|
|
|
|
|
next; |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
} |
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
# Assume that records are never hexilated; so |
684
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
# don't bother unhexilating if we won't be using Name, etc. |
686
|
|
|
|
|
|
|
|
687
|
0
|
0
|
|
|
|
|
if($val =~ m/\$/) { |
688
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
# Approximate wchar_t -> ASCII and remove NULs |
690
|
|
|
|
|
|
|
|
691
|
0
|
|
|
|
|
|
$val =~ s/\$00//g; # faster if we remove these first |
692
|
|
|
|
|
|
|
|
693
|
0
|
|
|
|
|
|
$val =~ s/\$([\dA-F]{2})/chr(hex($1))/ge; |
|
0
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
} |
696
|
|
|
|
|
|
|
|
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
|
699
|
0
|
|
|
|
|
|
$val_table{$key} = $val; |
700
|
|
|
|
|
|
|
|
701
|
0
|
0
|
|
|
|
|
print STDERR "$0: $file: $section: val $key = \"$val\"\n" |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
if ($verbose > 3); |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
} |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
} #end of mork_parse_value_table |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
########################################################################## |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
# parse a key table |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
########################################################################## |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
sub mork_parse_key_table { |
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
#my ($obj) = shift; |
723
|
0
|
|
|
0
|
0
|
|
my ($file, $section, $key_table) = (@_); |
724
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
|
727
|
0
|
0
|
|
|
|
|
print STDERR "\n" if ($verbose > 3); |
728
|
|
|
|
|
|
|
|
729
|
0
|
|
|
|
|
|
$key_table =~ s@\s+//.*$@@gm; |
730
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
|
733
|
0
|
|
|
|
|
|
my @pairs = split (m/\(([^\)]+)\)/s, $key_table); |
734
|
|
|
|
|
|
|
|
735
|
0
|
|
|
|
|
|
$key_table = undef; |
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
|
739
|
0
|
|
|
|
|
|
foreach (@pairs) { |
740
|
|
|
|
|
|
|
|
741
|
0
|
0
|
|
|
|
|
next unless (m/[^\s]/s); |
742
|
|
|
|
|
|
|
|
743
|
0
|
|
|
|
|
|
my ($key, $val) = m/([\dA-F]+)\s*=\s*(.*)/i; |
744
|
|
|
|
|
|
|
|
745
|
0
|
0
|
|
|
|
|
error ("$file: $section: unparsable key: $_") unless defined ($val); |
746
|
|
|
|
|
|
|
|
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
## If we're only emitting URLs and dates, don't even bother |
750
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
## saving the other fields that we aren't interested in. |
752
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
## |
754
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
#next if (!$show_all_p && |
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
# $val ne 'URL' && $val ne 'LastVisitDate' && |
758
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
# $val ne 'VisitCount'); |
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
|
763
|
0
|
|
|
|
|
|
$key_table{$key} = $val; |
764
|
|
|
|
|
|
|
|
765
|
0
|
0
|
|
|
|
|
print STDERR "$0: $file: $section: key $key = \"$val\"\n" |
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
if ($verbose > 3); |
768
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
} |
770
|
|
|
|
|
|
|
|
771
|
|
|
|
|
|
|
} |
772
|
|
|
|
|
|
|
#end of mork_parse_key_table() |
773
|
|
|
|
|
|
|
|
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
1; |
776
|
|
|
|
|
|
|
__END__ |