1 # |
|
2 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 # All rights reserved. |
|
4 # This component and the accompanying materials are made available |
|
5 # under the terms of "Eclipse Public License v1.0" |
|
6 # which accompanies this distribution, and is available |
|
7 # at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 # |
|
9 # Initial Contributors: |
|
10 # Nokia Corporation - initial contribution. |
|
11 # |
|
12 # Contributors: |
|
13 # |
|
14 # Description: |
|
15 # |
|
16 #------------------------------------------------------------------------------- |
|
17 # package: SysDefCollector |
|
18 # |
|
19 # usage: Interacts with the SysDefParser to obtain those parts of the system |
|
20 # definition which are relevant to building a named configuration within the |
|
21 # system definition. Contains a SysDefCollector::ParserClient instance which |
|
22 # acts as the interface to the SysDefParser. This separation reduces the |
|
23 # possibility of a method name clash due to the parser callback mechanism |
|
24 # requiring the client to implement methods of the same name as the XML |
|
25 # element tags of interest. |
|
26 # |
|
27 # public methods: |
|
28 # |
|
29 # new(configname, loghandle): constructs a new instance to collect system |
|
30 # definition info relating to the configuration name 'configname'. |
|
31 # |
|
32 # parserClient(): returns a reference to the SysDefCollector::ParserClient |
|
33 # instance - typically for passing to the parser. |
|
34 # |
|
35 # options(): returns a list of the abld options flags as specified in the |
|
36 # 'option' elements. |
|
37 # |
|
38 # targets(): returns a list of the abld target flags as specified by the |
|
39 # 'targetList' attributes for each 'buildLayer' element in the specified |
|
40 # configuration. |
|
41 # |
|
42 # specialInstructionsFlag(): returns true/false accordingly as any relevant |
|
43 # 'specialInstructions' elements are present/not present. Relevant means |
|
44 # instructions which invoke SETUPPRJ.BAT. |
|
45 # |
|
46 # components(): returns a hash of component name and bldFile directories |
|
47 # for each component to be built for the specified configuration. |
|
48 # |
|
49 # dump(): debug/development method to dump the internal data structures |
|
50 # |
|
51 # test(): debug/development method to dump the results of the methods |
|
52 # 'options()', 'targets()', 'specialInstructionsFlag()', 'components()'. |
|
53 # |
|
54 #------------------------------------------------------------------------------- |
|
55 package SysDefCollector; |
|
56 use strict; |
|
57 |
|
58 my $debugFlag = 0; |
|
59 |
|
60 sub new |
|
61 { |
|
62 my ($class, $configname, $loghandle) = @_; |
|
63 my $self = { client => SysDefCollector::ParserClient->new($configname,$loghandle), loghandle => $loghandle }; |
|
64 return bless $self, $class; |
|
65 } |
|
66 |
|
67 sub parserClient |
|
68 { |
|
69 my $self = shift; |
|
70 return $self->{client}; |
|
71 } |
|
72 |
|
73 #------------------------------------------------------------------------------- |
|
74 # sub options() - returns the translated list of options for each 'option' element |
|
75 #------------------------------------------------------------------------------- |
|
76 sub options |
|
77 { |
|
78 my $self = shift; |
|
79 return $self->_collectedList('option'); |
|
80 } |
|
81 |
|
82 #------------------------------------------------------------------------------- |
|
83 # sub targets() - returns the translated list of targets for each 'buildLayer' |
|
84 # in the named configuration. |
|
85 #------------------------------------------------------------------------------- |
|
86 sub targets |
|
87 { |
|
88 my $self = shift; |
|
89 |
|
90 my @targets; |
|
91 my @buildLayerTargetList = $self->_collectedList('buildLayerTargetList'); |
|
92 |
|
93 for my $layerTarget (@buildLayerTargetList) |
|
94 { |
|
95 my %targetListHash = $self->_collectedHash('targetList'); |
|
96 my @targetList = @{ $targetListHash{$layerTarget} }; |
|
97 push @targets, @targetList; |
|
98 } |
|
99 |
|
100 # eliminate any duplicates by storing as hash keys |
|
101 my %targetHash = map { $_, '' } @targets; |
|
102 |
|
103 # now translate via the target mapping |
|
104 my %targetMap = $self->_collectedHash('target'); |
|
105 @targets = map { $targetMap{$_} } keys %targetHash; |
|
106 |
|
107 return @targets; |
|
108 } |
|
109 |
|
110 #------------------------------------------------------------------------------- |
|
111 # sub specialInstructionsFlag() - returns true if 'specialInstructions' elements are present. |
|
112 #------------------------------------------------------------------------------- |
|
113 sub specialInstructionsFlag |
|
114 { |
|
115 my $self = shift; |
|
116 my $flag = 0; |
|
117 $flag = $self->_collected()->{specialInstructions} |
|
118 if exists $self->_collected()->{specialInstructions}; |
|
119 return $flag; |
|
120 } |
|
121 |
|
122 #------------------------------------------------------------------------------- |
|
123 # sub components() - returns an array of components to be built for the named |
|
124 # configuration. Each array element is a reference to a further array whose |
|
125 # element[0] is the component name and element[1] is the directory location |
|
126 # of that component's 'bld.inf' file. |
|
127 #------------------------------------------------------------------------------- |
|
128 sub components |
|
129 { |
|
130 my $self = shift; |
|
131 my $loghandle = $self->{loghandle}; |
|
132 |
|
133 my @unitNames; |
|
134 my @unitListRef = $self->_collectedList('unitListRef'); |
|
135 my %unitList = $self->_collectedHash('unitList'); |
|
136 my %unitListNamesHash; # Used to detect duplicates and then discarded! |
|
137 my %unitNamesHash; # Used to detect duplicates and then discarded! |
|
138 my %unitMap = $self->_collectedHash('unit'); |
|
139 |
|
140 for my $unitListName (@unitListRef) |
|
141 { |
|
142 if (defined $unitListNamesHash{$unitListName}) |
|
143 { # Duplicate unitListName! Ignore it! |
|
144 print $loghandle "Ignoring duplicated unitList: $unitListName\n"; |
|
145 next; |
|
146 } |
|
147 $unitListNamesHash{$unitListName} = 1; |
|
148 unless (defined $unitList{$unitListName}) |
|
149 { # No info for this unitList! |
|
150 print $loghandle "No Unit info for unitList: $unitListName\n"; |
|
151 next; |
|
152 } |
|
153 my @units = @{ $unitList{$unitListName} }; |
|
154 foreach my $unit (@units) |
|
155 { |
|
156 if (defined $unitNamesHash{$unit}) |
|
157 { # Duplicate unit name! Ignore it! |
|
158 print $loghandle "Ignoring duplicated Unit: $unit\n"; |
|
159 next; |
|
160 } |
|
161 $unitNamesHash{$unit} = 1; |
|
162 unless (defined $unitMap{$unit}) |
|
163 { # No bldFile (directory) info for this component! |
|
164 print $loghandle "No bldFile info for Unit: $unit\n"; |
|
165 next; |
|
166 } |
|
167 my @unitdef = ($unit, $unitMap{$unit}); |
|
168 push @unitNames, \@unitdef; |
|
169 } |
|
170 } |
|
171 |
|
172 return @unitNames; |
|
173 } |
|
174 |
|
175 #------------------------------------------------------------------------------- |
|
176 # |
|
177 #------------------------------------------------------------------------------- |
|
178 sub dump |
|
179 { |
|
180 my $self = shift; |
|
181 my $fh = shift; |
|
182 $self->parserClient($fh)->dump($fh); |
|
183 } |
|
184 |
|
185 #------------------------------------------------------------------------------- |
|
186 # |
|
187 #------------------------------------------------------------------------------- |
|
188 sub test |
|
189 { |
|
190 my $self = shift; |
|
191 my $fh = $self->{loghandle}; # Logfile handle |
|
192 |
|
193 my @options = $self->options(); |
|
194 my @targets = $self->targets(); |
|
195 my $special = $self->specialInstructionsFlag(); |
|
196 my @components = $self->components($fh); |
|
197 |
|
198 print $fh "\nTest Collected System Definition Query Methods\n"; |
|
199 print $fh "==============================================\n"; |
|
200 |
|
201 print $fh "options: ['", (join "', '", @options), "']\n"; |
|
202 print $fh "targets: ['", (join "', '", @targets), "']\n"; |
|
203 print $fh "special instructions: '", ($special ? "yes" : "no" ), "'\n"; |
|
204 print $fh "components:\n{\n"; |
|
205 for my $component (@components) |
|
206 { |
|
207 print $fh "\t'", $component->[0], "' => '", $component->[1], "'\n"; |
|
208 } |
|
209 print $fh "}\n"; |
|
210 print $fh "==============================================\n"; |
|
211 } |
|
212 |
|
213 #------------------------------------------------------------------------------- |
|
214 # private methods: |
|
215 #------------------------------------------------------------------------------- |
|
216 sub _collected |
|
217 { |
|
218 my $self = shift; |
|
219 return $self->parserClient()->{collected}; |
|
220 } |
|
221 |
|
222 sub _collectedHash |
|
223 { |
|
224 my ($self, $slot) = @_; |
|
225 my %hash = (); |
|
226 %hash = %{ $self->_collected()->{$slot} } |
|
227 if exists $self->_collected()->{$slot}; |
|
228 return %hash; |
|
229 } |
|
230 |
|
231 sub _collectedList |
|
232 { |
|
233 my ($self, $slot) = @_; |
|
234 my @list = (); |
|
235 @list = @{ $self->_collected()->{$slot} } |
|
236 if exists $self->_collected()->{$slot}; |
|
237 return @list; |
|
238 } |
|
239 |
|
240 #------------------------------------------------------------------------------- |
|
241 # package: SysDefCollector::ParserClient |
|
242 # |
|
243 # usage: Interacts directly with the SysDefParser to obtain those parts of the system |
|
244 # definition which are of interest. Implements the parser callback methods |
|
245 # for the XML elements for which we collect information. Some elements are |
|
246 # of interest only if they are enclosed within an outer element with certain |
|
247 # properties. Other elements are always of interest. The latter style of |
|
248 # element is always collected. The former is only collected when it is known |
|
249 # that we are within an appropriate enclosing element. The 'context' property |
|
250 # is used for testing this condition. |
|
251 # |
|
252 # methods: |
|
253 # |
|
254 # new(configname): constructs a new instance to collect system definition info |
|
255 # relating to the configuration name 'configname'. |
|
256 # |
|
257 # parserClient(): returns a reference to the SysDefCollector::ParserClient |
|
258 # instance - typically for passing to the parser. |
|
259 # |
|
260 #------------------------------------------------------------------------------- |
|
261 package SysDefCollector::ParserClient; |
|
262 use strict; |
|
263 |
|
264 sub new |
|
265 { |
|
266 my ($class, $configname, $loghandle) = @_; |
|
267 my $self = { configname => $configname, configfound => 0, context => {intask => 0}, collected => {}, loghandle => $loghandle }; |
|
268 return bless $self, $class; |
|
269 } |
|
270 |
|
271 #------------------------------------------------------------------------------- |
|
272 # The following methods 'configuration()', 'configuration_()' initiate and |
|
273 # terminate respectively the collection of element information found inside a |
|
274 # 'configuration' element with 'name' attribute matching the objects 'configname' |
|
275 # attribute. |
|
276 #------------------------------------------------------------------------------- |
|
277 sub configuration |
|
278 { |
|
279 my ($self, $expat, $element, %attrs) = @_; |
|
280 $self->_debugin(@_); |
|
281 my $loghandle = $self->{loghandle}; |
|
282 |
|
283 # start of a 'configuration' element - if the name of the element matches our |
|
284 # 'configname' attribute then we create contexts so that elements of interest |
|
285 # nested within this 'configuration' element can be collected. |
|
286 unless ($attrs{name} eq $self->{configname}) { return; } |
|
287 |
|
288 if ($self->{configfound}) |
|
289 { |
|
290 print $loghandle "Ignoring duplicated configuration: $attrs{name} ($attrs{description})\n"; |
|
291 } |
|
292 else |
|
293 { |
|
294 $self->{configfound} = 1; |
|
295 $self->{context}->{unitListRef} = []; |
|
296 $self->{context}->{buildLayerTargetList} = []; |
|
297 } |
|
298 } |
|
299 |
|
300 sub configuration_ |
|
301 { |
|
302 my ($self, $expat, $element) = @_; |
|
303 $self->_debugout(@_); |
|
304 |
|
305 # end of a 'configuration' element - save what we have collected within this |
|
306 # 'configuration' element and delete the context so as to terminate collection |
|
307 # of any subsequently encountered nested elements. |
|
308 |
|
309 if (exists $self->{context}->{unitListRef}) |
|
310 { |
|
311 $self->{collected}->{unitListRef} = $self->{context}->{unitListRef}; |
|
312 delete $self->{context}->{unitListRef}; |
|
313 } |
|
314 |
|
315 if (exists $self->{context}->{buildLayerTargetList}) |
|
316 { |
|
317 # eliminate duplicates |
|
318 my %hash = map { $_, '' } @{$self->{context}->{buildLayerTargetList}}; |
|
319 my @unique = keys %hash; |
|
320 $self->{collected}->{buildLayerTargetList} = \@unique; |
|
321 delete $self->{context}->{buildLayerTargetList}; |
|
322 } |
|
323 } |
|
324 |
|
325 #------------------------------------------------------------------------------- |
|
326 # Method 'unitListRef()' accumulates 'unitListRef' unitList information found |
|
327 # within a 'configuration element with matching name. |
|
328 #------------------------------------------------------------------------------- |
|
329 sub unitListRef |
|
330 { |
|
331 my ($self, $expat, $element, %attrs) = @_; |
|
332 $self->_debugin(@_); |
|
333 |
|
334 if($self->{context}->{intask}) |
|
335 { return; } # Task-specific unitListRef not supported |
|
336 |
|
337 # if there is a previously created context for 'unitListRef's then store this one. |
|
338 |
|
339 if (exists $self->{context}->{unitListRef}) |
|
340 { |
|
341 push @{$self->{context}->{unitListRef}}, $attrs{unitList}; |
|
342 } |
|
343 my $x = 1; |
|
344 } |
|
345 |
|
346 #------------------------------------------------------------------------------- |
|
347 # Methods 'task()' and 'task_()' track context (i.e. inside a task or not) |
|
348 # because task-specific activities are not supported. |
|
349 #------------------------------------------------------------------------------- |
|
350 sub task |
|
351 { |
|
352 my ($self, $expat, $element, %attrs) = @_; |
|
353 $self->_debugin(@_); |
|
354 $self->{context}->{intask} = 1; |
|
355 } |
|
356 |
|
357 sub task_ |
|
358 { |
|
359 my ($self, $expat, $element, %attrs) = @_; |
|
360 $self->_debugout(@_); |
|
361 $self->{context}->{intask} = 0; |
|
362 } |
|
363 |
|
364 #------------------------------------------------------------------------------- |
|
365 # Method 'buildlayer()' accumulates 'buildlayer' targetList information found |
|
366 # within a 'configuration element with matching name. |
|
367 #------------------------------------------------------------------------------- |
|
368 sub buildLayer |
|
369 { |
|
370 my ($self, $expat, $element, %attrs) = @_; |
|
371 $self->_debugin(@_); |
|
372 |
|
373 if (exists $self->{context}->{buildLayerTargetList}) |
|
374 { |
|
375 push @{$self->{context}->{buildLayerTargetList}}, (split /\s+/, $attrs{targetList}); |
|
376 } |
|
377 } |
|
378 |
|
379 #------------------------------------------------------------------------------- |
|
380 # The following three methods 'unitList()', 'unitList_()' and 'unitRef()' |
|
381 # accumulate 'unitList' and 'unitRef' information found within the 'build' elements. |
|
382 #------------------------------------------------------------------------------- |
|
383 sub unitList |
|
384 { |
|
385 my ($self, $expat, $element, %attrs) = @_; |
|
386 $self->_debugin(@_); |
|
387 |
|
388 # start of a 'unitList' element - create a context so that collection of all |
|
389 # 'unitRef's elements found within this 'unitList' element can be collected. |
|
390 |
|
391 die "Fatal: context already has unitList\n" if exists $self->{context}->{unitList}; |
|
392 $self->{context}->{unitList} = { name => $attrs{name}, list => [] }; |
|
393 } |
|
394 |
|
395 sub unitList_ |
|
396 { |
|
397 my ($self, $expat, $element, %attrs) = @_; |
|
398 $self->_debugout(@_); |
|
399 |
|
400 # end of the current 'unitList' element - save what we have collected |
|
401 # and delete the context |
|
402 |
|
403 $self->{collected}->{unitList} = {} if ! exists $self->{collected}->{unitList}; |
|
404 |
|
405 my $unitList = delete $self->{context}->{unitList}; |
|
406 $self->{collected}->{unitList}->{$unitList->{name}} = $unitList->{list}; |
|
407 |
|
408 } |
|
409 |
|
410 sub unitRef |
|
411 { |
|
412 my ($self, $expat, $element, %attrs) = @_; |
|
413 $self->_debugin(@_); |
|
414 |
|
415 # unitRef found - save unitRef data to current context |
|
416 |
|
417 die "Fatal: context requires unitList\n" if ! exists $self->{context}->{unitList}; |
|
418 push @{$self->{context}->{unitList}->{list}}, $attrs{unit}; |
|
419 } |
|
420 |
|
421 #------------------------------------------------------------------------------- |
|
422 # The method 'unit()' accumulates 'unit' information found within the 'systemModel' |
|
423 # elements. |
|
424 #------------------------------------------------------------------------------- |
|
425 sub unit |
|
426 { |
|
427 my ($self, $expat, $element, %attrs) = @_; |
|
428 $self->_debugin(@_); |
|
429 |
|
430 # no need to set up a temporary context to collect these since they have global scope |
|
431 $self->{collected}->{unit} = {} if ! exists $self->{collected}->{unit}; |
|
432 $self->{collected}->{unit}->{$attrs{unitID}} = $attrs{bldFile}; |
|
433 } |
|
434 |
|
435 #------------------------------------------------------------------------------- |
|
436 # sub option() - accumulates 'option' element information found within the |
|
437 # 'build' element. |
|
438 #------------------------------------------------------------------------------- |
|
439 sub option |
|
440 { |
|
441 my ($self, $expat, $element, %attrs) = @_; |
|
442 $self->_debugin(@_); |
|
443 |
|
444 if ($attrs{enable} =~ /[Yy]/) |
|
445 { |
|
446 # no need to set up a temporary context to collect these since they have global scope |
|
447 $self->{collected}->{option} = [] if ! exists $self->{collected}->{option}; |
|
448 push @{$self->{collected}->{option}}, $attrs{abldOption}; |
|
449 } |
|
450 } |
|
451 |
|
452 #------------------------------------------------------------------------------- |
|
453 # sub target() - accumulates 'target' element information found within the |
|
454 # 'build' element. |
|
455 #------------------------------------------------------------------------------- |
|
456 sub target |
|
457 { |
|
458 my ($self, $expat, $element, %attrs) = @_; |
|
459 $self->_debugin(@_); |
|
460 |
|
461 $self->{collected}->{target} = {} if ! exists $self->{collected}->{target}; |
|
462 $self->{collected}->{target}->{$attrs{name}} = $attrs{abldTarget}; |
|
463 } |
|
464 |
|
465 #------------------------------------------------------------------------------- |
|
466 # sub targetList() - accumulates 'targetList' element information found within the |
|
467 # 'build' element. |
|
468 #------------------------------------------------------------------------------- |
|
469 sub targetList |
|
470 { |
|
471 my ($self, $expat, $element, %attrs) = @_; |
|
472 $self->_debugin(@_); |
|
473 |
|
474 $self->{collected}->{targetList} = {} if ! exists $self->{collected}->{targetList}; |
|
475 my @list = split /\s+/, $attrs{target}; |
|
476 $self->{collected}->{targetList}->{$attrs{name}} = \@list; |
|
477 } |
|
478 |
|
479 #------------------------------------------------------------------------------- |
|
480 # sub specialInstructions() - sets the 'specialInstructions' flag if a |
|
481 # 'specialInstructions' element is encountered. In practice, we are only |
|
482 # interested in instructions which invoke SETUPPRJ.BAT as this will require |
|
483 # the inclusion of the "bootstrap" line in the output text file. |
|
484 #------------------------------------------------------------------------------- |
|
485 sub specialInstructions |
|
486 { |
|
487 my ($self, $expat, $element, %attrs) = @_; |
|
488 $self->_debugin(@_); |
|
489 if ($attrs{command} =~ /^setupprj.bat/i) |
|
490 { |
|
491 $self->{collected}->{specialInstructions} = 1; |
|
492 } |
|
493 } |
|
494 |
|
495 #------------------------------------------------------------------------------- |
|
496 # utility routines for development/debug purposes. |
|
497 #------------------------------------------------------------------------------- |
|
498 |
|
499 sub _debugin |
|
500 { |
|
501 ## return; ## Suppress this debugging! |
|
502 my $self = shift; |
|
503 my ($ignore0, $ignore2, $element, @args) = @_; |
|
504 my $loghandle = $self->{loghandle}; |
|
505 if ($debugFlag) { print $loghandle "Enter: $element (", (join ' ', @args), ")\n"; } |
|
506 } |
|
507 |
|
508 sub _debugout |
|
509 { |
|
510 ## return; ## Suppress this debugging! |
|
511 my $self = shift; |
|
512 my $loghandle = $self->{loghandle}; |
|
513 if ($debugFlag) { print $loghandle "Leave: $_[2]\n"; } |
|
514 } |
|
515 |
|
516 sub dump |
|
517 { |
|
518 my $self = shift; |
|
519 my $fh = shift; |
|
520 |
|
521 print $fh "\nDump Collected System Definition\n\n"; |
|
522 print $fh "================================\n"; |
|
523 |
|
524 if (keys %{$self->{collected}} > 0) |
|
525 { |
|
526 if (exists $self->{collected}->{option}) |
|
527 { |
|
528 my @option = @{$self->{collected}->{option}}; |
|
529 print $fh "option :[", (join ',', @option), "]\n"; |
|
530 } |
|
531 |
|
532 if (exists $self->{collected}->{specialInstructions}) |
|
533 { |
|
534 my $flag = $self->{collected}->{specialInstructions}; |
|
535 print $fh "specialInstructions : '", ($flag ? "yes" : "no"), "'\n"; |
|
536 } |
|
537 else |
|
538 { |
|
539 print $fh "specialInstructions : 'no'\n"; |
|
540 } |
|
541 |
|
542 if (exists $self->{collected}->{buildLayerTargetList}) |
|
543 { |
|
544 my @buildLayerTargetList = @{$self->{collected}->{buildLayerTargetList}}; |
|
545 print $fh "buildLayerTargetList :[", (join ',', @buildLayerTargetList), "]\n"; |
|
546 } |
|
547 |
|
548 if (exists $self->{collected}->{unitListRef}) |
|
549 { |
|
550 my @unitListRef = @{$self->{collected}->{unitListRef}}; |
|
551 print $fh "unitListRef :[", (join ',', @unitListRef), "]\n"; |
|
552 } |
|
553 |
|
554 if (exists $self->{collected}->{unitList}) |
|
555 { |
|
556 print $fh "unitList:\n{\n"; |
|
557 my %unitList = %{$self->{collected}->{unitList}}; |
|
558 for my $key (keys %unitList) |
|
559 { |
|
560 my @list = @{$unitList{$key}}; |
|
561 print $fh "\t'$key' has units:[", (join ',', @list), "]\n"; |
|
562 } |
|
563 print $fh "}\n"; |
|
564 } |
|
565 |
|
566 if (exists $self->{collected}->{target}) |
|
567 { |
|
568 print $fh "target:\n{\n"; |
|
569 my %target = %{$self->{collected}->{target}}; |
|
570 for my $key (keys %target) |
|
571 { |
|
572 print $fh "\t'$key' => '", $target{$key} , "'\n"; |
|
573 } |
|
574 print $fh "}\n"; |
|
575 } |
|
576 |
|
577 if (exists $self->{collected}->{targetList}) |
|
578 { |
|
579 print $fh "targetList:\n{\n"; |
|
580 my %targetList = %{$self->{collected}->{targetList}}; |
|
581 for my $key (keys %targetList) |
|
582 { |
|
583 my @list = @{$targetList{$key}}; |
|
584 print $fh "\t'$key' has targets:[", (join ',', @list), "]\n"; |
|
585 } |
|
586 print $fh "}\n"; |
|
587 } |
|
588 |
|
589 if (exists $self->{collected}->{unit}) |
|
590 { |
|
591 print $fh "unit:\n{\n"; |
|
592 my %unit = %{$self->{collected}->{unit}}; |
|
593 for my $key (keys %unit) |
|
594 { |
|
595 print $fh "\t'$key' => '", $unit{$key} , "'\n"; |
|
596 } |
|
597 print $fh "}\n"; |
|
598 } |
|
599 } |
|
600 else |
|
601 { |
|
602 print $fh "Nothing collected\n"; |
|
603 } |
|
604 print $fh "================================\n"; |
|
605 } |
|
606 |
|
607 #------------------------------------------------------------------------------- |
|
608 # -EOF- |
|
609 #------------------------------------------------------------------------------- |
|
610 1; |
|