File Coverage

blib/lib/Data/Nested/Multiele.pm
Criterion Covered Total %
statement 522 741 70.4
branch 232 344 67.4
condition 46 81 56.7
subroutine 41 44 93.1
pod 25 25 100.0
total 866 1235 70.1


line stmt bran cond sub pod time code
1             package Data::Nested::Multiele;
2             # Copyright (c) 2007-2010 Sullivan Beck. All rights reserved.
3             # This program is free software; you can redistribute it and/or modify it
4             # under the same terms as Perl itself.
5              
6             ###############################################################################
7             # GLOBAL VARIABLES
8             ###############################################################################
9              
10             ###############################################################################
11             # TODO
12             ###############################################################################
13              
14             ###############################################################################
15              
16             require 5.000;
17 59     59   26596 use strict;
  59         137  
  59         2847  
18 59     59   510 use warnings;
  59         111  
  59         2467  
19 59     59   42152 use YAML::Syck;
  59         82629  
  59         5831  
20 59     59   35453 use Data::Nested;
  59         180  
  59         2483  
21 59     59   350 use Storable qw(dclone);
  59         126  
  59         3925  
22              
23 59     59   358 use vars qw($VERSION);
  59         116  
  59         501853  
24             $VERSION = '3.12';
25              
26             ###############################################################################
27             # BASE METHODS
28             ###############################################################################
29             #
30             # $NDS always refers to a Data::Nested object
31             # $nds always refers to an actual NDS
32             # $ele always refers to an element name/index
33             # $self always refers to a Data::Nested::Multiele object
34              
35             sub new {
36 85     85 1 98495 my(@args) = @_;
37              
38             # Get the Data::Nested object (if any).
39              
40 85         208 my $class = 'Data::Nested::Multiele';
41 85         202 my $NDS = undef;
42              
43 85 50 33     1163 if (@args && ref($args[0]) eq $class) {
    50 33        
44             # $obj = $self->new;
45              
46 0         0 my $self = shift(@args);
47 0         0 $NDS = $self->nds();
48              
49             } elsif (@args && $args[0] eq $class) {
50             # $obj = new Data::Nested::Multiele [NDS];
51              
52 85         183 shift(@args);
53 85 100 66     644 if (@args && ref($args[0]) eq 'Data::Nested') {
54 54         111 $NDS = shift(@args);
55             } else {
56 31         334 $NDS = new Data::Nested;
57             }
58              
59             } else {
60 0         0 warn "ERROR: [new] first argument must be a $class class/object\n";
61 0         0 return undef;
62             }
63              
64             # Get the file (if any)
65              
66 85         226 my $file = '';
67 85 100       288 if (@args) {
68 54         105 $file = shift(@args);
69             }
70              
71             # Get the ordered argument (if any).
72              
73 85         163 my $ordered = 0;
74 85 100       272 if ($file) {
75 54 50 33     259 if (@args && $args[0] eq '1') {
76 0         0 $ordered = shift(@args);
77             }
78             }
79              
80             # Unknown arguments
81              
82 85 50       518 if (@args) {
83 0         0 warn "ERROR: [new] unknown arguments: @args\n";
84 0         0 return undef;
85             }
86              
87 85         1649 my $self = {
88             'nds' => $NDS, # Data::Nested object
89             'file' => '', # Path to YAML file
90             'list' => '', # 1 if the data is a list.
91             'ordered' => 0, # 1 if it is an ordered list.
92             'def' => [], # List of default elements.
93             # [ [ [NAME] ELE1 RULESET COND... ]
94             # [ [NAME] ELE2 RULESET COND... ] ]
95             # NAME is used only for hashes
96             'raw' => undef, # hash/list of elements
97             'data' => undef, # hash/list of full elements
98             'err' => '',
99             'errmsg' => '',
100             'elesx' => undef, # A list of all existing elements
101             'elesn' => undef, # A list of all non-empty elements
102             'elesxh' => {}, # A hash of { ELE => 1 } for existing elements
103             # Exactly equivalent to 'elesx'.
104             'elesnh' => undef, # A hash of { ELE => 0/1 } for empty/not
105              
106              
107             'eles' => {}, # A hash of all elements. The value is:
108             # 0 : exists
109             # 1 : constructed
110             # 2 : constructed, known empty
111             # 3 : constructed, known non-empty
112             'status' => 0, # Status of data
113             # 0 : no checks
114             # 1 : existance checked
115             # 2 : all element constructed
116             # 3 : empty checked
117             };
118 85         324 bless $self, $class;
119              
120 85 50       320 if ($ordered) {
121 0         0 $$self{'ordered'} = 1;
122             }
123              
124 85 100       311 if ($file) {
125 54         218 $self->file($file);
126 54 50       202 if ($self->err()) {
127 0         0 return undef;
128             }
129             }
130              
131 85         390 return $self;
132             }
133              
134             sub version {
135 0     0 1 0 my($self) = @_;
136              
137 0         0 return $VERSION;
138             }
139              
140             sub nds {
141 1888     1888 1 2340 my($self) = @_;
142              
143 1888         3703 return $$self{'nds'};
144             }
145              
146             sub err {
147 4794     4794 1 6284 my($self) = @_;
148              
149 4794         14456 return $$self{'err'};
150             }
151              
152             sub errmsg {
153 4     4 1 9 my($self) = @_;
154              
155 4         16 return $$self{'errmsg'};
156             }
157              
158             sub ordered_list {
159 3     3 1 32 my($self) = @_;
160              
161 3 50       20 if ($$self{'file'}) {
162 0         0 $$self{'err'} = 'ndserr02';
163 0         0 $$self{'errmsg'} = 'Cannot call ordered_list after a file is read.';
164 0         0 return;
165             }
166 3         7 $$self{'ordered'} = 1;
167             }
168              
169             ###############################################################################
170             # FILE METHODS
171             ###############################################################################
172              
173             sub file {
174 85     85 1 1594 my($self,$file,$nostruct) = @_;
175 85         418 $$self{'err'} = '';
176 85         189 $$self{'errmsg'} = '';
177 85         208 my $ordered = $$self{'ordered'};
178 85 50       318 my $new = ($nostruct ? 0 : 1);
179              
180             #
181             # Read the YAML data source
182             #
183              
184 85 50       415 if ($$self{'file'}) {
185 0         0 $$self{'err'} = 'nmefil01';
186 0         0 $$self{'errmsg'} = "File already set for this object: $$self{file}";
187 0         0 return;
188             }
189              
190 85 50       2261 if (! -f $file) {
191 0         0 $$self{'err'} = 'nmefil02';
192 0         0 $$self{'errmsg'} = "File not found: $file";
193 0         0 return;
194             }
195              
196 85 50       1521 if (! -r $file) {
197 0         0 $$self{'err'} = 'nmefil03';
198 0         0 $$self{'errmsg'} = "File not readable: $file";
199 0         0 return;
200             }
201              
202 85         565 my $ref = YAML::Syck::LoadFile($file);
203 85 100       26085 if (ref($ref) eq 'HASH') {
    50          
204 53         205 $$self{'list'} = 0;
205 53         135 $$self{'ordered'} = 0;
206 53         125 $$self{'data'} = {};
207 53 50       233 if ($ordered) {
208 0         0 $$self{'err'} = 'nmefil09';
209 0         0 $$self{'errmsg'} = "Ordered not valid for a file containing a hash: $file";
210 0         0 return;
211             }
212             } elsif (ref($ref) eq 'ARRAY') {
213 32         93 $$self{'list'} = 1;
214 32         82 $$self{'data'} = [];
215             } else {
216 0         0 $$self{'err'} = 'nmefil04';
217 0         0 $$self{'errmsg'} = "File must contain a list or hash: $file";
218 0         0 return;
219             }
220              
221             #
222             # Check the structure of each element
223             #
224              
225 85         232 my $NDS = $$self{'nds'};
226 85         161 my $err = 0;
227              
228 85 100       289 if ($$self{'list'}) {
229 32         152 for (my $i=0; $i<=$#$ref; $i++) {
230 94         357 $NDS->check_structure($$ref[$i],$new);
231 94         263 my $e = $NDS->err();
232 94 100       463 if ($e) {
233 1 50       4 if ($err) {
234 0         0 $$self{'errmsg'} .= " $i [$e]";
235             } else {
236 1         5 $$self{'errmsg'} = "Invalid element: $i [$e]";
237             }
238 1         5 $err = 1;
239             }
240             }
241              
242             } else {
243 53         244 foreach my $ele (CORE::keys %$ref) {
244 233         930 $NDS->check_structure($$ref{$ele},$new);
245 233         644 my $e = $NDS->err();
246 233 100       885 if ($e) {
247 1 50       4 if ($err) {
248 0         0 $$self{'errmsg'} .= " $ele [$e]";
249             } else {
250 1         6 $$self{'errmsg'} = "Invalid element: $ele [$e]";
251             }
252 1         3 $err = 1;
253             }
254             }
255              
256             }
257              
258 85 100       369 if ($err) {
259 2         11 $$self{'err'} = 'nmefil05';
260 2         13 return;
261             }
262              
263             #
264             # Store the data.
265             #
266              
267 83         204 $$self{'raw'} = $ref;
268 83         198 $$self{'file'} = $file;
269 83         207 $$self{'def'} = [];
270 83         275 return;
271             }
272              
273             ###############################################################################
274             # ELEMENT METHODS
275             ###############################################################################
276              
277             # Set a list of all existing or non-empty elements.
278             #
279             sub _eles {
280 2195     2195   8879 my($self,$exists) = @_;
281              
282 2195 100       4419 if ($exists) {
283 1900         2020 my @ele;
284 1900 100       3852 if ($$self{'list'}) {
285 953         1040 my $n = $#{ $$self{'raw'} };
  953         1881  
286 953         2383 @ele = (0..$n);
287              
288 953 100       1266 if ($#ele != $#{ $$self{'elesx'} }) {
  953         2703  
289 49         114 $$self{'elesx'} = [ @ele ];
290 49         93 %{ $$self{'elesxh'} } = map { $_,1 } @ele;
  49         248  
  152         263  
291             }
292              
293             } else {
294 947 100       2175 if (! defined($$self{'elesx'})) {
295 101         137 my @tmp = CORE::keys %{ $$self{'raw'} };
  101         376  
296 101         523 @tmp = sort @tmp;
297 101         272 $$self{'elesx'} = [ @tmp ];
298 101         202 %{ $$self{'elesxh'} } = map { $_,1 } @tmp;
  101         474  
  386         751  
299             }
300 947         1276 @ele = @{ $$self{'elesx'} };
  947         2698  
301             }
302              
303 1900         4025 return;
304             }
305              
306 295         660 _eles($self,'construct');
307 295         332 my(@non);
308              
309 295         363 foreach my $ele (@{ $$self{'elesx'} }) {
  295         672  
310 1081 100       2046 push(@non,$ele) if (! _ele_empty($self,$ele));
311             }
312              
313 295 100       767 if ($$self{'list'}) {
314 146         508 $$self{'elesn'} = [ sort { $a <=> $b } @non ];
  344         804  
315             } else {
316 149         698 $$self{'elesn'} = [ sort @non ];
317             }
318             }
319              
320             # Construct a data element from a raw element and all default elements.
321             #
322             sub _ele {
323 3517     3517   4461 my($self,$ele) = @_;
324              
325             # Test to see if the element has been constructed.
326 3517 100       6765 if ($$self{'list'}) {
327 1609 100       4421 return if (defined $$self{'data'}[$ele]);
328             } else {
329 1908 100       5519 return if (exists $$self{'data'}{$ele});
330             }
331              
332             # Initialize the data element using the raw data
333              
334 430 100       916 if ($$self{'list'}) {
335 288         448 $$self{'data'}[$ele] = undef;
336 288 100       3016 $$self{'data'}[$ele] = dclone($$self{'raw'}[$ele])
337             if (defined $$self{'raw'}[$ele]);
338             } else {
339 142         432 $$self{'data'}{$ele} = undef;
340 142 100       4782 $$self{'data'}{$ele} = dclone($$self{'raw'}{$ele})
341             if (defined $$self{'raw'}{$ele});
342             }
343              
344             # Merge in each default.
345              
346 430         1076 my $NDS = $self->nds();
347 430         559 foreach my $def (@{ $$self{'def'} }) {
  430         1170  
348 216 50       507 if ($$self{'list'}) {
349 0         0 my($defele,$ruleset,@cond) = @$def;
350 0         0 my $nds = _ele_nds($self,$ele);
351 0 0       0 if ($NDS->test_conditions($nds,@cond)) {
352 0         0 my $tmp = $$self{'data'}[$ele];
353 0 0       0 if (defined($tmp)) {
354 0         0 $NDS->merge($tmp,dclone($defele),$ruleset);
355             } else {
356 0         0 $tmp = dclone($defele);
357             }
358 0         0 $$self{'data'}[$ele] = $tmp;
359             }
360              
361             } else {
362 216         585 my($e,$defele,$ruleset,@cond) = @$def;
363 216         427 my $nds = _ele_nds($self,$ele);
364 216 100       762 if ($NDS->test_conditions($nds,@cond)) {
365 98         223 my $tmp = $$self{'data'}{$ele};
366 98 50       179 if (defined($tmp)) {
367 98         3207 $NDS->merge($tmp,dclone($defele),$ruleset);
368             } else {
369 0         0 $tmp = dclone($defele);
370             }
371 98         569 $$self{'data'}{$ele} = $tmp;
372             }
373             }
374             }
375             }
376              
377             # Test to see if an element is empty (construct it if necessary).
378             #
379             sub _ele_nonempty {
380 1134     1134   1544 my($self,$ele) = @_;
381              
382 1134         2434 my $NDS = $self->nds();
383 1134         2063 my $nds = _ele_nds($self,$ele);
384 1134         3715 my $val = $NDS->empty($nds);
385              
386 1134 50       2731 if (! defined $val) {
387 0         0 return undef;
388             }
389 1134         1544 $val = 1-$val;
390 1134         2194 $$self{'elesnh'}{$ele} = $val;
391 1134         1825 return $val;
392             }
393              
394             # Return the full NDS of an element.
395             #
396             # If $raw is 1, returns the raw element.
397             # If $noconstruct is 1, returns the current data element without constructing.
398             # Otherwise, returns the full element.
399             #
400             sub _ele_nds {
401 2469     2469   3661 my($self,$ele,$raw,$noconstruct) = @_;
402              
403 2469 100       4814 if ($raw) {
404 36 100       83 if ($$self{'list'}) {
405 5         266 return $$self{'raw'}[$ele];
406             } else {
407 31         305 return $$self{'raw'}{$ele};
408             }
409             }
410              
411             # $noconstruct is useful so that this can be called while in
412             # the process of merging in each of the defaults.
413 2433 50       4520 if (! $noconstruct) {
414 2433         4210 _ele($self,$ele);
415 2433 50       4697 return undef if ($self->err());
416             }
417              
418 2433 100       4909 if ($$self{'list'}) {
419 1058         2450 return $$self{'data'}[$ele];
420             } else {
421 1375         3480 return $$self{'data'}{$ele};
422             }
423             }
424              
425             sub _ele_exists {
426 1121     1121   1447 my($self,$ele) = @_;
427 1121         1926 _eles($self,'construct');
428 1121 100       8541 return 1 if (exists $$self{'elesxh'}{$ele});
429 14         75 return 0;
430             }
431              
432             sub _ele_empty {
433 1093     1093   1517 my($self,$ele) = @_;
434 1093 100       1852 return 1 if (! _ele_exists($self,$ele));
435 1084         2083 _ele($self,$ele);
436 1084         1868 _ele_nonempty($self,$ele);
437 1084         4294 return 1-$$self{'elesnh'}{$ele};
438             }
439              
440             ###############################################################################
441             # DEFAULT METHODS
442             ###############################################################################
443              
444             sub default_element {
445 75     75 1 2208 my($self,@args) = @_;
446 75         139 $$self{'err'} = '';
447 75         119 $$self{'errmsg'} = '';
448              
449 75 50       232 if (! $$self{'file'}) {
450 0         0 $$self{'err'} = 'nmefil06';
451 0         0 $$self{'errmsg'} = 'No file set.';
452 0         0 return;
453             }
454              
455             # For hashes, get the element
456              
457 75         153 my $ele;
458 75 100       197 if (! $$self{'list'}) {
459 63 50       150 if (! @args) {
460 0         0 $$self{'err'} = 'nmedef01';
461 0         0 $$self{'errmsg'} = 'Element name required for hashes';
462 0         0 return;
463             }
464 63         91 $ele = shift(@args);
465              
466 63 50       201 if (! exists $$self{'raw'}{$ele}) {
467 0         0 $$self{'err'} = 'nmedef02';
468 0         0 $$self{'errmsg'} = "The named element does not exist: $ele";
469 0         0 return;
470             }
471             }
472              
473             # Ruleset, conditions
474              
475 75         119 my $ruleset = 'default';
476 75         89 my @cond;
477              
478 75 100       214 if ( ($#args % 2) == 0) {
479             # odd number of arguments
480 7         16 $ruleset = shift(@args);
481 7         11 @cond = @args;
482             } else {
483 68         136 @cond = @args;
484             }
485              
486 75         204 my $NDS = $self->nds();
487 75 50       263 if (! $NDS->ruleset_valid($ruleset)) {
488 0         0 $$self{'err'} = 'nmedef03';
489 0         0 $$self{'errmsg'} = 'An invalid ruleset specified for merging ' .
490             "defaults: $ruleset";
491 0         0 return;
492             }
493              
494 75         160 my @tmp = @cond;
495 75         273 while (@tmp) {
496 55         96 my $path = shift(@tmp);
497 55         102 my $val = shift(@tmp);
498 55 50       207 if (! $NDS->get_structure($path,'valid')) {
499 0         0 $$self{'err'} = 'nmedef04';
500 0         0 $$self{'errmsg'} = 'An invalid path specified in a default ' .
501             "condition: $path";
502 0         0 return;
503             }
504             }
505              
506             # Move the default element into the list of defaults.
507              
508 75         104 my @def;
509 75 100       186 if ($$self{'list'}) {
510 12 50 33     69 if (! defined $$self{'raw'}[0] ||
511             $NDS->empty($$self{'raw'}[0])) {
512 0         0 $$self{'err'} = 'ndsdef06';
513 0         0 $$self{'errmsg'} = 'An undefined/empty element may not be used as ' .
514             'a default.';
515 0         0 return;
516             }
517 12         18 push(@def,splice(@{ $$self{'raw'} },0,1));
  12         35  
518              
519             } else {
520 63         111 push(@def,$ele);
521 63         130 push(@def,$$self{'raw'}{$ele});
522 63         149 delete $$self{'raw'}{$ele};
523             }
524 75         126 $$self{'elesx'} = undef;
525 75         168 push(@def,$ruleset,@cond);
526 75         93 push(@{ $$self{'def'} },[@def]);
  75         233  
527 75         272 return;
528             }
529              
530             sub is_default_value {
531 28     28 1 2598 my($self,$ele,$path) = @_;
532 28         54 $$self{'err'} = '';
533 28         42 $$self{'errmsg'} = '';
534              
535 28 50       66 if (! $$self{'file'}) {
536 0         0 $$self{'err'} = 'nmefil06';
537 0         0 $$self{'errmsg'} = 'No file set.';
538 0         0 return;
539             }
540              
541 28 50       81 if (! $self->ele($ele,1)) {
542 0         0 $$self{'err'} = 'nmeele01';
543 0         0 $$self{'errmsg'} = "The specified element does not exist: $ele";
544 0         0 return;
545             }
546              
547 28 50       69 if (! $self->path_valid($path)) {
548 0         0 $$self{'err'} = 'nmeacc03';
549 0         0 $$self{'errmsg'} = "Attempt to access data with an invalid path: $path";
550 0         0 return undef;
551             }
552              
553             # Get the current value at the path. If it's not defined, it didn't
554             # come from a default.
555              
556 28         67 my $val = $self->value($ele,$path);
557 28 100 66     60 if ($self->err() ||
558             ! defined $val) {
559 6         12 $$self{'err'} = '';
560 6         10 $$self{'errmsg'} = '';
561 6         19 return 0;
562             }
563              
564             # Get the raw value at the path. If it's not defined, the value had
565             # to come from a default.
566              
567 22         50 my $NDS = $self->nds();
568 22         45 my $nds = _ele_nds($self,$ele,1);
569 22         59 my $raw = $NDS->value($nds,$path);
570 22 100 66     61 if ($NDS->err() ||
571             ! defined $raw) {
572 10         20 $$NDS{'err'} = '';
573 10         14 $$NDS{'errmsg'} = '';
574 10         41 return 1;
575             }
576              
577             # Compare the current value to the raw value. If they are different,
578             # it came from a default.
579              
580 12 50       30 if (ref($val)) {
581             # Compare data structures (use the Data::Nested::identical method)
582 0 0       0 return 0 if ($NDS->identical($val,$raw));
583 0         0 return 1;
584              
585             } else {
586             # Compare scalars
587 12 50       40 return 1 if ($raw ne $val);
588 12         45 return 0;
589             }
590             }
591              
592             ###############################################################################
593             # ELEMENT EXISTANCE METHODS
594             ###############################################################################
595              
596             sub eles {
597 575     575 1 6399 my($self,$exists) = @_;
598 575         1020 $$self{'err'} = '';
599 575         841 $$self{'errmsg'} = '';
600              
601 575 100       1017 if ($exists) {
602 484         971 _eles($self,'construct');
603 484 50       993 return undef if ($self->err());
604 484         660 return @{ $$self{'elesx'} };
  484         1853  
605             } else {
606 91         202 _eles($self);
607 91 50       229 return undef if ($self->err());
608 91         115 return @{ $$self{'elesn'} };
  91         396  
609             }
610             }
611              
612             sub ele {
613 266     266 1 1908 my($self,$ele,$exists) = @_;
614 266         421 $$self{'err'} = '';
615 266         443 $$self{'errmsg'} = '';
616              
617 266 50       642 if (! $$self{'file'}) {
618 0         0 $$self{'err'} = 'nmefil06';
619 0         0 $$self{'errmsg'} = 'No file set.';
620 0         0 return;
621             }
622              
623             # Return 0 if it doesn't exist
624 266 100       559 if ($$self{'list'}) {
625 113 100       289 return 0 if (! defined $$self{'raw'}[$ele]);
626             } else {
627 153 100       424 return 0 if (! exists $$self{'raw'}{$ele});
628             }
629              
630 264 100       471 if ($exists) {
631 147         374 return 1;
632              
633             } else {
634 117 100       460 return $$self{'elesnh'}{$ele} if (exists $$self{'elesnh'}{$ele});
635 50         128 _ele_nonempty($self,$ele);
636 50         197 return $$self{'elesnh'}{$ele};
637             }
638             }
639              
640             ###############################################################################
641             # WHICH METHOD
642             ###############################################################################
643              
644             sub which {
645 204     204 1 14767 my($self,@cond) = @_;
646 204         422 my $NDS = nds($self);
647 204         395 $$self{'err'} = '';
648 204         311 $$self{'errmsg'} = '';
649              
650 204 50       483 if (! $$self{'file'}) {
651 0         0 $$self{'err'} = 'nmefil06';
652 0         0 $$self{'errmsg'} = 'No file set.';
653 0         0 return;
654             }
655              
656             # Test to make sure that all paths are valid, and that there are
657             # an even number of values.
658              
659 204 50       567 if (($#cond % 2) == 0) {
660 0         0 $$self{'err'} = 'nmeacc01';
661 0         0 $$self{'errmsg'} = 'When specifying conditions, an even number of ' .
662             'arguments is required.';
663 0         0 return ();
664             }
665              
666 204         483 my @tmp = @cond;
667 204         485 while (@tmp) {
668 204         348 my $path = shift(@tmp);
669 204         237 shift(@tmp);
670 204 50       697 if (! $NDS->get_structure($path,'valid')) {
671 0         0 $$self{'err'} = 'nmeacc02';
672 0         0 $$self{'errmsg'} = 'When specifying conditions, a valid path is ' .
673             "required: $path";
674 0         0 return ();
675             }
676             }
677              
678             # Test every element
679              
680 204         427 _eles($self);
681 204 50       550 return () if ($self->err());
682              
683 204         510 my @eles = $self->eles(1);
684 204         322 my @ret;
685              
686 204         319 foreach my $ele (@eles) {
687             # Test it.
688 816         1546 my $nds = _ele_nds($self,$ele);
689 816         2596 my $pass = $NDS->test_conditions($nds,@cond);
690 816 50       1831 return () if ($self->err());
691 816 100       2448 push(@ret,$ele) if ($pass);
692             }
693              
694 204         1052 return @ret;
695             }
696              
697             ###############################################################################
698             # PATH_VALID METHOD
699             ###############################################################################
700              
701             sub path_valid {
702 30     30 1 496 my($self,$path) = @_;
703 30         51 my $NDS = $$self{'nds'};
704              
705 30         99 return $NDS->get_structure($path,'valid');
706             }
707              
708             ###############################################################################
709             # VALUE, KEYS, VALUES METHODS
710             ###############################################################################
711              
712             sub value {
713 119     119 1 4146 my($self,$ele,$path,$copy,$raw) = @_;
714 119         206 $$self{'err'} = '';
715 119         303 $$self{'errmsg'} = '';
716 119 50       270 $copy = 0 if (! $copy);
717 119 100       227 $raw = 0 if (! $raw);
718              
719 119 50       264 if (! $$self{'file'}) {
720 0         0 $$self{'err'} = 'nmefil06';
721 0         0 $$self{'errmsg'} = 'No file set.';
722 0         0 return;
723             }
724              
725 119 50       277 if (! $self->ele($ele,1)) {
726 0         0 $$self{'err'} = 'nmeele01';
727 0         0 $$self{'errmsg'} = "The specified element does not exist: $ele";
728 0         0 return;
729             }
730              
731 119         258 my $NDS = $$self{'nds'};
732 119 50       368 if (! $NDS->get_structure($path,'valid')) {
733 0         0 $$self{'err'} = 'nmeacc03';
734 0         0 $$self{'errmsg'} = "Attempt to access data with an invalid path: $path";
735 0         0 return undef;
736             }
737              
738 119         252 my $nds = _ele_nds($self,$ele,$raw);
739 119         384 my $val = $NDS->value($nds,$path);
740 119 100       315 if ($NDS->err()) {
741 11         25 $$NDS{'err'} = '';
742 11         23 $$NDS{'errmsg'} = '';
743 11         19 $$self{'err'} = 'nmeacc04';
744 11         31 $$self{'errmsg'} = "The path does not exist in this element: $ele: $path";
745 11         101 return undef;
746             }
747              
748 108 50       220 if ($copy) {
749 0         0 $val = dclone($val);
750             }
751              
752 108         4741 return $val;
753             }
754              
755             sub keys {
756 47     47 1 4397 my($self,$ele,$path,$empty,$raw) = @_;
757 47         81 $$self{'err'} = '';
758 47         66 $$self{'errmsg'} = '';
759 47 100       115 $empty = 0 if (! $empty);
760 47 100       96 $raw = 0 if (! $raw);
761              
762 47 50       120 if (! $$self{'file'}) {
763 0         0 $$self{'err'} = 'nmefil06';
764 0         0 $$self{'errmsg'} = 'No file set.';
765 0         0 return;
766             }
767              
768 47         74 my $NDS = $$self{'nds'};
769 47 50       150 if (! $NDS->get_structure($path,'valid')) {
770 0         0 $$self{'err'} = 'nmeacc03';
771 0         0 $$self{'errmsg'} = "Attempt to access data with an invalid path: $path";
772 0         0 return undef;
773             }
774              
775 47         105 my $nds = _ele_nds($self,$ele,$raw);
776 47         153 my $val = $NDS->value($nds,$path);
777 47 100       127 if ($NDS->err()) {
778 2         5 $$NDS{'err'} = '';
779 2         4 $$NDS{'errmsg'} = '';
780 2         4 $$self{'err'} = 'nmeacc04';
781 2         6 $$self{'errmsg'} = "The path does not exist in this element: $ele: $path";
782 2         8 return undef;
783             }
784              
785 45         161 my @val;
786 45 100       138 if (ref($val) eq 'HASH') {
    100          
    50          
787 29         100 foreach my $k (sort keys %$val) {
788 47         78 my $v = $$val{$k};
789 47         63 my $v2 = $v;
790 47 50       148 $v2 = [$v2] if (! ref($v2));
791 47 100 66     191 push(@val,$k) if ( (! $empty && ! $NDS->empty($v2)) ||
      66        
792             $empty );
793             }
794              
795             } elsif (ref($val) eq 'ARRAY') {
796 12         39 for (my $i=0; $i<=$#$val; $i++) {
797 12         21 my $v = $$val[$i];
798 12         19 my $v2 = $v;
799 12 50       36 $v2 = [$v2] if (! ref($v2));
800 12 100 100     75 push(@val,$i) if ( (! $empty && ! $NDS->empty($v2)) ||
      100        
801             $empty );
802             }
803              
804             } elsif (! defined($val)) {
805              
806             } else {
807 0         0 $$self{'err'} = 'nmeacc05';
808 0         0 $$self{'errmsg'} = 'Keys method may not be used with a scalar path: ' .
809             "$path";
810             }
811              
812 45         196 return @val;
813             }
814              
815             sub values {
816 47     47 1 3835 my($self,$ele,$path,$empty,$copy,$raw) = @_;
817 47         81 $$self{'err'} = '';
818 47         78 $$self{'errmsg'} = '';
819 47 100       103 $empty = 0 if (! $empty);
820 47 50       88 $copy = 0 if (! $copy);
821 47 100       87 $raw = 0 if (! $raw);
822              
823 47 50       131 if (! $$self{'file'}) {
824 0         0 $$self{'err'} = 'nmefil06';
825 0         0 $$self{'errmsg'} = 'No file set.';
826 0         0 return;
827             }
828              
829 47         68 my $NDS = $$self{'nds'};
830 47 50       140 if (! $NDS->get_structure($path,'valid')) {
831 0         0 $$self{'err'} = 'nmeacc03';
832 0         0 $$self{'errmsg'} = "Attempt to access data with an invalid path: $path";
833 0         0 return undef;
834             }
835              
836 47         100 my $nds = _ele_nds($self,$ele,$raw);
837 47         151 my $val = $NDS->value($nds,$path);
838 47 100       129 if ($NDS->err()) {
839 2         4 $$NDS{'err'} = '';
840 2         5 $$NDS{'errmsg'} = '';
841 2         4 $$self{'err'} = 'nmeacc04';
842 2         6 $$self{'errmsg'} = "The path does not exist in this element: $ele: $path";
843 2         10 return undef;
844             }
845              
846 45         63 my @val;
847 45 100       128 if (ref($val) eq 'HASH') {
    100          
    50          
848 29         99 foreach my $k (sort (CORE::keys %$val)) {
849 47         81 my $v = $$val{$k};
850 47         64 my $v2 = $v;
851 47 50       130 $v2 = [$v2] if (! ref($v2));
852 47 100 66     194 if ( (! $empty && ! $NDS->empty($v2)) ||
      66        
853             $empty ) {
854 43 50 33     117 if ($copy && ref($v)) {
855 0         0 push(@val,dclone($v));
856             } else {
857 43         152 push(@val,$v);
858             }
859             }
860             }
861              
862             } elsif (ref($val) eq 'ARRAY') {
863 12         36 for (my $i=0; $i<=$#$val; $i++) {
864 12         17 my $v = $$val[$i];
865 12         15 my $v2 = $v;
866 12 50       32 $v2 = [$v2] if (! ref($v2));
867 12 100 100     56 if ( (! $empty && ! $NDS->empty($v2)) ||
      100        
868             $empty ) {
869 8 50 33     25 if ($copy && ref($v)) {
870 0         0 push(@val,dclone($v));
871             } else {
872 8         35 push(@val,$v);
873             }
874             }
875             }
876              
877             } elsif (! defined($val)) {
878              
879             } else {
880 0         0 $$self{'err'} = 'nmeacc06';
881 0         0 $$self{'errmsg'} = 'Values method may not be used with a scalar path: ' .
882             "$path";
883             }
884              
885 45         202 return @val;
886             }
887              
888             ###############################################################################
889             # PATH_VALUES METHOD
890             ###############################################################################
891              
892             sub path_values {
893 12     12 1 1140 my($self,$path,$empty,$copy) = @_;
894 12         22 $$self{'err'} = '';
895 12         32 $$self{'errmsg'} = '';
896 12         19 my $NDS = $$self{'nds'};
897              
898 12 50       35 if (! $$self{'file'}) {
899 0         0 $$self{'err'} = 'nmefil06';
900 0         0 $$self{'errmsg'} = 'No file set.';
901 0         0 return;
902             }
903              
904 12 50       42 if (! $NDS->get_structure($path,'valid')) {
905 0         0 $$self{'err'} = 'nmeacc03';
906 0         0 $$self{'errmsg'} = "Attempt to access data with an invalid path: $path";
907 0         0 return;
908             }
909              
910 12         17 my @eles;
911 12 100       29 if ($empty) {
912 6         19 @eles = $self->eles(1);
913             } else {
914 6         21 @eles = $self->eles();
915             }
916              
917 12         20 my %ret;
918 12         22 foreach my $ele (@eles) {
919              
920 36         90 my $nds = _ele_nds($self,$ele);
921 36         111 my $val = $NDS->value($nds,$path,0,1);
922 36 100       98 if ($NDS->err()) {
923 24         36 $$NDS{'err'} = '';
924 24         35 $$NDS{'errmsg'} = '';
925 24         48 next;
926             }
927              
928 12 50 33     34 $val = dclone($val) if (ref($val) && $copy);
929 12         34 $ret{$ele} = $val;
930             }
931              
932 12         72 return %ret;
933             }
934              
935             ###############################################################################
936             # PATH_IN_USE METHOD
937             ###############################################################################
938              
939             sub path_in_use {
940 5     5 1 567 my($self,$path,$empty) = @_;
941 5         11 $$self{'err'} = '';
942 5         14 $$self{'errmsg'} = '';
943 5         7 my $NDS = $$self{'nds'};
944              
945 5 50       19 if (! $$self{'file'}) {
946 0         0 $$self{'err'} = 'nmefil06';
947 0         0 $$self{'errmsg'} = 'No file set.';
948 0         0 return;
949             }
950              
951 5 50       23 if (! $NDS->get_structure($path,'valid')) {
952 0         0 $$self{'err'} = 'nmeacc03';
953 0         0 $$self{'errmsg'} = "Attempt to access data with an invalid path: $path";
954 0         0 return undef;
955             }
956              
957 5         8 my @eles;
958 5 50       12 if ($empty) {
959 0         0 @eles = $self->eles(1);
960             } else {
961 5         14 @eles = $self->eles();
962             }
963              
964 5         10 foreach my $ele (@eles) {
965              
966 22         45 my $nds = _ele_nds($self,$ele);
967 22         61 my $val = $NDS->value($nds,$path,0,1);
968 22 100       95 if ($NDS->err()) {
969 18         28 $$NDS{'err'} = '';
970 18         26 $$NDS{'errmsg'} = '';
971 18         35 next;
972             }
973              
974 4 100       21 return 1 if (defined $val);
975             }
976              
977 3         15 return 0;
978             }
979              
980             ###############################################################################
981             # DELETE_ELE METHOD
982             ###############################################################################
983              
984             sub delete_ele {
985 4     4 1 20 my($self,$ele) = @_;
986 4         9 $$self{'err'} = '';
987 4         11 $$self{'errmsg'} = '';
988              
989 4 50       17 if (! $$self{'file'}) {
990 0         0 $$self{'err'} = 'nmefil06';
991 0         0 $$self{'errmsg'} = 'No file set.';
992 0         0 return;
993             }
994              
995             # Test to see if the element exists.
996              
997 4 50       10 if (! _ele_exists($self,$ele)) {
998 0         0 $$self{'err'} = 'nmeele01';
999 0         0 $$self{'errmsg'} = "The specified element does not exist: $ele";
1000 0         0 return;
1001             }
1002              
1003             #
1004             # Delete both the raw element and the full element.
1005             #
1006              
1007 4         18 _delete_ele($self,$ele);
1008 4         11 return;
1009             }
1010              
1011             # Deletes an element. By default, deletes it fully. If $leaveraw is
1012             # passed in, it deletes only the constructed element.
1013             #
1014             sub _delete_ele {
1015 4     4   10 my($self,$ele,$leaveraw) = @_;
1016              
1017 4 50 66     36 if ($$self{'list'} && $$self{'ordered'}) {
    100          
1018              
1019             #
1020             # Delete an ordered list element (leaves an undef placeholder).
1021             #
1022              
1023 0 0       0 $$self{'data'}[$ele] = undef if (defined $$self{'data'}[$ele]);
1024 0 0 0     0 $$self{'raw'}[$ele] = undef if (defined $$self{'raw'}[$ele] &&
1025             ! $leaveraw);
1026              
1027             } elsif ($$self{'list'}) {
1028              
1029             #
1030             # Delete an unordered list element (removes it entirely)
1031             #
1032              
1033 2 50       5 if ($#{ $$self{'data'} } >= $ele) {
  2         10  
1034 2         3 splice( @{ $$self{'data'} },$ele,1);
  2         9  
1035             }
1036              
1037 2 50       13 if (! $leaveraw) {
1038 2         4 splice( @{ $$self{'raw'} },$ele,1);
  2         6  
1039             }
1040              
1041             } else {
1042              
1043             #
1044             # Delete a hash element
1045             #
1046              
1047 2         10 delete $$self{'data'}{$ele};
1048 2 50       7 if (! $leaveraw) {
1049 2         6 delete $$self{'raw'}{$ele};
1050             }
1051             }
1052              
1053 4         12 $$self{'elesx'} = undef;
1054 4         11 $$self{'elesxh'} = {};
1055 4         11 $$self{'elesn'} = undef;
1056 4         13 $$self{'elesnh'} = undef;
1057             }
1058              
1059             ###############################################################################
1060             # RENAME_ELE METHOD
1061             ###############################################################################
1062              
1063             sub rename_ele {
1064 3     3 1 13 my($self,$ele,$newele) = @_;
1065 3         8 $$self{'err'} = '';
1066 3         130 $$self{'errmsg'} = '';
1067 3 50 66     19 return if ($$self{'list'} && ! $$self{'ordered'});
1068              
1069 3 50       11 if (! $$self{'file'}) {
1070 0         0 $$self{'err'} = 'nmefil06';
1071 0         0 $$self{'errmsg'} = 'No file set.';
1072 0         0 return;
1073             }
1074              
1075             # Test to see if the element exists and new element doesn't (or is empty).
1076              
1077 3 50       7 if (! _ele_exists($self,$ele)) {
1078 0         0 $$self{'err'} = 'nmeele01';
1079 0         0 $$self{'errmsg'} = "The specified element does not exist: $ele";
1080 0         0 return;
1081             }
1082              
1083 3 50 33     9 if (_ele_exists($self,$newele) &&
1084             ! _ele_empty($self,$newele)) {
1085 0         0 $$self{'err'} = 'nmeele02';
1086 0         0 $$self{'errmsg'} = "Attempt to overwrite an existing element: $newele";
1087 0         0 return;
1088             }
1089              
1090             #
1091             # Rename the raw and combined data elements, and the element list.
1092             #
1093              
1094 3         12 _rename_ele($self,$ele,$newele);
1095 3         12 return;
1096             }
1097              
1098             # Move an element from one name to another. This will never be done
1099             # with a list.
1100             #
1101             sub _rename_ele {
1102 3     3   8 my($self,$ele,$newele) = @_;
1103              
1104             # Move both the data and raw elements.
1105              
1106 3 100       11 if ($$self{'list'}) {
1107 1 50       5 if (defined $$self{'data'}[$ele]) {
1108 1         2 $$self{'data'}[$newele] = $$self{'data'}[$ele];
1109 1         3 $$self{'data'}[$ele] = undef;
1110             }
1111 1         3 $$self{'raw'}[$newele] = $$self{'raw'}[$ele];
1112 1         2 $$self{'raw'}[$ele] = undef;
1113              
1114             } else {
1115 2 50       45 if (exists $$self{'data'}{$ele}) {
1116 2         7 $$self{'data'}{$newele} = $$self{'data'}{$ele};
1117 2         7 delete $$self{'data'}{$ele};
1118             }
1119 2         4 $$self{'raw'}{$newele} = $$self{'raw'}{$ele};
1120 2         5 delete $$self{'raw'}{$ele};
1121             }
1122              
1123 3         6 $$self{'elesx'} = undef;
1124 3         8 $$self{'elesxh'} = {};
1125 3         7 $$self{'elesn'} = undef;
1126 3         54 $$self{'elesnh'} = undef;
1127             }
1128              
1129             ###############################################################################
1130             # ADD_ELE METHOD
1131             ###############################################################################
1132              
1133             sub add_ele {
1134 19     19 1 79 my($self,@args) = @_;
1135 19         38 $$self{'err'} = '';
1136 19         34 $$self{'errmsg'} = '';
1137              
1138 19 50       55 if (! $$self{'file'}) {
1139 0         0 $$self{'err'} = 'nmefil06';
1140 0         0 $$self{'errmsg'} = 'No file set.';
1141 0         0 return;
1142             }
1143              
1144             # Parse arguments
1145              
1146 19         26 my($ele,$nds,$new);
1147 19         28 $ele = '';
1148              
1149 19 100       47 if ($$self{'list'}) {
1150 12 100       73 if ($args[0] =~ /^\d+$/) {
1151 6         17 ($ele,$nds,$new) = @args;
1152             } else {
1153 6         12 ($nds,$new) = @args;
1154             }
1155              
1156             } else {
1157 7         17 ($ele,$nds,$new) = @args;
1158             }
1159              
1160             # Check the structure
1161              
1162 19         84 my $NDS = $self->nds();
1163 19         74 $NDS->check_structure($nds,$new);
1164 19 50       57 if ($NDS->err()) {
1165 0         0 $$NDS{'err'} = '';
1166 0         0 $$NDS{'errmsg'} = '';
1167 0         0 $$self{'err'} = 'nmends01';
1168 0         0 $$self{'errmsg'} = 'The NDS has an invalid structure.';
1169 0         0 return;
1170             }
1171              
1172             # Store the element
1173              
1174 19         60 _add_ele($self,$ele,$nds);
1175 19         63 return;
1176             }
1177              
1178             sub _add_ele {
1179 25     25   44 my($self,$ele,$nds) = @_;
1180              
1181 25 100 100     148 if ($$self{'list'} && ! $$self{'ordered'}) {
    100          
1182              
1183             # For an unordered list
1184             # If $ele is given
1185             # It must refer to an existing element. Insert before it.
1186             # Else
1187             # Push onto the end.
1188              
1189 11 100       20 if ($ele) {
1190              
1191 4 100       12 if (! _ele_exists($self,$ele)) {
1192 1         2 $$self{'err'} = 'nmeele04';
1193 1         4 $$self{'errmsg'} = 'Attempt to add element to an unordered list ' .
1194             "using a non-existant element: $ele";
1195 1         2 return;
1196             }
1197 3         15 _add_element_insert($self,$ele,$nds);
1198              
1199             } else {
1200 7         21 _add_element_push($self,$nds);
1201             }
1202              
1203             } elsif ($$self{'list'}) {
1204              
1205             # For an ordered list
1206             # If $ele is given
1207             # If the element exists
1208             # If it is empty
1209             # Put the new element there
1210             # Else
1211             # Insert it before that element
1212             # Else
1213             # Put the new element there
1214             # Else
1215             # Push onto the end.
1216              
1217 4 100       7 if ($ele) {
1218              
1219 3 100       7 if (_ele_exists($self,$ele)) {
1220              
1221 2 100       5 if (_ele_empty($self,$ele)) {
1222 1         5 _add_element_setlist($self,$ele,$nds);
1223             } else {
1224 1         3 _add_element_insert($self,$ele,$nds);
1225             }
1226              
1227             } else {
1228 1         4 _add_element_setlist($self,$ele,$nds);
1229             }
1230              
1231             } else {
1232 1         4 _add_element_push($self,$nds);
1233             }
1234              
1235             } else {
1236              
1237             # For a hash
1238             # If $ele is given and it is empty
1239             # Put the new element there
1240             # Elsif $ele is given and it doesn't exist
1241             # Put it there
1242             # Else
1243             # Error
1244              
1245 10 100 66     42 if ($ele && _ele_empty($self,$ele)) {
    50 33        
1246 9         30 _add_element_sethash($self,$ele,$nds);
1247             } elsif ($ele && ! _ele_exists($self,$ele)) {
1248 0         0 _add_element_sethash($self,$ele,$nds);
1249             } else {
1250 1         3 $$self{'err'} = 'nmeele02';
1251 1         5 $$self{'errmsg'} = "Attempt to overwrite an existing element: $ele";
1252 1         3 return;
1253             }
1254             }
1255              
1256 23         44 $$self{'elesx'} = undef;
1257 23         52 $$self{'elesxh'} = {};
1258 23         49 $$self{'elesn'} = undef;
1259 23         55 $$self{'elesnh'} = undef;
1260             }
1261              
1262             sub _add_element_setlist {
1263 10     10   17 my($self,$ele,$nds) = @_;
1264              
1265 10         34 $$self{'raw'}[$ele] = $nds;
1266             }
1267              
1268             sub _add_element_insert {
1269 4     4   10 my($self,$ele,$nds) = @_;
1270              
1271 4         7 splice(@{ $$self{'raw'} },$ele,0,$nds);
  4         21  
1272 4 100       8 if ($#{ $$self{'data'} } >= $ele) {
  4         19  
1273 3         4 splice(@{ $$self{'data'} },$ele,0,undef);
  3         13  
1274             }
1275             }
1276              
1277             sub _add_element_push {
1278 8     8   14 my($self,$nds) = @_;
1279              
1280 8         11 my $n = $#{ $$self{'raw'} };
  8         16  
1281 8         13 $n++;
1282 8         24 _add_element_setlist($self,$n,$nds);
1283             }
1284              
1285             sub _add_element_sethash {
1286 9     9   207 my($self,$ele,$nds) = @_;
1287              
1288 9         33 $$self{'raw'}{$ele} = $nds;
1289             }
1290              
1291             ###############################################################################
1292             # UPDATE_ELE METHOD
1293             ###############################################################################
1294              
1295             sub update_ele {
1296 4     4 1 19 my($self,$ele,$path,$val,$new,$ruleset) = @_;
1297              
1298 4 50       18 if (! $$self{'file'}) {
1299 0         0 $$self{'err'} = 'nmefil06';
1300 0         0 $$self{'errmsg'} = 'No file set.';
1301 0         0 return;
1302             }
1303              
1304             # Check to make sure $ele is valid (it need only exist)
1305              
1306 4 50       13 if (! _ele_exists($self,$ele)) {
1307 0         0 $$self{'err'} = 'nmeele01';
1308 0         0 $$self{'errmsg'} = "The specified element does not exist: $ele";
1309 0         0 return;
1310             }
1311              
1312             # If $val is not passed in, erase the path.
1313              
1314 4         16 my $NDS = $self->nds();
1315 4         20 my $nds = $$self{'raw'}{$ele};
1316              
1317 4 50       12 if (! defined $val) {
1318 0         0 $NDS->erase($nds,$path);
1319 0 0       0 if ($NDS->err()) {
1320 0         0 $$NDS{'err'} = '';
1321 0         0 $$NDS{'errmsg'} = '';
1322 0         0 $$self{'err'} = 'nmends02';
1323 0         0 $$self{'errmsg'} = "Problem encountered while erasing a path: $path";
1324             }
1325              
1326             } else {
1327              
1328             # Check new/ruleset values
1329              
1330 4 50 33     41 if (! defined $ruleset &&
      33        
1331             defined $new &&
1332             $NDS->ruleset_valid($new)) {
1333 0         0 $ruleset = $new;
1334 0         0 $new = '';
1335             }
1336              
1337 4 50       13 $ruleset = 'replace' if (! $ruleset);
1338              
1339             # Merge in the new value
1340              
1341 4 50       28 if (! $NDS->ruleset_valid($ruleset)) {
1342 0         0 $$self{'err'} = 'ndserr01';
1343 0         0 $$self{'errmsg'} = "An invalid ruleset was passed in: $ruleset";
1344 0         0 return;
1345             }
1346              
1347 4         23 $NDS->merge_path($nds,$val,$path,$ruleset,$new);
1348              
1349 4 50       14 if ($NDS->err()) {
1350 0         0 $$NDS{'err'} = '';
1351 0         0 $$NDS{'errmsg'} = '';
1352 0         0 $$self{'err'} = 'nmends03';
1353 0         0 $$self{'errmsg'} = 'The value had an invalid structure.';
1354 0         0 return;
1355             }
1356             }
1357              
1358             # Update status information
1359              
1360 4         10 $$self{'elesx'} = undef;
1361 4         11 $$self{'elesxh'} = {};
1362 4         11 $$self{'elesn'} = undef;
1363 4         9 $$self{'elesnh'} = undef;
1364              
1365 4 50       18 if ($$self{'list'}) {
1366 0         0 $$self{'data'}[$ele] = undef;
1367             } else {
1368 4         27 delete $$self{'data'}{$ele};
1369             }
1370             }
1371              
1372             ###############################################################################
1373             # COPY_ELE METHOD
1374             ###############################################################################
1375              
1376             sub copy_ele {
1377 6     6 1 28 my($self,$ele,$newele) = @_;
1378              
1379 6 50       16 if (! $$self{'file'}) {
1380 0         0 $$self{'err'} = 'nmefil06';
1381 0         0 $$self{'errmsg'} = 'No file set.';
1382 0         0 return;
1383             }
1384              
1385             # Check to make sure $ele is valid (it need only exist)
1386              
1387 6 50       29 if (! _ele_exists($self,$ele)) {
1388 0         0 $$self{'err'} = 'nmeele01';
1389 0         0 $$self{'errmsg'} = "The specified element does not exist: $ele";
1390 0         0 return;
1391             }
1392              
1393             # Get the structure there.
1394              
1395 6         17 my $nds = dclone(_ele_nds($self,$ele,1));
1396 6         17 _add_ele($self,$newele,$nds);
1397             }
1398              
1399             ###############################################################################
1400             # DUMP METHOD
1401             ###############################################################################
1402              
1403             sub dump {
1404 0     0 1   my($self,$ele,$path,%opts) = @_;
1405              
1406 0           my $NDS = $$self{'nds'};
1407 0           my $nds = _ele_nds($self,$ele);
1408 0 0         if ($path) {
1409 0           $nds = $NDS->value($nds,$path);
1410             }
1411 0           return $NDS->print($nds,%opts);
1412             }
1413              
1414             ###############################################################################
1415             # SAVE METHOD
1416             ###############################################################################
1417              
1418             sub save {
1419 0     0 1   my($self,$nobackup) = @_;
1420 0           my $file = $$self{'file'};
1421 0 0         if (! $file) {
1422 0           $$self{'err'} = 'nmefil06';
1423 0           $$self{'errmsg'} = 'No file set.';
1424 0           return;
1425             }
1426              
1427             # Backup file
1428              
1429 0 0         if (! $nobackup) {
1430 0 0         if (! rename($file,"$file.bak")) {
1431 0           $$self{'err'} = 'nmefil07';
1432 0           $$self{'errmsg'} = "Unable to backup data file: $!";
1433 0           return undef;
1434             }
1435             }
1436              
1437             # The data that must be stored consists of the defaults and
1438             # the current raw data.
1439              
1440 0           my $data;
1441 0 0         if ($$self{'list'}) {
1442 0           my(@ele);
1443 0           foreach my $def (@{ $$self{'def'} }) {
  0            
1444 0           push(@ele,$$def[0]);
1445             }
1446 0           push(@ele,@{ $$self{'raw'} });
  0            
1447 0           $data = \@ele;
1448              
1449             } else {
1450 0           my(%ele);
1451 0           foreach my $def (@{ $$self{'def'} }) {
  0            
1452 0           $ele{$$def[0]} = $$def[1];
1453             }
1454 0           foreach my $key (CORE::keys %{ $$self{'raw'} }) {
  0            
1455 0           $ele{$key} = $$self{'raw'}{$key};
1456             }
1457 0           $data = \%ele;
1458             }
1459              
1460             # Write data
1461              
1462 0           my $out = new IO::File;
1463 0 0         if (! $out->open(">$file")) {
1464 0           $$self{'err'} = 'nmefil08';
1465 0           $$self{'errmsg'} = "Unable to write data file: $!";
1466 0           return undef;
1467             }
1468              
1469 0           print $out Dump($data);
1470 0           $out->close();
1471             }
1472              
1473             1;
1474             # Local Variables:
1475             # mode: cperl
1476             # indent-tabs-mode: nil
1477             # cperl-indent-level: 3
1478             # cperl-continued-statement-offset: 2
1479             # cperl-continued-brace-offset: 0
1480             # cperl-brace-offset: 0
1481             # cperl-brace-imaginary-offset: 0
1482             # cperl-label-offset: -2
1483             # End: