File Coverage

lib/SMS/Ringtone/RTTTL/Parser.pm
Criterion Covered Total %
statement 127 338 37.5
branch 46 130 35.3
condition 5 15 33.3
subroutine 14 35 40.0
pod 27 27 100.0
total 219 545 40.1


line stmt bran cond sub pod time code
1             package SMS::Ringtone::RTTTL::Parser;
2             #### Package information ####
3             # Description and copyright:
4             # See POD (i.e. perldoc SMS::Ringtone::RTTTL::Parser).
5             ####
6              
7             #### Class information ####
8             # Protected fields:
9             # -DEFAULTS: Reference to hash of defaults containing keys d,o,b,l,v,s.
10             # -ERRORS: Reference to array of errors.
11             # -NOTES: Reference to array of [duration, note, octave, dots] elements.
12             # -P1.VALID: Is part 1 valid?
13             # -P2.VALID: Is part 2 valid?
14             # -P3.VALID: Is part 3 valid?
15             # -PARTS: Reference to array of the 3 parts.
16             # -RTTTL: RTTTL string.
17             # -WARNINGS: Reference to array of warnings.
18             # Constructors:
19             # new()
20             # Protected methods:
21             # _parse()
22             # _parse_name()
23             # _parse_defaults()
24             # _parse_notes()
25             # Public methods:
26             # get_bpm(): Returns the effective BPM setting.
27             # get_errors(): Returns an array of error messages.
28             # get_part_defaults(): Returns the defaults part.
29             # get_part_name(): Returns name part.
30             # get_part_notes(): Returns notes part.
31             # get_note_count(): Return the amount of notes.
32             # get_notes(): Returns an array of [duration, note, octave, dots] elements.
33             # get_repeat(): Returns the effective repeat length.
34             # get_rtttl(): Returns the RTTTL string.
35             # get_style(): Returns the effective style.
36             # get_volume(): Returns the effective volume.
37             # get_warnings(): Returns an array of warning messages.
38             # has_errors()
39             # has_warnings()
40             # is_name_valid()
41             # is_defaults_valid()
42             # is_notes_valid()
43             # puke(): Dump parse results to STDOUT.
44             ####
45              
46 1     1   2251 use strict;
  1         2  
  1         35  
47 1     1   6 use Carp;
  1         2  
  1         4468  
