| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#! perl |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
package main; |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
our $options; |
|
6
|
|
|
|
|
|
|
our $config; |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
package ChordPro::Config; |
|
9
|
|
|
|
|
|
|
|
|
10
|
90
|
|
|
90
|
|
1469
|
use v5.26; |
|
|
90
|
|
|
|
|
393
|
|
|
11
|
90
|
|
|
90
|
|
562
|
use utf8; |
|
|
90
|
|
|
|
|
206
|
|
|
|
90
|
|
|
|
|
667
|
|
|
12
|
90
|
|
|
90
|
|
2952
|
use Carp; |
|
|
90
|
|
|
|
|
216
|
|
|
|
90
|
|
|
|
|
7966
|
|
|
13
|
90
|
|
|
90
|
|
668
|
use feature qw( signatures state ); |
|
|
90
|
|
|
|
|
199
|
|
|
|
90
|
|
|
|
|
18255
|
|
|
14
|
90
|
|
|
90
|
|
676
|
no warnings "experimental::signatures"; |
|
|
90
|
|
|
|
|
183
|
|
|
|
90
|
|
|
|
|
4949
|
|
|
15
|
|
|
|
|
|
|
|
|
16
|
90
|
|
|
90
|
|
63970
|
use ChordPro; |
|
|
90
|
|
|
|
|
397
|
|
|
|
90
|
|
|
|
|
26505
|
|
|
17
|
90
|
|
|
90
|
|
849
|
use ChordPro::Files; |
|
|
90
|
|
|
|
|
206
|
|
|
|
90
|
|
|
|
|
17407
|
|
|
18
|
90
|
|
|
90
|
|
682
|
use ChordPro::Paths; |
|
|
90
|
|
|
|
|
195
|
|
|
|
90
|
|
|
|
|
5333
|
|
|
19
|
90
|
|
|
90
|
|
676
|
use ChordPro::Utils; |
|
|
90
|
|
|
|
|
227
|
|
|
|
90
|
|
|
|
|
15502
|
|
|
20
|
90
|
|
|
90
|
|
577
|
use ChordPro::Utils qw( enumerated ); |
|
|
90
|
|
|
|
|
217
|
|
|
|
90
|
|
|
|
|
5238
|
|
|
21
|
90
|
|
|
90
|
|
586
|
use Scalar::Util qw(reftype); |
|
|
90
|
|
|
|
|
168
|
|
|
|
90
|
|
|
|
|
4874
|
|
|
22
|
90
|
|
|
90
|
|
524
|
use List::Util qw(any); |
|
|
90
|
|
|
|
|
179
|
|
|
|
90
|
|
|
|
|
5564
|
|
|
23
|
90
|
|
|
90
|
|
537
|
use Storable 'dclone'; |
|
|
90
|
|
|
|
|
208
|
|
|
|
90
|
|
|
|
|
4535
|
|
|
24
|
90
|
|
|
90
|
|
67387
|
use Hash::Util; |
|
|
90
|
|
|
|
|
428699
|
|
|
|
90
|
|
|
|
|
1137
|
|
|
25
|
90
|
|
|
90
|
|
18202
|
use Ref::Util qw( is_arrayref is_hashref ); |
|
|
90
|
|
|
|
|
222
|
|
|
|
90
|
|
|
|
|
15598
|
|
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
#sub hmerge($$;$); |
|
28
|
|
|
|
|
|
|
#sub clone($); |
|
29
|
|
|
|
|
|
|
#sub default_config(); |
|
30
|
|
|
|
|
|
|
|
|
31
|
342
|
|
|
342
|
0
|
321060
|
sub new ( $pkg, $cf = {} ) { |
|
|
342
|
|
|
|
|
965
|
|
|
|
342
|
|
|
|
|
837
|
|
|
|
342
|
|
|
|
|
688
|
|
|
32
|
342
|
|
|
|
|
24240
|
bless $cf => $pkg; |
|
33
|
|
|
|
|
|
|
} |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
sub pristine_config { |
|
36
|
90
|
|
|
90
|
|
53974
|
use ChordPro::Config::Data; |
|
|
90
|
|
|
|
|
410
|
|
|
|
90
|
|
|
|
|
812941
|
|
|
37
|
209
|
|
|
209
|
0
|
293310
|
__PACKAGE__->new(ChordPro::Config::Data::config()); |
|
38
|
|
|
|
|
|
|
} |
|
39
|
|
|
|
|
|
|
|
|
40
|
208
|
|
|
208
|
0
|
592
|
sub configurator ( $opts = undef ) { |
|
|
208
|
|
|
|
|
1783
|
|
|
|
208
|
|
|
|
|
474
|
|
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# Test programs call configurator without options. |
|
43
|
|
|
|
|
|
|
# Prepare a minimal config. |
|
44
|
208
|
100
|
|
|
|
1043
|
unless ( $opts ) { |
|
45
|
89
|
|
|
|
|
470
|
my $cfg = pristine_config(); |
|
46
|
89
|
|
|
|
|
250
|
$config = $cfg; |
|
47
|
89
|
|
|
|
|
554
|
$cfg->split_fc_aliases; |
|
48
|
89
|
|
|
|
|
431
|
$options = { verbose => 0 }; |
|
49
|
89
|
|
|
|
|
576
|
process_config( $cfg, "" ); |
|
50
|
89
|
|
|
|
|
630
|
$cfg->{settings}->{lineinfo} = 0; |
|
51
|
89
|
|
|
|
|
735
|
return $cfg; |
|
52
|
|
|
|
|
|
|
} |
|
53
|
119
|
100
|
|
|
|
896
|
if ( keys(%$opts) ) { |
|
54
|
9
|
|
50
|
|
|
21
|
$options = { %{$options//{}}, %$opts }; |
|
|
9
|
|
|
|
|
81
|
|
|
55
|
|
|
|
|
|
|
} |
|
56
|
|
|
|
|
|
|
|
|
57
|
119
|
|
|
|
|
311
|
my @cfg; |
|
58
|
119
|
|
100
|
|
|
807
|
my $verbose = $options->{verbose} //= 0; |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
# Load defaults. |
|
61
|
119
|
50
|
|
|
|
530
|
warn("Reading: \n") if $verbose > 1; |
|
62
|
119
|
|
|
|
|
573
|
my $cfg = pristine_config(); |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
# Default first. |
|
65
|
119
|
|
|
|
|
674
|
@cfg = prep_configs( $cfg, "" ); |
|
66
|
|
|
|
|
|
|
# Bubble default config to be the first. |
|
67
|
119
|
50
|
|
|
|
730
|
unshift( @cfg, pop(@cfg) ) if @cfg > 1; |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
# Collect other config files. |
|
70
|
|
|
|
|
|
|
my $add_config = sub { |
|
71
|
11
|
|
|
11
|
|
34
|
my $fn = shift; |
|
72
|
11
|
|
|
|
|
59
|
$cfg = get_config( $fn ); |
|
73
|
11
|
|
|
|
|
175
|
push( @cfg, $cfg->prep_configs($fn) ); |
|
74
|
119
|
|
|
|
|
1241
|
}; |
|
75
|
|
|
|
|
|
|
|
|
76
|
119
|
|
|
|
|
429
|
foreach my $c ( qw( sysconfig userconfig config ) ) { |
|
77
|
357
|
100
|
|
|
|
1737
|
next if $options->{"no$c"}; |
|
78
|
9
|
100
|
|
|
|
57
|
if ( ref($options->{$c}) eq 'ARRAY' ) { |
|
79
|
2
|
|
|
|
|
5
|
$add_config->($_) foreach @{ $options->{$c} }; |
|
|
2
|
|
|
|
|
14
|
|
|
80
|
|
|
|
|
|
|
} |
|
81
|
|
|
|
|
|
|
else { |
|
82
|
7
|
50
|
|
|
|
29
|
warn("Adding config for $c\n") if $verbose; |
|
83
|
7
|
|
|
|
|
34
|
$add_config->( $options->{$c} ); |
|
84
|
|
|
|
|
|
|
} |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
# Now we have a list of all config files. Weed out dups. |
|
88
|
119
|
|
|
|
|
770
|
for ( my $a = 0; $a < @cfg; $a++ ) { |
|
89
|
249
|
50
|
66
|
|
|
2441
|
if ( $a && $cfg[$a]->{_src} eq $cfg[$a-1]->{_src} ) { |
|
90
|
0
|
0
|
|
|
|
0
|
if ( $a == $#cfg ) { |
|
91
|
|
|
|
|
|
|
# If this is the last entry, splice/redo will create |
|
92
|
|
|
|
|
|
|
# a new, empty entry triggering issue #550. |
|
93
|
0
|
|
|
|
|
0
|
pop(@cfg); |
|
94
|
0
|
|
|
|
|
0
|
last; |
|
95
|
|
|
|
|
|
|
} |
|
96
|
0
|
|
|
|
|
0
|
splice( @cfg, $a, 1 ); |
|
97
|
0
|
|
|
|
|
0
|
redo; |
|
98
|
|
|
|
|
|
|
} |
|
99
|
249
|
50
|
|
|
|
938
|
warn("Config[$a]: ", $cfg[$a]->{_src}, "\n" ) |
|
100
|
|
|
|
|
|
|
if $verbose; |
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
|
|
103
|
119
|
|
|
|
|
334
|
$cfg = shift(@cfg); |
|
104
|
119
|
50
|
|
|
|
526
|
warn("Process: $cfg->{_src}\n") if $verbose > 1; |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
# Presets. |
|
107
|
119
|
50
|
|
|
|
578
|
if ( $options->{reference} ) { |
|
108
|
0
|
|
|
|
|
0
|
$cfg->{user}->{name} = "chordpro"; |
|
109
|
0
|
|
|
|
|
0
|
$cfg->{user}->{fullname} = ::runtimeinfo("short"); |
|
110
|
|
|
|
|
|
|
} |
|
111
|
|
|
|
|
|
|
else { |
|
112
|
|
|
|
|
|
|
$cfg->{user}->{name} = |
|
113
|
|
|
|
|
|
|
lc( $ENV{USER} || $ENV{LOGNAME} |
|
114
|
119
|
|
50
|
|
|
28263
|
|| getlogin() || getpwuid($<) || "chordpro" ); |
|
115
|
119
|
|
50
|
|
|
599
|
$cfg->{user}->{fullname} = eval { (getpwuid($<))[6] } || ""; |
|
116
|
|
|
|
|
|
|
} |
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
# Add some extra entries to prevent warnings. |
|
119
|
119
|
|
|
|
|
563
|
for ( qw(title subtitle footer) ) { |
|
120
|
357
|
100
|
|
|
|
1682
|
next if exists($cfg->{pdf}->{formats}->{first}->{$_}); |
|
121
|
238
|
|
|
|
|
994
|
$cfg->{pdf}->{formats}->{first}->{$_} = ""; |
|
122
|
|
|
|
|
|
|
} |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
my $backend_configurator = |
|
125
|
119
|
|
|
|
|
2230
|
UNIVERSAL::can( $options->{backend}, "configurator" ); |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
# Apply config files |
|
128
|
119
|
|
|
|
|
455
|
foreach my $new ( @cfg ) { |
|
129
|
130
|
|
|
|
|
546
|
my $file = $new->{_src}; # for diagnostics |
|
130
|
|
|
|
|
|
|
# Handle obsolete keys. |
|
131
|
130
|
|
|
|
|
448
|
my $ps = $new->{pdf}; |
|
132
|
130
|
50
|
|
|
|
665
|
if ( exists $ps->{diagramscolumn} ) { |
|
133
|
0
|
|
0
|
|
|
0
|
$ps->{diagrams}->{show} //= "right"; |
|
134
|
0
|
|
|
|
|
0
|
delete $ps->{diagramscolumn}; |
|
135
|
0
|
|
|
|
|
0
|
warn("$file: pdf.diagramscolumn is obsolete, use pdf.diagrams.show instead\n"); |
|
136
|
|
|
|
|
|
|
} |
|
137
|
130
|
50
|
|
|
|
926
|
if ( exists $ps->{formats}->{default}->{'toc-title'} ) { |
|
138
|
0
|
|
0
|
|
|
0
|
$new->{toc}->{title} //= $ps->{formats}->{default}->{'toc-title'}; |
|
139
|
0
|
|
|
|
|
0
|
delete $ps->{formats}->{default}->{'toc-title'}; |
|
140
|
0
|
|
|
|
|
0
|
warn("$file: pdf.formats.default.toc-title is obsolete, use toc.title instead\n"); |
|
141
|
|
|
|
|
|
|
} |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# Page controls. |
|
144
|
|
|
|
|
|
|
# Check for old and newer keywords conflicts. |
|
145
|
130
|
50
|
33
|
|
|
976
|
if ( $ps->{songbook} |
|
|
|
|
33
|
|
|
|
|
|
146
|
|
|
|
|
|
|
&& is_hashref($ps->{songbook}) |
|
147
|
0
|
|
|
|
|
0
|
&& %{$ps->{songbook}} ) { |
|
148
|
|
|
|
|
|
|
# Using new style page controls. |
|
149
|
0
|
|
|
|
|
0
|
my @depr; |
|
150
|
0
|
|
|
|
|
0
|
for ( qw( front-matter back-matter sort-pages ) ) { |
|
151
|
0
|
0
|
|
|
|
0
|
push( @depr, $_) if $ps->{$_}; |
|
152
|
|
|
|
|
|
|
} |
|
153
|
|
|
|
|
|
|
push( @depr, "even-odd-songs" ) |
|
154
|
0
|
0
|
0
|
|
|
0
|
if defined($ps->{'even-odd-songs'}) && $ps->{'even-odd-songs'} <= 0; |
|
155
|
|
|
|
|
|
|
push( @depr, "pagealign-songs" ) |
|
156
|
0
|
0
|
0
|
|
|
0
|
if defined($ps->{'pagealign-songs'}) && $ps->{'pagealign-songs'} != 1; |
|
157
|
0
|
0
|
|
|
|
0
|
if ( @depr ) { |
|
158
|
|
|
|
|
|
|
warn("Config \"$file\" uses \"pdf.songbook\", ignoring ", |
|
159
|
0
|
|
|
|
|
0
|
enumerated( map { qq{"pdf.$_"} } @depr ), "\n" ); |
|
|
0
|
|
|
|
|
0
|
|
|
160
|
0
|
|
|
|
|
0
|
delete $ps->{$_} for @depr; |
|
161
|
|
|
|
|
|
|
} |
|
162
|
|
|
|
|
|
|
} |
|
163
|
|
|
|
|
|
|
else { |
|
164
|
130
|
|
|
|
|
708
|
migrate_songbook_pagectrl( $new, $ps ); |
|
165
|
|
|
|
|
|
|
} |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
# use DDP; p $ps->{songbook}, as => "after \"$file\""; |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
# Process. |
|
170
|
130
|
|
|
|
|
133262
|
local $::config = dclone($cfg); |
|
171
|
130
|
|
|
|
|
1186
|
process_config( $new, $file ); |
|
172
|
|
|
|
|
|
|
# Merge final. |
|
173
|
130
|
|
|
|
|
1088
|
$cfg = hmerge( $cfg, $new ); |
|
174
|
|
|
|
|
|
|
# die("PANIC! Config merge error") |
|
175
|
|
|
|
|
|
|
# unless UNIVERSAL::isa( $cfg->{settings}->{strict}, 'JSON::Boolean' ); |
|
176
|
|
|
|
|
|
|
# use DDP; p $cfg->{pdf}->{songbook}, as => "accum after \"$file\""; |
|
177
|
|
|
|
|
|
|
} |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
# Handle defines from the command line. |
|
180
|
|
|
|
|
|
|
# $cfg = hmerge( $cfg, prp2cfg( $options->{define}, $cfg ) ); |
|
181
|
|
|
|
|
|
|
# use DDP; p $options->{define}, as => "clo"; |
|
182
|
119
|
|
|
|
|
526
|
prpadd2cfg( $cfg, %{$options->{define}} ); |
|
|
119
|
|
|
|
|
1440
|
|
|
183
|
119
|
|
|
|
|
687
|
migrate_songbook_pagectrl($cfg); |
|
184
|
|
|
|
|
|
|
# use DDP; p $cfg->{pdf}->{songbook}, as => "accum after clo"; |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
# Sanitize added extra entries. |
|
187
|
119
|
|
|
|
|
387
|
for my $format ( qw(title subtitle footer) ) { |
|
188
|
|
|
|
|
|
|
delete($cfg->{pdf}->{formats}->{first}->{$format}) |
|
189
|
357
|
100
|
50
|
|
|
2366
|
if ($cfg->{pdf}->{formats}->{first}->{$format} // 1) eq ""; |
|
190
|
357
|
|
|
|
|
745
|
for my $c ( qw(title first default filler) ) { |
|
191
|
1428
|
|
|
|
|
2694
|
for my $class ( $c, $c."-even" ) { |
|
192
|
2856
|
|
|
|
|
6073
|
my $t = $cfg->{pdf}->{formats}->{$class}->{$format}; |
|
193
|
|
|
|
|
|
|
# Allowed: null, false, [3], [[3], ...]. |
|
194
|
2856
|
100
|
|
|
|
6224
|
next unless defined $t; |
|
195
|
833
|
50
|
|
|
|
1669
|
$cfg->{pdf}->{formats}->{$class}->{$format} = ["","",""], next |
|
196
|
|
|
|
|
|
|
unless $t; |
|
197
|
833
|
50
|
|
|
|
1786
|
die("Config error in pdf.formats.$class.$format: not an array\n") |
|
198
|
|
|
|
|
|
|
unless is_arrayref($t); |
|
199
|
833
|
50
|
|
|
|
2589
|
$t = [ $t ] unless is_arrayref($t->[0]); |
|
200
|
833
|
|
|
|
|
1550
|
for ( @$t) { |
|
201
|
833
|
50
|
33
|
|
|
3154
|
die("Config error in pdf.formats.$class.$format: ", |
|
202
|
|
|
|
|
|
|
scalar(@$_), " fields instead of 3\n") |
|
203
|
|
|
|
|
|
|
if @$_ && @$_ != 3; |
|
204
|
|
|
|
|
|
|
} |
|
205
|
833
|
|
|
|
|
2425
|
$cfg->{pdf}->{formats}->{$class}->{$format} = $t; |
|
206
|
|
|
|
|
|
|
} |
|
207
|
|
|
|
|
|
|
} |
|
208
|
|
|
|
|
|
|
} |
|
209
|
|
|
|
|
|
|
|
|
210
|
119
|
50
|
|
|
|
844
|
if ( $cfg->{pdf}->{fontdir} ) { |
|
211
|
119
|
|
|
|
|
304
|
my @a; |
|
212
|
119
|
50
|
|
|
|
1426
|
if ( ref($cfg->{pdf}->{fontdir}) eq 'ARRAY' ) { |
|
213
|
119
|
|
|
|
|
275
|
@a = @{ $cfg->{pdf}->{fontdir} }; |
|
|
119
|
|
|
|
|
571
|
|
|
214
|
|
|
|
|
|
|
} |
|
215
|
|
|
|
|
|
|
else { |
|
216
|
0
|
|
|
|
|
0
|
@a = ( $cfg->{pdf}->{fontdir} ); |
|
217
|
|
|
|
|
|
|
} |
|
218
|
119
|
|
|
|
|
447
|
$cfg->{pdf}->{fontdir} = []; |
|
219
|
119
|
50
|
|
|
|
1762
|
my $split = $^O =~ /^MS*/ ? qr(;) : qr(:); |
|
220
|
119
|
|
|
|
|
565
|
foreach ( @a ) { |
|
221
|
0
|
|
|
|
|
0
|
push( @{ $cfg->{pdf}->{fontdir} }, |
|
222
|
0
|
|
|
|
|
0
|
map { expand_tilde($_) } split( $split, $_ ) ); |
|
|
0
|
|
|
|
|
0
|
|
|
223
|
|
|
|
|
|
|
} |
|
224
|
|
|
|
|
|
|
} |
|
225
|
|
|
|
|
|
|
else { |
|
226
|
0
|
|
|
|
|
0
|
$cfg->{pdf}->{fontdir} = []; |
|
227
|
|
|
|
|
|
|
} |
|
228
|
|
|
|
|
|
|
|
|
229
|
119
|
|
|
|
|
285
|
my @allfonts = keys(%{$cfg->{pdf}->{fonts}}); |
|
|
119
|
|
|
|
|
1022
|
|
|
230
|
119
|
|
|
|
|
403
|
for my $ff ( @allfonts ) { |
|
231
|
|
|
|
|
|
|
# Derived chords can have size or color only. Disable |
|
232
|
|
|
|
|
|
|
# this test for now. |
|
233
|
1428
|
|
|
|
|
1896
|
unless ( 1 || $cfg->{pdf}->{fonts}->{$ff}->{name} |
|
234
|
|
|
|
|
|
|
|| $cfg->{pdf}->{fonts}->{$ff}->{description} |
|
235
|
|
|
|
|
|
|
|| $cfg->{pdf}->{fonts}->{$ff}->{file} ) { |
|
236
|
|
|
|
|
|
|
delete( $cfg->{pdf}->{fonts}->{$ff} ); |
|
237
|
|
|
|
|
|
|
next; |
|
238
|
|
|
|
|
|
|
} |
|
239
|
1428
|
|
50
|
|
|
7028
|
$cfg->{pdf}->{fonts}->{$ff}->{color} //= "foreground"; |
|
240
|
1428
|
|
100
|
|
|
6124
|
$cfg->{pdf}->{fonts}->{$ff}->{background} //= "background"; |
|
241
|
1428
|
|
|
|
|
2436
|
for ( qw(name file description size) ) { |
|
242
|
|
|
|
|
|
|
delete( $cfg->{pdf}->{fonts}->{$ff}->{$_} ) |
|
243
|
5712
|
100
|
|
|
|
15062
|
unless defined( $cfg->{pdf}->{fonts}->{$ff}->{$_} ); |
|
244
|
|
|
|
|
|
|
} |
|
245
|
|
|
|
|
|
|
} |
|
246
|
|
|
|
|
|
|
|
|
247
|
119
|
50
|
|
|
|
2124
|
if ( defined $options->{diagrams} ) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
warn( "Invalid value for diagrams: ", |
|
249
|
|
|
|
|
|
|
$options->{diagrams}, "\n" ) |
|
250
|
0
|
0
|
|
|
|
0
|
unless $options->{diagrams} =~ /^(all|none|user)$/i; |
|
251
|
0
|
|
|
|
|
0
|
$cfg->{diagrams}->{show} = lc $options->{'diagrams'}; |
|
252
|
|
|
|
|
|
|
} |
|
253
|
|
|
|
|
|
|
elsif ( defined $options->{'user-chord-grids'} ) { |
|
254
|
|
|
|
|
|
|
$cfg->{diagrams}->{show} = |
|
255
|
0
|
0
|
|
|
|
0
|
$options->{'user-chord-grids'} ? "user" : 0; |
|
256
|
|
|
|
|
|
|
} |
|
257
|
|
|
|
|
|
|
elsif ( defined $options->{'chord-grids'} ) { |
|
258
|
|
|
|
|
|
|
$cfg->{diagrams}->{show} = |
|
259
|
0
|
0
|
|
|
|
0
|
$options->{'chord-grids'} ? "all" : 0; |
|
260
|
|
|
|
|
|
|
} |
|
261
|
|
|
|
|
|
|
|
|
262
|
119
|
|
|
|
|
386
|
for ( qw( transpose transcode decapo lyrics-only strict ) ) { |
|
263
|
595
|
100
|
|
|
|
1713
|
next unless defined $options->{$_}; |
|
264
|
18
|
|
|
|
|
124
|
$cfg->{settings}->{$_} = $options->{$_}; |
|
265
|
|
|
|
|
|
|
} |
|
266
|
|
|
|
|
|
|
|
|
267
|
119
|
|
|
|
|
338
|
for ( "cover", "front-matter", "back-matter" ) { |
|
268
|
357
|
100
|
|
|
|
1070
|
next unless defined $options->{$_}; |
|
269
|
6
|
|
|
|
|
26
|
$cfg->{pdf}->{songbook}->{$_} = $options->{$_}; |
|
270
|
|
|
|
|
|
|
} |
|
271
|
|
|
|
|
|
|
|
|
272
|
119
|
50
|
|
|
|
491
|
if ( defined $options->{'chord-grids-sorted'} ) { |
|
273
|
0
|
|
|
|
|
0
|
$cfg->{diagrams}->{sorted} = $options->{'chord-grids-sorted'}; |
|
274
|
|
|
|
|
|
|
} |
|
275
|
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
# For convenience... |
|
277
|
119
|
|
|
|
|
452
|
bless( $cfg, __PACKAGE__ ); |
|
278
|
|
|
|
|
|
|
|
|
279
|
119
|
50
|
|
|
|
450
|
return $cfg if $options->{'cfg-print'}; |
|
280
|
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
# Backend specific configs. |
|
282
|
119
|
100
|
|
|
|
517
|
$backend_configurator->($cfg) if $backend_configurator; |
|
283
|
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
# Locking the hash is mainly for development. |
|
285
|
119
|
|
|
|
|
883
|
$cfg->lock; |
|
286
|
|
|
|
|
|
|
|
|
287
|
119
|
50
|
|
|
|
329827
|
if ( $options->{verbose} > 1 ) { |
|
288
|
0
|
|
0
|
|
|
0
|
my $cp = ChordPro::Chords::get_parser() // ""; |
|
289
|
0
|
|
|
|
|
0
|
warn("Parsers:\n"); |
|
290
|
0
|
|
|
|
|
0
|
while ( my ($k, $v) = each %{ChordPro::Chords::Parser->parsers} ) { |
|
|
0
|
|
|
|
|
0
|
|
|
291
|
0
|
0
|
|
|
|
0
|
warn( " $k", |
|
292
|
|
|
|
|
|
|
$v eq $cp ? " (active)": "", |
|
293
|
|
|
|
|
|
|
"\n"); |
|
294
|
|
|
|
|
|
|
} |
|
295
|
|
|
|
|
|
|
} |
|
296
|
|
|
|
|
|
|
|
|
297
|
119
|
|
|
|
|
116414
|
return $cfg; |
|
298
|
|
|
|
|
|
|
} |
|
299
|
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
# Get the decoded contents of a single config file. |
|
301
|
132
|
|
|
132
|
0
|
297
|
sub get_config ( $file ) { |
|
|
132
|
|
|
|
|
324
|
|
|
|
132
|
|
|
|
|
258
|
|
|
302
|
132
|
50
|
|
|
|
637
|
Carp::confess("FATAL: Undefined config") unless defined $file; |
|
303
|
132
|
|
|
|
|
477
|
my $verbose = $options->{verbose}; |
|
304
|
132
|
50
|
|
|
|
517
|
warn("Reading: $file\n") if $verbose > 1; |
|
305
|
132
|
|
|
|
|
857
|
$file = expand_tilde($file); |
|
306
|
|
|
|
|
|
|
|
|
307
|
132
|
50
|
|
|
|
1224
|
if ( $file =~ /\.json$/i ) { |
|
|
|
0
|
|
|
|
|
|
|
308
|
132
|
50
|
|
|
|
1332
|
if ( my $lines = fs_load( $file, { split => 1, fail => "soft" } ) ) { |
|
309
|
132
|
|
|
|
|
15161
|
my $new = json_load( join( "\n", @$lines, '' ), $file ); |
|
310
|
132
|
|
|
|
|
1568
|
precheck( $new, $file ); |
|
311
|
132
|
|
|
|
|
2766
|
return __PACKAGE__->new($new); |
|
312
|
|
|
|
|
|
|
} |
|
313
|
|
|
|
|
|
|
else { |
|
314
|
0
|
|
|
|
|
0
|
die("Cannot open config $file [$!]\n"); |
|
315
|
|
|
|
|
|
|
} |
|
316
|
|
|
|
|
|
|
} |
|
317
|
|
|
|
|
|
|
elsif ( $file =~ /\.prp$/i ) { |
|
318
|
0
|
0
|
|
|
|
0
|
if ( fs_test( efr => $file ) ) { |
|
319
|
0
|
|
|
|
|
0
|
require ChordPro::Config::Properties; |
|
320
|
0
|
|
|
|
|
0
|
my $cfg = Data::Properties->new; |
|
321
|
0
|
|
|
|
|
0
|
$cfg->parse_file($file); |
|
322
|
0
|
|
|
|
|
0
|
return __PACKAGE__->new($cfg->data); |
|
323
|
|
|
|
|
|
|
} |
|
324
|
|
|
|
|
|
|
else { |
|
325
|
0
|
|
|
|
|
0
|
die("Cannot open config $file [$!]\n"); |
|
326
|
|
|
|
|
|
|
} |
|
327
|
|
|
|
|
|
|
} |
|
328
|
|
|
|
|
|
|
else { |
|
329
|
0
|
|
|
|
|
0
|
Carp::confess("Unrecognized config type: $file\n"); |
|
330
|
|
|
|
|
|
|
} |
|
331
|
|
|
|
|
|
|
} |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
# Check config for includes, and prepend them. |
|
334
|
249
|
|
|
249
|
0
|
710
|
sub prep_configs ( $cfg, $src ) { |
|
|
249
|
|
|
|
|
640
|
|
|
|
249
|
|
|
|
|
713
|
|
|
|
249
|
|
|
|
|
582
|
|
|
335
|
249
|
|
|
|
|
1195
|
$cfg->{_src} = $src; |
|
336
|
|
|
|
|
|
|
|
|
337
|
249
|
|
|
|
|
589
|
my @res; |
|
338
|
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
# If there are includes, add them first. |
|
340
|
249
|
|
|
|
|
2223
|
my ( $vol, $dir, undef ) = fn_splitpath($cfg->{_src}); |
|
341
|
249
|
|
|
|
|
882
|
foreach my $c ( @{ $cfg->{include} } ) { |
|
|
249
|
|
|
|
|
1414
|
|
|
342
|
|
|
|
|
|
|
# Check for resource names. |
|
343
|
119
|
50
|
0
|
|
|
708
|
if ( $c !~ m;[/.]; ) { |
|
|
|
0
|
|
|
|
|
|
|
344
|
119
|
|
|
|
|
770
|
$c = CP->findcfg($c); |
|
345
|
|
|
|
|
|
|
} |
|
346
|
|
|
|
|
|
|
elsif ( $dir ne "" |
|
347
|
|
|
|
|
|
|
&& !fn_is_absolute($c) ) { |
|
348
|
|
|
|
|
|
|
# Prepend dir of the caller, if needed. |
|
349
|
0
|
|
|
|
|
0
|
$c = fn_catpath( $vol, $dir, $c ); |
|
350
|
|
|
|
|
|
|
} |
|
351
|
119
|
|
|
|
|
653
|
my $cfg = get_config($c); |
|
352
|
|
|
|
|
|
|
# Recurse. |
|
353
|
119
|
|
|
|
|
2171
|
push( @res, $cfg->prep_configs($c) ); |
|
354
|
|
|
|
|
|
|
} |
|
355
|
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
# Push this and return. |
|
357
|
249
|
|
|
|
|
1532
|
$cfg->split_fc_aliases; |
|
358
|
249
|
|
|
|
|
1503
|
$cfg->expand_font_shortcuts; |
|
359
|
249
|
|
|
|
|
894
|
push( @res, $cfg ); |
|
360
|
249
|
|
|
|
|
1290
|
return @res; |
|
361
|
|
|
|
|
|
|
} |
|
362
|
|
|
|
|
|
|
|
|
363
|
219
|
|
|
219
|
0
|
643
|
sub process_config ( $cfg, $file ) { |
|
|
219
|
|
|
|
|
624
|
|
|
|
219
|
|
|
|
|
716
|
|
|
|
219
|
|
|
|
|
508
|
|
|
364
|
219
|
|
|
|
|
933
|
my $verbose = $options->{verbose}; |
|
365
|
|
|
|
|
|
|
|
|
366
|
219
|
50
|
|
|
|
1131
|
warn("Process: $file\n") if $verbose > 1; |
|
367
|
|
|
|
|
|
|
|
|
368
|
219
|
100
|
|
|
|
1080
|
if ( $cfg->{tuning} ) { |
|
369
|
208
|
|
|
|
|
1717
|
my $res = |
|
370
|
|
|
|
|
|
|
ChordPro::Chords::set_tuning( $cfg ); |
|
371
|
208
|
50
|
|
|
|
2857
|
warn( "Invalid tuning in config: ", $res, "\n" ) if $res; |
|
372
|
208
|
|
|
|
|
1054
|
$cfg->{_tuning} = $cfg->{tuning}; |
|
373
|
208
|
|
|
|
|
837
|
$cfg->{tuning} = []; |
|
374
|
|
|
|
|
|
|
} |
|
375
|
|
|
|
|
|
|
|
|
376
|
219
|
|
|
|
|
1197
|
ChordPro::Chords::reset_parser; |
|
377
|
219
|
|
|
|
|
1484
|
ChordPro::Chords::Parser->reset_parsers; |
|
378
|
219
|
|
|
|
|
1194
|
local $::config = dclone(hmerge( $::config, $cfg )); |
|
379
|
219
|
100
|
|
|
|
11669
|
if ( $cfg->{chords} ) { |
|
380
|
208
|
|
|
|
|
2371
|
ChordPro::Chords::push_parser($cfg->{notes}->{system}); |
|
381
|
208
|
|
|
|
|
874
|
my $c = $cfg->{chords}; |
|
382
|
208
|
50
|
66
|
|
|
2296
|
if ( @$c && $c->[0] eq "append" ) { |
|
383
|
0
|
|
|
|
|
0
|
shift(@$c); |
|
384
|
|
|
|
|
|
|
} |
|
385
|
208
|
|
|
|
|
834
|
foreach ( @$c ) { |
|
386
|
49742
|
|
|
|
|
140550
|
my $res = |
|
387
|
|
|
|
|
|
|
ChordPro::Chords::add_config_chord($_); |
|
388
|
|
|
|
|
|
|
warn( "Invalid chord in config: ", |
|
389
|
49742
|
50
|
|
|
|
173408
|
$_->{name}, ": ", $res, "\n" ) if $res; |
|
390
|
|
|
|
|
|
|
} |
|
391
|
208
|
50
|
|
|
|
1116
|
if ( $verbose > 1 ) { |
|
392
|
0
|
|
|
|
|
0
|
warn( "Processed ", scalar(@$c), " chord entries\n"); |
|
393
|
0
|
|
|
|
|
0
|
warn( "Totals: ", |
|
394
|
|
|
|
|
|
|
ChordPro::Chords::chord_stats(), "\n" ); |
|
395
|
|
|
|
|
|
|
} |
|
396
|
208
|
|
|
|
|
1145
|
$cfg->{_chords} = delete $cfg->{chords}; |
|
397
|
208
|
|
|
|
|
1065
|
ChordPro::Chords::pop_parser(); |
|
398
|
|
|
|
|
|
|
} |
|
399
|
219
|
|
|
|
|
1530
|
$cfg->split_fc_aliases; |
|
400
|
219
|
|
|
|
|
1295
|
$cfg->expand_font_shortcuts; |
|
401
|
|
|
|
|
|
|
} |
|
402
|
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
# Expand pdf.fonts.foo: bar to pdf.fonts.foo { description: bar }. |
|
404
|
|
|
|
|
|
|
|
|
405
|
470
|
|
|
470
|
0
|
5573
|
sub expand_font_shortcuts ( $cfg ) { |
|
|
470
|
|
|
|
|
999
|
|
|
|
470
|
|
|
|
|
904
|
|
|
406
|
470
|
100
|
|
|
|
92292
|
return unless exists $cfg->{pdf}->{fonts}; |
|
407
|
210
|
|
|
|
|
602
|
for my $f ( keys %{$cfg->{pdf}->{fonts}} ) { |
|
|
210
|
|
|
|
|
2196
|
|
|
408
|
2506
|
100
|
|
|
|
8001
|
next if ref($cfg->{pdf}->{fonts}->{$f}) eq 'HASH'; |
|
409
|
2501
|
|
|
|
|
6295
|
for ( $cfg->{pdf}->{fonts}->{$f} ) { |
|
410
|
2501
|
|
|
|
|
4520
|
my $v = $_; |
|
411
|
2501
|
|
|
|
|
7003
|
$v =~ s/\s*;\s*$//; |
|
412
|
2501
|
|
|
|
|
3925
|
my $i = {}; |
|
413
|
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
# Break out ;xx=yy properties. |
|
415
|
2501
|
|
|
|
|
11038
|
while ( $v =~ s/\s*;\s*(\w+)\s*=\s*(.*?)\s*(;|$)/$3/ ) { |
|
416
|
624
|
|
|
|
|
2400
|
my ( $k, $v ) = ( $1, $2 ); |
|
417
|
624
|
50
|
|
|
|
3593
|
if ( $k =~ /^(colou?r|background|frame|numbercolou?r|size)$/ ) { |
|
418
|
624
|
|
|
|
|
1509
|
$k =~ s/colour/color/; |
|
419
|
624
|
|
|
|
|
2997
|
$v =~ s/^(['"]?)(.*)\1$/$2/; |
|
420
|
624
|
|
|
|
|
3389
|
$i->{$k} = $v; |
|
421
|
|
|
|
|
|
|
} |
|
422
|
|
|
|
|
|
|
else { |
|
423
|
0
|
|
|
|
|
0
|
warn("Unknown font property: $k (ignored)\n"); |
|
424
|
|
|
|
|
|
|
} |
|
425
|
|
|
|
|
|
|
} |
|
426
|
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
# Break out size. |
|
428
|
2501
|
50
|
|
|
|
21775
|
if ( $v =~ /(.*?)(?:\s+(\d+(?:\.\d+)?))?\s*(?:;|$)/ ) { |
|
429
|
2501
|
100
|
33
|
|
|
15991
|
$i->{size} //= $2 if $2; |
|
430
|
2501
|
|
|
|
|
4722
|
$v = $1; |
|
431
|
|
|
|
|
|
|
} |
|
432
|
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
# Check for filename. |
|
434
|
2501
|
100
|
|
|
|
9434
|
if ( $v =~ /^.*\.(ttf|otf)$/i ) { |
|
|
|
100
|
|
|
|
|
|
|
435
|
1
|
|
|
|
|
5
|
$i->{file} = $v; |
|
436
|
|
|
|
|
|
|
} |
|
437
|
|
|
|
|
|
|
# Check for corefonts. |
|
438
|
|
|
|
|
|
|
elsif ( is_corefont($v) ) { |
|
439
|
2081
|
|
|
|
|
4384
|
$i->{name} = is_corefont($v); |
|
440
|
|
|
|
|
|
|
} |
|
441
|
|
|
|
|
|
|
else { |
|
442
|
419
|
|
|
|
|
1395
|
$i->{description} = $v; |
|
443
|
|
|
|
|
|
|
$i->{description} .= " " . delete($i->{size}) |
|
444
|
419
|
100
|
|
|
|
2134
|
if $i->{size}; |
|
445
|
|
|
|
|
|
|
} |
|
446
|
2501
|
|
|
|
|
17618
|
$_ = $i; |
|
447
|
|
|
|
|
|
|
} |
|
448
|
|
|
|
|
|
|
} |
|
449
|
|
|
|
|
|
|
} |
|
450
|
|
|
|
|
|
|
|
|
451
|
90
|
|
|
90
|
|
1132
|
use Storable qw(dclone); |
|
|
90
|
|
|
|
|
215
|
|
|
|
90
|
|
|
|
|
662045
|
|
|
452
|
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
# Split fontconfig aliases into separate entries. |
|
454
|
|
|
|
|
|
|
|
|
455
|
557
|
|
|
557
|
0
|
1360
|
sub split_fc_aliases ( $cfg ) { |
|
|
557
|
|
|
|
|
1177
|
|
|
|
557
|
|
|
|
|
1181
|
|
|
456
|
|
|
|
|
|
|
|
|
457
|
557
|
100
|
|
|
|
3933
|
if ( $cfg->{pdf}->{fontconfig} ) { |
|
458
|
|
|
|
|
|
|
# Orig. |
|
459
|
297
|
|
|
|
|
970
|
my $fc = $cfg->{pdf}->{fontconfig}; |
|
460
|
|
|
|
|
|
|
# Since we're going to delete/insert keys, we need a copy. |
|
461
|
297
|
|
|
|
|
3614
|
my %fc = %$fc; |
|
462
|
297
|
|
|
|
|
2109
|
while ( my($k,$v) = each(%fc) ) { |
|
463
|
|
|
|
|
|
|
# Split on comma. |
|
464
|
2643
|
|
|
|
|
8955
|
my @k = split( /\s*,\s*/, $k ); |
|
465
|
2643
|
100
|
|
|
|
9886
|
if ( @k > 1 ) { |
|
466
|
|
|
|
|
|
|
# We have aliases. Delete the original. |
|
467
|
624
|
|
|
|
|
1555
|
delete( $fc->{$k} ); |
|
468
|
|
|
|
|
|
|
# And insert individual entries. |
|
469
|
624
|
|
|
|
|
102601
|
$fc->{$_} = dclone($v) for @k; |
|
470
|
|
|
|
|
|
|
} |
|
471
|
|
|
|
|
|
|
} |
|
472
|
|
|
|
|
|
|
} |
|
473
|
|
|
|
|
|
|
} |
|
474
|
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
# Reverse of config_expand_font_shortcuts. |
|
476
|
|
|
|
|
|
|
|
|
477
|
1
|
|
|
1
|
0
|
9
|
sub simplify_fonts( $cfg ) { |
|
|
1
|
|
|
|
|
5
|
|
|
|
1
|
|
|
|
|
2
|
|
|
478
|
|
|
|
|
|
|
|
|
479
|
1
|
50
|
|
|
|
13
|
return $cfg unless $cfg->{pdf}->{fonts}; |
|
480
|
|
|
|
|
|
|
|
|
481
|
1
|
|
|
|
|
3
|
foreach my $font ( keys %{$cfg->{pdf}->{fonts}} ) { |
|
|
1
|
|
|
|
|
8
|
|
|
482
|
5
|
|
|
|
|
13
|
for ( $cfg->{pdf}->{fonts}->{$font} ) { |
|
483
|
5
|
100
|
|
|
|
16
|
next unless is_hashref($_); |
|
484
|
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
delete $_->{color} |
|
486
|
4
|
50
|
33
|
|
|
12
|
if $_->{color} && $_->{color} eq "foreground"; |
|
487
|
|
|
|
|
|
|
delete $_->{background} |
|
488
|
4
|
50
|
33
|
|
|
16
|
if $_->{background} && $_->{background} eq "background"; |
|
489
|
|
|
|
|
|
|
|
|
490
|
4
|
100
|
33
|
|
|
26
|
if ( exists( $_->{file} ) ) { |
|
|
|
100
|
33
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
491
|
1
|
|
|
|
|
3
|
delete $_->{description}; |
|
492
|
1
|
|
|
|
|
4
|
delete $_->{name}; |
|
493
|
|
|
|
|
|
|
} |
|
494
|
|
|
|
|
|
|
elsif ( exists( $_->{description} ) ) { |
|
495
|
2
|
|
|
|
|
5
|
delete $_->{name}; |
|
496
|
2
|
100
|
66
|
|
|
24
|
if ( $_->{size} && $_->{description} !~ /\s+[\d.]+$/ ) { |
|
497
|
1
|
|
|
|
|
6
|
$_->{description} .= " " . $_->{size}; |
|
498
|
|
|
|
|
|
|
} |
|
499
|
2
|
|
|
|
|
5
|
delete $_->{size}; |
|
500
|
2
|
50
|
|
|
|
12
|
$_ = $_->{description} if keys %$_ == 1; |
|
501
|
|
|
|
|
|
|
} |
|
502
|
|
|
|
|
|
|
elsif ( exists( $_->{name} ) |
|
503
|
|
|
|
|
|
|
&& exists( $_->{size}) |
|
504
|
|
|
|
|
|
|
&& keys %$_ == 2 |
|
505
|
|
|
|
|
|
|
) { |
|
506
|
1
|
|
|
|
|
8
|
$_ = $_->{name} .= " " . $_->{size}; |
|
507
|
|
|
|
|
|
|
} |
|
508
|
|
|
|
|
|
|
} |
|
509
|
|
|
|
|
|
|
} |
|
510
|
|
|
|
|
|
|
} |
|
511
|
|
|
|
|
|
|
|
|
512
|
249
|
|
|
249
|
0
|
646
|
sub migrate_songbook_pagectrl( $self, $ps = undef ) { |
|
|
249
|
|
|
|
|
598
|
|
|
|
249
|
|
|
|
|
596
|
|
|
|
249
|
|
|
|
|
476
|
|
|
513
|
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
# Migrate old to new. |
|
515
|
249
|
|
66
|
|
|
1437
|
$ps //= $self->{pdf}; |
|
516
|
249
|
|
100
|
|
|
1486
|
my $sb = $ps->{songbook} // {}; |
|
517
|
249
|
|
|
|
|
917
|
for ( qw( front-matter back-matter ) ) { |
|
518
|
498
|
50
|
|
|
|
1957
|
$sb->{$_} = delete($ps->{$_}) if $ps->{$_}; |
|
519
|
|
|
|
|
|
|
} |
|
520
|
249
|
|
|
|
|
1053
|
for ( $ps->{'even-odd-pages'} ) { |
|
521
|
249
|
100
|
|
|
|
1339
|
next unless defined; |
|
522
|
3
|
|
|
|
|
13
|
$sb->{'dual-pages'} = !!$_; |
|
523
|
3
|
100
|
|
|
|
18
|
$sb->{'align-songs-spread'} = 1 if $_ < 0; |
|
524
|
|
|
|
|
|
|
} |
|
525
|
249
|
|
|
|
|
1001
|
for ( $ps->{'pagealign-songs'} ) { |
|
526
|
249
|
100
|
|
|
|
998
|
next unless defined; |
|
527
|
4
|
|
|
|
|
17
|
$sb->{'align-songs'} = !!$_; |
|
528
|
4
|
|
|
|
|
18
|
$sb->{'align-songs-extend'} = $_ > 1; |
|
529
|
|
|
|
|
|
|
} |
|
530
|
249
|
|
|
|
|
933
|
for ( $ps->{'sort-pages'} ) { |
|
531
|
249
|
50
|
|
|
|
939
|
next unless defined; |
|
532
|
0
|
|
|
|
|
0
|
my $a = $_; |
|
533
|
0
|
|
|
|
|
0
|
$a =~ s/\s+//g; |
|
534
|
0
|
|
|
|
|
0
|
my ( $sort, $desc, $spread, $compact ); |
|
535
|
0
|
|
|
|
|
0
|
$sort = $desc = ""; |
|
536
|
0
|
|
|
|
|
0
|
for ( split( /,/, lc $a ) ) { |
|
537
|
0
|
0
|
|
|
|
0
|
if ( $_ eq "title" ) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
538
|
0
|
|
|
|
|
0
|
$sort = "title"; |
|
539
|
|
|
|
|
|
|
} |
|
540
|
|
|
|
|
|
|
elsif ( $_ eq "subtitle" ) { |
|
541
|
0
|
|
0
|
|
|
0
|
$sort //= "subtitle"; |
|
542
|
|
|
|
|
|
|
} |
|
543
|
|
|
|
|
|
|
elsif ( $_ eq "2page" ) { |
|
544
|
0
|
|
|
|
|
0
|
$spread++; |
|
545
|
|
|
|
|
|
|
} |
|
546
|
|
|
|
|
|
|
elsif ( $_ eq "desc" ) { |
|
547
|
0
|
|
|
|
|
0
|
$desc = "-"; |
|
548
|
|
|
|
|
|
|
} |
|
549
|
|
|
|
|
|
|
elsif ( $_ eq "compact" ) { |
|
550
|
0
|
|
|
|
|
0
|
$compact++; |
|
551
|
|
|
|
|
|
|
} |
|
552
|
|
|
|
|
|
|
else { |
|
553
|
0
|
|
|
|
|
0
|
warn("??? \"$_\"\n"); |
|
554
|
|
|
|
|
|
|
} |
|
555
|
|
|
|
|
|
|
} |
|
556
|
0
|
|
|
|
|
0
|
$sb->{'sort-songs'} = "${desc}${sort}"; |
|
557
|
0
|
0
|
|
|
|
0
|
$sb->{'compact-songs'} = 1 if $compact; |
|
558
|
0
|
0
|
|
|
|
0
|
$sb->{'align-songs-spread'} = 1 if $spread; |
|
559
|
|
|
|
|
|
|
} |
|
560
|
249
|
|
|
|
|
930
|
$ps->{songbook} = $sb; |
|
561
|
|
|
|
|
|
|
# Remove the obsoleted entries. |
|
562
|
|
|
|
|
|
|
delete( $ps->{$_} ) |
|
563
|
249
|
|
|
|
|
1562
|
for qw( even-odd-pages sort-pages pagealign-songs ); |
|
564
|
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
} |
|
566
|
|
|
|
|
|
|
|
|
567
|
0
|
|
|
0
|
0
|
0
|
sub config_final ( %args ) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
568
|
0
|
|
0
|
|
|
0
|
my $delta = $args{delta} || 0; |
|
569
|
0
|
|
0
|
|
|
0
|
my $default = $args{default} || 0; |
|
570
|
0
|
|
|
|
|
0
|
$options->{'cfg-print'} = 1; |
|
571
|
|
|
|
|
|
|
|
|
572
|
0
|
|
|
|
|
0
|
my $defcfg; # pristine config |
|
573
|
|
|
|
|
|
|
my $cfg; # actual config |
|
574
|
0
|
0
|
0
|
|
|
0
|
if ( $default || $delta ) { |
|
575
|
0
|
|
|
|
|
0
|
local $options->{nosysconfig} = 1; |
|
576
|
0
|
|
|
|
|
0
|
local $options->{nouserconfig} = 1; |
|
577
|
0
|
|
|
|
|
0
|
local $options->{noconfig} = 1; |
|
578
|
0
|
|
|
|
|
0
|
$defcfg = pristine_config(); |
|
579
|
0
|
|
|
|
|
0
|
split_fc_aliases($defcfg); |
|
580
|
0
|
|
|
|
|
0
|
expand_font_shortcuts($defcfg); |
|
581
|
0
|
0
|
|
|
|
0
|
if ( $delta ) { |
|
582
|
0
|
|
|
|
|
0
|
delete $defcfg->{chords}; |
|
583
|
0
|
|
|
|
|
0
|
delete $defcfg->{include}; |
|
584
|
|
|
|
|
|
|
} |
|
585
|
0
|
|
|
|
|
0
|
bless $defcfg => __PACKAGE__; |
|
586
|
0
|
0
|
|
|
|
0
|
$cfg = $defcfg if $default; |
|
587
|
|
|
|
|
|
|
} |
|
588
|
|
|
|
|
|
|
|
|
589
|
0
|
|
0
|
|
|
0
|
$cfg //= configurator($options); |
|
590
|
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
# Remove unwanted data. |
|
592
|
0
|
|
|
|
|
0
|
$cfg->unlock; |
|
593
|
0
|
|
|
|
|
0
|
$cfg->{tuning} = delete $cfg->{_tuning}; |
|
594
|
0
|
0
|
|
|
|
0
|
if ( $delta ) { |
|
595
|
0
|
|
|
|
|
0
|
for ( qw( tuning ) ) { |
|
596
|
0
|
0
|
|
|
|
0
|
delete($cfg->{$_}) unless defined($cfg->{$_}); |
|
597
|
|
|
|
|
|
|
} |
|
598
|
0
|
|
|
|
|
0
|
for my $f ( keys( %{$cfg->{pdf}{fonts}} ) ) { |
|
|
0
|
|
|
|
|
0
|
|
|
599
|
0
|
|
|
|
|
0
|
for ( qw( background color ) ) { |
|
600
|
0
|
0
|
|
|
|
0
|
next if defined($defcfg->{pdf}{fonts}{$f}{$_}); |
|
601
|
0
|
|
|
|
|
0
|
delete($cfg->{pdf}{fonts}{$f}{$_}); |
|
602
|
0
|
|
|
|
|
0
|
delete($defcfg->{pdf}{fonts}{$f}{$_}); |
|
603
|
|
|
|
|
|
|
} |
|
604
|
|
|
|
|
|
|
} |
|
605
|
|
|
|
|
|
|
} |
|
606
|
0
|
|
|
|
|
0
|
delete $cfg->{_chords}; |
|
607
|
0
|
|
|
|
|
0
|
delete $cfg->{chords}; |
|
608
|
0
|
|
|
|
|
0
|
delete $cfg->{_src}; |
|
609
|
|
|
|
|
|
|
|
|
610
|
0
|
|
|
|
|
0
|
my $parser = JSON::Relaxed::Parser->new( key_order => 1 ); |
|
611
|
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
# Load schema. |
|
613
|
0
|
|
|
|
|
0
|
my $schema = do { |
|
614
|
0
|
|
|
|
|
0
|
my $schema = CP->findres( "config.schema", class => "config" ); |
|
615
|
0
|
|
|
|
|
0
|
my $data = fs_load( $schema, { split => 0 } ); |
|
616
|
0
|
|
|
|
|
0
|
$parser->decode($data); |
|
617
|
|
|
|
|
|
|
}; |
|
618
|
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
# Delta cannot handle reference config yet. |
|
620
|
0
|
0
|
|
|
|
0
|
if ( $delta ) { |
|
621
|
0
|
|
|
|
|
0
|
$defcfg->unlock; |
|
622
|
0
|
|
|
|
|
0
|
$cfg->reduce( $defcfg ); |
|
623
|
0
|
|
|
|
|
0
|
return $parser->encode( data => {%$cfg}, |
|
624
|
|
|
|
|
|
|
pretty => 1, schema => $schema ); |
|
625
|
|
|
|
|
|
|
} |
|
626
|
|
|
|
|
|
|
|
|
627
|
0
|
|
|
|
|
0
|
my $config = do { |
|
628
|
0
|
|
|
|
|
0
|
my $config = CP->findres( "chordpro.json", class => "config" ); |
|
629
|
0
|
|
|
|
|
0
|
my $data = fs_load( $config, { split => 0 } ); |
|
630
|
0
|
|
|
|
|
0
|
$parser->decode($data); |
|
631
|
|
|
|
|
|
|
}; |
|
632
|
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
# $cfg = hmerge( $config, $cfg ); |
|
634
|
0
|
|
|
|
|
0
|
$cfg->simplify_fonts; |
|
635
|
0
|
|
|
|
|
0
|
return $parser->encode( data => {%{$cfg}}, |
|
|
0
|
|
|
|
|
0
|
|
|
636
|
|
|
|
|
|
|
pretty => 1, schema => $schema ); |
|
637
|
|
|
|
|
|
|
} |
|
638
|
|
|
|
|
|
|
|
|
639
|
0
|
|
|
0
|
0
|
0
|
sub convert_config ( $from, $to ) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
640
|
|
|
|
|
|
|
# This is a completely independent function. |
|
641
|
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
# Establish a key order retaining parser. |
|
643
|
0
|
|
|
|
|
0
|
my $parser = JSON::Relaxed::Parser->new( key_order => 1 ); |
|
644
|
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
# First find and process the schema. |
|
646
|
0
|
|
|
|
|
0
|
my $schema = CP->findres( "config.schema", class => "config" ); |
|
647
|
0
|
|
|
|
|
0
|
my $o = { split => 0, fail => 'soft' }; |
|
648
|
0
|
|
|
|
|
0
|
my $data = fs_load( $schema, $o ); |
|
649
|
0
|
0
|
|
|
|
0
|
die("$schema: ", $o->{error}, "\n") if $o->{error}; |
|
650
|
0
|
|
|
|
|
0
|
$schema = $parser->decode($data); |
|
651
|
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
# Then load the config to be converted. |
|
653
|
0
|
|
|
|
|
0
|
my $new; |
|
654
|
0
|
|
|
|
|
0
|
$o = { split => 1, fail => 'soft' }; |
|
655
|
0
|
|
|
|
|
0
|
$data = fs_load( $from, $o ); |
|
656
|
0
|
0
|
|
|
|
0
|
die("Cannot open config $from [", $o->{error}, "]\n") if $o->{error}; |
|
657
|
0
|
|
|
|
|
0
|
$data = join( "\n", @$data ); |
|
658
|
|
|
|
|
|
|
|
|
659
|
0
|
0
|
|
|
|
0
|
if ( $data =~ /^\s*#/m ) { # #-comments -> prp |
|
660
|
0
|
|
|
|
|
0
|
require ChordPro::Config::Properties; |
|
661
|
0
|
|
|
|
|
0
|
my $cfg = Data::Properties->new; |
|
662
|
0
|
|
|
|
|
0
|
$cfg->parse_file($from); |
|
663
|
0
|
|
|
|
|
0
|
$new = $cfg->data; |
|
664
|
|
|
|
|
|
|
} |
|
665
|
|
|
|
|
|
|
else { # assume JSON, RJSON, RRJSON |
|
666
|
0
|
|
|
|
|
0
|
$new = $parser->decode($data); |
|
667
|
|
|
|
|
|
|
} |
|
668
|
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
# And re-encode it using the schema. |
|
670
|
0
|
|
|
|
|
0
|
my $res = $parser->encode( data => $new, pretty => 1, |
|
671
|
|
|
|
|
|
|
nounicodeescapes => 1, schema => $schema ); |
|
672
|
|
|
|
|
|
|
# use DDP; p $res; |
|
673
|
|
|
|
|
|
|
# Add trailer. |
|
674
|
0
|
|
|
|
|
0
|
$res .= "\n// End of Config.\n"; |
|
675
|
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
# Write if out. |
|
677
|
0
|
0
|
0
|
|
|
0
|
if ( $to && $to ne "-" ) { |
|
678
|
0
|
0
|
|
|
|
0
|
open( my $fd, '>', $to ) |
|
679
|
|
|
|
|
|
|
or die("$to: $!\n"); |
|
680
|
0
|
|
|
|
|
0
|
print $fd $res; |
|
681
|
0
|
|
|
|
|
0
|
$fd->close; |
|
682
|
|
|
|
|
|
|
} |
|
683
|
|
|
|
|
|
|
else { |
|
684
|
0
|
|
|
|
|
0
|
print $res; |
|
685
|
|
|
|
|
|
|
} |
|
686
|
|
|
|
|
|
|
|
|
687
|
0
|
|
|
|
|
0
|
1; |
|
688
|
|
|
|
|
|
|
} |
|
689
|
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
# Config in properties format. |
|
691
|
|
|
|
|
|
|
|
|
692
|
0
|
|
|
0
|
0
|
0
|
sub cfg2props ( $o, $path = "" ) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
693
|
0
|
|
0
|
|
|
0
|
$path //= ""; |
|
694
|
0
|
|
|
|
|
0
|
my $ret = ""; |
|
695
|
0
|
0
|
|
|
|
0
|
if ( !defined $o ) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
696
|
0
|
|
|
|
|
0
|
$ret .= "$path: undef\n"; |
|
697
|
|
|
|
|
|
|
} |
|
698
|
|
|
|
|
|
|
elsif ( is_hashref($o) ) { |
|
699
|
0
|
0
|
|
|
|
0
|
$path .= "." unless $path eq ""; |
|
700
|
0
|
|
|
|
|
0
|
for ( sort keys %$o ) { |
|
701
|
0
|
|
|
|
|
0
|
$ret .= cfg2props( $o->{$_}, $path . $_ ); |
|
702
|
|
|
|
|
|
|
} |
|
703
|
|
|
|
|
|
|
} |
|
704
|
|
|
|
|
|
|
elsif ( is_arrayref($o) ) { |
|
705
|
0
|
0
|
|
|
|
0
|
$path .= "." unless $path eq ""; |
|
706
|
0
|
|
|
|
|
0
|
for ( my $i = 0; $i < @$o; $i++ ) { |
|
707
|
0
|
|
|
|
|
0
|
$ret .= cfg2props( $o->[$i], $path . "$i" ); |
|
708
|
|
|
|
|
|
|
} |
|
709
|
|
|
|
|
|
|
} |
|
710
|
|
|
|
|
|
|
elsif ( $o =~ /^\d+$/ ) { |
|
711
|
0
|
|
|
|
|
0
|
$ret .= "$path: $o\n"; |
|
712
|
|
|
|
|
|
|
} |
|
713
|
|
|
|
|
|
|
else { |
|
714
|
0
|
|
|
|
|
0
|
$o =~ s/\\/\\\\/g; |
|
715
|
0
|
|
|
|
|
0
|
$o =~ s/"/\\"/g; |
|
716
|
0
|
|
|
|
|
0
|
$o =~ s/\n/\\n/; |
|
717
|
0
|
|
|
|
|
0
|
$o =~ s/\t/\\t/; |
|
718
|
0
|
|
|
|
|
0
|
$o =~ s/([^\x00-\xff])/sprintf("\\x{%x}", ord($1))/ge; |
|
|
0
|
|
|
|
|
0
|
|
|
719
|
0
|
|
|
|
|
0
|
$ret .= "$path: \"$o\"\n"; |
|
720
|
|
|
|
|
|
|
} |
|
721
|
|
|
|
|
|
|
|
|
722
|
0
|
|
|
|
|
0
|
return $ret; |
|
723
|
|
|
|
|
|
|
} |
|
724
|
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
# Locking/unlocking. Locking the hash is mainly for development, to |
|
726
|
|
|
|
|
|
|
# trap accidental modifications and typos. |
|
727
|
|
|
|
|
|
|
|
|
728
|
355
|
|
|
355
|
0
|
815
|
sub lock ( $self ) { |
|
|
355
|
|
|
|
|
859
|
|
|
|
355
|
|
|
|
|
695
|
|
|
729
|
355
|
|
|
|
|
2230
|
Hash::Util::lock_hashref_recurse($self); |
|
730
|
|
|
|
|
|
|
} |
|
731
|
|
|
|
|
|
|
|
|
732
|
276
|
|
|
276
|
0
|
678
|
sub unlock ( $self ) { |
|
|
276
|
|
|
|
|
676
|
|
|
|
276
|
|
|
|
|
549
|
|
|
733
|
276
|
|
|
|
|
2124
|
Hash::Util::unlock_hashref_recurse($self); |
|
734
|
|
|
|
|
|
|
} |
|
735
|
|
|
|
|
|
|
|
|
736
|
5
|
|
|
5
|
0
|
13
|
sub is_locked ( $self ) { |
|
|
5
|
|
|
|
|
10
|
|
|
|
5
|
|
|
|
|
23
|
|
|
737
|
5
|
|
|
|
|
83
|
Hash::Util::hashref_locked($self); |
|
738
|
|
|
|
|
|
|
} |
|
739
|
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
# Augment / Reduce. |
|
741
|
|
|
|
|
|
|
|
|
742
|
4
|
|
|
4
|
0
|
2153
|
sub augment ( $self, $hash ) { |
|
|
4
|
|
|
|
|
10
|
|
|
|
4
|
|
|
|
|
10
|
|
|
|
4
|
|
|
|
|
15
|
|
|
743
|
|
|
|
|
|
|
|
|
744
|
4
|
|
|
|
|
24
|
my $locked = $self->is_locked; |
|
745
|
4
|
100
|
|
|
|
60
|
$self->unlock if $locked; |
|
746
|
|
|
|
|
|
|
|
|
747
|
4
|
|
|
|
|
7262
|
$self->_augment( $hash, "" ); |
|
748
|
|
|
|
|
|
|
|
|
749
|
4
|
100
|
|
|
|
21
|
$self->lock if $locked; |
|
750
|
|
|
|
|
|
|
|
|
751
|
4
|
|
|
|
|
6414
|
$self; |
|
752
|
|
|
|
|
|
|
} |
|
753
|
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
|
|
755
|
15
|
|
|
15
|
|
738
|
sub _augment ( $self, $hash, $path ) { |
|
|
15
|
|
|
|
|
28
|
|
|
|
15
|
|
|
|
|
21
|
|
|
|
15
|
|
|
|
|
22
|
|
|
|
15
|
|
|
|
|
18
|
|
|
756
|
|
|
|
|
|
|
|
|
757
|
15
|
|
|
|
|
44
|
for my $key ( keys(%$hash) ) { |
|
758
|
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
warn("Config augment error: unknown item $path$key\n") |
|
760
|
17
|
0
|
33
|
|
|
54
|
unless exists $self->{$key} |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
761
|
|
|
|
|
|
|
|| $path =~ /^pdf\.(?:info|fonts|fontconfig)\./ |
|
762
|
|
|
|
|
|
|
|| $path =~ /^pdf\.formats\.\w+-even\./ |
|
763
|
|
|
|
|
|
|
|| $path =~ /^(meta|gridstrum\.symbols)\./ |
|
764
|
|
|
|
|
|
|
|| $path =~ /^markup\.shortcodes\./ |
|
765
|
|
|
|
|
|
|
|| $path =~ /^delegates\./ |
|
766
|
|
|
|
|
|
|
|| $key =~ /^_/; |
|
767
|
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
# Hash -> Hash. |
|
769
|
|
|
|
|
|
|
# Hash -> Array. |
|
770
|
17
|
100
|
66
|
|
|
66
|
if ( ref($hash->{$key}) eq 'HASH' ) { |
|
|
|
100
|
|
|
|
|
|
|
771
|
11
|
50
|
|
|
|
29
|
if ( ref($self->{$key}) eq 'HASH' ) { |
|
|
|
0
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
# Hashes. Recurse. |
|
774
|
11
|
|
|
|
|
56
|
_augment( $self->{$key}, $hash->{$key}, "$path$key." ); |
|
775
|
|
|
|
|
|
|
} |
|
776
|
|
|
|
|
|
|
elsif ( ref($self->{$key}) eq 'ARRAY' ) { |
|
777
|
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
# Hash -> Array. |
|
779
|
|
|
|
|
|
|
# Update single array element using a hash index. |
|
780
|
0
|
|
|
|
|
0
|
foreach my $ix ( keys(%{$hash->{$key}}) ) { |
|
|
0
|
|
|
|
|
0
|
|
|
781
|
0
|
0
|
|
|
|
0
|
die unless $ix =~ /^\d+$/; |
|
782
|
0
|
|
|
|
|
0
|
$self->{$key}->[$ix] = $hash->{$key}->{$ix}; |
|
783
|
|
|
|
|
|
|
} |
|
784
|
|
|
|
|
|
|
} |
|
785
|
|
|
|
|
|
|
else { |
|
786
|
|
|
|
|
|
|
# Overwrite. |
|
787
|
0
|
|
|
|
|
0
|
$self->{$key} = $hash->{$key}; |
|
788
|
|
|
|
|
|
|
} |
|
789
|
|
|
|
|
|
|
} |
|
790
|
|
|
|
|
|
|
|
|
791
|
|
|
|
|
|
|
# Array -> Array. |
|
792
|
|
|
|
|
|
|
elsif ( ref($hash->{$key}) eq 'ARRAY' |
|
793
|
|
|
|
|
|
|
and ref($self->{$key}) eq 'ARRAY' ) { |
|
794
|
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
# Arrays. Overwrite or append. |
|
796
|
2
|
50
|
|
|
|
6
|
if ( @{$hash->{$key}} ) { |
|
|
2
|
|
|
|
|
7
|
|
|
797
|
2
|
|
|
|
|
6
|
my @v = @{ $hash->{$key} }; |
|
|
2
|
|
|
|
|
8
|
|
|
798
|
2
|
50
|
|
|
|
10
|
if ( $v[0] eq "append" ) { |
|
|
|
100
|
|
|
|
|
|
|
799
|
0
|
|
|
|
|
0
|
shift(@v); |
|
800
|
|
|
|
|
|
|
# Append the rest. |
|
801
|
0
|
|
|
|
|
0
|
push( @{ $self->{$key} }, @v ); |
|
|
0
|
|
|
|
|
0
|
|
|
802
|
|
|
|
|
|
|
} |
|
803
|
|
|
|
|
|
|
elsif ( $v[0] eq "prepend" ) { |
|
804
|
1
|
|
|
|
|
3
|
shift(@v); |
|
805
|
|
|
|
|
|
|
# Prepend the rest. |
|
806
|
1
|
|
|
|
|
3
|
unshift( @{ $self->{$key} }, @v ); |
|
|
1
|
|
|
|
|
5
|
|
|
807
|
|
|
|
|
|
|
} |
|
808
|
|
|
|
|
|
|
else { |
|
809
|
|
|
|
|
|
|
# Overwrite. |
|
810
|
1
|
|
|
|
|
5
|
$self->{$key} = $hash->{$key}; |
|
811
|
|
|
|
|
|
|
} |
|
812
|
|
|
|
|
|
|
} |
|
813
|
|
|
|
|
|
|
else { |
|
814
|
|
|
|
|
|
|
# Overwrite. |
|
815
|
0
|
|
|
|
|
0
|
$self->{$key} = $hash->{$key}; |
|
816
|
|
|
|
|
|
|
} |
|
817
|
|
|
|
|
|
|
} |
|
818
|
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
else { |
|
820
|
|
|
|
|
|
|
# Overwrite. |
|
821
|
4
|
|
|
|
|
16
|
$self->{$key} = $hash->{$key}; |
|
822
|
|
|
|
|
|
|
} |
|
823
|
|
|
|
|
|
|
} |
|
824
|
|
|
|
|
|
|
|
|
825
|
15
|
|
|
|
|
30
|
$self; |
|
826
|
|
|
|
|
|
|
} |
|
827
|
|
|
|
|
|
|
|
|
828
|
90
|
|
|
90
|
|
1161
|
use constant DEBUG => 0; |
|
|
90
|
|
|
|
|
353
|
|
|
|
90
|
|
|
|
|
454996
|
|
|
829
|
|
|
|
|
|
|
|
|
830
|
1
|
|
|
1
|
0
|
2027
|
sub reduce ( $self, $hash ) { |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
2
|
|
|
831
|
|
|
|
|
|
|
|
|
832
|
1
|
|
|
|
|
5
|
my $locked = $self->is_locked; |
|
833
|
|
|
|
|
|
|
|
|
834
|
1
|
|
|
|
|
9
|
warn("O: ", qd($hash,1), "\n") if DEBUG > 1; |
|
835
|
1
|
|
|
|
|
2
|
warn("N: ", qd($self,1), "\n") if DEBUG > 1; |
|
836
|
1
|
|
|
|
|
6
|
my $state = _reduce( $self, $hash, "" ); |
|
837
|
|
|
|
|
|
|
|
|
838
|
1
|
50
|
|
|
|
29
|
$self->lock if $locked; |
|
839
|
|
|
|
|
|
|
|
|
840
|
1
|
|
|
|
|
3
|
warn("== ", qd($self,1), "\n") if DEBUG > 1; |
|
841
|
1
|
|
|
|
|
5
|
return $self; |
|
842
|
|
|
|
|
|
|
} |
|
843
|
|
|
|
|
|
|
|
|
844
|
68
|
|
|
68
|
|
111
|
sub _ref ( $self ) { |
|
|
68
|
|
|
|
|
120
|
|
|
|
68
|
|
|
|
|
100
|
|
|
845
|
68
|
|
66
|
|
|
419
|
reftype($self) // ref($self); |
|
846
|
|
|
|
|
|
|
} |
|
847
|
|
|
|
|
|
|
|
|
848
|
6
|
|
|
6
|
|
11
|
sub _reduce ( $self, $orig, $path ) { |
|
|
6
|
|
|
|
|
14
|
|
|
|
6
|
|
|
|
|
9
|
|
|
|
6
|
|
|
|
|
13
|
|
|
|
6
|
|
|
|
|
8
|
|
|
849
|
|
|
|
|
|
|
|
|
850
|
6
|
|
|
|
|
10
|
my $state; |
|
851
|
|
|
|
|
|
|
|
|
852
|
6
|
100
|
66
|
|
|
15
|
if ( _ref($self) eq 'HASH' && _ref($orig) eq 'HASH' ) { |
|
853
|
|
|
|
|
|
|
|
|
854
|
3
|
|
|
|
|
7
|
warn("D: ", qd($self,1), "\n") if DEBUG && !%$orig; |
|
855
|
3
|
50
|
|
|
|
11
|
return 'D' unless %$orig; |
|
856
|
|
|
|
|
|
|
|
|
857
|
3
|
|
|
|
|
15
|
my %hh = map { $_ => 1 } keys(%$self), keys(%$orig); |
|
|
12
|
|
|
|
|
32
|
|
|
858
|
3
|
|
|
|
|
17
|
for my $key ( sort keys(%hh) ) { |
|
859
|
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
warn("Config reduce error: unknown item $path$key\n") |
|
861
|
6
|
0
|
33
|
|
|
25
|
unless exists $self->{$key} |
|
|
|
|
33
|
|
|
|
|
|
862
|
|
|
|
|
|
|
|| $key =~ /^_/ |
|
863
|
|
|
|
|
|
|
|| $path =~ /^pdf\/\.fonts\./; |
|
864
|
|
|
|
|
|
|
|
|
865
|
6
|
50
|
|
|
|
17
|
unless ( exists $orig->{$key} ) { |
|
866
|
0
|
|
|
|
|
0
|
warn("D: $path$key\n") if DEBUG; |
|
867
|
0
|
|
|
|
|
0
|
delete $self->{$key}; |
|
868
|
0
|
|
0
|
|
|
0
|
$state //= 'M'; |
|
869
|
0
|
|
|
|
|
0
|
next; |
|
870
|
|
|
|
|
|
|
} |
|
871
|
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
# Hash -> Hash. |
|
873
|
6
|
100
|
66
|
|
|
18
|
if ( _ref($orig->{$key}) eq 'HASH' |
|
|
|
100
|
66
|
|
|
|
|
|
|
|
50
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
874
|
|
|
|
|
|
|
and _ref($self->{$key}) eq 'HASH' |
|
875
|
|
|
|
|
|
|
or |
|
876
|
|
|
|
|
|
|
_ref($orig->{$key}) eq 'ARRAY' |
|
877
|
|
|
|
|
|
|
and _ref($self->{$key}) eq 'ARRAY' ) { |
|
878
|
|
|
|
|
|
|
# Recurse. |
|
879
|
4
|
|
|
|
|
37
|
my $m = _reduce( $self->{$key}, $orig->{$key}, "$path$key." ); |
|
880
|
4
|
50
|
33
|
|
|
29
|
delete $self->{$key} if $m eq 'D' || $m eq 'I'; |
|
881
|
4
|
50
|
100
|
|
|
25
|
$state //= 'M' if $m ne 'I'; |
|
882
|
|
|
|
|
|
|
} |
|
883
|
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
elsif ( ($self->{$key}//'') eq ($orig->{$key}//'') ) { |
|
885
|
1
|
|
|
|
|
3
|
warn("I: $path$key\n") if DEBUG; |
|
886
|
1
|
|
|
|
|
4
|
delete $self->{$key}; |
|
887
|
|
|
|
|
|
|
} |
|
888
|
|
|
|
|
|
|
elsif ( !defined($self->{$key}) |
|
889
|
|
|
|
|
|
|
and _ref($orig->{$key}) eq 'ARRAY' |
|
890
|
0
|
|
|
|
|
0
|
and !@{$orig->{$key}} |
|
891
|
|
|
|
|
|
|
or |
|
892
|
|
|
|
|
|
|
!defined($orig->{$key}) |
|
893
|
|
|
|
|
|
|
and _ref($self->{$key}) eq 'ARRAY' |
|
894
|
0
|
|
|
|
|
0
|
and !@{$self->{$key}} ) { |
|
895
|
|
|
|
|
|
|
# Properties input [] yields undef. |
|
896
|
0
|
|
|
|
|
0
|
warn("I: $path$key\n") if DEBUG; |
|
897
|
0
|
|
|
|
|
0
|
delete $self->{$key}; |
|
898
|
|
|
|
|
|
|
} |
|
899
|
|
|
|
|
|
|
else { |
|
900
|
|
|
|
|
|
|
# Overwrite. |
|
901
|
1
|
|
|
|
|
2
|
warn("M: $path$key => $self->{$key}\n") if DEBUG; |
|
902
|
1
|
|
50
|
|
|
10
|
$state //= 'M'; |
|
903
|
|
|
|
|
|
|
} |
|
904
|
|
|
|
|
|
|
} |
|
905
|
3
|
|
50
|
|
|
16
|
return $state // 'I'; |
|
906
|
|
|
|
|
|
|
} |
|
907
|
|
|
|
|
|
|
|
|
908
|
3
|
50
|
33
|
|
|
9
|
if ( _ref($self) eq 'ARRAY' && _ref($orig) eq 'ARRAY' ) { |
|
909
|
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
# Arrays. |
|
911
|
3
|
100
|
|
5
|
|
27
|
if ( any { _ref($_) } @$self ) { |
|
|
5
|
|
|
|
|
41
|
|
|
912
|
|
|
|
|
|
|
# Complex arrays. Recurse. |
|
913
|
1
|
|
|
|
|
8
|
for ( my $key = 0; $key < @$self; $key++ ) { |
|
914
|
1
|
|
|
|
|
12
|
my $m = _reduce( $self->[$key], $orig->[$key], "$path$key." ); |
|
915
|
|
|
|
|
|
|
#delete $self->{$key} if $m eq 'D'; # TODO |
|
916
|
1
|
50
|
50
|
|
|
13
|
$state //= 'M' if $m ne 'I'; |
|
917
|
|
|
|
|
|
|
} |
|
918
|
1
|
|
50
|
|
|
6
|
return $state // 'I'; |
|
919
|
|
|
|
|
|
|
} |
|
920
|
|
|
|
|
|
|
|
|
921
|
|
|
|
|
|
|
# Simple arrays (only scalar values). |
|
922
|
2
|
100
|
|
|
|
17
|
if ( my $dd = @$self - @$orig ) { |
|
923
|
1
|
|
|
|
|
10
|
$path =~ s/\.$//; |
|
924
|
1
|
50
|
|
|
|
4
|
if ( $dd > 0 ) { |
|
925
|
|
|
|
|
|
|
# New is larger. Check for prepend/append. |
|
926
|
|
|
|
|
|
|
# Deal with either one, not both. Maybe later. |
|
927
|
1
|
|
|
|
|
4
|
my $t; |
|
928
|
1
|
|
|
|
|
4
|
for ( my $ix = 0; $ix < @$orig; $ix++ ) { |
|
929
|
1
|
50
|
|
|
|
7
|
next if $orig->[$ix] eq $self->[$ix]; |
|
930
|
1
|
|
|
|
|
4
|
$t++; |
|
931
|
1
|
|
|
|
|
3
|
last; |
|
932
|
|
|
|
|
|
|
} |
|
933
|
1
|
50
|
|
|
|
7
|
unless ( $t ) { |
|
934
|
0
|
|
|
|
|
0
|
warn("M: $path append @{$self}[-$dd..-1]\n") if DEBUG; |
|
935
|
0
|
|
|
|
|
0
|
splice( @$self, 0, $dd, "append" ); |
|
936
|
0
|
|
|
|
|
0
|
return 'M'; |
|
937
|
|
|
|
|
|
|
} |
|
938
|
1
|
|
|
|
|
2
|
undef $t; |
|
939
|
1
|
|
|
|
|
5
|
for ( my $ix = $dd; $ix < @$self; $ix++ ) { |
|
940
|
2
|
50
|
|
|
|
11
|
next if $orig->[$ix-$dd] eq $self->[$ix]; |
|
941
|
0
|
|
|
|
|
0
|
$t++; |
|
942
|
0
|
|
|
|
|
0
|
last; |
|
943
|
|
|
|
|
|
|
} |
|
944
|
1
|
50
|
|
|
|
5
|
unless ( $t ) { |
|
945
|
1
|
|
|
|
|
2
|
warn("M: $path prepend @{$self}[0..$dd-1]\n") if DEBUG; |
|
946
|
1
|
|
|
|
|
5
|
splice( @$self, $dd ); |
|
947
|
1
|
|
|
|
|
4
|
unshift( @$self, "prepend" ); |
|
948
|
1
|
|
|
|
|
5
|
return 'M'; |
|
949
|
|
|
|
|
|
|
} |
|
950
|
0
|
|
|
|
|
0
|
warn("M: $path => @$self\n") if DEBUG; |
|
951
|
0
|
|
|
|
|
0
|
$state = 'M'; |
|
952
|
|
|
|
|
|
|
} |
|
953
|
|
|
|
|
|
|
else { |
|
954
|
0
|
|
|
|
|
0
|
warn("M: $path => @$self\n") if DEBUG; |
|
955
|
0
|
|
|
|
|
0
|
$state = 'M'; |
|
956
|
|
|
|
|
|
|
} |
|
957
|
0
|
|
0
|
|
|
0
|
return $state // 'I'; |
|
958
|
|
|
|
|
|
|
} |
|
959
|
|
|
|
|
|
|
|
|
960
|
|
|
|
|
|
|
# Equal length arrays with scalar values. |
|
961
|
1
|
|
|
|
|
2
|
my $t; |
|
962
|
1
|
|
|
|
|
4
|
for ( my $ix = 0; $ix < @$orig; $ix++ ) { |
|
963
|
1
|
50
|
|
|
|
5
|
next if $orig->[$ix] eq $self->[$ix]; |
|
964
|
1
|
|
|
|
|
290
|
warn("M: $path$ix => $self->[$ix]\n") if DEBUG; |
|
965
|
1
|
|
|
|
|
6
|
$t++; |
|
966
|
1
|
|
|
|
|
3
|
last; |
|
967
|
|
|
|
|
|
|
} |
|
968
|
1
|
50
|
|
|
|
6
|
if ( $t ) { |
|
969
|
1
|
|
|
|
|
1
|
warn("M: $path\n") if DEBUG; |
|
970
|
1
|
|
|
|
|
9
|
return 'M'; |
|
971
|
|
|
|
|
|
|
} |
|
972
|
0
|
|
|
|
|
0
|
warn("I: $path\[]\n") if DEBUG; |
|
973
|
0
|
|
|
|
|
0
|
return 'I'; |
|
974
|
|
|
|
|
|
|
} |
|
975
|
|
|
|
|
|
|
|
|
976
|
|
|
|
|
|
|
# Two scalar values. |
|
977
|
0
|
|
|
|
|
0
|
$path =~ s/\.$//; |
|
978
|
0
|
0
|
|
|
|
0
|
if ( $self eq $orig ) { |
|
979
|
0
|
|
|
|
|
0
|
warn("I: $path\n") if DEBUG; |
|
980
|
0
|
|
|
|
|
0
|
return 'I'; |
|
981
|
|
|
|
|
|
|
} |
|
982
|
|
|
|
|
|
|
|
|
983
|
0
|
|
|
|
|
0
|
warn("M $path $self\n") if DEBUG; |
|
984
|
0
|
|
|
|
|
0
|
return 'M'; |
|
985
|
|
|
|
|
|
|
} |
|
986
|
|
|
|
|
|
|
|
|
987
|
8858
|
|
|
8858
|
0
|
13204
|
sub hmerge( $left, $right, $path = "" ) { |
|
|
8858
|
|
|
|
|
12995
|
|
|
|
8858
|
|
|
|
|
13254
|
|
|
|
8858
|
|
|
|
|
14167
|
|
|
|
8858
|
|
|
|
|
12385
|
|
|
988
|
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
# Merge hashes. Right takes precedence. |
|
990
|
|
|
|
|
|
|
# Based on Hash::Merge::Simple by Robert Krimen. |
|
991
|
|
|
|
|
|
|
|
|
992
|
8858
|
|
|
|
|
65276
|
my %res = %$left; |
|
993
|
|
|
|
|
|
|
|
|
994
|
8858
|
|
|
|
|
27547
|
for my $key ( keys(%$right) ) { |
|
995
|
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
warn("Config error: unknown item $path$key\n") |
|
997
|
36751
|
50
|
66
|
|
|
87733
|
unless exists $res{$key} |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
998
|
|
|
|
|
|
|
|| $path eq "pdf.fontconfig." |
|
999
|
|
|
|
|
|
|
|| $path =~ /^pdf\.(?:info|fonts)\./ |
|
1000
|
|
|
|
|
|
|
|| $path =~ /^pdf\.formats\.\w+-even\./ |
|
1001
|
|
|
|
|
|
|
|| ( $path =~ /^pdf\.formats\./ && $key =~ /\w+-even$/ ) |
|
1002
|
|
|
|
|
|
|
|| $path =~ /^(meta|gridstrum\.symbols)\./ |
|
1003
|
|
|
|
|
|
|
|| $path =~ /^delegates\./ |
|
1004
|
|
|
|
|
|
|
|| $path =~ /^parser\.preprocess\./ |
|
1005
|
|
|
|
|
|
|
|| $path =~ /^markup\.shortcodes\./ |
|
1006
|
|
|
|
|
|
|
|| $path =~ /^debug\./ |
|
1007
|
|
|
|
|
|
|
|| $key =~ /^_/; |
|
1008
|
|
|
|
|
|
|
|
|
1009
|
36751
|
100
|
66
|
|
|
131403
|
if ( ref($right->{$key}) eq 'HASH' |
|
|
|
100
|
100
|
|
|
|
|
|
1010
|
|
|
|
|
|
|
and |
|
1011
|
|
|
|
|
|
|
ref($res{$key}) eq 'HASH' ) { |
|
1012
|
|
|
|
|
|
|
# Hashes. Recurse. |
|
1013
|
8507
|
|
|
|
|
25835
|
$res{$key} = hmerge( $res{$key}, $right->{$key}, "$path$key." ); |
|
1014
|
|
|
|
|
|
|
} |
|
1015
|
|
|
|
|
|
|
elsif ( ref($right->{$key}) eq 'ARRAY' |
|
1016
|
|
|
|
|
|
|
and |
|
1017
|
|
|
|
|
|
|
ref($res{$key}) eq 'ARRAY' ) { |
|
1018
|
|
|
|
|
|
|
warn("AMERGE $key: ", |
|
1019
|
|
|
|
|
|
|
join(" ", map { qq{"$_"} } @{ $res{$key} }), |
|
1020
|
|
|
|
|
|
|
" + ", |
|
1021
|
3157
|
|
|
|
|
4938
|
join(" ", map { qq{"$_"} } @{ $right->{$key} }), |
|
1022
|
|
|
|
|
|
|
" \n") if 0; |
|
1023
|
|
|
|
|
|
|
# Arrays. Overwrite or append. |
|
1024
|
3157
|
100
|
|
|
|
4599
|
if ( @{$right->{$key}} ) { |
|
|
3157
|
|
|
|
|
9562
|
|
|
1025
|
1769
|
|
|
|
|
2670
|
my @v = @{ $right->{$key} }; |
|
|
1769
|
|
|
|
|
16318
|
|
|
1026
|
1769
|
50
|
|
|
|
5551
|
if ( $v[0] eq "append" ) { |
|
|
|
50
|
|
|
|
|
|
|
1027
|
0
|
|
|
|
|
0
|
shift(@v); |
|
1028
|
|
|
|
|
|
|
# Append the rest. |
|
1029
|
|
|
|
|
|
|
warn("PRE: ", |
|
1030
|
|
|
|
|
|
|
join(" ", map { qq{"$_"} } @{ $res{$key} }), |
|
1031
|
|
|
|
|
|
|
" + ", |
|
1032
|
0
|
|
|
|
|
0
|
join(" ", map { qq{"$_"} } @v), |
|
1033
|
|
|
|
|
|
|
"\n") if 0; |
|
1034
|
0
|
|
|
|
|
0
|
push( @{ $res{$key} }, @v ); |
|
|
0
|
|
|
|
|
0
|
|
|
1035
|
|
|
|
|
|
|
warn("POST: ", |
|
1036
|
0
|
|
|
|
|
0
|
join(" ", map { qq{"$_"} } @{ $res{$key} }), |
|
1037
|
|
|
|
|
|
|
"\n") if 0; |
|
1038
|
|
|
|
|
|
|
} |
|
1039
|
|
|
|
|
|
|
elsif ( $v[0] eq "prepend" ) { |
|
1040
|
0
|
|
|
|
|
0
|
shift(@v); |
|
1041
|
|
|
|
|
|
|
# Prepend the rest. |
|
1042
|
0
|
|
|
|
|
0
|
unshift( @{ $res{$key} }, @v ); |
|
|
0
|
|
|
|
|
0
|
|
|
1043
|
|
|
|
|
|
|
} |
|
1044
|
|
|
|
|
|
|
else { |
|
1045
|
|
|
|
|
|
|
# Overwrite. |
|
1046
|
1769
|
|
|
|
|
7161
|
$res{$key} = $right->{$key}; |
|
1047
|
|
|
|
|
|
|
} |
|
1048
|
|
|
|
|
|
|
} |
|
1049
|
|
|
|
|
|
|
else { |
|
1050
|
|
|
|
|
|
|
# Overwrite. |
|
1051
|
1388
|
|
|
|
|
3557
|
$res{$key} = $right->{$key}; |
|
1052
|
|
|
|
|
|
|
} |
|
1053
|
|
|
|
|
|
|
} |
|
1054
|
|
|
|
|
|
|
else { |
|
1055
|
|
|
|
|
|
|
# Overwrite. |
|
1056
|
25087
|
|
|
|
|
47906
|
$res{$key} = $right->{$key}; |
|
1057
|
|
|
|
|
|
|
} |
|
1058
|
|
|
|
|
|
|
} |
|
1059
|
|
|
|
|
|
|
|
|
1060
|
8858
|
|
|
|
|
470636
|
return \%res; |
|
1061
|
|
|
|
|
|
|
} |
|
1062
|
|
|
|
|
|
|
|
|
1063
|
40
|
|
|
40
|
0
|
130
|
sub clone ( $source ) { |
|
|
40
|
|
|
|
|
109
|
|
|
|
40
|
|
|
|
|
82
|
|
|
1064
|
|
|
|
|
|
|
|
|
1065
|
40
|
50
|
|
|
|
154
|
return if not defined($source); |
|
1066
|
|
|
|
|
|
|
|
|
1067
|
90
|
|
|
90
|
|
1085
|
use Storable; |
|
|
90
|
|
|
|
|
224
|
|
|
|
90
|
|
|
|
|
129565
|
|
|
1068
|
40
|
|
|
|
|
85019
|
my $clone = Storable::dclone($source); |
|
1069
|
40
|
|
|
|
|
454
|
$clone->unlock; |
|
1070
|
40
|
|
|
|
|
108511
|
return $clone; |
|
1071
|
|
|
|
|
|
|
|
|
1072
|
|
|
|
|
|
|
} |
|
1073
|
|
|
|
|
|
|
|
|
1074
|
132
|
|
|
132
|
0
|
390
|
sub precheck ( $cfg, $file ) { |
|
|
132
|
|
|
|
|
307
|
|
|
|
132
|
|
|
|
|
332
|
|
|
|
132
|
|
|
|
|
262
|
|
|
1075
|
|
|
|
|
|
|
|
|
1076
|
132
|
|
|
|
|
719
|
my $verbose = $options->{verbose}; |
|
1077
|
132
|
50
|
|
|
|
597
|
warn("Verify config \"$file\"\n") if $verbose > 1; |
|
1078
|
132
|
|
|
|
|
357
|
my $p; |
|
1079
|
|
|
|
|
|
|
$p = sub { |
|
1080
|
283922
|
|
|
283922
|
|
520539
|
my ( $o, $path ) = @_; |
|
1081
|
283922
|
|
100
|
|
|
493393
|
$path //= ""; |
|
1082
|
283922
|
100
|
|
|
|
773317
|
if ( is_hashref($o) ) { |
|
|
|
100
|
|
|
|
|
|
|
1083
|
50376
|
100
|
|
|
|
103239
|
$path .= "." unless $path eq ""; |
|
1084
|
50376
|
|
|
|
|
177493
|
for ( sort keys %$o ) { |
|
1085
|
119944
|
|
|
|
|
279533
|
$p->( $o->{$_}, $path . $_ ); |
|
1086
|
|
|
|
|
|
|
} |
|
1087
|
|
|
|
|
|
|
} |
|
1088
|
|
|
|
|
|
|
elsif ( is_arrayref($o) ) { |
|
1089
|
19175
|
50
|
|
|
|
39836
|
$path .= "." unless $path eq ""; |
|
1090
|
19175
|
|
|
|
|
43999
|
for ( my $i = 0; $i < @$o; $i++ ) { |
|
1091
|
163846
|
|
|
|
|
390368
|
$p->( $o->[$i], $path . "$i" ); |
|
1092
|
|
|
|
|
|
|
} |
|
1093
|
|
|
|
|
|
|
} |
|
1094
|
132
|
|
|
|
|
1552
|
}; |
|
1095
|
|
|
|
|
|
|
|
|
1096
|
132
|
|
|
|
|
701
|
$p->($cfg); |
|
1097
|
|
|
|
|
|
|
} |
|
1098
|
|
|
|
|
|
|
|
|
1099
|
|
|
|
|
|
|
|
|
1100
|
|
|
|
|
|
|
## Data::Properties compatible API. |
|
1101
|
|
|
|
|
|
|
# |
|
1102
|
|
|
|
|
|
|
# Note: Lookup always takes the context into account. |
|
1103
|
|
|
|
|
|
|
# Note: Always signals undefined values. |
|
1104
|
|
|
|
|
|
|
|
|
1105
|
|
|
|
|
|
|
my $prp_context = ""; |
|
1106
|
|
|
|
|
|
|
|
|
1107
|
12
|
|
|
12
|
0
|
22
|
sub get_property ( $p, $prp, $def = undef ) { |
|
|
12
|
|
|
|
|
23
|
|
|
|
12
|
|
|
|
|
24
|
|
|
|
12
|
|
|
|
|
29
|
|
|
|
12
|
|
|
|
|
23
|
|
|
1108
|
12
|
100
|
|
|
|
107
|
for ( split( /\./, |
|
1109
|
|
|
|
|
|
|
$prp_context eq "" |
|
1110
|
|
|
|
|
|
|
? $prp |
|
1111
|
|
|
|
|
|
|
: "$prp_context.$prp" ) ) { |
|
1112
|
34
|
100
|
|
|
|
133
|
if ( /^\d+$/ ) { |
|
1113
|
5
|
50
|
|
|
|
14
|
die("No config $prp\n") unless _ref($p) eq 'ARRAY'; |
|
1114
|
5
|
|
|
|
|
22
|
$p = $p->[$_]; |
|
1115
|
|
|
|
|
|
|
} |
|
1116
|
|
|
|
|
|
|
else { |
|
1117
|
29
|
50
|
|
|
|
68
|
die("No config $prp\n") unless _ref($p) eq 'HASH'; |
|
1118
|
29
|
|
|
|
|
99
|
$p = $p->{$_}; |
|
1119
|
|
|
|
|
|
|
} |
|
1120
|
|
|
|
|
|
|
} |
|
1121
|
12
|
|
66
|
|
|
44
|
$p //= $def; |
|
1122
|
12
|
50
|
|
|
|
33
|
die("No config $prp\n") unless defined $p; |
|
1123
|
12
|
|
|
|
|
77
|
$p; |
|
1124
|
|
|
|
|
|
|
} |
|
1125
|
|
|
|
|
|
|
|
|
1126
|
|
|
|
|
|
|
*gps = \&get_property; |
|
1127
|
|
|
|
|
|
|
|
|
1128
|
|
|
|
|
|
|
sub set_property { |
|
1129
|
0
|
|
|
0
|
0
|
0
|
...; |
|
1130
|
|
|
|
|
|
|
} |
|
1131
|
|
|
|
|
|
|
|
|
1132
|
2
|
|
|
2
|
0
|
7
|
sub set_context ( $self, $ctx = "" ) { |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
6
|
|
|
|
2
|
|
|
|
|
4
|
|
|
1133
|
2
|
|
|
|
|
6
|
$prp_context = $ctx; |
|
1134
|
|
|
|
|
|
|
} |
|
1135
|
|
|
|
|
|
|
|
|
1136
|
0
|
|
|
0
|
0
|
0
|
sub get_context () { |
|
|
0
|
|
|
|
|
0
|
|
|
1137
|
0
|
|
|
|
|
0
|
$prp_context; |
|
1138
|
|
|
|
|
|
|
} |
|
1139
|
|
|
|
|
|
|
|
|
1140
|
|
|
|
|
|
|
# For testing |
|
1141
|
90
|
|
|
90
|
|
884
|
use Exporter 'import'; |
|
|
90
|
|
|
|
|
212
|
|
|
|
90
|
|
|
|
|
27402
|
|
|
1142
|
|
|
|
|
|
|
our @EXPORT = qw( _c ); |
|
1143
|
12
|
|
|
12
|
|
344276
|
sub _c ( @args ) { $::config->gps(@args) } |
|
|
12
|
|
|
|
|
40
|
|
|
|
12
|
|
|
|
|
23
|
|
|
|
12
|
|
|
|
|
60
|
|
|
1144
|
|
|
|
|
|
|
|
|
1145
|
|
|
|
|
|
|
# For convenience. |
|
1146
|
112
|
|
|
112
|
0
|
238
|
sub diagram_strings ( $self ) { |
|
|
112
|
|
|
|
|
252
|
|
|
|
112
|
|
|
|
|
212
|
|
|
1147
|
|
|
|
|
|
|
# tuning is usually removed from the config. |
|
1148
|
|
|
|
|
|
|
# scalar( @{ $self->{tuning} } ); |
|
1149
|
112
|
|
|
|
|
623
|
ChordPro::Chords::strings(); |
|
1150
|
|
|
|
|
|
|
} |
|
1151
|
|
|
|
|
|
|
|
|
1152
|
0
|
|
|
0
|
0
|
|
sub diagram_keys ( $self ) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
1153
|
0
|
|
|
|
|
|
$self->{kbdiagrams}->{keys}; |
|
1154
|
|
|
|
|
|
|
} |
|
1155
|
|
|
|
|
|
|
|
|
1156
|
|
|
|
|
|
|
# For debugging messages. |
|
1157
|
0
|
|
|
0
|
0
|
|
sub qd ( $val, $compact = 0 ) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
1158
|
90
|
|
|
90
|
|
82444
|
use Data::Dumper qw(); |
|
|
90
|
|
|
|
|
1236583
|
|
|
|
90
|
|
|
|
|
47287
|
|
|
1159
|
0
|
|
|
|
|
|
local $Data::Dumper::Sortkeys = 1; |
|
1160
|
0
|
|
|
|
|
|
local $Data::Dumper::Indent = 1; |
|
1161
|
0
|
|
|
|
|
|
local $Data::Dumper::Quotekeys = 0; |
|
1162
|
0
|
|
|
|
|
|
local $Data::Dumper::Deparse = 1; |
|
1163
|
0
|
|
|
|
|
|
local $Data::Dumper::Terse = 1; |
|
1164
|
0
|
|
|
|
|
|
local $Data::Dumper::Trailingcomma = !$compact; |
|
1165
|
0
|
|
|
|
|
|
local $Data::Dumper::Useperl = 1; |
|
1166
|
0
|
|
|
|
|
|
local $Data::Dumper::Useqq = 0; # I want unicode visible |
|
1167
|
0
|
|
|
|
|
|
my $x = Data::Dumper::Dumper($val); |
|
1168
|
0
|
0
|
|
|
|
|
if ( $compact ) { |
|
1169
|
0
|
|
|
|
|
|
$x =~ s/^bless\( (.*), '[\w:]+' \)$/$1/s; |
|
1170
|
0
|
|
|
|
|
|
$x =~ s/\s+/ /gs; |
|
1171
|
|
|
|
|
|
|
} |
|
1172
|
0
|
0
|
|
|
|
|
defined wantarray ? $x : warn($x,"\n"); |
|
1173
|
|
|
|
|
|
|
} |
|
1174
|
|
|
|
|
|
|
|
|
1175
|
|
|
|
|
|
|
1; |