/[suikacvs]/messaging/manakai/lib/Message/Field/Path.pm
Suika

Contents of /messaging/manakai/lib/Message/Field/Path.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (show annotations) (download)
Tue Apr 2 11:52:12 2002 UTC (22 years, 8 months ago) by wakaba
Branch: MAIN
2002-04-02  wakaba <w@suika.fam.cx>

	* Path.pm: New module.

1
2 =head1 NAME
3
4 Message::Field::Path Perl module
5
6 =head1 DESCRIPTION
7
8 Perl module for C<Path:> header field.
9
10 =cut
11
12 package Message::Field::Path;
13 use strict;
14 use vars qw(%REG $VERSION);
15 $VERSION=do{my @r=(q$Revision: 1.4 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
16 use overload '@{}' => sub {shift->{path}},
17 '""' => sub {shift->stringify};
18 require Message::Util;
19 use Carp;
20 $REG{WSP} = qr/[\x20\x09]+/;
21 $REG{FWS} = qr/[\x20\x09]*/;
22
23 $REG{delimiter} = qr/[^0-9A-Za-z.:_-]+/;
24 $REG{delimiter_char} = qr#[!%,/?]#;
25 $REG{path_identity} = qr/[0-9A-Za-z.:_-]+/;
26 $REG{NON_delimiter} = qr#[^!%,/?]#;
27 $REG{NON_path_identity} = qr/[^0-9A-Za-z.:_-]/;
28
29 my %DEFAULT = (
30 check_invalid_path_identity => 1,
31 max_line_length => 50,
32 output_obs_delimiter => -1,
33 );
34
35 =head2 Message::Field::Path->new ()
36
37 Returns new instance for Message::Field::Path.
38
39 =cut
40
41 sub new ($;%) {
42 my $self = bless {option => {@_}, path => []}, shift;
43 for (%DEFAULT) {$self->{option}->{$_} ||= $DEFAULT{$_}}
44 $self;
45 }
46
47 =head2 Message::Field::Path->parse ($unfolded-field-body)
48
49 Parses C<field-body> as C<Path> field.
50
51 =cut
52
53 sub parse ($$;%) {
54 my $self = bless {}, shift;
55 my $fbody = shift;
56 my %option = @_;
57 for (%DEFAULT) {$option{$_} ||= $DEFAULT{$_}}
58 $self->{option} = \%option;
59 my @p = ();
60 $fbody =~ s{^$REG{FWS}($REG{path_identity})}{
61 push @p, [$1, ''];
62 '';
63 }ex;
64 $fbody =~ s{($REG{delimiter})($REG{path_identity})}{
65 my ($delimiter, $path_identity) = ($1, $2);
66 $delimiter =~ tr/\x09\x20//d;
67 push @p, [$path_identity, $delimiter];
68 '';
69 }gex;
70 $self->{path} = \@p;
71 $self;
72 }
73
74 =head2 $self->add ($path-identity, [$delimiter], [%options])
75
76 Adds new C<path-identity> and C<delimiter> (optional).
77 Only one option, C<check_invalid_path_identity> is available.
78
79 See also L<EXAMPLE>.
80
81 =cut
82
83 sub add ($$;$%) {
84 my $self = shift;
85 my ($path_identity, $delimiter, %option) = (@_);
86 $option{check_invalid_path_identity}
87 ||= $self->{option}->{check_invalid_path_identity};
88 croak "add: $path_identity: invalid path-identity"
89 if $option{check_invalid_path_identity}>0
90 && $path_identity =~ /$REG{NON_path_identity}/;
91 unshift @{$self->{path}}, [$path_identity, ''];
92 $self->{path}->[1]->[1] = $delimiter if $#{$self->{path}} > 0;
93 $self;
94 }
95
96 =head2 $self->path_identity ($index)
97
98 Returns C<$index>'th C<path-identity>, if any.
99 You can't set value. (Is it necessary?) Use C<add> method
100 to add new C<path-identity>.
101
102 =cut
103
104 sub path_identity ($$) {
105 my $self = shift;
106 my $i = shift;
107 $self->{path}->[$i]->[0] if ref $self->{path}->[$i];
108 }
109
110 =head2 $self->delimiter ($index)
111
112 Returns C<$index>'th C<delimiter>, if any.
113 You can't set new value. (Is it necessary?)
114
115 Note that C<$self-E<gt>delimiter (0)> would return
116 no value in most situation.
117
118 =cut
119
120 sub delimiter ($$) {
121 my $self = shift;
122 my $i = shift;
123 $self->{path}->[$i]->[1] if ref $self->{path}->[$i];
124 }
125
126 sub stringify ($;%) {
127 my $self = shift;
128 my %option = @_;
129 $option{check_invalid_path_identity}
130 ||= $self->{option}->{check_invalid_path_identity};
131 $option{max_line_length} ||= $self->{option}->{max_line_length};
132 $option{output_obs_delimiter} ||= $self->{option}->{output_obs_delimiter};
133 my ($r, $l) = ('', 0);
134 for (@{$self->{path}}) {
135 my ($path_identity, $delimiter) = (${$_}[0], ${$_}[1] || '!');
136 next unless $path_identity;
137 next if $option{check_invalid_path_identity}>0
138 && $path_identity =~ /$REG{NON_path_identity}/;
139 if ($l) {
140 $delimiter = '!' if $option{output_obs_delimiter}<0
141 && $delimiter !~ /^$REG{delimiter_char}$/;
142 if ($option{max_line_length}>0 && $l > $option{max_line_length}) {
143 $delimiter .= ' '; $l = 0;
144 }
145 $r .= $delimiter; $l += length $delimiter;
146 }
147 $r .= $path_identity; $l += length $path_identity;
148 }
149 $r;
150 }
151
152 =head2 $self->option ($option_name, [$option_value])
153
154 Set/gets new value of the option.
155
156 =cut
157
158 sub option ($$;$) {
159 my $self = shift;
160 my ($name, $value) = @_;
161 if (defined $value) {
162 $self->{option}->{$name} = $value;
163 }
164 $self->{option}->{$name};
165 }
166
167 =head1 NOTE
168
169 C<stringify> of this module insert SPACE when C<Path-content>
170 is too long. ("long" is determined by the value of option
171 C<max_line_length>.) This is intended to be able to fold
172 C<Path:> field body. But some of implementions does not support
173 folding this line though article format specifications
174 (except son-of-RFC1036) allow to insert white-space character.
175
176 Implementor shold set value of C<max_line_length> as long as
177 possible. (Default value C<50> can be too small...)
178 When C<max_line_length> is C<-1>, C<stringify> does not
179 insert any white-space characters.
180
181 =head1 EXAMPLE
182
183 use Message::Field::Path;
184
185 ## Parse Path: field-body and print path-identity list.
186 my $path = 'foo.isp.example/foo-server/bar.isp.example?'
187 .'10.123.12.2/old.site.example!barbaz/baz.isp.example'
188 .'%dialup123.baz.isp.example!x';
189 my $p = Message::Field::Path->parse ($path);
190
191 for my $i (0..$#$p) {
192 print $p->delimiter ($i), "\t", $p->path_identity ($i), "\n";
193 }
194
195 ## Compose new Path: header field content. (You won't do
196 ## such stupid operation usually. This is only an example.)
197 my $p = new Message::Field::Path;
198 $p->add ('not-for-mail');
199 $p->add ('spool.foo.example', '!');
200 $p->add ('injecter.foo.example', '%');
201 $p->add ('news.bar.example', '/');
202 $p->add ('news.local.example', '/');
203 print "Path: ", fold ($p), "\n"; ## fold() is assumed as a function to fold
204 # Path: news.local.example/news.bar.example/injecter.foo.example%
205 # spool.foo.example!not-for-mail
206
207 =head1 LICENSE
208
209 Copyright 2002 wakaba E<lt>w@suika.fam.cxE<gt>.
210
211 This program is free software; you can redistribute it and/or modify
212 it under the terms of the GNU General Public License as published by
213 the Free Software Foundation; either version 2 of the License, or
214 (at your option) any later version.
215
216 This program is distributed in the hope that it will be useful,
217 but WITHOUT ANY WARRANTY; without even the implied warranty of
218 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
219 GNU General Public License for more details.
220
221 You should have received a copy of the GNU General Public License
222 along with this program; see the file COPYING. If not, write to
223 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
224 Boston, MA 02111-1307, USA.
225
226 =head1 CHANGE
227
228 See F<ChangeLog>.
229 $Date: 2002/03/31 13:11:55 $
230
231 =cut
232
233 1;

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24