line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# Copyright 1995 Francesco Callari, McGill University. See notice |
2
|
|
|
|
|
|
|
# at end of this file. |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# Filename: Resources.pm |
5
|
|
|
|
|
|
|
# Author: Francesco Callari (franco@cim.mcgill.ca) |
6
|
|
|
|
|
|
|
# Created: Wed May 31 17:55:21 1995 |
7
|
|
|
|
|
|
|
# Version: $Id: |
8
|
|
|
|
|
|
|
# Resources.pm,v 0.1 1995/10/19 02:49:43 franco Exp franco $ |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 NAME |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
Resources - handling application defaults in Perl. |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 SYNOPSIS |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
use Resources; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
$res = new Resources; |
20
|
|
|
|
|
|
|
$res = new Resources "resfile"; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 DESCRIPTION |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
Resources are a way to specify information of interest to program or |
25
|
|
|
|
|
|
|
packages. |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
Applications use resource files to specify and document the values of |
28
|
|
|
|
|
|
|
quantities or attributes of interest. |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
Resources can be loaded from or saved to resource files. Methods are |
31
|
|
|
|
|
|
|
provided to search, modify and create resources. |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
Packages use resources to hardwire in their code the default values for |
34
|
|
|
|
|
|
|
their attributes, along with documentation for the attibutes themselves. |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
Packages inherit resources when subclassed, and the resource names are |
37
|
|
|
|
|
|
|
updated dynamically to reflect a class hierarchy. |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
Methods are provided for interactive resource inspection and editing. |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=head2 1. Resource inheritance |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
Package attributes are inherited from base and member classes, their names are |
44
|
|
|
|
|
|
|
dynamically updated to reflect the inheritance, and values specified in |
45
|
|
|
|
|
|
|
derived/container classes override those inherited from base/member classes. |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
More precisely, there a few rules governing the inheritance of resource |
48
|
|
|
|
|
|
|
names and values, and they will be explained by way of examples. |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
As far as resource names, the rules are: |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
=over 8 |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=item Base class |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
If Vehicle has a "speed" property, then it can use a resource named |
57
|
|
|
|
|
|
|
"vehicle.speed" to specify its default value. |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=item Derived class |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
If Car B Vehicle, then Car has a "car.speed" resource automagically |
62
|
|
|
|
|
|
|
defined by inheritance from the base class. |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=item Container class |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
If Car B member object called Tire, and Tire has a "tire.pressure" |
67
|
|
|
|
|
|
|
resource, then Car inherits a "car.tire.pressure" resource from the member |
68
|
|
|
|
|
|
|
class. |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
=item Application class |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
All resources of Car objects used by a program named "race" have the prefix |
73
|
|
|
|
|
|
|
"race." prepended to their names, e.g. "race.car.speed", |
74
|
|
|
|
|
|
|
"race.car.tire.pressure", etc. |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=back |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
With regard to assigning values to resources, the rules are: |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=over 8 |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
=item Specification in a file |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
Resources specified in a resource file always override hardcoded resources |
85
|
|
|
|
|
|
|
(with the exception of "hidden" resources, see below). |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=item Inheritance |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
Resources defined in a derived class (like Car) override those specified in |
90
|
|
|
|
|
|
|
a base class. Likewise, resources defined in a container class override |
91
|
|
|
|
|
|
|
those specified in the members. |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
In the above example, a default value for "car.speed" in Car overrides the |
94
|
|
|
|
|
|
|
value of "vehicle.speed" in any Car object, otherwise "car.speed" assumes the |
95
|
|
|
|
|
|
|
value of "vehicle.speed". Same for "car.tire.pressure". |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=back |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=head2 2. Resource Files. |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
A resource specification in a (text) resource file is a line of the form: |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
sequence: value |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
There may be any number of whitespaces between the name and the colon |
106
|
|
|
|
|
|
|
character, and between the colon and the value. |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=over 8 |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=item B can have four forms: |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
(1) word |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
A B not containing whitespaces, colons (':'), dots ('.') or asterisks |
115
|
|
|
|
|
|
|
('*'), nor starting with an underscore ('_'). |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
Or, recursively: |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
(2) word.sequence |
120
|
|
|
|
|
|
|
(3) word*sequence |
121
|
|
|
|
|
|
|
(4) *sequence |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
The asterisks in a resource name act as wildcards, matching any sequence of |
124
|
|
|
|
|
|
|
characters. |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
For cases (3) or (4) the B must be or match the current application |
127
|
|
|
|
|
|
|
class, otherwise the resource specification is silently ignored (this means |
128
|
|
|
|
|
|
|
that an applications loads from a file only its own resources, and those whose |
129
|
|
|
|
|
|
|
application class is a wildcard). |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
No distinction is made between uppercase and lowercase letters. |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=item B can be: |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
An unadorned word or a quoted sequence of whitespace-separated words. Both |
136
|
|
|
|
|
|
|
single (' ') and double quotes quotes (" ") are allowed, and they must be |
137
|
|
|
|
|
|
|
paired. |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
Any I scalar constructor in Perl, including anon references to |
140
|
|
|
|
|
|
|
constant arrays or hashes. |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
The special words B, B, B, B (case insensitive) are |
143
|
|
|
|
|
|
|
treated as boolean resources and converted 1 and 0, unless they are quoted. |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=back |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
Examples of valid resource specifications: |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
car*brand : Ferrari # A word. |
150
|
|
|
|
|
|
|
car.price : 200K # Another word |
151
|
|
|
|
|
|
|
car.name : '312 BB' # A quoted sentence |
152
|
|
|
|
|
|
|
car*runs*alot : yes # A boolean, converted to 1. |
153
|
|
|
|
|
|
|
car*noise*lotsa : 'yes' # yes, taken verbatim |
154
|
|
|
|
|
|
|
car.size : [1, [2, 3]] # An anon array. |
155
|
|
|
|
|
|
|
car.lett : {"P"=>1, "Q"=>[2, 3]} # An anon hash. |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
Examples of illegal resource names: |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
car pedal # Whitespace in the name. |
160
|
|
|
|
|
|
|
.carpedal # Leading dot in name. |
161
|
|
|
|
|
|
|
car._pedal # Leading underscore in _dog. |
162
|
|
|
|
|
|
|
carpedal* # Trailing asterisk. |
163
|
|
|
|
|
|
|
carpedal. # Trailing dot. |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
A resource file may contain comments: anything from a hash ('#') character to |
166
|
|
|
|
|
|
|
the end of a line is ignored, unless the hash character appears inside a |
167
|
|
|
|
|
|
|
quoted value string. |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
Resource specifications may be split across successive lines, by terminating |
170
|
|
|
|
|
|
|
the split lines with a backslash, as per cpp(1). |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=head2 3. The Resources hash |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
A non-my hash named %Resources can be used to specify the default values for |
175
|
|
|
|
|
|
|
the attributes of a package in its source code, along with documentation for |
176
|
|
|
|
|
|
|
the attributes themselves. The documentation itself is "dynamical" (as opposed |
177
|
|
|
|
|
|
|
to the static, pod-like variety) in that it follows a class hyerarchy and is |
178
|
|
|
|
|
|
|
suitable for interactive display and editing. |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
The %Resources hash is just a hash of |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
$Name => [$Value, $Doc] |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
things. Each hash key B<$Name> is a resource name in the above sequence |
185
|
|
|
|
|
|
|
form. Each hash value is a reference to an anon array B<[$Value, $Doc]>, with |
186
|
|
|
|
|
|
|
B<$Doc> being an optional resource documentation. |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
The resource $Name I contain wildcard ('*') or colon (':') characters, |
189
|
|
|
|
|
|
|
nor start or end with a dot ('.'). Also, it must I be prefixed with the |
190
|
|
|
|
|
|
|
package name (since this is automatically prepended by the B method, |
191
|
|
|
|
|
|
|
see below). Names starting with an underscore ('_') character are special in |
192
|
|
|
|
|
|
|
that they define "hidden" resources. These may not be specified in resource |
193
|
|
|
|
|
|
|
files, nor dynamically viewed/edited: they come handy to specify global |
194
|
|
|
|
|
|
|
parameters when you do not want to use global application-wide variables, |
195
|
|
|
|
|
|
|
and/or want to take advantage of the inheritance mechanism. |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
The resource $Value can be any I scalar Perl constructor, including |
198
|
|
|
|
|
|
|
references to arrays and/or hashes of constants (or references |
199
|
|
|
|
|
|
|
thereof). Boolean values must be specified as 1 or 0. |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
The resource documentation is a just string of any length: it will be |
202
|
|
|
|
|
|
|
appropriately broken into lines for visualization purposes. It can also be |
203
|
|
|
|
|
|
|
missing, in which case an inherited documentation is used (if any exists, see |
204
|
|
|
|
|
|
|
the B method below). |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
The content of a resource hash is registered in a global Resource object using |
207
|
|
|
|
|
|
|
the B method. |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
Here is an example of deafults specification for a package. |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
package Car; |
212
|
|
|
|
|
|
|
@ISA = qw( Vehicle ); |
213
|
|
|
|
|
|
|
use vars qw( %Resources ); |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
%Resources = ( |
216
|
|
|
|
|
|
|
brand => ["FIAT", "The carmaker"], |
217
|
|
|
|
|
|
|
noise => ["Ashtmatic", "Auditory feeling"], |
218
|
|
|
|
|
|
|
sucks => [1, "Is it any good?"], |
219
|
|
|
|
|
|
|
nuts => [ { on => 2, off => [3, 5] }, "Spares"], |
220
|
|
|
|
|
|
|
'_ghost' => [0, "Hidden. Mr. Invisible"] |
221
|
|
|
|
|
|
|
'tire.flat' => [0], |
222
|
|
|
|
|
|
|
); |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
The last line overrides a default in member class Tire. The corresponding |
225
|
|
|
|
|
|
|
doc string is supposedly in the source of that class. The last two hash keys |
226
|
|
|
|
|
|
|
are quoted because of the non alphanumeric characters in them. |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
=head2 4. Objects and resources |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
The recommended way to use resources with Perl objects is to pass a |
231
|
|
|
|
|
|
|
Resource object to the "new" method of a package. The method itself will |
232
|
|
|
|
|
|
|
merge the passed resources with the package defaults, and the passed resource |
233
|
|
|
|
|
|
|
will override the defaults where needed. |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
Resource inheritance via subclassing is then easily achieved via the B |
236
|
|
|
|
|
|
|
method, as shown in the EXAMPLES section. |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
=cut |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
require 5.001; |
241
|
|
|
|
|
|
|
package Resources; |
242
|
1
|
|
|
1
|
|
821
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
31
|
|
243
|
1
|
|
|
1
|
|
6
|
use Carp; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
100
|
|
244
|
1
|
|
|
1
|
|
3546
|
use Safe; |
|
1
|
|
|
|
|
54619
|
|
|
1
|
|
|
|
|
65
|
|
245
|
1
|
|
|
1
|
|
871
|
use FileHandle; |
|
1
|
|
|
|
|
13192
|
|
|
1
|
|
|
|
|
7
|
|
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
# |
248
|
|
|
|
|
|
|
# Global variables |
249
|
|
|
|
|
|
|
# |
250
|
1
|
|
|
1
|
|
418
|
use vars qw( $VERSION %Resources $NAME $Value $Doc $Loaded $Merged ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
1964
|
|
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
$VERSION = "1.03"; |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
$Value=0, $Doc=1, $Loaded=2, $Merged=3; # Indices in resource value |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
# Resources of Resources ;-) |
258
|
|
|
|
|
|
|
%Resources = |
259
|
|
|
|
|
|
|
( |
260
|
|
|
|
|
|
|
'resources.appclass' => [$0, |
261
|
|
|
|
|
|
|
"The application name of this Resource " . |
262
|
|
|
|
|
|
|
"object."], |
263
|
|
|
|
|
|
|
'resources.editor' => ["/bin/vi", |
264
|
|
|
|
|
|
|
"Resource editor command."], |
265
|
|
|
|
|
|
|
'resources.mergeclass' => [1, |
266
|
|
|
|
|
|
|
"Boolean. True to merge with " . |
267
|
|
|
|
|
|
|
"class inheritance."], |
268
|
|
|
|
|
|
|
'resources.pager' => ["/bin/cat", |
269
|
|
|
|
|
|
|
"Resource pager command."], |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
'resources.resources' => ['%Resources', |
272
|
|
|
|
|
|
|
"The name of the standard default hash."], |
273
|
|
|
|
|
|
|
'resources.separator' => [':', |
274
|
|
|
|
|
|
|
"Pattern separating names from values in " . |
275
|
|
|
|
|
|
|
"resource files."], |
276
|
|
|
|
|
|
|
'resources.tmpfil' => ["/tmp/resedit$$", |
277
|
|
|
|
|
|
|
"Editor temporary file."], |
278
|
|
|
|
|
|
|
'resources.updates' => [0, |
279
|
|
|
|
|
|
|
"Number of resource updates."], |
280
|
|
|
|
|
|
|
'resources.verbosity' => [1, |
281
|
|
|
|
|
|
|
"True to print warnings."], |
282
|
|
|
|
|
|
|
'resources.viewcols' => [78, |
283
|
|
|
|
|
|
|
"Width of view/edit window."], |
284
|
|
|
|
|
|
|
'resources.viewmincols' => [15, |
285
|
|
|
|
|
|
|
"Minimum width of a comment line in view."], |
286
|
|
|
|
|
|
|
'resources.writepod' => [0, |
287
|
|
|
|
|
|
|
"Boolean. True if the write method should " . |
288
|
|
|
|
|
|
|
"output in POD format."], |
289
|
|
|
|
|
|
|
); |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
# |
292
|
|
|
|
|
|
|
# Method declarations |
293
|
|
|
|
|
|
|
# |
294
|
|
|
|
|
|
|
sub new; |
295
|
|
|
|
|
|
|
sub DESTROY; |
296
|
|
|
|
|
|
|
sub load; |
297
|
|
|
|
|
|
|
sub merge; |
298
|
|
|
|
|
|
|
sub put; |
299
|
|
|
|
|
|
|
sub valbyname; |
300
|
|
|
|
|
|
|
sub docbyname; |
301
|
|
|
|
|
|
|
sub valbypattern; |
302
|
|
|
|
|
|
|
sub docbypattern; |
303
|
|
|
|
|
|
|
sub namebyclass; |
304
|
|
|
|
|
|
|
sub valbyclass; |
305
|
|
|
|
|
|
|
sub docbyclass; |
306
|
|
|
|
|
|
|
sub each; |
307
|
|
|
|
|
|
|
sub names; |
308
|
|
|
|
|
|
|
sub view; |
309
|
|
|
|
|
|
|
sub edit; |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
# |
313
|
|
|
|
|
|
|
# Unexported subroutines |
314
|
|
|
|
|
|
|
# |
315
|
|
|
|
|
|
|
sub _chain_classes; |
316
|
|
|
|
|
|
|
sub _parse; |
317
|
|
|
|
|
|
|
sub _parse_ref; |
318
|
|
|
|
|
|
|
sub _error; |
319
|
|
|
|
|
|
|
sub _printformat; |
320
|
|
|
|
|
|
|
sub _dump; |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
=head2 5. Methods in class Resources |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
=head2 5.1. Creation and initialization |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
=over 8 |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
=item B |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
Creates a new resource database, initialized with the defaults for |
331
|
|
|
|
|
|
|
class Resources (see below for a list of them). |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
If a nonempty file name is specified in $resfile, it initializes the object |
334
|
|
|
|
|
|
|
with the content of the so named resource file. For safe (non overwriting) |
335
|
|
|
|
|
|
|
loading, see the B method below. |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
If the special file name "_RES_NODEFAULTS" is specified, the object is created |
338
|
|
|
|
|
|
|
completely empty, with not even the Resources class defaults in it. |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
Returns the new object, or undef in case of error. |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
=cut |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
sub new { |
345
|
1
|
|
|
1
|
1
|
67
|
my $type = shift; |
346
|
1
|
|
|
|
|
3
|
my $resfile = shift; |
347
|
1
|
|
|
|
|
3
|
my ($name, $valdoc, $app); |
348
|
1
|
|
|
|
|
3
|
my $res = bless {}; |
349
|
|
|
|
|
|
|
|
350
|
1
|
|
|
|
|
8
|
$res->{Load} = 0; # 1 if loading |
351
|
1
|
|
|
|
|
2
|
$res->{Merge} = 0; # 1 if merging |
352
|
1
|
|
|
|
|
5
|
$res->{Wilds} = {}; # Wildcarded resources. |
353
|
1
|
|
|
|
|
3
|
$res->{Res} = {}; # Named resources. |
354
|
1
|
|
|
|
|
3
|
$res->{Owned} = {}; # Inverted index of member clases. |
355
|
1
|
|
|
|
|
3
|
$res->{Isa} = {}; # Inverted index of base classes. |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
# Safe environment for the evaluation of constructors. |
358
|
1
|
50
|
|
|
|
11
|
$res->{Safe} = new Safe or |
359
|
|
|
|
|
|
|
($res->_error("new", "can't get a Safe object."), return undef); |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
# Hack hack - the special filename "_RES_NODEFAULTS" is |
362
|
|
|
|
|
|
|
# used to prevent resource initialization (e.g. when called by the |
363
|
|
|
|
|
|
|
# "bypattern" method |
364
|
1
|
50
|
33
|
|
|
2272
|
unless ($resfile && $resfile eq "_RES_NODEFAULTS") { |
365
|
|
|
|
|
|
|
# Must make sure this is not overridden by a wildcard |
366
|
1
|
|
|
|
|
6
|
$res->{Wilds}->{'.*resources\.updates'} = [0]; |
367
|
1
|
|
|
|
|
5
|
$res->{Res}->{'resources.updates'}->[$Value] = 0; |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
# Get appclass without extensions |
370
|
1
|
50
|
|
|
|
9
|
if (($app = $Resources{'resources.appclass'}->[$Value]) =~ /\./) { |
371
|
1
|
|
|
|
|
6
|
$Resources{'resources.appclass'}->[$Value] = (split(/\./, $app))[0]; |
372
|
|
|
|
|
|
|
} |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
# Bootstrap defaults. We don't want any subclassing here |
375
|
1
|
|
|
|
|
7
|
while (($name, $valdoc) = each(%Resources)) { |
376
|
12
|
|
|
|
|
40
|
$res->{Res}->{$name} = $valdoc; |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
|
380
|
1
|
50
|
33
|
|
|
4
|
if ($resfile && $resfile ne "_RES_NODEFAULTS") { |
381
|
0
|
0
|
|
|
|
0
|
$res->load($resfile) || |
382
|
|
|
|
|
|
|
($res->_error("new", "can't load"), return undef); |
383
|
|
|
|
|
|
|
} |
384
|
|
|
|
|
|
|
|
385
|
1
|
|
|
|
|
4
|
$res; |
386
|
|
|
|
|
|
|
} |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
sub DESTROY { |
390
|
1
|
|
|
1
|
|
30
|
my $res=shift; |
391
|
1
|
|
|
|
|
25
|
Safe::DESTROY($res->{Safe}); |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
=item B |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
Loads resources from a file named $resfile into a resource database. |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
The $nonew argument controls whether loading of non already defined resurces is |
400
|
|
|
|
|
|
|
allowed. If it is true, safe loading is performed: attempting to load |
401
|
|
|
|
|
|
|
non-wildcarded resource names that do not match those already present in the |
402
|
|
|
|
|
|
|
database causes an error. This can be useful if you want to make sure that |
403
|
|
|
|
|
|
|
only pre-defined resources (for which you presumably have hardwired defaults) |
404
|
|
|
|
|
|
|
are loaded. It can be a safety net against typos in a resource file. |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
Use is made of B to parse values specified through Perl |
407
|
|
|
|
|
|
|
constructors (only constants, anon hashes and anon arrays are allowed). |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
Returns 1 if ok, 0 if error. |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
=cut |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
sub load { |
414
|
0
|
|
|
0
|
1
|
0
|
my $res = shift; |
415
|
0
|
|
|
|
|
0
|
my ($filnam, $nonew) = @_; |
416
|
0
|
|
|
|
|
0
|
my ($lin, $prevlin, $comlin, @line); |
417
|
0
|
|
|
|
|
0
|
my ($name, @allvals, $value, %allres, $def, @dum); |
418
|
0
|
|
|
|
|
0
|
my ($sep, $expr, $evaled); |
419
|
0
|
|
|
|
|
0
|
my ($app, $mrgcls); |
420
|
|
|
|
|
|
|
|
421
|
0
|
0
|
0
|
|
|
0
|
$res->_error("load","No filename.") && return 0 unless defined $filnam; |
422
|
|
|
|
|
|
|
|
423
|
0
|
0
|
0
|
|
|
0
|
$res->_error("load", $!) && return 0 unless open(_RESFILE, $filnam); |
424
|
0
|
|
|
|
|
0
|
$res->{Safe}->share('$expr'); |
425
|
0
|
|
0
|
|
|
0
|
$sep = $res->{Res}->{'resources.separator'}->[$Value] || ':'; |
426
|
0
|
|
|
|
|
0
|
$app = $res->{Res}->{'resources.appclass'}->[$Value]; |
427
|
0
|
|
|
|
|
0
|
$mrgcls = $res->{Res}->{'resources.mergeclass'}->[$Value]; |
428
|
|
|
|
|
|
|
|
429
|
0
|
|
|
|
|
0
|
$prevlin = ''; |
430
|
0
|
|
|
|
|
0
|
while ($lin = <_RESFILE>) { |
431
|
0
|
|
|
|
|
0
|
chomp $lin; |
432
|
0
|
|
|
|
|
0
|
$comlin = $prevlin . $lin; |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
# Hash chars in quoted strings are not comments. |
435
|
0
|
|
|
|
|
0
|
1 while $comlin =~ s/^(.*\".*)\#(.*\".*)$/$1__RES_NO_COMM__$2/ ; |
436
|
0
|
|
|
|
|
0
|
1 while $comlin =~ s/^(.*\'.*)\#(.*\'.*)$/$1__RES_NO_COMM__$2/ ; |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
# Join split lines |
439
|
0
|
0
|
0
|
|
|
0
|
if ($comlin !~ /\#/ && $comlin =~ /\\$/) { |
440
|
0
|
|
|
|
|
0
|
$prevlin .= $comlin; |
441
|
0
|
|
|
|
|
0
|
next; |
442
|
|
|
|
|
|
|
} else { |
443
|
0
|
|
|
|
|
0
|
$prevlin = ''; |
444
|
|
|
|
|
|
|
} |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
# Now get rid of comments |
447
|
0
|
|
|
|
|
0
|
@line = split(/\#/, $comlin); |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
# Skip empty lines, get def and put hashes back in place |
450
|
0
|
|
0
|
|
|
0
|
$def = $line[0] || next; |
451
|
0
|
|
|
|
|
0
|
$def =~ s/__RES_NO_COMM__/\#/go; |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
# Split def on first separator |
454
|
0
|
|
|
|
|
0
|
($name, @allvals)=split(/$sep/, $def); |
455
|
0
|
|
|
|
|
0
|
$value=join($sep, @allvals); |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
# Get rid of trailing/leading whitespaces. |
458
|
0
|
|
|
|
|
0
|
$name =~ s/^\s+|\s+$//g; |
459
|
0
|
|
|
|
|
0
|
$value =~ s/^\s+|\s+$//g; |
460
|
|
|
|
|
|
|
|
461
|
0
|
0
|
|
|
|
0
|
next unless $name; |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
# Application class check |
464
|
0
|
0
|
0
|
|
|
0
|
next if ($mrgcls && $name !~ /^\*|^$app\./); |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
# Name may not |
467
|
|
|
|
|
|
|
# - contain whitespaces or |
468
|
|
|
|
|
|
|
# - terminate with wildcard or dot, |
469
|
|
|
|
|
|
|
# - start with dot |
470
|
|
|
|
|
|
|
# - contain ._ sequences (which are for hidden resources only) |
471
|
0
|
0
|
0
|
|
|
0
|
$res->_error("load", "$filnam: line $.: bad resource name: $name") |
472
|
|
|
|
|
|
|
&& return 0 if $name =~ /\s+|^\.|\.$|\*$|\._/o; |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
# Parse value: |
475
|
|
|
|
|
|
|
# If the whole thing is quoted, take it as it is: |
476
|
0
|
0
|
|
|
|
0
|
if ($value =~ s/^\'(.*)\'$|^\"(.*)\"$/$1/ ) { |
|
|
0
|
|
|
|
|
|
477
|
0
|
|
|
|
|
0
|
$allres{$name} = [ $value ]; |
478
|
|
|
|
|
|
|
} elsif ($value =~ /^[\[\{].*/) { |
479
|
|
|
|
|
|
|
# Do anon hashes and arrays |
480
|
0
|
|
|
|
|
0
|
$evaled = $res->{Safe}->reval('$expr=' . $value); |
481
|
0
|
0
|
|
|
|
0
|
if ($@) { |
482
|
0
|
|
|
|
|
0
|
$res->_error("load", |
483
|
|
|
|
|
|
|
"$filnam: error in line $. ($@) - $name : $value"); |
484
|
0
|
|
|
|
|
0
|
return 0; |
485
|
|
|
|
|
|
|
} else { |
486
|
0
|
|
|
|
|
0
|
$allres{$name} = [ $evaled ]; |
487
|
|
|
|
|
|
|
} |
488
|
|
|
|
|
|
|
} else { |
489
|
|
|
|
|
|
|
# Swallow it anyway, babe ;-) |
490
|
0
|
|
|
|
|
0
|
$allres{$name} = [ $value ]; |
491
|
|
|
|
|
|
|
} |
492
|
|
|
|
|
|
|
} |
493
|
0
|
|
|
|
|
0
|
close(_RESFILE); |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
# Safe loading checks |
496
|
0
|
0
|
|
|
|
0
|
if ($nonew) { |
497
|
0
|
|
|
|
|
0
|
my $resnames = join(' ', sort($res->names())); |
498
|
|
|
|
|
|
|
|
499
|
0
|
|
|
|
|
0
|
foreach $name (keys(%allres)) { |
500
|
0
|
0
|
|
|
|
0
|
unless ($resnames =~ /$name/) { |
501
|
0
|
|
|
|
|
0
|
$res->_error("load", "unknown resource $name in $filnam"); |
502
|
0
|
|
|
|
|
0
|
return(0); |
503
|
|
|
|
|
|
|
} |
504
|
|
|
|
|
|
|
} |
505
|
|
|
|
|
|
|
} |
506
|
|
|
|
|
|
|
|
507
|
0
|
|
|
|
|
0
|
$res->{Load}=1; |
508
|
0
|
|
|
|
|
0
|
while (($name, $value) = each(%allres)) { |
509
|
0
|
0
|
|
|
|
0
|
$res->put($name, @{$value}) || do { |
|
0
|
|
|
|
|
0
|
|
510
|
0
|
|
|
|
|
0
|
_error("load", "failed put $name : $value"); |
511
|
0
|
|
|
|
|
0
|
$res->{Load}=0; |
512
|
0
|
|
|
|
|
0
|
return 0; |
513
|
|
|
|
|
|
|
}; |
514
|
|
|
|
|
|
|
} |
515
|
0
|
|
|
|
|
0
|
$res->{Load}=0; |
516
|
|
|
|
|
|
|
|
517
|
0
|
|
|
|
|
0
|
1; |
518
|
|
|
|
|
|
|
} |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
=item B |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
Merges the %Resources hash of the package defining $class with |
524
|
|
|
|
|
|
|
those of its @memberclasses, writing the result in the resource database. |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
The merging reflects the resource inheritance explained above: the %Resources |
527
|
|
|
|
|
|
|
of all base classes and member classes of $class are inherited along the |
528
|
|
|
|
|
|
|
way. Eventually all these resources have their names prefixed with the name of |
529
|
|
|
|
|
|
|
the package in which $class is defined (lowercased and stripped of all |
530
|
|
|
|
|
|
|
foo::bar:: prefixes), and with the application class as well. |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
In the above example, the defaults of a Car object will be renamed, after |
533
|
|
|
|
|
|
|
merging as: |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
car.brand, car.noise, ..., |
536
|
|
|
|
|
|
|
car.tire.flat |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
and for a Civic object, where Civic is a (i.e. ISA) Car, they will be |
539
|
|
|
|
|
|
|
translated instead as |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
civic.brand, civic.noise, ..., |
542
|
|
|
|
|
|
|
civic.tire.flat |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
Finally, the application name ($0, a.k.a $PROGRAM_NAME in English) is |
545
|
|
|
|
|
|
|
prepended to all resource names, so, if the above Civic package is used |
546
|
|
|
|
|
|
|
by a Perl script named "ilove.pl", the final names after merging are |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
ilove.civic.brand, ilove.civic.noise, ..., |
549
|
|
|
|
|
|
|
ilove.civic.tire.flat |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
The new names are the ones to use when accessing these resources by name. |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
The resource values are inherited accoring to the rules previously indicated, |
554
|
|
|
|
|
|
|
hence with resource files having priority over hardcoded defaults, nnd derived |
555
|
|
|
|
|
|
|
or container classes over base or member classes. |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
Returns 1 if for success, otherwise 0. |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
=cut |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
sub merge { |
562
|
3
|
|
|
3
|
1
|
189
|
my ($res, $class, @members) = @_; |
563
|
3
|
|
|
|
|
4
|
my ($app, @tops, $top, $topclass, $toppack, $mem); |
564
|
0
|
|
|
|
|
0
|
my ($level, $caller, @ignore); |
565
|
0
|
|
|
|
|
0
|
my ($isaname, $isa, $base); |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
# Add to inverted indexes. |
568
|
|
|
|
|
|
|
# Members |
569
|
3
|
|
|
|
|
7
|
for $mem (@members) { |
570
|
1
|
50
|
|
|
|
8
|
$res->{Owned}->{$mem} = '' unless $res->{Owned}->{$mem}; |
571
|
1
|
|
|
|
|
4
|
$res->{Owned}->{$mem} .= "$class "; |
572
|
|
|
|
|
|
|
} |
573
|
|
|
|
|
|
|
# Base classes |
574
|
3
|
|
|
|
|
3
|
do { |
575
|
1
|
|
|
1
|
|
8
|
no strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
4967
|
|
576
|
3
|
|
|
|
|
4
|
$isaname = "$class\::ISA"; |
577
|
3
|
|
|
|
|
9
|
$isa = \@$isaname; |
578
|
|
|
|
|
|
|
}; |
579
|
3
|
100
|
|
|
|
3
|
if (defined(@{$isa})) { |
|
3
|
|
|
|
|
8
|
|
580
|
2
|
|
|
|
|
3
|
for $base (@{$isa}) { |
|
2
|
|
|
|
|
7
|
|
581
|
2
|
100
|
|
|
|
8
|
$res->{Isa}->{$base} = '' unless $res->{Isa}->{$base}; |
582
|
2
|
|
|
|
|
7
|
$res->{Isa}->{$base} .= "$class "; |
583
|
|
|
|
|
|
|
} |
584
|
|
|
|
|
|
|
} |
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
# Walk up the caller frames. |
587
|
|
|
|
|
|
|
# If one of the callers is in the Isa list for $class, then $class |
588
|
|
|
|
|
|
|
# defaults have been already merged, so we can bail out. |
589
|
|
|
|
|
|
|
# Otherwise make up class name for $object, taking into account the Owned |
590
|
|
|
|
|
|
|
# list. |
591
|
3
|
50
|
33
|
|
|
22
|
if ($class ne "main" |
592
|
|
|
|
|
|
|
&& $class ne lc($res->{Res}->{'resources.appclass'}->[$Value])) { |
593
|
3
|
|
|
|
|
4
|
$level=0; |
594
|
3
|
|
|
|
|
3
|
$toppack = $class; |
595
|
3
|
|
|
|
|
31
|
while (($caller, @ignore)=caller(++$level)) { |
596
|
4
|
100
|
|
|
|
15
|
last if $caller eq "main"; |
597
|
2
|
100
|
66
|
|
|
32
|
if (exists($res->{Isa}->{$class}) |
598
|
|
|
|
|
|
|
&& $res->{Isa}->{$class} =~ /\b$caller\b/) { |
599
|
1
|
|
|
|
|
5
|
return 1; |
600
|
|
|
|
|
|
|
} |
601
|
|
|
|
|
|
|
|
602
|
1
|
50
|
33
|
|
|
26
|
if (exists($res->{Owned}->{$toppack}) |
603
|
|
|
|
|
|
|
&& $res->{Owned}->{$toppack} =~ /\b$caller\b/) { |
604
|
1
|
|
|
|
|
2
|
$toppack = $caller; |
605
|
1
|
|
|
|
|
7
|
($topclass = lc($toppack)) =~ s/(.*::)?(\w+)/$2/; |
606
|
1
|
|
|
|
|
15
|
unshift(@tops, $topclass); |
607
|
|
|
|
|
|
|
} |
608
|
|
|
|
|
|
|
} |
609
|
2
|
50
|
|
|
|
38
|
shift(@tops) if $tops[0] =~ /main/o; # get rid of main |
610
|
|
|
|
|
|
|
} |
611
|
2
|
50
|
|
|
|
8
|
unshift(@tops, lc($res->{Res}->{'resources.appclass'}->[$Value])) |
612
|
|
|
|
|
|
|
if $res->valbyname('resources.mergeclass'); |
613
|
2
|
|
|
|
|
5
|
$app = join('.', @tops); |
614
|
2
|
50
|
|
|
|
5
|
$app .= '.' if $app; |
615
|
2
|
|
|
|
|
14
|
($top = lc($class)) =~ s/(.*::)?(\w+)/$2/; |
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
# Now recursive merge. |
618
|
2
|
|
|
|
|
4
|
$res->{Merge} = 1; |
619
|
2
|
|
|
|
|
3
|
unshift(@members, $class); |
620
|
2
|
|
|
|
|
4
|
for $mem (@members) { |
621
|
3
|
|
|
|
|
10
|
$res->_merge_pack($app, $top, $mem); |
622
|
|
|
|
|
|
|
} |
623
|
2
|
|
|
|
|
3
|
$res->{Merge} = 0; |
624
|
|
|
|
|
|
|
|
625
|
2
|
|
|
|
|
8
|
1; |
626
|
|
|
|
|
|
|
} |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
=head2 5.2. Looking up resources |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
The values and documentation strings stored in a Resource object can be |
631
|
|
|
|
|
|
|
accessed by specifying their names in three basic ways: |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
=item directly ("byname" methods) |
634
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
As in "my.nice.cosy.couch" . |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
=item by a pattern ("bypattern" methods) |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
As in "m??nice.*" . |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
=item hierarchically ("byclass" methods) |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
If class Nice B Cosy, then asking for "couch" in package Cosy gets you |
644
|
|
|
|
|
|
|
the value/doc of "my.couch". If, instead, Nice B Cosy member, that the |
645
|
|
|
|
|
|
|
method gets you "my.nice.cosy.couch". This behaviour is essential for the |
646
|
|
|
|
|
|
|
proper initialization of subclassed and member packages, as explained in |
647
|
|
|
|
|
|
|
detail below. |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
=back |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
It is also possible to retrieve the whole content of a resource database |
652
|
|
|
|
|
|
|
("names" and "each" methods) |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
Note that all the resource lookup methods return named (non "wildcarded") |
655
|
|
|
|
|
|
|
resources only. Wildcarded resources (i.e. those specified in resource files, |
656
|
|
|
|
|
|
|
and whose names contain one or more '*') are best thought as placeholders, to |
657
|
|
|
|
|
|
|
be used when the value of an actual named resource is set. |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
For example, a line in a resource file like |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
*background : yellow |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
fixes to yellow the color of all resources whose name ends with "background". |
664
|
|
|
|
|
|
|
However, your actual packages will never worry about unless they really need |
665
|
|
|
|
|
|
|
a background. In this case they either have a "background" resource in |
666
|
|
|
|
|
|
|
their defaults hash, or subclass a package that has one. |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
=over 8 |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
=item B |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
Retrieves the value of a named resource from a Resource database. The $name |
673
|
|
|
|
|
|
|
argument is a string containing a resource name with no wildcards. |
674
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
Returns the undefined value if no such resource is defined. |
676
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
=cut |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
sub valbyname { |
680
|
30
|
|
|
30
|
1
|
52
|
my $res = shift; |
681
|
30
|
|
|
|
|
36
|
my ($name) = @_; |
682
|
30
|
|
|
|
|
26
|
my $fullname; |
683
|
|
|
|
|
|
|
|
684
|
30
|
|
|
|
|
65
|
$fullname = $res->{Res}->{'resources.appclass'}->[$Value] . ".$name"; |
685
|
|
|
|
|
|
|
|
686
|
30
|
50
|
|
|
|
92
|
if (exists($res->{Res}->{$fullname})) { |
|
|
50
|
|
|
|
|
|
687
|
0
|
|
|
|
|
0
|
return $res->{Res}->{$fullname}->[$Value]; |
688
|
|
|
|
|
|
|
} elsif (exists($res->{Res}->{$name})) { |
689
|
30
|
|
|
|
|
89
|
return $res->{Res}->{$name}->[$Value]; |
690
|
|
|
|
|
|
|
} else { |
691
|
0
|
|
|
|
|
0
|
return undef; |
692
|
|
|
|
|
|
|
} |
693
|
|
|
|
|
|
|
} |
694
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
=item B |
696
|
|
|
|
|
|
|
|
697
|
|
|
|
|
|
|
Retrieves the documentation string of a named resource from a Resource |
698
|
|
|
|
|
|
|
database. The $name argument is a string containing a resource name with no |
699
|
|
|
|
|
|
|
wildcards. |
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
Returns the undefined value if no such resource is defined. |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
=cut |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
sub docbyname { |
706
|
22
|
|
|
22
|
1
|
26
|
my $res = shift; |
707
|
22
|
|
|
|
|
23
|
my ($name) = @_; |
708
|
22
|
|
|
|
|
19
|
my $fullname; |
709
|
|
|
|
|
|
|
|
710
|
22
|
|
|
|
|
42
|
$fullname = $res->{Res}->{'resources.appclass'}->[$Value] . ".$name"; |
711
|
|
|
|
|
|
|
|
712
|
22
|
50
|
|
|
|
65
|
if (exists($res->{Res}->{$fullname})) { |
|
|
50
|
|
|
|
|
|
713
|
0
|
|
|
|
|
0
|
return $res->{Res}->{$fullname}->[$Doc]; |
714
|
|
|
|
|
|
|
} elsif (exists($res->{Res}->{$name})) { |
715
|
22
|
|
|
|
|
47
|
$res->{Res}->{$name}->[$Doc]; |
716
|
|
|
|
|
|
|
} else { |
717
|
0
|
|
|
|
|
0
|
return undef; |
718
|
|
|
|
|
|
|
} |
719
|
|
|
|
|
|
|
} |
720
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
=item B |
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
Retrieves the full names, values and documentation strings of all the named |
725
|
|
|
|
|
|
|
(non wildcarded) resources whose name matches the given $pattern. The pattern |
726
|
|
|
|
|
|
|
itself is string containing a Perl regular expression, I enclosed in |
727
|
|
|
|
|
|
|
slashes. |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
Returns a new Resource object containing only the matching resources, or |
730
|
|
|
|
|
|
|
the undefined value if no matches are found. |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
=cut |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
sub bypattern { |
735
|
0
|
|
|
0
|
1
|
0
|
my $res = shift; |
736
|
0
|
|
|
|
|
0
|
my ($pattern) = @_; |
737
|
0
|
|
|
|
|
0
|
my ($name, $valdoc); |
738
|
0
|
|
0
|
|
|
0
|
my $newres = new Resources() || return undef; |
739
|
|
|
|
|
|
|
|
740
|
0
|
|
|
|
|
0
|
while (($name, $valdoc) = $res->each()) { |
741
|
0
|
0
|
|
|
|
0
|
$newres->put($name, @{$valdoc}) if $name =~ /$pattern/ ; |
|
0
|
|
|
|
|
0
|
|
742
|
|
|
|
|
|
|
} |
743
|
|
|
|
|
|
|
|
744
|
0
|
0
|
|
|
|
0
|
return $newres if %{$newres->{Res}}; |
|
0
|
|
|
|
|
0
|
|
745
|
0
|
|
|
|
|
0
|
undef; |
746
|
|
|
|
|
|
|
} |
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
=item B |
749
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
Retrieves the full names and values of all named (non wildcarded) resources |
751
|
|
|
|
|
|
|
whose name matches the given pattern. |
752
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
Returns a new Resource object containing only names and values of the matching |
754
|
|
|
|
|
|
|
resources (i.e. with undefined doc strings), or the undefined value if no |
755
|
|
|
|
|
|
|
matches are found. |
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
=cut |
758
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
sub valbypattern { |
760
|
0
|
|
|
0
|
1
|
0
|
my $res = shift; |
761
|
0
|
|
|
|
|
0
|
my ($pattern) = @_; |
762
|
0
|
|
|
|
|
0
|
my ($newres, $i); |
763
|
|
|
|
|
|
|
|
764
|
0
|
|
0
|
|
|
0
|
$newres = $res->bypattern($pattern) || return undef; |
765
|
0
|
|
|
|
|
0
|
for $i ($newres->names()) { |
766
|
0
|
|
|
|
|
0
|
undef($newres->{Res}->{$i}->[$Doc]); |
767
|
|
|
|
|
|
|
} |
768
|
|
|
|
|
|
|
|
769
|
0
|
|
|
|
|
0
|
$newres; |
770
|
|
|
|
|
|
|
} |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
=item B |
773
|
|
|
|
|
|
|
|
774
|
|
|
|
|
|
|
Retrieves the full names and documentation strings of all named (non |
775
|
|
|
|
|
|
|
wildcarded) resources whose name matches the given pattern. |
776
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
Returns a new Resource object containing only names and docs of the matching |
778
|
|
|
|
|
|
|
resources (i.e. with undefined resource values), or the undefined value if no |
779
|
|
|
|
|
|
|
matches are found. |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
=cut |
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
sub docbypattern { |
784
|
0
|
|
|
0
|
1
|
0
|
my $res = shift; |
785
|
0
|
|
|
|
|
0
|
my ($pattern) = @_; |
786
|
0
|
|
|
|
|
0
|
my ($newres, $i); |
787
|
|
|
|
|
|
|
|
788
|
0
|
|
0
|
|
|
0
|
$newres = $res->bypattern($pattern) || return undef; |
789
|
0
|
|
|
|
|
0
|
for $i ($newres->names()) { |
790
|
0
|
|
|
|
|
0
|
undef($newres->{Res}->{$i}->[$Value]); |
791
|
|
|
|
|
|
|
} |
792
|
|
|
|
|
|
|
|
793
|
0
|
|
|
|
|
0
|
$newres; |
794
|
|
|
|
|
|
|
} |
795
|
|
|
|
|
|
|
|
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
=item B |
799
|
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
To properly initialize the attributes of a package via resources we need a |
801
|
|
|
|
|
|
|
way to know whether the package defaults (contained in its %Resources hash) |
802
|
|
|
|
|
|
|
have been overridden by a derived or container class. For example, to set |
803
|
|
|
|
|
|
|
a field like $dog->{Weight} in a Dog object, we must know if this $dog |
804
|
|
|
|
|
|
|
is being subclassed by Poodle or Bulldog, or if it is a member of Family, |
805
|
|
|
|
|
|
|
since all these other classes might override whatever "weight" default is |
806
|
|
|
|
|
|
|
defined in the %Resources hash of Dog.pm. |
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
This information must of course be gathered at runtime: if you tried to name |
809
|
|
|
|
|
|
|
explicitly a resource like "family.dog.weight" inside Dog.pm all the OOP |
810
|
|
|
|
|
|
|
crowd would start booing at you. Your object would not be reusable anymore, |
811
|
|
|
|
|
|
|
being explicitly tied to a particular container class. After all we do use |
812
|
|
|
|
|
|
|
objects mainly because we want to easily reuse code... |
813
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
Enter the "by class" resource lookup methods: B, B and |
815
|
|
|
|
|
|
|
B. |
816
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
Given an $object and a resource $suffix (i.e. a resource name stripped of all |
818
|
|
|
|
|
|
|
container and derived class prefixes), the B method returns a 3 |
819
|
|
|
|
|
|
|
element list containing the name/value/doc of that resource in $object. The |
820
|
|
|
|
|
|
|
returned name will be fully qualified with all derived/container classes, up |
821
|
|
|
|
|
|
|
to the application class. |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
For example, in a program called "bark", the statements |
824
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
$dog = new Dog ($res); # $res is a Resources database |
826
|
|
|
|
|
|
|
($name,$value,$doc) = $res->byclass($dog, "weight"); |
827
|
|
|
|
|
|
|
|
828
|
|
|
|
|
|
|
will set $name, $value and $doc equal to those of the "bark.poodle.weight" |
829
|
|
|
|
|
|
|
resource, if this Dog is subclassed by Poodle, and to those of |
830
|
|
|
|
|
|
|
"bark.family.dog.weight", if it is a member of Family instead. |
831
|
|
|
|
|
|
|
|
832
|
|
|
|
|
|
|
The passed name suffix must not contain wildcards nor dots. |
833
|
|
|
|
|
|
|
|
834
|
|
|
|
|
|
|
Be careful not to confuse the "byclass" with the "byname" and "bypattern" |
835
|
|
|
|
|
|
|
retrieval methods: they are used for two radically different goals. See the |
836
|
|
|
|
|
|
|
EXAMPLES section for more. |
837
|
|
|
|
|
|
|
|
838
|
|
|
|
|
|
|
Returns the empty list if no resources are found for the given suffix, |
839
|
|
|
|
|
|
|
or if the suffix is incorrect. |
840
|
|
|
|
|
|
|
|
841
|
|
|
|
|
|
|
=cut |
842
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
sub byclass { |
844
|
4
|
|
|
4
|
1
|
12
|
my ($res, $object, $suffix) = @_; |
845
|
4
|
|
|
|
|
5
|
my ($class, $name, $value, $doc); |
846
|
0
|
|
|
|
|
0
|
my ($level, $topclass, $toppack, @ignore, @tops); |
847
|
|
|
|
|
|
|
|
848
|
4
|
50
|
|
|
|
9
|
($class = ref($object)) || do { |
849
|
0
|
|
|
|
|
0
|
$res->_error("byclass", "must pass an object reference"); |
850
|
0
|
|
|
|
|
0
|
return (); |
851
|
|
|
|
|
|
|
}; |
852
|
|
|
|
|
|
|
# No patterns or leading/trailing dots |
853
|
4
|
50
|
|
|
|
15
|
$suffix =~ /\.|\*/ && do { |
854
|
0
|
|
|
|
|
0
|
$res->_error("byclass", "bad suffix $suffix"); |
855
|
0
|
|
|
|
|
0
|
return (); |
856
|
|
|
|
|
|
|
}; |
857
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
# Walk up the caller frames. |
859
|
|
|
|
|
|
|
# If one of the callers is in the Isa list for $class, then $class |
860
|
|
|
|
|
|
|
# defaults have been already merged, so we can bail out. |
861
|
|
|
|
|
|
|
# Otherwise make up class name for $object, taking into account the Owned |
862
|
|
|
|
|
|
|
# list. |
863
|
4
|
|
|
|
|
4
|
$level=0; |
864
|
4
|
|
|
|
|
18
|
($name = lc($class)) =~ s/(.*::)?(\w+)/$2/; |
865
|
4
|
|
|
|
|
9
|
unshift(@tops, $name); |
866
|
4
|
|
|
|
|
30
|
while (($toppack, @ignore)=caller(++$level)) { |
867
|
10
|
100
|
|
|
|
29
|
last if $toppack eq "main"; |
868
|
|
|
|
|
|
|
|
869
|
6
|
|
|
|
|
27
|
($topclass = lc($toppack)) =~ s/(.*::)?(\w+)/$2/; |
870
|
|
|
|
|
|
|
|
871
|
6
|
100
|
100
|
|
|
54
|
if (exists($res->{Isa}->{$class}) |
872
|
|
|
|
|
|
|
&& $res->{Isa}->{$class} =~ /\b$toppack\b/) { |
873
|
2
|
|
|
|
|
2
|
shift(@tops); |
874
|
2
|
|
|
|
|
4
|
unshift(@tops, $topclass); |
875
|
2
|
|
|
|
|
3
|
$class = $toppack; |
876
|
2
|
|
|
|
|
18
|
next; |
877
|
|
|
|
|
|
|
} |
878
|
|
|
|
|
|
|
|
879
|
4
|
100
|
100
|
|
|
70
|
if (exists($res->{Owned}->{$class}) |
880
|
|
|
|
|
|
|
&& $res->{Owned}->{$class} =~ /\b$toppack\b/) { |
881
|
2
|
|
|
|
|
4
|
unshift(@tops, $topclass); |
882
|
2
|
|
|
|
|
18
|
$class = $toppack; |
883
|
|
|
|
|
|
|
} |
884
|
|
|
|
|
|
|
} |
885
|
|
|
|
|
|
|
|
886
|
4
|
|
|
|
|
10
|
unshift(@tops, lc($res->{Res}->{'resources.appclass'}->[$Value])); |
887
|
|
|
|
|
|
|
|
888
|
4
|
|
|
|
|
13
|
$name = join('.', @tops) . ".$suffix"; |
889
|
|
|
|
|
|
|
|
890
|
4
|
50
|
|
|
|
11
|
return () unless exists($res->{Res}->{$name}); |
891
|
|
|
|
|
|
|
|
892
|
4
|
|
|
|
|
4
|
($value, $doc) = @{$res->{Res}->{$name}}; |
|
4
|
|
|
|
|
11
|
|
893
|
|
|
|
|
|
|
|
894
|
4
|
|
|
|
|
20
|
return ($name, $value, $doc); |
895
|
|
|
|
|
|
|
} |
896
|
|
|
|
|
|
|
|
897
|
|
|
|
|
|
|
|
898
|
|
|
|
|
|
|
=item B |
899
|
|
|
|
|
|
|
|
900
|
|
|
|
|
|
|
As the B method above, but returns just the resource name (i.e. the |
901
|
|
|
|
|
|
|
suffix with all the subclasses prepended). |
902
|
|
|
|
|
|
|
|
903
|
|
|
|
|
|
|
=cut |
904
|
|
|
|
|
|
|
|
905
|
|
|
|
|
|
|
sub namebyclass { |
906
|
0
|
|
|
0
|
1
|
0
|
my ($res, $obj, $suffix) = @_; |
907
|
0
|
|
|
|
|
0
|
my @nvd = $res->byclass($obj, $suffix); |
908
|
|
|
|
|
|
|
|
909
|
0
|
|
|
|
|
0
|
$nvd[0]; |
910
|
|
|
|
|
|
|
} |
911
|
|
|
|
|
|
|
|
912
|
|
|
|
|
|
|
=item B |
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
As the B method above, but returns just the resource value. |
915
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
=cut |
917
|
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
sub valbyclass { |
919
|
2
|
|
|
2
|
1
|
11
|
my ($res, $obj, $suffix) = @_; |
920
|
2
|
|
|
|
|
5
|
my @nvd = $res->byclass($obj, $suffix); |
921
|
|
|
|
|
|
|
|
922
|
2
|
|
|
|
|
18
|
$nvd[1]; |
923
|
|
|
|
|
|
|
} |
924
|
|
|
|
|
|
|
|
925
|
|
|
|
|
|
|
|
926
|
|
|
|
|
|
|
=item B |
927
|
|
|
|
|
|
|
|
928
|
|
|
|
|
|
|
As the B method above, but returns just the resource documentation. |
929
|
|
|
|
|
|
|
|
930
|
|
|
|
|
|
|
=cut |
931
|
|
|
|
|
|
|
|
932
|
|
|
|
|
|
|
sub docbyclass { |
933
|
0
|
|
|
0
|
1
|
0
|
my ($res, $suffix) = @_; |
934
|
0
|
|
|
|
|
0
|
my @nvd = $res->byclass($suffix); |
935
|
|
|
|
|
|
|
|
936
|
0
|
|
|
|
|
0
|
$nvd[2]; |
937
|
|
|
|
|
|
|
} |
938
|
|
|
|
|
|
|
|
939
|
|
|
|
|
|
|
|
940
|
|
|
|
|
|
|
|
941
|
|
|
|
|
|
|
=item B |
942
|
|
|
|
|
|
|
|
943
|
|
|
|
|
|
|
Returns the next name/[value,doc] pair of the named (non wildcarded) resources |
944
|
|
|
|
|
|
|
in a resource database, exactly as the B Perl routine. |
945
|
|
|
|
|
|
|
|
946
|
|
|
|
|
|
|
=cut |
947
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
sub each { |
949
|
0
|
|
|
0
|
1
|
0
|
my $res=shift; |
950
|
0
|
|
|
|
|
0
|
return each(%{$res->{Res}}); |
|
0
|
|
|
|
|
0
|
|
951
|
|
|
|
|
|
|
} |
952
|
|
|
|
|
|
|
|
953
|
|
|
|
|
|
|
|
954
|
|
|
|
|
|
|
=item B |
955
|
|
|
|
|
|
|
|
956
|
|
|
|
|
|
|
Returns a list of the names of all named (non-wildcarded) resources in a |
957
|
|
|
|
|
|
|
resource database, or undef if the databasee is empty. |
958
|
|
|
|
|
|
|
|
959
|
|
|
|
|
|
|
=cut |
960
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
sub names { |
962
|
1
|
|
|
1
|
1
|
2
|
my $res=shift; |
963
|
1
|
|
|
|
|
2
|
return keys(%{$res->{Res}}); |
|
1
|
|
|
|
|
16
|
|
964
|
|
|
|
|
|
|
} |
965
|
|
|
|
|
|
|
|
966
|
|
|
|
|
|
|
=head2 5.3. Assigning and removing Resources |
967
|
|
|
|
|
|
|
|
968
|
|
|
|
|
|
|
=item B |
969
|
|
|
|
|
|
|
|
970
|
|
|
|
|
|
|
Writes the value and doc of a resource in the database. It is possible to |
971
|
|
|
|
|
|
|
specify an empty documentation string, but name and value must be defined. |
972
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
Wildcards ('*' characters) are allowed in the $name, but the $doc is ignored |
974
|
|
|
|
|
|
|
in this case (documentation is intended for single resources, not for sets |
975
|
|
|
|
|
|
|
of them). |
976
|
|
|
|
|
|
|
|
977
|
|
|
|
|
|
|
The value is written unchanged unless the resource database already |
978
|
|
|
|
|
|
|
contains a wildcarded resource whose name includes $name (foo*bar |
979
|
|
|
|
|
|
|
includes foo.bar, foo.baz.bar, etc.). In this case the value of the |
980
|
|
|
|
|
|
|
wildcarded resource overrides the passed $value. |
981
|
|
|
|
|
|
|
|
982
|
|
|
|
|
|
|
Returns 1 if ok, 0 if error. |
983
|
|
|
|
|
|
|
|
984
|
|
|
|
|
|
|
=cut |
985
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
# Resource locking |
987
|
|
|
|
|
|
|
# Some conditions may affect if and how a resource gets put inthe database. |
988
|
|
|
|
|
|
|
# In order to implement the value priority policy (loaded resources have |
989
|
|
|
|
|
|
|
# priority, derived and container class have priority over base and member |
990
|
|
|
|
|
|
|
# classes) use is made to the Load and Merge fields in a Resources object, |
991
|
|
|
|
|
|
|
# and of two additional fields in the resources value (indexed by the global |
992
|
|
|
|
|
|
|
# variables $Loaded and $Merged). |
993
|
|
|
|
|
|
|
# |
994
|
|
|
|
|
|
|
sub put { |
995
|
24
|
|
|
24
|
1
|
27
|
my $res=shift; |
996
|
24
|
|
|
|
|
33
|
my ($name, $value, $doc) = @_; |
997
|
24
|
|
|
|
|
25
|
my (@words); |
998
|
|
|
|
|
|
|
|
999
|
24
|
50
|
0
|
|
|
153
|
$res->_error("put", "name or value undefined") and return 0 |
|
|
|
33
|
|
|
|
|
1000
|
|
|
|
|
|
|
unless defined($name) && defined($value); |
1001
|
|
|
|
|
|
|
|
1002
|
24
|
|
|
|
|
44
|
$name = lc($name); |
1003
|
24
|
|
|
|
|
44
|
@words = split(/\s+/, $name); |
1004
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
# Name must be one word and may not terminate with wildcard or dot |
1006
|
|
|
|
|
|
|
# or start with dot. Must check here too because of defaults. |
1007
|
24
|
50
|
0
|
|
|
174
|
$res->_error("put", "bad resource name: $name") && return 0 |
|
|
|
33
|
|
|
|
|
1008
|
|
|
|
|
|
|
if scalar(@words) > 1 || $name=~/^\.|\.$|\*$/; |
1009
|
|
|
|
|
|
|
|
1010
|
|
|
|
|
|
|
|
1011
|
|
|
|
|
|
|
# Do booleans. |
1012
|
24
|
|
|
|
|
41
|
$value =~ s/^true$|^yes$/1/i; |
1013
|
24
|
|
|
|
|
27
|
$value =~ s/^false$|^no$/0/i; |
1014
|
|
|
|
|
|
|
|
1015
|
|
|
|
|
|
|
# Do wildcards (they take priority over named) |
1016
|
|
|
|
|
|
|
# Match of wildcards is done hyerarchically: |
1017
|
|
|
|
|
|
|
# *b contains a*b |
1018
|
|
|
|
|
|
|
# a*b contains a*c*b |
1019
|
|
|
|
|
|
|
# In case of conlict, newer overwrite older ones. |
1020
|
24
|
50
|
|
|
|
45
|
if ($name =~ /\*/) { |
1021
|
0
|
|
|
|
|
0
|
my ($I_have, $r, $patname, $wild); |
1022
|
|
|
|
|
|
|
|
1023
|
0
|
|
|
|
|
0
|
$I_have=0; |
1024
|
|
|
|
|
|
|
|
1025
|
|
|
|
|
|
|
# Dots must be matched literally when name is used as a pattern |
1026
|
0
|
|
|
|
|
0
|
($patname = $name) =~ s/\./\\\./go; |
1027
|
|
|
|
|
|
|
|
1028
|
|
|
|
|
|
|
# a*b => a.*b (regexp cannot start with *) |
1029
|
0
|
|
|
|
|
0
|
$patname =~ s/\*/\.\*/g; |
1030
|
|
|
|
|
|
|
|
1031
|
|
|
|
|
|
|
# First compare with known wildcarded resources. |
1032
|
0
|
|
|
|
|
0
|
foreach $wild (keys(%{$res->{Wilds}})) { |
|
0
|
|
|
|
|
0
|
|
1033
|
|
|
|
|
|
|
# Remove old wildcards if the new one contains them |
1034
|
0
|
0
|
|
|
|
0
|
($wild =~ /$patname\Z/) && delete($res->{Wilds}->{$wild}); |
1035
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
# Skip if a more general old one is found |
1037
|
0
|
0
|
|
|
|
0
|
($name =~ /$wild\Z/) && ($I_have = 1, last); |
1038
|
|
|
|
|
|
|
} |
1039
|
0
|
0
|
|
|
|
0
|
$res->{Wilds}->{$patname}=[$value, undef] unless $I_have; |
1040
|
|
|
|
|
|
|
|
1041
|
|
|
|
|
|
|
# Then update the old named ones |
1042
|
0
|
|
|
|
|
0
|
foreach $r (keys(%{$res->{Res}})) { |
|
0
|
|
|
|
|
0
|
|
1043
|
0
|
0
|
|
|
|
0
|
$res->{Res}->{$r}->[$Value] = $value if $r =~ /$patname\Z/; |
1044
|
|
|
|
|
|
|
} |
1045
|
|
|
|
|
|
|
|
1046
|
|
|
|
|
|
|
} else { |
1047
|
|
|
|
|
|
|
# Named resources. |
1048
|
|
|
|
|
|
|
# Check if it is already wildcarded: if so, use wildcard's value |
1049
|
24
|
|
|
|
|
24
|
my ($wild, $nref, $ex, $putall, $putdoc); |
1050
|
|
|
|
|
|
|
|
1051
|
24
|
|
|
|
|
23
|
foreach $wild (keys(%{$res->{Wilds}})) { |
|
24
|
|
|
|
|
63
|
|
1052
|
24
|
50
|
|
|
|
119
|
if ($name =~ /$wild\Z/) { |
1053
|
0
|
|
|
|
|
0
|
$value = $res->{Wilds}->{$wild}->[$Value]; |
1054
|
0
|
|
|
|
|
0
|
last; |
1055
|
|
|
|
|
|
|
} |
1056
|
|
|
|
|
|
|
} |
1057
|
|
|
|
|
|
|
|
1058
|
|
|
|
|
|
|
# Do merging-locking stuff and write |
1059
|
|
|
|
|
|
|
# Had to use a Karnaugh map to find the right condition... |
1060
|
24
|
|
100
|
|
|
78
|
$ex = exists($res->{Res}->{$name}) || 0; |
1061
|
24
|
100
|
|
|
|
91
|
$nref = $ex ? $res->{Res}->{$name} : undef; |
1062
|
24
|
|
100
|
|
|
221
|
$putall = $res->{Load} || !$ex || |
1063
|
|
|
|
|
|
|
!$nref->[$Loaded] && (!$res->{Merge} || !$nref->[$Merged]) || 0; |
1064
|
24
|
|
50
|
|
|
149
|
$putdoc = !$putall && $ex && (!$nref->[$Doc] && $doc) || 0; |
1065
|
|
|
|
|
|
|
|
1066
|
24
|
100
|
|
|
|
53
|
if ($putall) { |
|
|
50
|
|
|
|
|
|
1067
|
12
|
|
|
|
|
29
|
$res->{Res}->{$name}->[$Value] = $value; |
1068
|
12
|
50
|
|
|
|
22
|
$res->{Res}->{$name}->[$Doc] = $doc if $doc; |
1069
|
12
|
|
|
|
|
23
|
$res->{Res}->{$name}->[$Loaded] = $res->{Load}; |
1070
|
12
|
|
|
|
|
26
|
$res->{Res}->{$name}->[$Merged] = $res->{Merge}; |
1071
|
|
|
|
|
|
|
} elsif ($putdoc) { |
1072
|
0
|
|
|
|
|
0
|
$res->{Res}->{$name}->[$Doc] = $doc; |
1073
|
|
|
|
|
|
|
} |
1074
|
|
|
|
|
|
|
} |
1075
|
|
|
|
|
|
|
|
1076
|
24
|
|
|
|
|
69
|
1; |
1077
|
|
|
|
|
|
|
} |
1078
|
|
|
|
|
|
|
|
1079
|
|
|
|
|
|
|
|
1080
|
|
|
|
|
|
|
=item B |
1081
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
Removes the named (non wildcarded) resources from the database. |
1083
|
|
|
|
|
|
|
|
1084
|
|
|
|
|
|
|
Returns 1 if OK, 0 if the resource is not found in the database. |
1085
|
|
|
|
|
|
|
|
1086
|
|
|
|
|
|
|
=cut |
1087
|
|
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
sub removebyname { |
1089
|
0
|
|
|
0
|
1
|
0
|
my $res = shift; |
1090
|
0
|
|
|
|
|
0
|
my ($name) = @_; |
1091
|
0
|
|
|
|
|
0
|
my ($i, $cnt, $newres); |
1092
|
|
|
|
|
|
|
|
1093
|
0
|
0
|
|
|
|
0
|
return 0 unless exists $res->{Res}->{$name}; |
1094
|
0
|
|
|
|
|
0
|
delete($res->{Res}->{$name}); |
1095
|
0
|
|
|
|
|
0
|
1; |
1096
|
|
|
|
|
|
|
} |
1097
|
|
|
|
|
|
|
|
1098
|
|
|
|
|
|
|
=item B |
1099
|
|
|
|
|
|
|
|
1100
|
|
|
|
|
|
|
Removes from the database all resources (both named I wildcarded) whose |
1101
|
|
|
|
|
|
|
name mathes $pattern. An exactly matching name must be specified for |
1102
|
|
|
|
|
|
|
wildcarded resources (foo*bar to remove foo*bar). |
1103
|
|
|
|
|
|
|
|
1104
|
|
|
|
|
|
|
Returns the number of removed resources. |
1105
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
=cut |
1107
|
|
|
|
|
|
|
|
1108
|
|
|
|
|
|
|
sub removebypattern { |
1109
|
0
|
|
|
0
|
1
|
0
|
my $res = shift; |
1110
|
0
|
|
|
|
|
0
|
my ($name) = @_; |
1111
|
0
|
|
|
|
|
0
|
my ($i, $cnt, $newres); |
1112
|
|
|
|
|
|
|
|
1113
|
0
|
|
0
|
|
|
0
|
$newres=$res->bypattern($name) || return 0; |
1114
|
|
|
|
|
|
|
|
1115
|
0
|
|
|
|
|
0
|
foreach $i ($newres->names()) { |
1116
|
0
|
|
|
|
|
0
|
delete($res->{Res}->{$i}); |
1117
|
0
|
|
|
|
|
0
|
$cnt++; |
1118
|
|
|
|
|
|
|
} |
1119
|
0
|
|
|
|
|
0
|
foreach $i (keys(%{$res->{Wilds}})) { |
|
0
|
|
|
|
|
0
|
|
1120
|
0
|
0
|
|
|
|
0
|
($cnt++ , delete($res->{Wilds}->{$i})) if $i eq $name; |
1121
|
|
|
|
|
|
|
} |
1122
|
|
|
|
|
|
|
|
1123
|
0
|
|
|
|
|
0
|
$cnt; |
1124
|
|
|
|
|
|
|
} |
1125
|
|
|
|
|
|
|
|
1126
|
|
|
|
|
|
|
|
1127
|
|
|
|
|
|
|
=head2 5.6. Viewing and editing resources. |
1128
|
|
|
|
|
|
|
|
1129
|
|
|
|
|
|
|
=item B |
1130
|
|
|
|
|
|
|
|
1131
|
|
|
|
|
|
|
Outputs the current content of a Resource object by piping to a pager program. |
1132
|
|
|
|
|
|
|
|
1133
|
|
|
|
|
|
|
The environment variable $ENV{RESPAGER}, the resource "resources.pager" and |
1134
|
|
|
|
|
|
|
the environment variable $ENV{PAGER} are looked up, in this very order, to |
1135
|
|
|
|
|
|
|
find the pager program. Defaults to B if none of them is found. |
1136
|
|
|
|
|
|
|
|
1137
|
|
|
|
|
|
|
The output format is the same of a resource file, with the resource names |
1138
|
|
|
|
|
|
|
alphabetically ordered, and the resource documentation strings written |
1139
|
|
|
|
|
|
|
as comments. |
1140
|
|
|
|
|
|
|
|
1141
|
|
|
|
|
|
|
Returns 1 if ok, 0 if error. |
1142
|
|
|
|
|
|
|
|
1143
|
|
|
|
|
|
|
=cut |
1144
|
|
|
|
|
|
|
|
1145
|
|
|
|
|
|
|
sub view { |
1146
|
0
|
|
|
0
|
1
|
0
|
my $res=shift; |
1147
|
0
|
|
|
|
|
0
|
my ($name, $value, $doc, $view, $pager, $p); |
1148
|
|
|
|
|
|
|
|
1149
|
0
|
0
|
|
|
|
0
|
if ($p = $ENV{RESPAGER}) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1150
|
0
|
|
|
|
|
0
|
$pager = $p; |
1151
|
|
|
|
|
|
|
} elsif ($p = $res->valbyname("resources.pager")) { |
1152
|
0
|
|
|
|
|
0
|
$pager = $p; |
1153
|
|
|
|
|
|
|
} elsif ($p = $ENV{PAGER}) { |
1154
|
0
|
|
|
|
|
0
|
$pager = $p; |
1155
|
|
|
|
|
|
|
} else { |
1156
|
0
|
|
|
|
|
0
|
$pager='/bin/more'; |
1157
|
|
|
|
|
|
|
} |
1158
|
|
|
|
|
|
|
|
1159
|
|
|
|
|
|
|
# Make sure we don't output POD. |
1160
|
0
|
|
|
|
|
0
|
my $pod = $res->valbyname("resources.writepod"); |
1161
|
0
|
|
|
|
|
0
|
$res->put("resources.writepod", 0); |
1162
|
|
|
|
|
|
|
|
1163
|
0
|
|
|
|
|
0
|
$p = $res->write("|$pager"); |
1164
|
0
|
0
|
|
|
|
0
|
$res->_error("view", "write failed") unless $p; |
1165
|
|
|
|
|
|
|
|
1166
|
0
|
|
|
|
|
0
|
$res->put("resources.writepod", $pod); |
1167
|
|
|
|
|
|
|
|
1168
|
0
|
|
|
|
|
0
|
return $p; |
1169
|
|
|
|
|
|
|
} |
1170
|
|
|
|
|
|
|
|
1171
|
|
|
|
|
|
|
|
1172
|
|
|
|
|
|
|
=item B |
1173
|
|
|
|
|
|
|
|
1174
|
|
|
|
|
|
|
Provides dynamical resource editing of a Resource object via an external |
1175
|
|
|
|
|
|
|
editor program. Only resource names and values can be edited (anyway, what is |
1176
|
|
|
|
|
|
|
the point of editing a resource comment on the fly?). |
1177
|
|
|
|
|
|
|
|
1178
|
|
|
|
|
|
|
The environment variables $ENV{RESEDITOR} and the resource "resouces.editor", |
1179
|
|
|
|
|
|
|
are looked up, in this very order, to find the editor program. Defaults to |
1180
|
|
|
|
|
|
|
B if none is found. |
1181
|
|
|
|
|
|
|
|
1182
|
|
|
|
|
|
|
The editor buffer is initialized in the same format of a resource file, with |
1183
|
|
|
|
|
|
|
the resource names alphabetically ordered, and the resource documentation |
1184
|
|
|
|
|
|
|
strings written as comments. The temporary file specified by the |
1185
|
|
|
|
|
|
|
"resources.tmpfil" resource is used to initialize the editor, or |
1186
|
|
|
|
|
|
|
'/tmp/resedit' if that resource is undefined. |
1187
|
|
|
|
|
|
|
|
1188
|
|
|
|
|
|
|
When the editor is exited (after saving the buffer) the method attempts to |
1189
|
|
|
|
|
|
|
reload the edited resources. If an error is found the initial object is left |
1190
|
|
|
|
|
|
|
unchanged, a warning with the first offending line in the file is printed, and |
1191
|
|
|
|
|
|
|
the method returns with undef. Controlled resource loading is obtained by |
1192
|
|
|
|
|
|
|
specifying a true value for the $nonew argument (see B). |
1193
|
|
|
|
|
|
|
|
1194
|
|
|
|
|
|
|
If the loading is successful, a new (edited) resource object is returned, |
1195
|
|
|
|
|
|
|
which can be assigned to the old one for replacement. |
1196
|
|
|
|
|
|
|
|
1197
|
|
|
|
|
|
|
After a successful edit, the value of the resource "resources.updates" (which |
1198
|
|
|
|
|
|
|
is always defined to 0 whenever a new resource is created) is increased by |
1199
|
|
|
|
|
|
|
one. This is meant to notify program the and/or packages of the resource |
1200
|
|
|
|
|
|
|
change, so they can proceed accordingly if they wish. |
1201
|
|
|
|
|
|
|
|
1202
|
|
|
|
|
|
|
=cut |
1203
|
|
|
|
|
|
|
|
1204
|
|
|
|
|
|
|
sub edit { |
1205
|
1
|
|
|
1
|
1
|
13
|
my ($res, $nonew) = @_; |
1206
|
1
|
|
|
|
|
2
|
my ($newres, $editor, $p, $status, $tmpfil); |
1207
|
|
|
|
|
|
|
|
1208
|
1
|
50
|
|
|
|
6
|
if ($p = $ENV{RESEDITOR}) { |
|
|
50
|
|
|
|
|
|
1209
|
0
|
|
|
|
|
0
|
$editor = $p; |
1210
|
|
|
|
|
|
|
} elsif ($p = $res->valbyname("resources.editor")) { |
1211
|
1
|
|
|
|
|
9
|
$editor = $p; |
1212
|
|
|
|
|
|
|
} |
1213
|
|
|
|
|
|
|
|
1214
|
1
|
|
33
|
|
|
3
|
$tmpfil = ($res->valbyname("resources.tmpfil") || "/tmp/resedit$$.txt"); |
1215
|
|
|
|
|
|
|
|
1216
|
|
|
|
|
|
|
# Make sure we don't output POD. |
1217
|
1
|
|
|
|
|
3
|
my $pod = $res->valbyname("resources.writepod"); |
1218
|
1
|
|
|
|
|
3
|
$res->put("resources.writepod", 0); |
1219
|
1
|
|
|
|
|
6
|
$p = $res->write($tmpfil); |
1220
|
1
|
|
|
|
|
4
|
$res->put("resources.writepod", $pod); |
1221
|
|
|
|
|
|
|
|
1222
|
1
|
50
|
0
|
|
|
4
|
$p || ($res->_error("edit", "write failed") && return $p); |
1223
|
|
|
|
|
|
|
|
1224
|
1
|
|
|
|
|
7530
|
$status = system("$editor $tmpfil"); |
1225
|
1
|
50
|
|
|
|
160
|
return 0 if $status>>8; # Editor failed |
1226
|
|
|
|
|
|
|
|
1227
|
0
|
|
0
|
|
|
0
|
$newres = new Resources("_RES_NODEFAULTS") || undef; |
1228
|
0
|
0
|
|
|
|
0
|
$newres->load($tmpfil, $nonew) || undef($newres); |
1229
|
0
|
|
|
|
|
0
|
unlink($tmpfil); |
1230
|
|
|
|
|
|
|
|
1231
|
0
|
|
|
|
|
0
|
for $p ($newres->names()) { |
1232
|
0
|
0
|
0
|
|
|
0
|
if (exists($res->{Res}->{$p}) && defined($res->{Res}->{$p}->[$Doc])) { |
1233
|
0
|
|
|
|
|
0
|
$newres->{Res}->{$p}->[$Doc] = $res->{Res}->{$p}->[$Doc]; |
1234
|
|
|
|
|
|
|
} |
1235
|
|
|
|
|
|
|
} |
1236
|
0
|
|
|
|
|
0
|
++$newres->{Res}->{'resources.updates'}->[$Value]; |
1237
|
0
|
|
|
|
|
0
|
return $newres; |
1238
|
|
|
|
|
|
|
} |
1239
|
|
|
|
|
|
|
|
1240
|
|
|
|
|
|
|
=head2 5.5. Miscellaneous methods |
1241
|
|
|
|
|
|
|
|
1242
|
|
|
|
|
|
|
=item B |
1243
|
|
|
|
|
|
|
|
1244
|
|
|
|
|
|
|
Outputs all resources of a resource database into a resource file (overwriting |
1245
|
|
|
|
|
|
|
it). |
1246
|
|
|
|
|
|
|
|
1247
|
|
|
|
|
|
|
The resource documentation strings are normally written as comments, so the |
1248
|
|
|
|
|
|
|
file itself is immediately available for resource loading. However, if the |
1249
|
|
|
|
|
|
|
boolean resource "resources.writepod" is true, then the (non wildcarded) |
1250
|
|
|
|
|
|
|
resources are output in POD format for your documentational pleasure. |
1251
|
|
|
|
|
|
|
|
1252
|
|
|
|
|
|
|
As usual in Perl, the filename can allo be of the form "|command", in which |
1253
|
|
|
|
|
|
|
case the output is piped into "comma1nd". |
1254
|
|
|
|
|
|
|
|
1255
|
|
|
|
|
|
|
For resources whose value is a reference to an anon array or hash, it produces |
1256
|
|
|
|
|
|
|
the appropriate constant Perl contructor by reverse parsing. The parser itself |
1257
|
|
|
|
|
|
|
is available as a separate method named B<_parse> (see package source for |
1258
|
|
|
|
|
|
|
documentation). |
1259
|
|
|
|
|
|
|
|
1260
|
|
|
|
|
|
|
Returns 1 if ok, 0 if error. |
1261
|
|
|
|
|
|
|
|
1262
|
|
|
|
|
|
|
=cut |
1263
|
|
|
|
|
|
|
|
1264
|
|
|
|
|
|
|
sub write { |
1265
|
1
|
|
|
1
|
1
|
2
|
my $res = shift; |
1266
|
1
|
|
|
|
|
2
|
my ($filnam) = @_; |
1267
|
1
|
|
|
|
|
1
|
my ($name, $value, $doc, $view); |
1268
|
|
|
|
|
|
|
|
1269
|
1
|
50
|
0
|
|
|
4
|
$res->_error("write", "No filename") && return 0 unless defined $filnam; |
1270
|
1
|
50
|
|
|
|
14
|
$filnam = ">$filnam" unless $filnam =~ /^\|/; |
1271
|
1
|
50
|
0
|
|
|
189
|
($res->_error("write", $!) && return 0) unless open(RESOUT, $filnam); |
1272
|
|
|
|
|
|
|
|
1273
|
1
|
|
|
|
|
16
|
autoflush RESOUT (1); |
1274
|
|
|
|
|
|
|
|
1275
|
1
|
50
|
|
|
|
62
|
if ($res->valbyname("resources.writepod")) { |
1276
|
|
|
|
|
|
|
|
1277
|
0
|
|
|
|
|
0
|
print RESOUT "=head2 Resources\n\n=over 8\n"; |
1278
|
|
|
|
|
|
|
|
1279
|
0
|
|
|
|
|
0
|
for $name (sort($res->names())) { |
1280
|
0
|
0
|
|
|
|
0
|
next if $name =~ /\._/; # hidden |
1281
|
|
|
|
|
|
|
|
1282
|
0
|
|
|
|
|
0
|
my $val = $res->valbyname($name); |
1283
|
0
|
|
|
|
|
0
|
my @doclines=split(/ /, $res->docbyname($name)); |
1284
|
0
|
|
|
|
|
0
|
my $len=0; |
1285
|
0
|
|
|
|
|
0
|
my $lin; |
1286
|
|
|
|
|
|
|
|
1287
|
0
|
0
|
|
|
|
0
|
$val = $res->_parse($val) if ref($val); |
1288
|
0
|
|
|
|
|
0
|
print RESOUT "\n=item $name : $val\n\n"; |
1289
|
|
|
|
|
|
|
|
1290
|
0
|
|
|
|
|
0
|
while (scalar(@doclines)) { |
1291
|
0
|
|
|
|
|
0
|
$lin=''; |
1292
|
0
|
|
0
|
|
|
0
|
while (length($lin)<60 && scalar(@doclines)) { |
1293
|
0
|
|
|
|
|
0
|
$lin .= shift(@doclines) . ' '; |
1294
|
|
|
|
|
|
|
} |
1295
|
0
|
|
|
|
|
0
|
chomp $lin; |
1296
|
0
|
|
|
|
|
0
|
print RESOUT "$lin\n"; |
1297
|
|
|
|
|
|
|
} |
1298
|
|
|
|
|
|
|
} |
1299
|
|
|
|
|
|
|
|
1300
|
|
|
|
|
|
|
} else { |
1301
|
1
|
|
|
|
|
2
|
$view = "#\n# Wildcarded resources\n#\n"; |
1302
|
|
|
|
|
|
|
|
1303
|
1
|
|
|
|
|
2
|
for $name (sort(keys(%{$res->{Wilds}}))) { |
|
1
|
|
|
|
|
5
|
|
1304
|
1
|
|
|
|
|
2
|
($value, $doc) = @{$res->{Wilds}->{$name}}; |
|
1
|
|
|
|
|
3
|
|
1305
|
1
|
50
|
|
|
|
5
|
$doc = '' unless $doc; |
1306
|
1
|
|
|
|
|
5
|
$name =~ s/\\\./\./go; |
1307
|
1
|
|
|
|
|
33
|
$name =~ s/\.\*/\*/go; |
1308
|
1
|
50
|
|
|
|
5
|
$value = $res->_parse($value) if ref($value); |
1309
|
1
|
|
|
|
|
7
|
$view .= "$name : $value\__RES_COMM__$doc\n"; |
1310
|
|
|
|
|
|
|
} |
1311
|
|
|
|
|
|
|
|
1312
|
1
|
|
|
|
|
2
|
$view .= "#\n# Named resources\n#\n"; |
1313
|
|
|
|
|
|
|
|
1314
|
1
|
|
|
|
|
4
|
for $name (sort($res->names())) { |
1315
|
22
|
50
|
|
|
|
53
|
next if $name =~ /\._/o; # "hidden" resource |
1316
|
22
|
|
|
|
|
41
|
$value = $res->valbyname($name); |
1317
|
22
|
|
|
|
|
44
|
$doc = $res->docbyname($name); |
1318
|
22
|
50
|
|
|
|
41
|
$value = $res->_parse($value) if ref($value); |
1319
|
22
|
100
|
|
|
|
74
|
$view .= "$name : $value\__RES_COMM__" . ($doc ? "$doc\n" : "\n"); |
1320
|
|
|
|
|
|
|
} |
1321
|
|
|
|
|
|
|
|
1322
|
1
|
|
|
|
|
8
|
$res->_printformat(\*RESOUT, $view); |
1323
|
1
|
|
|
|
|
15
|
close(RESOUT); |
1324
|
|
|
|
|
|
|
} |
1325
|
|
|
|
|
|
|
} |
1326
|
|
|
|
|
|
|
|
1327
|
|
|
|
|
|
|
|
1328
|
|
|
|
|
|
|
# |
1329
|
|
|
|
|
|
|
# LOCAL (UNEXPORTED) METHODS |
1330
|
|
|
|
|
|
|
# |
1331
|
|
|
|
|
|
|
# |
1332
|
|
|
|
|
|
|
|
1333
|
|
|
|
|
|
|
|
1334
|
|
|
|
|
|
|
# $res->_dump -- dumps the content of res on stderr. Used for debugging. |
1335
|
|
|
|
|
|
|
# |
1336
|
|
|
|
|
|
|
sub _dump { |
1337
|
0
|
|
|
0
|
|
0
|
my $res=shift; |
1338
|
0
|
|
|
|
|
0
|
my ($name, $value, $doc, $valdoc); |
1339
|
0
|
|
|
|
|
0
|
warn "_dump: WILDCARDED RESOURCES\n"; |
1340
|
0
|
|
|
|
|
0
|
for $name (sort(keys(%{$res->{Wilds}}))) { |
|
0
|
|
|
|
|
0
|
|
1341
|
0
|
|
|
|
|
0
|
$value= $res->{Wilds}->{$name}->[$Value]; |
1342
|
0
|
|
|
|
|
0
|
$name =~ s/\.\*/\*/g; |
1343
|
0
|
|
|
|
|
0
|
$name =~ s/\\//g; |
1344
|
0
|
|
|
|
|
0
|
warn "_dump: $name : $value\n"; |
1345
|
|
|
|
|
|
|
} |
1346
|
|
|
|
|
|
|
|
1347
|
0
|
|
|
|
|
0
|
warn "_dump: NAMED RESOURCES\n"; |
1348
|
0
|
|
|
|
|
0
|
for $name (sort(keys(%{$res->{Res}}))) { |
|
0
|
|
|
|
|
0
|
|
1349
|
0
|
|
|
|
|
0
|
$valdoc= $res->{Res}->{$name}; |
1350
|
0
|
|
|
|
|
0
|
$name =~ s/\\//g; |
1351
|
0
|
|
|
|
|
0
|
$value= $valdoc->[$Value]; |
1352
|
0
|
|
|
|
|
0
|
$doc=$valdoc->[$Doc]; |
1353
|
0
|
|
0
|
|
|
0
|
warn "_dump: $name : $value #" . ($doc || '') . "\n"; |
1354
|
|
|
|
|
|
|
} |
1355
|
|
|
|
|
|
|
} |
1356
|
|
|
|
|
|
|
|
1357
|
|
|
|
|
|
|
# _parse($value) -- Returns a string containing the value of a resource $name, |
1358
|
|
|
|
|
|
|
# written in the same format as for a resource file (i.e. in |
1359
|
|
|
|
|
|
|
# Perl syntax if the value is not a scalar. |
1360
|
|
|
|
|
|
|
# Returns the string, or undef in case of errors. |
1361
|
|
|
|
|
|
|
# |
1362
|
|
|
|
|
|
|
sub _parse { |
1363
|
0
|
|
|
0
|
|
0
|
my $res=shift; |
1364
|
0
|
|
|
|
|
0
|
my ($value) = @_; |
1365
|
0
|
|
|
|
|
0
|
my ($ref); |
1366
|
|
|
|
|
|
|
|
1367
|
0
|
0
|
|
|
|
0
|
return $value unless $ref = ref($value); |
1368
|
0
|
|
|
|
|
0
|
return _parse_ref($value, $ref); |
1369
|
|
|
|
|
|
|
} |
1370
|
|
|
|
|
|
|
|
1371
|
|
|
|
|
|
|
# |
1372
|
|
|
|
|
|
|
# _parse_ref -- This does recursive parsing for hass/array references . |
1373
|
|
|
|
|
|
|
# |
1374
|
|
|
|
|
|
|
sub _parse_ref { |
1375
|
0
|
|
|
0
|
|
0
|
my ($value, $ref) =@_; |
1376
|
0
|
|
|
|
|
0
|
my $parsed=''; |
1377
|
|
|
|
|
|
|
|
1378
|
0
|
0
|
|
|
|
0
|
$ref eq 'ARRAY' && do { |
1379
|
0
|
|
|
|
|
0
|
my $element; |
1380
|
0
|
|
|
|
|
0
|
$parsed = '['; |
1381
|
0
|
|
|
|
|
0
|
for $element (@{$value}) { |
|
0
|
|
|
|
|
0
|
|
1382
|
0
|
|
|
|
|
0
|
my $refref; |
1383
|
0
|
0
|
0
|
|
|
0
|
if ($refref = ref($element)) { |
|
|
0
|
|
|
|
|
|
1384
|
0
|
|
0
|
|
|
0
|
my $parspars = _parse_ref($element, $refref) |
1385
|
|
|
|
|
|
|
|| return undef; |
1386
|
0
|
|
|
|
|
0
|
$parsed .= $parspars; |
1387
|
|
|
|
|
|
|
} elsif (_isint($element) || _isreal($element)) { |
1388
|
0
|
|
|
|
|
0
|
$parsed .= "$element, "; |
1389
|
|
|
|
|
|
|
} else { |
1390
|
0
|
|
|
|
|
0
|
$parsed .= "'$element', "; |
1391
|
|
|
|
|
|
|
} |
1392
|
|
|
|
|
|
|
} |
1393
|
0
|
|
|
|
|
0
|
$parsed =~ s/,\s$//; |
1394
|
0
|
|
|
|
|
0
|
$parsed .= ']'; |
1395
|
0
|
|
|
|
|
0
|
return $parsed; |
1396
|
|
|
|
|
|
|
}; |
1397
|
|
|
|
|
|
|
|
1398
|
0
|
0
|
|
|
|
0
|
$ref eq 'HASH' && do { |
1399
|
0
|
|
|
|
|
0
|
my ($nam, $val); |
1400
|
0
|
|
|
|
|
0
|
$parsed = '{'; |
1401
|
0
|
|
|
|
|
0
|
while (($nam, $val) = each(%{$value})) { |
|
0
|
|
|
|
|
0
|
|
1402
|
0
|
|
|
|
|
0
|
my $refref; |
1403
|
0
|
0
|
|
|
|
0
|
return undef if (ref($nam)); |
1404
|
0
|
0
|
0
|
|
|
0
|
if ($refref = ref($val)) { |
|
|
0
|
|
|
|
|
|
1405
|
0
|
|
0
|
|
|
0
|
my $parspars = _parse_ref($val, $refref) |
1406
|
|
|
|
|
|
|
|| return undef; |
1407
|
0
|
|
|
|
|
0
|
$parsed .= "'$nam' => $parspars, "; |
1408
|
|
|
|
|
|
|
} elsif (_isint($val) || _isreal($val)) { |
1409
|
0
|
|
|
|
|
0
|
$parsed .= "'$nam' => $val, "; |
1410
|
|
|
|
|
|
|
} else { |
1411
|
0
|
|
|
|
|
0
|
$parsed .= "'$nam' => '$val', "; |
1412
|
|
|
|
|
|
|
} |
1413
|
|
|
|
|
|
|
} |
1414
|
0
|
|
|
|
|
0
|
$parsed =~ s/,\s$//; |
1415
|
0
|
|
|
|
|
0
|
$parsed .= '}'; |
1416
|
0
|
|
|
|
|
0
|
return $parsed; |
1417
|
|
|
|
|
|
|
}; |
1418
|
|
|
|
|
|
|
|
1419
|
0
|
|
|
|
|
0
|
return undef; # We do only arrays and hashes |
1420
|
|
|
|
|
|
|
|
1421
|
|
|
|
|
|
|
sub _isint { |
1422
|
0
|
|
|
0
|
|
0
|
my ($num)=@_; |
1423
|
0
|
|
|
|
|
0
|
$num =~ /\A-?\d+/o; |
1424
|
|
|
|
|
|
|
} |
1425
|
|
|
|
|
|
|
sub _isreal { |
1426
|
0
|
|
|
0
|
|
0
|
my ($num)=@_; |
1427
|
0
|
|
|
|
|
0
|
$num =~ /((-?\d*\.\d+)|(-?\d*\.\d+[eE]-?\d+))/o; |
1428
|
|
|
|
|
|
|
} |
1429
|
|
|
|
|
|
|
} |
1430
|
|
|
|
|
|
|
|
1431
|
|
|
|
|
|
|
|
1432
|
|
|
|
|
|
|
# _merge_pack($app, $class) |
1433
|
|
|
|
|
|
|
# |
1434
|
|
|
|
|
|
|
# Recursively merges the %Resources of object $obj of package $pack into a |
1435
|
|
|
|
|
|
|
# $res object in application $app. The merging is done topdown, from |
1436
|
|
|
|
|
|
|
# derived and container classes to base and member ones. |
1437
|
|
|
|
|
|
|
# |
1438
|
|
|
|
|
|
|
# The algorithm is as follows: |
1439
|
|
|
|
|
|
|
# 1) Resource names are syntax-checked, then merging is performed for those |
1440
|
|
|
|
|
|
|
# not yet defined |
1441
|
|
|
|
|
|
|
# 2) All base classes of $pack are _merge_packed in turn. |
1442
|
|
|
|
|
|
|
# |
1443
|
|
|
|
|
|
|
# Returns 1 for success, 0 otherwise. |
1444
|
|
|
|
|
|
|
# |
1445
|
|
|
|
|
|
|
sub _merge_pack { |
1446
|
6
|
|
|
6
|
|
14
|
my ($res, $app, $top, $pack, $packclass) = @_; |
1447
|
6
|
|
|
|
|
7
|
my ($defname, $def); |
1448
|
|
|
|
|
|
|
|
1449
|
6
|
100
|
|
|
|
23
|
$packclass || ($packclass = lc($pack)) =~ s/(.*::)?(\w+)/$2/; |
1450
|
|
|
|
|
|
|
|
1451
|
6
|
|
|
|
|
6
|
do { |
1452
|
1
|
|
|
1
|
|
10
|
no strict; # To use symbolic references |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
613
|
|
1453
|
6
|
|
|
|
|
13
|
$_ = $res->{Res}->{"resources.resources"}->[$Value]; |
1454
|
6
|
50
|
|
|
|
19
|
unless (/^%/) { |
1455
|
0
|
|
|
|
|
0
|
$res->_error("merge", "bad name for %Resources hash: $_"); |
1456
|
0
|
|
|
|
|
0
|
return 0; |
1457
|
|
|
|
|
|
|
} |
1458
|
6
|
|
|
|
|
15
|
s/^%//; |
1459
|
6
|
|
|
|
|
10
|
$defname = "$pack\::$_"; |
1460
|
6
|
|
|
|
|
5
|
$def = \%{$defname}; |
|
6
|
|
|
|
|
52
|
|
1461
|
|
|
|
|
|
|
}; |
1462
|
|
|
|
|
|
|
|
1463
|
6
|
50
|
|
|
|
7
|
if (defined(%{$def})) { |
|
6
|
|
|
|
|
14
|
|
1464
|
6
|
|
|
|
|
6
|
my ($dname, $dvalue, $val, $vref); |
1465
|
6
|
|
|
|
|
8
|
defloop: while (($dname, $dvalue) = each(%{$def})) { |
|
28
|
|
|
|
|
88
|
|
1466
|
|
|
|
|
|
|
# Check for bad args: |
1467
|
|
|
|
|
|
|
# Names cannot contain * or :, nor start/end with a dot |
1468
|
22
|
50
|
|
|
|
86
|
$dname =~ /\*|^\.|\.$|\:/ && do { |
1469
|
0
|
|
|
|
|
0
|
$res->error("merge", "Bad default resource name: $dname "); |
1470
|
0
|
|
|
|
|
0
|
return 0; |
1471
|
|
|
|
|
|
|
}; |
1472
|
|
|
|
|
|
|
# Values must be 2-elements arrays, with a scalar 2nd |
1473
|
|
|
|
|
|
|
# component (the doc) |
1474
|
22
|
50
|
33
|
|
|
161
|
unless(($vref = ref($dvalue)) && ($vref =~ /ARRAY/o) && |
|
22
|
|
33
|
|
|
120
|
|
|
|
|
33
|
|
|
|
|
1475
|
|
|
|
|
|
|
scalar(@{$dvalue})<=2 && !ref($dvalue->[1]) ) { |
1476
|
0
|
|
|
|
|
0
|
$res->_error("merge", "Bad default resource value for ". |
1477
|
|
|
|
|
|
|
"resource $dname in hash $defname"); |
1478
|
0
|
|
|
|
|
0
|
return 0; |
1479
|
|
|
|
|
|
|
}; |
1480
|
|
|
|
|
|
|
|
1481
|
|
|
|
|
|
|
# Build class name for resource by inheritance |
1482
|
22
|
50
|
|
|
|
47
|
if ($top eq "main") { |
|
|
100
|
|
|
|
|
|
1483
|
0
|
|
|
|
|
0
|
$dname = $app . $dname; |
1484
|
|
|
|
|
|
|
} elsif ($top eq $packclass) { |
1485
|
15
|
|
|
|
|
31
|
$dname = "$app$top\.$dname"; |
1486
|
|
|
|
|
|
|
} else { |
1487
|
7
|
|
|
|
|
46
|
$dname = "$app$top\.$packclass\.$dname"; |
1488
|
|
|
|
|
|
|
} |
1489
|
|
|
|
|
|
|
|
1490
|
22
|
50
|
0
|
|
|
23
|
$res->put($dname, @{$dvalue}) || |
|
22
|
|
|
|
|
49
|
|
1491
|
|
|
|
|
|
|
($res->_error("merge", "error on $dname: $dvalue") && return 0); |
1492
|
|
|
|
|
|
|
} |
1493
|
|
|
|
|
|
|
} |
1494
|
|
|
|
|
|
|
|
1495
|
|
|
|
|
|
|
# Now let's recur on base classes of $obj |
1496
|
|
|
|
|
|
|
# |
1497
|
6
|
|
|
|
|
7
|
my ($isaname, $isa, $base); |
1498
|
0
|
|
|
|
|
0
|
my (@hasa, $mem); |
1499
|
|
|
|
|
|
|
|
1500
|
|
|
|
|
|
|
# Base classes |
1501
|
6
|
|
|
|
|
6
|
do { |
1502
|
1
|
|
|
1
|
|
7
|
no strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
948
|
|
1503
|
6
|
|
|
|
|
8
|
$isaname = "$pack\::ISA"; |
1504
|
6
|
|
|
|
|
17
|
$isa = \@$isaname; |
1505
|
|
|
|
|
|
|
}; |
1506
|
6
|
100
|
|
|
|
6
|
if (defined(@{$isa})) { |
|
6
|
|
|
|
|
14
|
|
1507
|
3
|
|
|
|
|
4
|
for $base (@{$isa}) { |
|
3
|
|
|
|
|
6
|
|
1508
|
3
|
50
|
|
|
|
9
|
return 0 unless $res->_merge_pack($app, $top, $base, $packclass); |
1509
|
|
|
|
|
|
|
} |
1510
|
|
|
|
|
|
|
} |
1511
|
|
|
|
|
|
|
|
1512
|
|
|
|
|
|
|
# All done. |
1513
|
6
|
|
|
|
|
19
|
return 1; |
1514
|
|
|
|
|
|
|
} |
1515
|
|
|
|
|
|
|
|
1516
|
|
|
|
|
|
|
|
1517
|
|
|
|
|
|
|
# |
1518
|
|
|
|
|
|
|
# _error ($subname) - wrapper around caller(), used for debugging |
1519
|
|
|
|
|
|
|
# |
1520
|
|
|
|
|
|
|
sub _error { |
1521
|
0
|
|
|
0
|
|
0
|
my $res=shift; |
1522
|
0
|
|
|
|
|
0
|
my ($place, $msg) = @_; |
1523
|
|
|
|
|
|
|
|
1524
|
0
|
0
|
|
|
|
0
|
$res->valbyname("resources.verbosity") && |
1525
|
|
|
|
|
|
|
warn("error: $0: Resources: $place, $msg\n"); |
1526
|
|
|
|
|
|
|
|
1527
|
0
|
|
|
|
|
0
|
1; |
1528
|
|
|
|
|
|
|
} |
1529
|
|
|
|
|
|
|
|
1530
|
|
|
|
|
|
|
|
1531
|
|
|
|
|
|
|
# |
1532
|
|
|
|
|
|
|
# _printformat($fh, $msg) |
1533
|
|
|
|
|
|
|
# prints to filehandle $fh the documentation $doc. |
1534
|
|
|
|
|
|
|
# formatted in resources.viewcolumn columns, not breking expression and |
1535
|
|
|
|
|
|
|
# continuing comments. |
1536
|
|
|
|
|
|
|
# |
1537
|
|
|
|
|
|
|
|
1538
|
|
|
|
|
|
|
sub _printformat { |
1539
|
1
|
|
|
1
|
|
2
|
my $res=shift; |
1540
|
1
|
|
|
|
|
3
|
my ($fh, $msg) = @_; |
1541
|
1
|
|
|
|
|
2
|
my ($line, $cols, $def, $comm, @comms, $below); |
1542
|
0
|
|
|
|
|
0
|
my ($deflen, $commlen, $mincols, $whites); |
1543
|
|
|
|
|
|
|
|
1544
|
1
|
|
|
|
|
3
|
$cols = $res->valbyname("resources.viewcols"); |
1545
|
1
|
|
|
|
|
3
|
$mincols = $res->valbyname("resources.viewmincols"); |
1546
|
1
|
50
|
|
|
|
4
|
$cols = 78 unless $cols; |
1547
|
|
|
|
|
|
|
|
1548
|
1
|
|
|
|
|
13
|
for $line (split(/\n/, $msg)) { |
1549
|
|
|
|
|
|
|
# print right away if it's short |
1550
|
29
|
100
|
|
|
|
54
|
if (length($line) <= $cols) { |
1551
|
24
|
|
|
|
|
52
|
$line =~ s/__RES_COMM__$//o; |
1552
|
24
|
|
|
|
|
48
|
$line =~ s/__RES_COMM__/ \# /; |
1553
|
24
|
|
|
|
|
277
|
print $fh "$line\n"; |
1554
|
24
|
|
|
|
|
35
|
next; |
1555
|
|
|
|
|
|
|
} |
1556
|
|
|
|
|
|
|
|
1557
|
5
|
|
|
|
|
17
|
($def, $comm) = split(/__RES_COMM__/, $line); |
1558
|
5
|
|
|
|
|
9
|
$deflen = length($def)+1; |
1559
|
|
|
|
|
|
|
# down one line if def is too long |
1560
|
5
|
50
|
|
|
|
12
|
if (($commlen = $cols-($deflen % $cols)) < $mincols) { |
1561
|
0
|
|
|
|
|
0
|
$below=1; |
1562
|
0
|
|
|
|
|
0
|
$commlen=$cols/2; |
1563
|
|
|
|
|
|
|
} else { |
1564
|
5
|
|
|
|
|
7
|
$below=0; |
1565
|
|
|
|
|
|
|
} |
1566
|
|
|
|
|
|
|
|
1567
|
5
|
|
|
|
|
20
|
@comms = split(/\s+/, $comm); |
1568
|
5
|
50
|
|
|
|
12
|
shift(@comms) unless $comms[0]; |
1569
|
|
|
|
|
|
|
|
1570
|
5
|
50
|
|
|
|
8
|
unless ($below) { |
1571
|
5
|
|
|
|
|
14
|
print $fh ("$def # ", _commwds($commlen, \@comms), "\n"); |
1572
|
5
|
|
|
|
|
9
|
$whites = $deflen % $cols; |
1573
|
5
|
|
|
|
|
12
|
while ($comm=_commwds($commlen, \@comms)) { |
1574
|
2
|
|
|
|
|
7
|
$comm = (' ' x $whites) . "# $comm"; |
1575
|
2
|
|
|
|
|
23
|
print $fh "$comm\n"; |
1576
|
|
|
|
|
|
|
} |
1577
|
|
|
|
|
|
|
} else { |
1578
|
0
|
|
|
|
|
0
|
print $fh "$def\n"; |
1579
|
0
|
|
|
|
|
0
|
$whites = $cols/2 - 1; |
1580
|
0
|
|
|
|
|
0
|
while ($comm=_commwds($commlen, \@comms)) { |
1581
|
0
|
|
|
|
|
0
|
$comm = (' ' x $whites) . "# $comm"; |
1582
|
0
|
|
|
|
|
0
|
print $fh "$comm\n"; |
1583
|
|
|
|
|
|
|
} |
1584
|
|
|
|
|
|
|
} |
1585
|
|
|
|
|
|
|
} |
1586
|
|
|
|
|
|
|
|
1587
|
|
|
|
|
|
|
sub _commwds { |
1588
|
12
|
|
|
12
|
|
16
|
my ($len, $comp) = @_; |
1589
|
12
|
|
|
|
|
11
|
my ($shft, $wd, $ls, $lw); |
1590
|
|
|
|
|
|
|
|
1591
|
12
|
|
|
|
|
13
|
$ls=1; |
1592
|
12
|
|
|
|
|
16
|
$shft = $wd = ''; |
1593
|
12
|
|
|
|
|
10
|
while (1) { |
1594
|
52
|
|
|
|
|
43
|
$wd=shift(@{$comp}); |
|
52
|
|
|
|
|
71
|
|
1595
|
52
|
100
|
|
|
|
82
|
last unless $wd; |
1596
|
42
|
|
|
|
|
40
|
$lw=length($wd)+1; |
1597
|
42
|
100
|
|
|
|
76
|
last if $lw + $ls > $len; |
1598
|
40
|
|
|
|
|
46
|
$shft .= "$wd "; |
1599
|
40
|
|
|
|
|
60
|
$ls += $lw; |
1600
|
|
|
|
|
|
|
} |
1601
|
12
|
100
|
|
|
|
28
|
unshift(@{$comp}, $wd) if $wd; |
|
2
|
|
|
|
|
4
|
|
1602
|
12
|
|
|
|
|
83
|
return $shft; |
1603
|
|
|
|
|
|
|
} |
1604
|
|
|
|
|
|
|
} |
1605
|
|
|
|
|
|
|
|
1606
|
|
|
|
|
|
|
|
1607
|
|
|
|
|
|
|
1; |
1608
|
|
|
|
|
|
|
|
1609
|
|
|
|
|
|
|
__END__ |