File Coverage

blib/lib/CAD/Drawing/IO/Split.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package CAD::Drawing::IO::Split;
2             our $VERSION = '0.02';
3              
4 1     1   1595 use CAD::Drawing;
  0            
  0            
5             use CAD::Drawing::Defined;
6              
7             use warnings;
8             use strict;
9             use Carp;
10              
11             my $dbg = 0;
12              
13             =pod
14              
15             =head1 NAME
16              
17             CAD::Drawing::IO::Split - Fast distributed text file methods.
18              
19             =head1 AUTHOR
20              
21             Eric L. Wilhelm
22              
23             http://scratchcomputing.com
24              
25             =head1 COPYRIGHT
26              
27             This module is copyright (C) 2004-2006 by Eric L. Wilhelm. Portions
28             copyright (C) 2003 by Eric L. Wilhelm and A. Zahner Co.
29              
30             =head1 LICENSE
31              
32             This module is distributed under the same terms as Perl. See the Perl
33             source package for details.
34              
35             You may use this software under one of the following licenses:
36              
37             (1) GNU General Public License
38             (found at http://www.gnu.org/copyleft/gpl.html)
39             (2) Artistic License
40             (found at http://www.perl.com/pub/language/misc/Artistic.html)
41              
42             =head1 NO WARRANTY
43              
44             This software is distributed with ABSOLUTELY NO WARRANTY. The author,
45             his former employer, and any other contributors will in no way be held
46             liable for any loss or damages resulting from its use.
47              
48             =head1 Modifications
49              
50             The source code of this module is made freely available and
51             distributable under the GPL or Artistic License. Modifications to and
52             use of this software must adhere to one of these licenses. Changes to
53             the code should be noted as such and this notification (as well as the
54             above copyright information) must remain intact on all copies of the
55             code.
56              
57             Additionally, while the author is actively developing this code,
58             notification of any intended changes or extensions would be most helpful
59             in avoiding repeated work for all parties involved. Please contact the
60             author with any such development plans.
61              
62             =head1 SEE ALSO
63              
64             CAD::Drawing
65             CAD::Drawing::IO
66              
67             =cut
68             ########################################################################
69              
70             =head1 Requisite Plug-in Functions
71              
72             See CAD::Drawing::IO for a description of the plug-in architecture.
73              
74             =cut
75             ########################################################################
76             # the following are required to be a disc I/O plugin:
77             our $can_save_type = "split";
78             our $can_load_type = $can_save_type;
79             our $is_inherited = 1;
80              
81             =head2 check_type
82              
83             Returns true if $type is "split" or $filename is a directory (need a tag?)
84              
85             $fact = check_type($filename, $type);
86              
87             =cut
88             sub check_type {
89             my ($filename, $type) = @_;
90             if(defined($type)) {
91             ($type eq "split") && return("split");
92             return();
93             }
94             elsif((-d $filename) && (0)) { # FIXME: this needs something
95             return("split");
96             }
97             elsif(($filename =~ s/^split://) and (-d $filename)) {
98             return("split");
99             }
100             return();
101             } # end subroutine check_type definition
102             ########################################################################
103              
104             =head1 Load/Save Methods
105              
106             Concept here is to strip data down to the absolute bare minumum in an
107             effort to find a generic and extensible incarnation of same.
108              
109             =cut
110             ########################################################################
111             our %save_functions = (
112             plines => sub {
113             my ($pline, $data) = @_;
114             # note the danger here (loading dwg into existing will
115             # create compounding buildup
116             my $filename = _sp_filename($pline, $data);
117             open(PL, ">$filename") or croak();
118             print PL join(":", map({join(",", @$_)} @{$pline->{pts}})), "\n";
119             print PL "$pline->{color}\n";
120             close(PL);
121             }, # end plines sub
122             lines => sub {
123             my ($line, $data) = @_;
124             $dbg && print "a line!\n";
125             my $filename = _sp_filename($line, $data);
126             open(LN, ">$filename") or croak();
127             print LN join(":", map({join(",", @$_)} @{$line->{pts}})), "\n";
128             print LN "$line->{color}\n";
129             close(LN);
130             },
131             points => sub {
132             my ($point, $data) = @_;
133             # print "a point\n";
134             my $filename = _sp_filename($point, $data);
135             open(PT, ">$filename") or croak();
136             print PT join(",", @{$point->{pt}}), "\n";
137             print PT "$point->{color}\n";
138             close(PT);
139             }, # end points sub
140             circles => sub {
141             my ($circ, $data) = @_;
142             my $filename = _sp_filename($circ, $data);
143             open(CI, ">$filename") or croak();
144             $dbg && print "saving @{$circ->{pt}}\n$circ->{rad}\n$circ->{color}\n";
145             print CI join(",", @{$circ->{pt}}), "\n";
146             print CI "$circ->{rad}\n";
147             print CI "$circ->{color}\n";
148             close(CI);
149             }, # end circs sub
150              
151             ); # end %save_functions
152             ########################################################################
153              
154             =head2 save
155              
156             Saves data into $toplevel_directory under a directory for each layer,
157             each type, and a file for each id.
158              
159             save($drw, $toplevel_directory, \%options);
160              
161             Requires that the directory already exists.
162              
163             Selective saves not yet supported.
164              
165             Unfortunately, the file-formats are rather primitive and the code needs
166             refactoring. These are nowhere near stable, so don't expect version
167             compatibility yet!
168              
169             Needs a clear_all_like => $regex option.
170              
171             =cut
172             sub save{
173             my $dbg = 0;
174             my $self = shift;
175             $dbg && print "here\n";
176             my ($dir, $opt) = @_;
177             $dir =~ s/^split://;
178             (-d $dir) or die "no $dir\n";
179             my %data = (
180             dir => $dir,
181             );
182             $dbg && print "saving out $dir\n";
183             $self->outloop(\%save_functions, \%data);
184             } # end subroutine save definition
185             ########################################################################
186              
187             our %load_functions = (
188             plines => sub {
189             my ($self, $file, $info) = @_;
190             open(PL, $file) or croak();
191             chomp(my $pts = );
192             chomp(my $color = );
193             close(PL);
194             $dbg && print "points: $pts\ncolor:$color\n";
195             my @pts = map({[split(/,/, $_)]} split(/:/, $pts));
196             $self->addpolygon(\@pts, {%$info, color => $color});
197             },
198             lines => sub {
199             my ($self, $file, $info) = @_;
200             open(LN, $file) or croak();
201             chomp(my $pts = );
202             chomp(my $color = );
203             close(LN);
204             $dbg && print "points: $pts\ncolor:$color\n";
205             my @pts = map({[split(/,/, $_)]} split(/:/, $pts));
206             $self->addline(\@pts, {%$info, color => $color});
207             },
208             points => sub {
209             my ($self, $file, $info) = @_;
210             open(PT, $file) or croak();
211             chomp(my $pt = );
212             chomp(my $co = );
213             close(PT);
214             $self->addpoint([split(/,/, $pt)], {%$info, color => $co});
215             },
216             circles => sub {
217             my ($self, $file, $info) = @_;
218             open(CI, $file) or croak();
219             chomp(my $pt = );
220             chomp(my $rad = );
221             chomp(my $co = );
222             close(CI);
223             $self->addcircle([split(/,/, $pt)], $rad, {%$info, color => $co});
224             },
225             );
226              
227             =head2 load
228              
229             load($drw, $toplevel_directory, \%options);
230              
231             %options may include selective-load arguments
232              
233             =cut
234             sub load{
235             my $self = shift;
236             my ($dir, $opts) = @_;
237             $dir =~ s/^split://;
238             (-d $dir) or croak("no such directory: $dir\n");
239             my %opt;
240             (ref($opts) eq "HASH") && (%opt = %$opts);
241             my @layers;
242             my ($s, $n) = check_select(\%opt);
243             if($s->{l}) {
244             @layers = grep({$s->{l}{$_}} _dir_list($dir));
245             }
246             else {
247             @layers = _dir_list($dir);
248             }
249             foreach my $layer (@layers) {
250             my %info = (layer => $layer);
251             foreach my $type (keys(%load_functions)) {
252             $s->{t} && ($s->{t}{$type} || next);
253             $n->{t} && ($n->{t}{$type} && next);
254             my $path = join("/", $dir, $layer, $type);
255             (-d $path) || next;
256             $info{type} = $type;
257             my @ids = _dir_list($path);
258             foreach my $id (@ids) {
259             $info{id} = $id;
260             my $filename = $path . "/" . $id;
261             # hmm. slipping select color / select linetype in here
262             # is tricky
263             $load_functions{$type}->($self, $filename, {%info});
264             }
265             } # end foreach $type
266             } # end foreach $layer
267              
268              
269             } # end subroutine load definition
270             ########################################################################
271              
272             =head1 Naming Functions
273              
274             =cut
275              
276             =head2 _dir_list
277              
278             @list = _dir_list($dir);
279              
280             =cut
281             sub _dir_list {
282             my $dir = shift;
283             opendir(DIR, $dir);
284             my @list = grep(! /^\.+$/, readdir(DIR));
285             closedir(DIR);
286             # print "listed @list\n";exit;
287             return(@list);
288             } # end subroutine _dir_list definition
289             ########################################################################
290              
291             =head2 _sp_filename
292              
293             Creates nested directories which are required to save %obj and returns the filename which should be saved into.
294              
295             _sp_filename(\%obj, \%data);
296              
297             =cut
298             sub _sp_filename {
299             my ($obj, $data) = @_;
300             my @dirs = (
301             $data->{dir},
302             $obj->{addr}{layer},
303             $obj->{addr}{type},
304             );
305             my $filename;
306             foreach my $dir (@dirs) {
307             $filename .= $dir . "/";
308             if(-d $filename) {
309             $dbg && print "$filename exists\n";
310             next;
311             }
312             (-e $filename) and
313             croak("$filename exists, but is not a directory");
314             $dbg && print "making $filename\n";
315             mkdir($filename);
316             }
317             $filename .= $obj->{addr}{id};
318             $dbg && print "filename to be $filename\n";#exit;
319             return($filename);
320             } # end subroutine _sp_filename definition
321             ########################################################################
322              
323             =head1 Inherited Methods
324              
325             =cut
326              
327             =head2 clear_dir
328              
329             Removes layers (and items) from the split directory $dir.
330              
331             Defaults to removing all.
332              
333             $drw->clear_dir($dir, \%options);
334              
335             =over
336              
337             =item Available options:
338              
339             like => qr/regex/, # if regex matches layer name
340             not_like => qr/regex/, # negative of above (compounded)
341              
342             =item check_select() options:
343              
344             %options is passed through CAD::Drawing::Defined::check_select(), so the selections returned by it will be utilized here.
345              
346             select_layers => \@layer_list,
347             select_types => \@types_list,
348              
349             Returns the number of items removed or undef() if $dir does not exist.
350              
351             =back
352              
353             =cut
354             sub clear_dir {
355             my $self = shift;
356             my ($dir, $opts) = @_;
357             $dir =~ s#/*$#/#;
358             my %opt;
359             (ref($opts) eq "HASH") && (%opt = %$opts);
360             my $like = $opt{like};
361             my $notlike = $opt{not_like};
362             my ($s, $n) = check_select(\%opt);
363             (-d $dir) or return();
364             my @kill_layers = _dir_list($dir);
365             if($like) {
366             (ref($like) eq "Regexp") or
367             croak("$like is not a regex");
368             @kill_layers = grep(/$like/, @kill_layers);
369             $dbg && print "now ", scalar(@kill_layers), "\n";
370             }
371             if($notlike) {
372             (ref($notlike) eq "Regexp") or
373             croak("$notlike is not a regex");
374             @kill_layers = grep(! /$notlike/, @kill_layers);
375             $dbg && print "now ", scalar(@kill_layers), "\n";
376             }
377             my $count;
378             foreach my $layer (@kill_layers) {
379             $s->{l} && ($s->{l}{$layer} || next);
380             $n->{l} && ($n->{l}{$layer} && next);
381             my $ldir = $dir . $layer . "/";
382             my @types = _dir_list($ldir);
383             $dbg && print "removing $layer\n";
384             my $tfail = 0;
385             foreach my $type (@types) {
386             $s->{t} && ($s->{t}{$type} || next);
387             $n->{t} && ($n->{t}{$type} && next);
388             $dbg && print "$type\n";
389             my $tdir = $ldir . $type . "/";
390             my @items = _dir_list($tdir);
391             $dbg && print "items: @items\n";
392             my $ifail = 0;
393             foreach my $item (@items) {
394             my $file = $tdir . $item;
395             if(unlink($file)) {
396             $count ++;
397             }
398             else {
399             carp("unlink failed on $file");
400             $ifail++;
401             }
402             }
403             unless($ifail) {
404             unless(rmdir($tdir)) {
405             carp("rmdir failed on $tdir");
406             $tfail++;
407             }
408             }
409             } # end foreach $type
410             unless($tfail) {
411             unless(rmdir($ldir)) {
412             carp("rmdir failed on $ldir");
413             }
414             }
415             }
416              
417             return($count);
418              
419             } # end subroutine clear_dir definition
420             ########################################################################
421              
422              
423              
424             1;