48             our @ISA = qw(Exporter);
49             our @EXPORT = qw(is_valid_bpm
50             is_valid_duration
51             is_valid_octave
52             is_valid_repeat
53             is_valid_volume
54             nearest_bpm
55             nearest_duration
56             nearest_octave);
57             our $VERSION = '0.07';
58              
59             1;
60              
61             sub _get_nearest {
62 0     0   0 my $value = shift;
63 0         0 my $aref = shift;
64 0         0 my $i = 0;
65 0         0 while ($i < @{$aref}) {
  0         0  
66 0 0       0 if ($aref->[$i] == $value) {
67 0         0 return $aref->[$i];
68             }
69 0 0       0 if ($aref->[$i] > $value) {
70 0 0       0 if ($i >= 1) {
71 0         0 my $l = $aref->[$i-1];
72 0         0 my $h = $aref->[$i];
73 0 0       0 return ($value - $l) < ($h - $value) ? $l : $h;
74             }
75 0         0 return $aref->[$i];
76             }
77 0         0 $i++;
78             }
79 0         0 return $aref->[scalar(@{$aref})-1];
  0         0  
80             }
81              
82             sub _inarray {
83 1053     1053   1042 my $e = shift;
84 1053         1037 my $aref = shift;
85 1053         937 foreach (@{$aref}) {
  1053         1407  
86 3460 100       5620 if ($e eq $_) {
87 1053         2376 return 1;
88             }
89             }
90 0         0 return 0;
91             }
92              
93             our @BPM = ( '25', '28', '31', '35', '40', '45', '50',
94             '56', '63', '70', '80', '90', '100', '112',
95             '125', '140', '160', '180', '200', '225', '250',
96             '285', '320', '355', '400', '450', '500', '565',
97             '635', '715', '800', '900');
98              
99             sub is_valid_bpm {
100 15     15 1 32 return &_inarray(pop,\@BPM);
101             }
102              
103             sub nearest_bpm {
104 0     0 1 0 return &_get_nearest(pop,\@BPM);
105             }
106              
107             our @DURATION = ('1','2','4','8','16','32');
108              
109             sub is_valid_duration {
110 518     518 1 795 return &_inarray(pop,\@DURATION);
111             }
112              
113             sub nearest_duration {
114 0     0 1 0 return &_get_nearest(pop,\@DURATION);
115             }
116              
117             our @OCTAVE = ('4','5','6','7'); # Octave 4 note A is 440Hz.
118              
119             sub is_valid_octave {
120 520     520 1 762 return &_inarray(pop,\@OCTAVE);
121             }
122              
123             sub nearest_octave {
124 0     0 1 0 return &_get_nearest(pop,\@OCTAVE);
125             }
126              
127             sub is_valid_repeat {
128 15     15 1 24 my $i = pop;
129 15   33     127 return(($i =~ /^\d+$/o) && ($i >= 0) && ($i <= 15));
130             }
131              
132             sub is_valid_volume {
133 0     0 1 0 my $i = pop;
134 0   0     0 return(($i =~ /^\d+$/o) && ($i >= 0) && ($i <= 15));
135             }
136              
137             our %DEFAULTS = ('d' => 4, 'o' => 6, 'b' => 63, 'v' => 7, 's' => 'n', 'l' => 0);
138              
139             ####
140             # Constructor new()
141             # Parameters:
142             # 1. RTTTL string
143             # 2. Optional reference to hash of options.
144             ####
145             sub new {
146 15     15 1 1256 my $package = shift;
147 15         18 my $rtttl = shift;
148 15         17 my $options = shift;
149 15         20 my $self = {};
150 15         19 bless $self;
151              
152             # Check parameters
153 15 50       56 unless(defined($rtttl)) {
154 0         0 croak("RTTTL parameter missing or undefined!\n");
155             }
156              
157             # Set private fields
158 15         73 my %defs = %DEFAULTS;
159 15         41 $self->{'-DEFAULTS'} = \%defs;
160 15         25 $self->{'-ERRORS'} = [];
161 15         23 $self->{'-NOTES'} = [];
162 15         19 $self->{'-P1.VALID'} = 0;
163 15         22 $self->{'-P2.VALID'} = 0;
164 15         31 $self->{'-P3.VALID'} = 0;
165 15         20 $self->{'-PARTS'} = [];
166 15         36 $self->{'-RTTTL'} = $rtttl;
167 15         18 $self->{'-WARNINGS'} = [];
168 15 50 33     70 if (defined($options) && defined($options->{'STRICT_NOTE_PART_ORDER'})) {
169 15         22 $self->{'-STRICT_NOTE_PART_ORDER'} = $options->{'STRICT_NOTE_PART_ORDER'};
170             }
171             else {
172 0         0 $self->{'-STRICT_NOTE_PART_ORDER'} = 1;
173             }
174              
175             # Parse RTTTL
176 15         31 $self->_parse();
177              
178             # Return self reference
179 15         38 return $self;
180             }
181              
182             ####
183             # Method : _parse
184             # Description : Parses RTTTL string
185             # Parameters : none.
186             # Returns : Boolean result.
187             #####
188             sub _parse {
189 15     15   13 my $self = shift;
190 15         26 my $rtttl = $self->{'-RTTTL'};
191             #if ($rtttl =~ s/\s+$//o) {
192             # push(@{$self->{'-WARNINGS'}},'Trailing white space found and removed from RTTTL string.');
193             #}
194             # Split parts
195 15         54 my @parts = split(':',$rtttl);
196 15 50       35 unless(@parts == 3) {
197 0         0 push(@{$self->{'-ERRORS'}},'Invalid number of parts. Should be 3 parts: [] +');
  0         0  
198 0         0 return 0;
199             }
200 15         18 @{$self->{'-PARTS'}} = @parts;
  15         32  
201              
202             # Parse name
203 15         32 $self->{'-P1.VALID'} = $self->_parse_name($parts[0]);
204              
205             # Parse defaults
206 15         38 $self->{'-P2.VALID'} = $self->_parse_defaults($parts[1]);
207              
208             # Parse notes
209 15         31 $self->{'-P3.VALID'} = $self->_parse_notes($parts[2]);
210 15         29 return 1;
211             }
212              
213             ####
214             # Method : _parse_name
215             # Description : Parses name part of RTTTL string
216             # Parameters : 1. Name part.
217             # Returns : Boolean result.
218             #####
219             sub _parse_name {
220 15     15   14 my $self = shift;
221 15         17 my $name = shift;
222 15 50       26 if (length($name) <= 15) {
223 15         18 $self->{'-P1.VALID'} = 1;
224 15         27 return 1;
225             }
226             else {
227 0         0 push(@{$self->{'-WARNINGS'}},"Length of name part exceeds 15 characters: $name");
  0         0  
228             }
229 0         0 return 0;
230             }
231              
232             ####
233             # Method : _parse_defaults
234             # Description : Parses defaults part of RTTTL string
235             # Parameters : 1. Defaults part.
236             # Returns : Boolean result.
237             #####
238             sub _parse_defaults {
239 15     15   18 my $self = shift;
240 15         15 my $part = shift;
241 15         18 my $errors = $self->{'-ERRORS'};
242 15         18 my $warnings = $self->{'-WARNINGS'};
243 15         14 my $result = 1;
244 15         16 my $d;
245             my $o;
246 0         0 my $b;
247 0         0 my $l;
248 0         0 my $v;
249 0         0 my $s;
250             #if ($part =~ s/\s//go) {
251             # push(@{$warnings},'White space found and removed from defaults part.');
252             #}
253 15 50       28 if (length($part)) {
254 15         42 my @defs = split(',',$part);
255 15         23 foreach my $def (@defs) {
256 50 50       197 unless ($def =~ /^(([doblv])=(\d+)|(s)=([ncs]))$/o) {
257 0         0 push(@{$warnings},"Invalid entry in defaults part: $def");
  0         0  
258 0         0 $result = 0;
259 0         0 next;
260             }
261 50         45 my $key;
262             my $value;
263 50 50       89 if (defined($2)) {
264 50         67 $key = $2;
265 50         64 $value = $3;
266             }
267             else {
268 0         0 $key = $4;
269 0         0 $value = $5;
270             }
271 50 100       125 if ($key eq 'd') {
    100          
    100          
    50          
    0          
    0          
272 9 50       17 if (defined($d)) {
273 0         0 push(@{$warnings},"Duration entry in defaults specified more than once: $part");
  0         0  
274 0         0 $result = 0;
275             }
276 9         10 my $i = $value;
277 9 50       16 unless(&is_valid_duration($i)) {
278 0         0 my $nearest = &nearest_octave($i);
279 0         0 push(@{$errors},"Invalid duration setting $i in defaults replaced with $nearest: $part");
  0         0  
280 0         0 $i = $nearest;
281 0         0 $result = 0;
282             }
283 9         22 $d = $i;
284             }
285             elsif ($key eq 'o') {
286 11 50       30 if (defined($o)) {
287 0         0 push(@{$warnings},"Octave (scale) entry in defaults specified more than once: $part");
  0         0  
288 0         0 $result = 0;
289             }
290 11         12 my $i = $value;
291 11 50       22 unless(&is_valid_octave($i)) {
292 0         0 my $nearest = &nearest_octave($i);
293 0         0 push(@{$errors},"Invalid octave (scale) setting $i in defaults replaced with $nearest: $part");
  0         0  
294 0         0 $i = $nearest;
295 0         0 $result = 0;
296             }
297 11         34 $o = $i;
298             }
299             elsif ($key eq 'b') {
300 15 50       27 if (defined($b)) {
301 0         0 push(@{$warnings},"BPM entry in defaults specified more than once: $part");
  0         0  
302 0         0 $result = 0;
303             }
304 15         21 my $i = $value;
305 15 50       22 unless(&is_valid_bpm($i)) {
306 0         0 my $nearest = &nearest_bpm($i);
307 0         0 push(@{$warnings},"Invalid BPM setting $i in defaults replaced with $nearest: $part");
  0         0  
308 0         0 $i = $nearest;
309 0         0 $result = 0;
310             }
311 15         28 $b = $i;
312             }
313             elsif ($key eq 'l') {
314 15 50       27 if (defined($l)) {
315 0         0 push(@{$warnings},"Length entry in defaults specified more than once: $part");
  0         0  
316 0         0 $result = 0;
317             }
318 15 50       23 if (&is_valid_repeat($value)) {
319 15         35 $l = $value;
320             }
321             else {
322 0         0 push(@{$errors},"Invalid length setting $value in defaults.");
  0         0  
323 0         0 $result = 0;
324             }
325             }
326             elsif ($key eq 'v') {
327 0 0       0 if (defined($v)) {
328 0         0 push(@{$warnings},"Volume entry in defaults specified more than once: $part");
  0         0  
329 0         0 $result = 0;
330             }
331 0 0       0 if (&is_valid_volume($value)) {
332 0         0 $v = $value;
333             }
334             else {
335 0         0 push(@{$errors},"Invalid volume setting $value in defaults.");
  0         0  
336 0         0 $result = 0;
337             }
338             }
339             elsif ($key eq 's') {
340 0 0       0 if (defined($s)) {
341 0         0 push(@{$warnings},"Style entry in defaults specified more than once: $part");
  0         0  
342 0         0 $result = 0;
343             }
344 0         0 $s = $value;
345             }
346             }
347             }
348 15 100       32 if (defined($d)) {
349 9         19 $self->{'-DEFAULTS'}->{'d'} = $d;
350             }
351 15 100       24 if (defined($o)) {
352 11         22 $self->{'-DEFAULTS'}->{'o'} = $o;
353             }
354 15 50       24 if (defined($b)) {
355 15         28 $self->{'-DEFAULTS'}->{'b'} = $b;
356             }
357 15 50       22 if (defined($l)) {
358 15         24 $self->{'-DEFAULTS'}->{'l'} = $l;
359             }
360 15 50       26 if (defined($v)) {
361 0         0 $self->{'-DEFAULTS'}->{'v'} = $v;
362             }
363 15 50       21 if (defined($s)) {
364 0         0 $self->{'-DEFAULTS'}->{'s'} = $s;
365             }
366 15         33 return $result;
367             }
368              
369             ####
370             # Method : _parse_notes
371             # Description : Parses notes part of RTTTL string
372             # Parameters : 1. Notes part.
373             # Returns : Boolean result.
374             #####
375             sub _parse_notes {
376 15     15   14 my $self = shift;
377 15         160 my @notespart = split(',',shift);
378 15         32 my $errors = $self->{'-ERRORS'};
379 15         20 my $strict_note_part_order = $self->{'-STRICT_NOTE_PART_ORDER'};
380 15 50       28 unless(@notespart) {
381 0         0 push(@{$errors},'No notes present in notes part.');
  0         0  
382 0         0 return 0;
383             }
384 15         14 my $result = 1;
385 15         17 my $warnings = $self->{'-WARNINGS'};
386 15         24 my $def_d = $self->{'-DEFAULTS'}->{'d'};
387 15         18 my $def_o = $self->{'-DEFAULTS'}->{'o'};
388 15         15 my $notes = $self->{'-NOTES'};
389 15         14 my $i = 0;
390 15         23 foreach my $e (@notespart) {
391 509         526 $i++;
392             # The substitution below was added in v0.06 by Igor Ivoilov
393             # because there are a lot of RTTTL generators that generate rtttl that
394             # doesn't strictly follow the specification but have a not form like:
395             # := [] [] []
396             # instead of:
397             # := [] [] []
398 509 50 33     893 if (!$strict_note_part_order && ($e =~ /^(\d*)([P;BEH]|[CDFGA]#?)([\.;&]?)(\d*)$/oi)) {
399 0         0 $e = "$1$2$4$3";
400             }
401 509 50       1857 unless($e =~ /^(\d*)([P;BEH]|[CDFGA]#?)(\d*)([\.;&])?$/oi) {
402 0         0 push(@{$errors},"Invalid syntax in note $i: $e");
  0         0  
403 0         0 $result = 0;
404 0         0 next;
405             }
406 509 100       963 my $duration = length($1) ? $1 : $def_d;
407 509 50       749 unless(&is_valid_duration($duration)) {
408 0         0 push(@{$errors},"Invalid duration $duration in note $i: $e");
  0         0  
409 0         0 $result = 0;
410             }
411 509         814 my $note = uc($2);
412 509 50       1102 if ($note eq 'H') {
    50          
413 0         0 $note = 'B';
414             }
415             elsif ($note eq ';') {
416 0         0 $note = 'P';
417             }
418 509 100       843 my $octave = length($3) ? $3 : $def_o;
419 509 50       720 unless(&is_valid_octave($octave)) {
420 0         0 push(@{$errors},"Invalid octave $octave in note $i: $e");
  0         0  
421 0         0 $result = 0;
422             }
423 509         537 my $dots = 0;
424 509 100 66     1058 if (defined($4) && length($4)) {
425 4 50       9 if ($4 eq '.') {
    0          
    0          
426 4         5 $dots = 1;
427             }
428             elsif ($4 eq ';') {
429 0         0 $dots = 2;
430             }
431             elsif ($4 eq '&') {
432 0         0 $dots = 3;
433             }
434             }
435 509         440 push(@{$notes},[$duration,$note,$octave,$dots]);
  509         1609  
436             }
437 15         82 return $result;
438             }
439              
440             ####
441             # Method : get_bpm()
442             # Description : Returns BPM setting of RTTTL string.
443             # Parameters : none
444             # Returns : Decimal result
445             #####
446             sub get_bpm {
447 0     0 1 0 my $self = shift;
448 0         0 return $self->{'-DEFAULTS'}->{'b'};
449             }
450              
451             ####
452             # Method : get_part_defaults()
453             # Description : Returns defaults part of RTTTL string.
454             # Parameters : none
455             # Returns : String result
456             #####
457             sub get_part_defaults {
458 0     0 1 0 my $self = shift;
459 0         0 return $self->{'-PARTS'}->[1];
460             }
461              
462             ####
463             # Method : get_part_name()
464             # Description : Returns name part of RTTTL string.
465             # Parameters : none
466             # Returns : String result
467             #####
468             sub get_part_name {
469 0     0 1 0 my $self = shift;
470 0         0 return $self->{'-PARTS'}->[0];
471             }
472              
473             ####
474             # Method : get_part_notes()
475             # Description : Returns notes part of RTTTL string.
476             # Parameters : none
477             # Returns : String result
478             #####
479             sub get_part_notes {
480 0     0 1 0 my $self = shift;
481 0         0 return $self->{'-PARTS'}->[2];
482             }
483              
484             ####
485             # Method : get_errors()
486             # Description : Returns (a reference to) an array of parse errors.
487             # Parameters : none
488             # Returns : Array or array reference.
489             #####
490             sub get_errors {
491 0     0 1 0 my $self = shift;
492 0 0       0 if (wantarray) {
493 0         0 return @{$self->{'-ERRORS'}};
  0         0  
494             }
495             else {
496 0         0 return $self->{'-ERRORS'};
497             }
498             }
499              
500             ####
501             # Method : get_note_count()
502             # Description : Returns note count of RTTTL string.
503             # Parameters : none
504             # Returns : Decimal result
505             #####
506             sub get_note_count {
507 0     0 1 0 my $self = shift;
508 0         0 return scalar(@{$self->{'-NOTES'}});
  0         0  
509             }
510              
511             ####
512             # Method : get_notes()
513             # Description : Returns an array of [duration, note, octave, dots] elements.
514             # Parameters : none
515             # Returns : Array or array reference.
516             #####
517             sub get_notes {
518 0     0 1 0 my $self = shift;
519 0 0       0 if (wantarray) {
520 0         0 return @{$self->{'-NOTES'}};
  0         0  
521             }
522             else {
523 0         0 return $self->{'-NOTES'};
524             }
525             }
526              
527             ####
528             # Method : get_repeat()
529             # Description : Returns repeat length setting of RTTTL string.
530             # Parameters : none
531             # Returns : Decimal result
532             #####
533             sub get_repeat {
534 0     0 1 0 my $self = shift;
535 0         0 return $self->{'-DEFAULTS'}->{'l'};
536             }
537              
538             ####
539             # Method : get_rtttl()
540             # Description : Reconstructs the RTTTL string.
541             # Parameters : none
542             # Returns : Optimized RTTTL string or undef if errors present.
543             #####
544             sub get_rtttl {
545 0     0 1 0 my $self = shift;
546 0 0       0 if ($self->has_errors()) {
547 0         0 return undef;
548             }
549 0         0 my $name = substr($self->get_part_name(),0,15);
550             # Find the most common duration and most common octave
551 0         0 my %d = map{$_,0} @DURATION;
  0         0  
552 0         0 my %o = map{$_,0} @OCTAVE;
  0         0  
553 0         0 my $notes = $self->get_notes();
554 0         0 foreach my $n (@{$notes}) { #[duration, note, octave, dots]
  0         0  
555 0         0 $d{$n->[0]}++;
556 0         0 $o{$n->[2]}++;
557             }
558 0         0 my $defdur = $DURATION[0];
559 0         0 my $maxuse = 0;
560 0         0 foreach (keys %d) {
561 0 0       0 if ($d{$_} > $maxuse) {
562 0         0 $defdur = $_;
563 0         0 $maxuse = $d{$_};
564             }
565             }
566 0         0 my $defoct = $OCTAVE[0];
567 0         0 $maxuse = 0;
568 0         0 foreach (keys %o) {
569 0 0       0 if ($o{$_} > $maxuse) {
570 0         0 $defoct = $_;
571 0         0 $maxuse = $o{$_};
572             }
573             }
574 0         0 my @defs;
575             # Add most common duration and octave to defaults.
576 0 0       0 unless($defdur == $DEFAULTS{'d'}) {
577 0         0 push(@defs,"d=$defdur");
578             }
579 0 0       0 unless($defoct == $DEFAULTS{'o'}) {
580 0         0 push(@defs,"o=$defoct");
581             }
582 0 0       0 unless($self->get_bpm() == $DEFAULTS{'b'}) {
583 0         0 push(@defs,'b=' . $self->get_bpm());
584             }
585 0 0       0 unless($self->get_style() eq $DEFAULTS{'s'}) {
586 0         0 push(@defs,'s=' . $self->get_style());
587             }
588 0 0       0 unless($self->get_repeat() == $DEFAULTS{'l'}) {
589 0         0 push(@defs,'l=' . $self->get_repeat());
590             }
591 0 0       0 unless($self->get_volume() == $DEFAULTS{'v'}) {
592 0         0 push(@defs,'v=' . $self->get_volume());
593             }
594             # Construct notes.
595 0         0 my @rtttlnotes;
596 0         0 foreach my $n (@{$notes}) { #[duration, note, octave, dots]
  0         0  
597 0         0 my $note = '';
598 0 0       0 unless($defdur == $n->[0]) {
599 0         0 $note .= $n->[0];
600             }
601 0         0 $note .= $n->[1];
602 0 0       0 unless($defoct == $n->[2]) {
603 0         0 $note .= $n->[2];
604             }
605 0 0       0 if ($n->[3] > 0) {
606 0 0       0 if ($n->[3] == 1) {
    0          
607 0         0 $note .= '.';
608             }
609             elsif ($n->[3] == 2) {
610 0         0 $note .= ';';
611             }
612             else {
613 0         0 $note .= '&';
614             }
615             }
616 0         0 push(@rtttlnotes,$note);
617             }
618 0         0 return "$name:" . join(',',@defs) . ':' . join(',',@rtttlnotes);
619             }
620              
621             ####
622             # Method : get_style()
623             # Description : Returns style setting of RTTTL string.
624             # Parameters : none
625             # Returns : Decimal result
626             #####
627             sub get_style {
628 0     0 1 0 my $self = shift;
629 0         0 return $self->{'-DEFAULTS'}->{'s'};
630             }
631              
632             ####
633             # Method : get_volume()
634             # Description : Returns volume setting of RTTTL string.
635             # Parameters : none
636             # Returns : Decimal result
637             #####
638             sub get_volume {
639 0     0 1 0 my $self = shift;
640 0         0 return $self->{'-DEFAULTS'}->{'v'};
641             }
642              
643             ####
644             # Method : get_warnings()
645             # Description : Returns (a reference to) an array of parse warnings.
646             # Parameters : none
647             # Returns : Array or array reference.
648             #####
649             sub get_warnings {
650 0     0 1 0 my $self = shift;
651 0 0       0 if (wantarray) {
652 0         0 return @{$self->{'-WARNINGS'}};
  0         0  
653             }
654             else {
655 0         0 return $self->{'-WARNINGS'};
656             }
657             }
658              
659             ####
660             # Method : has_errors()
661             # Description : Indicates if any parse errors occured.
662             # Parameters : none
663             # Returns : The amount of errors.
664             #####
665             sub has_errors {
666 15     15 1 67 my $self = shift;
667 15         16 return scalar(@{$self->{'-ERRORS'}});
  15         34  
668             }
669              
670             ####
671             # Method : has_warnings()
672             # Description : Indicates if any parse warnings occured.
673             # Parameters : none
674             # Returns : The amount of warnings.
675             #####
676             sub has_warnings {
677 15     15 1 40 my $self = shift;
678 15         14 return scalar(@{$self->{'-WARNINGS'}});
  15         30  
679             }
680              
681             ####
682             # Method : is_name_valid()
683             # Description : Tells if name part of RTTTL string is valid.
684             # Parameters : none
685             # Returns : Boolean result
686             #####
687             sub is_name_valid {
688 0     0 1   my $self = shift;
689 0           return $self->{'-P1.VALID'};
690             }
691              
692             ####
693             # Method : is_defaults_valid()
694             # Description : Tells if defaults part of RTTTL string is valid.
695             # Parameters : none
696             # Returns : Boolean result
697             #####
698             sub is_defaults_valid {
699 0     0 1   my $self = shift;
700 0           return $self->{'-P2.VALID'};
701             }
702              
703             ####
704             # Method : is_notes_valid()
705             # Description : Tells if notes part of RTTTL string is valid.
706             # Parameters : none
707             # Returns : Boolean result
708             #####
709             sub is_notes_valid {
710 0     0 1   my $self = shift;
711 0           return $self->{'-P3.VALID'};
712             }
713              
714             ####
715             # Method : puke()
716             # Description : Dumps parse results to STDOUT.
717             # Parameters : none
718             # Returns : void
719             #####
720             sub puke {
721 0     0 1   my $self = shift;
722 0           print 'Name part: ' . $self->get_part_name() . "\n";
723 0           print 'Defaults part: ' . $self->get_part_defaults() . "\n";
724 0           print 'Notes part: ' . $self->get_part_notes() . "\n";
725 0           my $defs = $self->{'-DEFAULTS'};
726 0           print 'Effective defaults: d=' . $defs->{'d'} . ',o=' . $defs->{'o'} . ',b=' . $defs->{'b'} . "\n";
727 0           print "Effective notes (duration,note,octave,dots):\n";
728 0           foreach my $note ($self->get_notes()) {
729 0           print "\t[ " . sprintf('%2s',$note->[0]) . ' , ' . sprintf('%2s',$note->[1]) . ' , ' . $note->[2] . ' , ' . $note->[3] . " ]\n";
730             }
731 0           print "WARNINGS:\n";
732 0           foreach ($self->get_warnings()) {
733 0           print "\t$_\n";
734             }
735 0           print "ERRORS:\n";
736 0           foreach ($self->get_errors()) {
737 0           print "\t$_\n";
738             }
739             }
740              
741             __END__