OLD | NEW |
| (Empty) |
1 # Copyright © 2007-2009 Raphaël Hertzog <hertzog@debian.org> | |
2 # | |
3 # This program is free software; you can redistribute it and/or modify | |
4 # it under the terms of the GNU General Public License as published by | |
5 # the Free Software Foundation; either version 2 of the License, or | |
6 # (at your option) any later version. | |
7 # | |
8 # This program is distributed in the hope that it will be useful, | |
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 # GNU General Public License for more details. | |
12 # | |
13 # You should have received a copy of the GNU General Public License | |
14 # along with this program. If not, see <https://www.gnu.org/licenses/>. | |
15 | |
16 package Dpkg::Control::HashCore; | |
17 | |
18 use strict; | |
19 use warnings; | |
20 | |
21 our $VERSION = '1.01'; | |
22 | |
23 use Dpkg::Gettext; | |
24 use Dpkg::ErrorHandling; | |
25 use Dpkg::Control::FieldsCore; | |
26 | |
27 # This module cannot use Dpkg::Control::Fields, because that one makes use | |
28 # of Dpkg::Vendor which at the same time uses this module, which would turn | |
29 # into a compilation error. We can use Dpkg::Control::FieldsCore instead. | |
30 | |
31 use parent qw(Dpkg::Interface::Storable); | |
32 | |
33 use overload | |
34 '%{}' => sub { ${$_[0]}->{fields} }, | |
35 'eq' => sub { "$_[0]" eq "$_[1]" }; | |
36 | |
37 =encoding utf8 | |
38 | |
39 =head1 NAME | |
40 | |
41 Dpkg::Control::HashCore - parse and manipulate a block of RFC822-like fields | |
42 | |
43 =head1 DESCRIPTION | |
44 | |
45 The Dpkg::Control::Hash object is a hash-like representation of a set of | |
46 RFC822-like fields. The fields names are case insensitive and are always | |
47 capitalized the same when output (see field_capitalize function in | |
48 Dpkg::Control::Fields). | |
49 The order in which fields have been set is remembered and is used | |
50 to be able to dump back the same content. The output order can also be | |
51 overridden if needed. | |
52 | |
53 You can store arbitrary values in the hash, they will always be properly | |
54 escaped in the output to conform to the syntax of control files. This is | |
55 relevant mainly for multilines values: while the first line is always output | |
56 unchanged directly after the field name, supplementary lines are | |
57 modified. Empty lines and lines containing only dots are prefixed with | |
58 " ." (space + dot) while other lines are prefixed with a single space. | |
59 | |
60 During parsing, trailing spaces are stripped on all lines while leading | |
61 spaces are stripped only on the first line of each field. | |
62 | |
63 =head1 FUNCTIONS | |
64 | |
65 =over 4 | |
66 | |
67 =item my $c = Dpkg::Control::Hash->new(%opts) | |
68 | |
69 Creates a new object with the indicated options. Supported options | |
70 are: | |
71 | |
72 =over 8 | |
73 | |
74 =item allow_pgp | |
75 | |
76 Configures the parser to accept PGP signatures around the control | |
77 information. Value can be 0 (default) or 1. | |
78 | |
79 =item allow_duplicate | |
80 | |
81 Configures the parser to allow duplicate fields in the control | |
82 information. Value can be 0 (default) or 1. | |
83 | |
84 =item drop_empty | |
85 | |
86 Defines if empty fields are dropped during the output. Value can be 0 | |
87 (default) or 1. | |
88 | |
89 =item name | |
90 | |
91 The user friendly name of the information stored in the object. It might | |
92 be used in some error messages or warnings. A default name might be set | |
93 depending on the type. | |
94 | |
95 =back | |
96 | |
97 =cut | |
98 | |
99 sub new { | |
100 my ($this, %opts) = @_; | |
101 my $class = ref($this) || $this; | |
102 | |
103 # Object is a scalar reference and not a hash ref to avoid | |
104 # infinite recursion due to overloading hash-derefencing | |
105 my $self = \{ | |
106 in_order => [], | |
107 out_order => [], | |
108 is_pgp_signed => 0, | |
109 allow_pgp => 0, | |
110 allow_duplicate => 0, | |
111 drop_empty => 0, | |
112 }; | |
113 bless $self, $class; | |
114 | |
115 $$self->{fields} = Dpkg::Control::HashCore::Tie->new($self); | |
116 | |
117 # Options set by the user override default values | |
118 $$self->{$_} = $opts{$_} foreach keys %opts; | |
119 | |
120 return $self; | |
121 } | |
122 | |
123 # There is naturally a circular reference between the tied hash and its | |
124 # containing object. Happily, the extra layer of scalar reference can | |
125 # be used to detect the destruction of the object and break the loop so | |
126 # that everything gets garbage-collected. | |
127 | |
128 sub DESTROY { | |
129 my ($self) = @_; | |
130 delete $$self->{fields}; | |
131 } | |
132 | |
133 =item $c->set_options($option, %opts) | |
134 | |
135 Changes the value of one or more options. | |
136 | |
137 =cut | |
138 | |
139 sub set_options { | |
140 my ($self, %opts) = @_; | |
141 $$self->{$_} = $opts{$_} foreach keys %opts; | |
142 } | |
143 | |
144 =item my $value = $c->get_option($option) | |
145 | |
146 Returns the value of the corresponding option. | |
147 | |
148 =cut | |
149 | |
150 sub get_option { | |
151 my ($self, $k) = @_; | |
152 return $$self->{$k}; | |
153 } | |
154 | |
155 =item $c->load($file) | |
156 | |
157 Parse the content of $file. Exits in case of errors. Returns true if some | |
158 fields have been parsed. | |
159 | |
160 =item $c->parse_error($file, $fmt, ...) | |
161 | |
162 Prints an error message and dies on syntax parse errors. | |
163 | |
164 =cut | |
165 | |
166 sub parse_error { | |
167 my ($self, $file, $msg) = (shift, shift, shift); | |
168 | |
169 $msg = sprintf($msg, @_) if (@_); | |
170 error(_g('syntax error in %s at line %d: %s'), $file, $., $msg); | |
171 } | |
172 | |
173 =item $c->parse($fh, $description) | |
174 | |
175 Parse a control file from the given filehandle. Exits in case of errors. | |
176 $description is used to describe the filehandle, ideally it's a filename | |
177 or a description of where the data comes from. It's used in error | |
178 messages. Returns true if some fields have been parsed. | |
179 | |
180 =cut | |
181 | |
182 sub parse { | |
183 my ($self, $fh, $desc) = @_; | |
184 | |
185 my $paraborder = 1; | |
186 my $parabody = 0; | |
187 my $cf; # Current field | |
188 my $expect_pgp_sig = 0; | |
189 | |
190 while (<$fh>) { | |
191 chomp; | |
192 next if m/^\s*$/ and $paraborder; | |
193 next if (m/^#/); | |
194 $paraborder = 0; | |
195 if (m/^(\S+?)\s*:\s*(.*)$/) { | |
196 $parabody = 1; | |
197 if ($1 =~ m/^-/) { | |
198 $self->parse_error($desc, _g('field cannot start with a hyphen')
); | |
199 } | |
200 my ($name, $value) = ($1, $2); | |
201 if (exists $self->{$name}) { | |
202 unless ($$self->{allow_duplicate}) { | |
203 $self->parse_error($desc, _g('duplicate field %s found'), $n
ame); | |
204 } | |
205 } | |
206 $value =~ s/\s*$//; | |
207 $self->{$name} = $value; | |
208 $cf = $name; | |
209 } elsif (m/^\s(\s*\S.*)$/) { | |
210 my $line = $1; | |
211 unless (defined($cf)) { | |
212 $self->parse_error($desc, _g('continued value line not in field'
)); | |
213 } | |
214 if ($line =~ /^\.+$/) { | |
215 $line = substr $line, 1; | |
216 } | |
217 $line =~ s/\s*$//; | |
218 $self->{$cf} .= "\n$line"; | |
219 } elsif (m/^-----BEGIN PGP SIGNED MESSAGE-----[\r\t ]*$/) { | |
220 $expect_pgp_sig = 1; | |
221 if ($$self->{allow_pgp} and not $parabody) { | |
222 # Skip PGP headers | |
223 while (<$fh>) { | |
224 last if m/^\s*$/; | |
225 } | |
226 } else { | |
227 $self->parse_error($desc, _g('PGP signature not allowed here')); | |
228 } | |
229 } elsif (m/^\s*$/ || | |
230 ($expect_pgp_sig && m/^-----BEGIN PGP SIGNATURE-----[\r\t ]*$/)
) { | |
231 if ($expect_pgp_sig) { | |
232 # Skip empty lines | |
233 $_ = <$fh> while defined($_) && $_ =~ /^\s*$/; | |
234 unless (length $_) { | |
235 $self->parse_error($desc, _g('expected PGP signature, ' . | |
236 'found EOF after blank line')); | |
237 } | |
238 chomp; | |
239 unless (m/^-----BEGIN PGP SIGNATURE-----[\r\t ]*$/) { | |
240 $self->parse_error($desc, _g('expected PGP signature, ' . | |
241 "found something else \`%s'"),
$_); | |
242 } | |
243 # Skip PGP signature | |
244 while (<$fh>) { | |
245 chomp; | |
246 last if m/^-----END PGP SIGNATURE-----[\r\t ]*$/; | |
247 } | |
248 unless (defined($_)) { | |
249 $self->parse_error($desc, _g('unfinished PGP signature')); | |
250 } | |
251 # This does not mean the signature is correct, that needs to | |
252 # be verified by gnupg. | |
253 $$self->{is_pgp_signed} = 1; | |
254 } | |
255 last; # Finished parsing one block | |
256 } else { | |
257 $self->parse_error($desc, | |
258 _g('line with unknown format (not field-colon-val
ue)')); | |
259 } | |
260 } | |
261 | |
262 if ($expect_pgp_sig and not $$self->{is_pgp_signed}) { | |
263 $self->parse_error($desc, _g('unfinished PGP signature')); | |
264 } | |
265 | |
266 return defined($cf); | |
267 } | |
268 | |
269 =item $c->find_custom_field($name) | |
270 | |
271 Scan the fields and look for a user specific field whose name matches the | |
272 following regex: /X[SBC]*-$name/i. Return the name of the field found or | |
273 undef if nothing has been found. | |
274 | |
275 =cut | |
276 | |
277 sub find_custom_field { | |
278 my ($self, $name) = @_; | |
279 foreach my $key (keys %$self) { | |
280 return $key if $key =~ /^X[SBC]*-\Q$name\E$/i; | |
281 } | |
282 return; | |
283 } | |
284 | |
285 =item $c->get_custom_field($name) | |
286 | |
287 Identify a user field and retrieve its value. | |
288 | |
289 =cut | |
290 | |
291 sub get_custom_field { | |
292 my ($self, $name) = @_; | |
293 my $key = $self->find_custom_field($name); | |
294 return $self->{$key} if defined $key; | |
295 return; | |
296 } | |
297 | |
298 =item $c->save($filename) | |
299 | |
300 Write the string representation of the control information to a | |
301 file. | |
302 | |
303 =item my $str = $c->output() | |
304 | |
305 =item "$c" | |
306 | |
307 Get a string representation of the control information. The fields | |
308 are sorted in the order in which they have been read or set except | |
309 if the order has been overridden with set_output_order(). | |
310 | |
311 =item $c->output($fh) | |
312 | |
313 Print the string representation of the control information to a | |
314 filehandle. | |
315 | |
316 =cut | |
317 | |
318 sub output { | |
319 my ($self, $fh) = @_; | |
320 my $str = ''; | |
321 my @keys; | |
322 if (@{$$self->{out_order}}) { | |
323 my $i = 1; | |
324 my $imp = {}; | |
325 $imp->{$_} = $i++ foreach @{$$self->{out_order}}; | |
326 @keys = sort { | |
327 if (defined $imp->{$a} && defined $imp->{$b}) { | |
328 $imp->{$a} <=> $imp->{$b}; | |
329 } elsif (defined($imp->{$a})) { | |
330 -1; | |
331 } elsif (defined($imp->{$b})) { | |
332 1; | |
333 } else { | |
334 $a cmp $b; | |
335 } | |
336 } keys %$self; | |
337 } else { | |
338 @keys = @{$$self->{in_order}}; | |
339 } | |
340 | |
341 foreach my $key (@keys) { | |
342 if (exists $self->{$key}) { | |
343 my $value = $self->{$key}; | |
344 # Skip whitespace-only fields | |
345 next if $$self->{drop_empty} and $value !~ m/\S/; | |
346 # Escape data to follow control file syntax | |
347 my @lines = split(/\n/, $value); | |
348 $value = (scalar @lines) ? shift @lines : ''; | |
349 foreach (@lines) { | |
350 s/\s+$//; | |
351 if (/^$/ or /^\.+$/) { | |
352 $value .= "\n .$_"; | |
353 } else { | |
354 $value .= "\n $_"; | |
355 } | |
356 } | |
357 # Print it out | |
358 if ($fh) { | |
359 print { $fh } "$key: $value\n" | |
360 or syserr(_g('write error on control data')); | |
361 } | |
362 $str .= "$key: $value\n" if defined wantarray; | |
363 } | |
364 } | |
365 return $str; | |
366 } | |
367 | |
368 =item $c->set_output_order(@fields) | |
369 | |
370 Define the order in which fields will be displayed in the output() method. | |
371 | |
372 =cut | |
373 | |
374 sub set_output_order { | |
375 my ($self, @fields) = @_; | |
376 | |
377 $$self->{out_order} = [@fields]; | |
378 } | |
379 | |
380 =item $c->apply_substvars($substvars) | |
381 | |
382 Update all fields by replacing the variables references with | |
383 the corresponding value stored in the Dpkg::Substvars object. | |
384 | |
385 =cut | |
386 | |
387 sub apply_substvars { | |
388 my ($self, $substvars, %opts) = @_; | |
389 | |
390 # Add substvars to refer to other fields | |
391 foreach my $f (keys %$self) { | |
392 $substvars->set_as_used("F:$f", $self->{$f}); | |
393 } | |
394 | |
395 foreach my $f (keys %$self) { | |
396 my $v = $substvars->substvars($self->{$f}, %opts); | |
397 if ($v ne $self->{$f}) { | |
398 my $sep; | |
399 | |
400 $sep = field_get_sep_type($f); | |
401 | |
402 # If we replaced stuff, ensure we're not breaking | |
403 # a dependency field by introducing empty lines, or multiple | |
404 # commas | |
405 | |
406 if ($sep & (FIELD_SEP_COMMA | FIELD_SEP_LINE)) { | |
407 # Drop empty/whitespace-only lines | |
408 $v =~ s/\n[ \t]*(\n|$)/$1/; | |
409 } | |
410 | |
411 if ($sep & FIELD_SEP_COMMA) { | |
412 $v =~ s/,[\s,]*,/,/g; | |
413 $v =~ s/^\s*,\s*//; | |
414 $v =~ s/\s*,\s*$//; | |
415 } | |
416 } | |
417 $v =~ s/\$\{\}/\$/g; # XXX: what for? | |
418 | |
419 $self->{$f} = $v; | |
420 } | |
421 } | |
422 | |
423 package Dpkg::Control::HashCore::Tie; | |
424 | |
425 # This object is used to tie a hash. It implements hash-like functions by | |
426 # normalizing the name of fields received in keys (using | |
427 # Dpkg::Control::Fields::field_capitalize). It also stores the order in | |
428 # which fields have been added in order to be able to dump them in the | |
429 # same order. But the order information is stored in a parent object of | |
430 # type Dpkg::Control. | |
431 | |
432 use Dpkg::Checksums; | |
433 use Dpkg::Control::FieldsCore; | |
434 | |
435 use Carp; | |
436 use Tie::Hash; | |
437 use parent -norequire, qw(Tie::ExtraHash); | |
438 | |
439 # $self->[0] is the real hash | |
440 # $self->[1] is a reference to the hash contained by the parent object. | |
441 # This reference bypasses the top-level scalar reference of a | |
442 # Dpkg::Control::Hash, hence ensuring that that reference gets DESTROYed | |
443 # properly. | |
444 | |
445 # Dpkg::Control::Hash->new($parent) | |
446 # | |
447 # Return a reference to a tied hash implementing storage of simple | |
448 # "field: value" mapping as used in many Debian-specific files. | |
449 | |
450 sub new { | |
451 my $class = shift; | |
452 my $hash = {}; | |
453 tie %{$hash}, $class, @_; | |
454 return $hash; | |
455 } | |
456 | |
457 sub TIEHASH { | |
458 my ($class, $parent) = @_; | |
459 croak 'parent object must be Dpkg::Control::Hash' | |
460 if not $parent->isa('Dpkg::Control::HashCore') and | |
461 not $parent->isa('Dpkg::Control::Hash'); | |
462 return bless [ {}, $$parent ], $class; | |
463 } | |
464 | |
465 sub FETCH { | |
466 my ($self, $key) = @_; | |
467 $key = lc($key); | |
468 return $self->[0]->{$key} if exists $self->[0]->{$key}; | |
469 return; | |
470 } | |
471 | |
472 sub STORE { | |
473 my ($self, $key, $value) = @_; | |
474 my $parent = $self->[1]; | |
475 $key = lc($key); | |
476 if (not exists $self->[0]->{$key}) { | |
477 push @{$parent->{in_order}}, field_capitalize($key); | |
478 } | |
479 $self->[0]->{$key} = $value; | |
480 } | |
481 | |
482 sub EXISTS { | |
483 my ($self, $key) = @_; | |
484 $key = lc($key); | |
485 return exists $self->[0]->{$key}; | |
486 } | |
487 | |
488 sub DELETE { | |
489 my ($self, $key) = @_; | |
490 my $parent = $self->[1]; | |
491 my $in_order = $parent->{in_order}; | |
492 $key = lc($key); | |
493 if (exists $self->[0]->{$key}) { | |
494 delete $self->[0]->{$key}; | |
495 @$in_order = grep { lc($_) ne $key } @$in_order; | |
496 return 1; | |
497 } else { | |
498 return 0; | |
499 } | |
500 } | |
501 | |
502 sub FIRSTKEY { | |
503 my $self = shift; | |
504 my $parent = $self->[1]; | |
505 foreach (@{$parent->{in_order}}) { | |
506 return $_ if exists $self->[0]->{lc($_)}; | |
507 } | |
508 } | |
509 | |
510 sub NEXTKEY { | |
511 my ($self, $last) = @_; | |
512 my $parent = $self->[1]; | |
513 my $found = 0; | |
514 foreach (@{$parent->{in_order}}) { | |
515 if ($found) { | |
516 return $_ if exists $self->[0]->{lc($_)}; | |
517 } else { | |
518 $found = 1 if $_ eq $last; | |
519 } | |
520 } | |
521 return; | |
522 } | |
523 | |
524 1; | |
525 | |
526 =back | |
527 | |
528 =head1 CHANGES | |
529 | |
530 =head2 Version 1.01 | |
531 | |
532 New method: parse_error(). | |
533 | |
534 =head1 AUTHOR | |
535 | |
536 Raphaël Hertzog <hertzog@debian.org>. | |
537 | |
538 =cut | |
539 | |
540 1; | |
OLD | NEW |