line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package BTRIEVE::SAVE; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
7549
|
use Carp; |
|
1
|
|
|
|
|
80
|
|
|
1
|
|
|
|
|
131
|
|
4
|
1
|
|
|
1
|
|
9
|
use strict; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
49
|
|
5
|
1
|
|
|
|
|
6981
|
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $DEBUG $TEST |
6
|
1
|
|
|
1
|
|
5
|
); |
|
1
|
|
|
|
|
7
|
|
7
|
|
|
|
|
|
|
$VERSION = '0.35'; |
8
|
|
|
|
|
|
|
$DEBUG = 0; |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
require Exporter; |
11
|
|
|
|
|
|
|
require 5.004; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
@ISA = qw(Exporter); |
14
|
|
|
|
|
|
|
@EXPORT= qw(); |
15
|
|
|
|
|
|
|
@EXPORT_OK= qw(); |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# Preloaded methods go here. |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
#################################################################### |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
# This is the constructor method that creates the BTRIEVE object. |
23
|
|
|
|
|
|
|
# It will attempt to set up info from the config file. |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
#################################################################### |
26
|
|
|
|
|
|
|
sub new { |
27
|
2
|
|
|
2
|
1
|
625
|
my $proto = shift; |
28
|
2
|
|
33
|
|
|
17
|
my $class = ref($proto) || $proto; |
29
|
2
|
|
|
|
|
4
|
my $config_file= shift ; |
30
|
2
|
|
100
|
|
|
8
|
my $file = shift ||undef; |
31
|
|
|
|
|
|
|
|
32
|
2
|
|
|
|
|
10
|
my $save_btr = {opt=>{}, array=>[]}; |
33
|
2
|
|
|
|
|
6
|
$save_btr->{'opt'}{'config'}=$config_file; |
34
|
|
|
|
|
|
|
|
35
|
2
|
|
|
|
|
4
|
bless $save_btr, $class; |
36
|
2
|
50
|
|
|
|
30
|
if (-e $config_file) { |
37
|
2
|
|
|
|
|
10
|
$save_btr->config($config_file); |
38
|
|
|
|
|
|
|
} else { |
39
|
0
|
|
|
|
|
0
|
return $save_btr; |
40
|
|
|
|
|
|
|
} |
41
|
2
|
100
|
|
|
|
5
|
if (!$file) {return $save_btr}; |
|
1
|
|
|
|
|
7
|
|
42
|
1
|
|
|
|
|
4
|
$save_btr->{'opt'}{'file'}=$file; |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
|
45
|
1
|
|
|
|
|
4
|
$save_btr->_initbtrieve(); |
46
|
1
|
|
|
|
|
3
|
return $save_btr; |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
################################################################### |
50
|
|
|
|
|
|
|
# _initbtrieve() sets up config and filehandle |
51
|
|
|
|
|
|
|
################################################################### |
52
|
|
|
|
|
|
|
sub _initbtrieve { |
53
|
1
|
|
|
1
|
|
2
|
my $save_btr = shift; |
54
|
1
|
|
|
|
|
3
|
my $config_file = $save_btr->{'opt'}{'config'}; |
55
|
1
|
|
|
|
|
3
|
$save_btr->{'opt'}{'increment'} = -1; |
56
|
|
|
|
|
|
|
|
57
|
1
|
|
|
|
|
2
|
my $file = $save_btr->{'opt'}{'file'}; |
58
|
1
|
50
|
|
|
|
20
|
if (not(-e $file)) {carp "File \"$file\" doesn't exist"; return} |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
59
|
1
|
|
|
|
|
33
|
open (*file, $file); |
60
|
1
|
|
|
|
|
3
|
binmode *file; |
61
|
1
|
|
|
|
|
4
|
$save_btr->{'opt'}{'handle'}=\*file; #store filehandle in object |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
################################################################### |
65
|
|
|
|
|
|
|
# config() looks for a config file which tells us where the |
66
|
|
|
|
|
|
|
# offsets are in the fixed part of the record, their types and |
67
|
|
|
|
|
|
|
# what to call them locally. |
68
|
|
|
|
|
|
|
################################################################### |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
sub config { |
71
|
2
|
|
|
2
|
1
|
5
|
my $save_btr = shift; |
72
|
2
|
|
|
|
|
20
|
my $proto_rec = BTRIEVE::SAVE::REC->newconfig($save_btr->{'opt'}{'config'}); |
73
|
2
|
|
|
|
|
8
|
$save_btr->{'opt'}{'proto_rec'} = $proto_rec; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
################################################################### |
77
|
|
|
|
|
|
|
# parse_file() reads from a BTRIEVE SAVE file. Can do so |
78
|
|
|
|
|
|
|
# incrementally. |
79
|
|
|
|
|
|
|
################################################################### |
80
|
|
|
|
|
|
|
sub parse_file { |
81
|
1
|
|
|
1
|
1
|
4
|
my $save_btr = shift; |
82
|
1
|
|
|
|
|
3
|
my $increment = $save_btr->{'opt'}{'increment'}; #pick out increment from the object |
83
|
1
|
|
|
|
|
2
|
my $recordcount = 0; |
84
|
|
|
|
|
|
|
|
85
|
1
|
|
33
|
|
|
6
|
while ($increment==-1 or $recordcount<$increment) { |
86
|
3
|
|
|
|
|
10
|
my $curr_rec = $save_btr->next_rec; |
87
|
3
|
100
|
|
|
|
6
|
last unless $curr_rec; |
88
|
2
|
|
|
|
|
3
|
push @{$save_btr->{'array'}},$curr_rec; |
|
2
|
|
|
|
|
5
|
|
89
|
2
|
|
|
|
|
5
|
$recordcount++; |
90
|
|
|
|
|
|
|
} #end reading this record |
91
|
1
|
|
|
|
|
2
|
return $recordcount; |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
#################################################################### |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# Returns a new BTRIEVE::SAVE::REC based on the next bits. |
97
|
|
|
|
|
|
|
# Returns undef if we have reached the end. |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
#################################################################### |
100
|
|
|
|
|
|
|
sub next_rec { |
101
|
3
|
|
|
3
|
1
|
4
|
my $save_btr=shift; |
102
|
3
|
|
|
|
|
9
|
my ($rec,$eor) = $save_btr->next_recbits; |
103
|
3
|
100
|
|
|
|
12
|
return undef if $eor eq "\cZ"; |
104
|
2
|
50
|
|
|
|
6
|
return undef unless defined($rec); |
105
|
2
|
|
|
|
|
4
|
my $proto_rec = $save_btr->{'opt'}{'proto_rec'}; |
106
|
2
|
|
|
|
|
6
|
my $curr_rec = $proto_rec->copy_struct(); |
107
|
|
|
|
|
|
|
|
108
|
2
|
|
|
|
|
9
|
$curr_rec->parse_string($rec); |
109
|
2
|
|
|
|
|
7
|
return $curr_rec; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
#################################################################### |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
# Reads thru the handle looking for the bits forming the $rec |
115
|
|
|
|
|
|
|
# and for the bits that should be $eor (end-of-record). |
116
|
|
|
|
|
|
|
# Returns ($rec,$eor). $eor is undef if the read is at EOF. |
117
|
|
|
|
|
|
|
# $eor is undef if we are at the DOS EOF ("\cZ") at the |
118
|
|
|
|
|
|
|
# appropriate defined place. |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
#################################################################### |
121
|
|
|
|
|
|
|
sub next_recbits { |
122
|
3
|
|
|
3
|
1
|
4
|
my $save_btr = shift; |
123
|
3
|
|
|
|
|
7
|
my $handle = $save_btr->{'opt'}{'handle'}; |
124
|
|
|
|
|
|
|
#need to use read to get the right bytes. Bummer. |
125
|
3
|
|
|
|
|
4
|
my $pos= tell($handle); |
126
|
3
|
|
|
|
|
4
|
my $info=""; |
127
|
3
|
|
|
|
|
23
|
my $rc= read($handle,$info,14); #assumes that no record is more than 10 gigabytes |
128
|
3
|
50
|
|
|
|
7
|
return (undef,undef) unless $rc; #EOF... |
129
|
3
|
100
|
|
|
|
13
|
return (undef,"\cZ") if $info=~/^\cZ/; |
130
|
2
|
|
|
|
|
8
|
my ($length)= $info=~/^(\d+)[, ]/; #definition of btrieve save file format. |
131
|
|
|
|
|
|
|
#error check here to see if $length is defined. |
132
|
2
|
|
|
|
|
20
|
seek($handle,$pos,0); #go back to where we were. |
133
|
2
|
|
|
|
|
4
|
my $rec=""; |
134
|
2
|
|
|
|
|
20
|
$rc= read($handle,$rec,$length +length($length)+1); #definition of btrieve save file format. |
135
|
2
|
|
|
|
|
7
|
$rec = substr($rec,length($length)+1); #kills the \d+[, ], keeps the rest. |
136
|
2
|
|
|
|
|
5
|
my $eor=""; |
137
|
2
|
|
|
|
|
4
|
$rc = read($handle,$eor,2); #skip over \r\n, or find \cZ |
138
|
2
|
|
|
|
|
48
|
return ($rec,$eor); |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
#################################################################### |
141
|
|
|
|
|
|
|
# openbtr() reads in a BTRIEVE SAVE file. It takes a hashref |
142
|
|
|
|
|
|
|
# with key 'file' (name of the btrieve file). Increment |
143
|
|
|
|
|
|
|
# defines how many records to read in and is taken from the object. |
144
|
|
|
|
|
|
|
#################################################################### |
145
|
|
|
|
|
|
|
sub openbtr { |
146
|
0
|
|
|
0
|
1
|
0
|
my $save_btr=shift; |
147
|
0
|
|
|
|
|
0
|
my $params=shift; |
148
|
0
|
|
|
|
|
0
|
my $file=$params->{'file'}; |
149
|
0
|
0
|
|
|
|
0
|
if (not(-e $file)) {carp "File \"$file\" doesn't exist"; return} |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
150
|
0
|
|
|
|
|
0
|
my $totalrecord; |
151
|
0
|
|
0
|
|
|
0
|
$save_btr->{'opt'}{'increment'} |
|
|
|
0
|
|
|
|
|
152
|
|
|
|
|
|
|
||= $params->{'increment'} |
153
|
|
|
|
|
|
|
||= 1; |
154
|
|
|
|
|
|
|
#store increment in the object, default is 1 |
155
|
0
|
|
|
|
|
0
|
open (*file, $file); |
156
|
0
|
|
|
|
|
0
|
binmode *file; |
157
|
0
|
|
|
|
|
0
|
$save_btr->{'opt'}{'handle'}=\*file; #store filehandle in object |
158
|
|
|
|
|
|
|
|
159
|
0
|
0
|
|
|
|
0
|
print "read in $totalrecord records\n" if $DEBUG; |
160
|
0
|
0
|
|
|
|
0
|
if ($totalrecord==0) {$totalrecord="0 but true"} |
|
0
|
|
|
|
|
0
|
|
161
|
0
|
|
|
|
|
0
|
return $totalrecord; |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
#################################################################### |
165
|
|
|
|
|
|
|
# closebtr() will close a file-handle that was opened with |
166
|
|
|
|
|
|
|
# openbtr() |
167
|
|
|
|
|
|
|
#################################################################### |
168
|
|
|
|
|
|
|
sub closebtr { |
169
|
0
|
|
|
0
|
1
|
0
|
my $marc = shift; |
170
|
0
|
|
|
|
|
0
|
$marc->{'opt'}{'increment'}=0; |
171
|
0
|
0
|
|
|
|
0
|
if (not($marc->{'opt'}{'handle'})) {carp "There isn't a BTRIEVE SAVE file to close"; return} |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
172
|
0
|
|
|
|
|
0
|
my $ok = close $marc->{'opt'}{'handle'}; |
173
|
0
|
|
|
|
|
0
|
$marc->{'opt'}{'handle'}=undef; |
174
|
0
|
|
|
|
|
0
|
return $ok; |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
#################################################################### |
178
|
|
|
|
|
|
|
# nextbtr() will read in more records from a file that has |
179
|
|
|
|
|
|
|
# already been opened with openbtr(). the increment can be |
180
|
|
|
|
|
|
|
# adjusted if necessary by passing a new value as a parameter. the |
181
|
|
|
|
|
|
|
# new records will be APPENDED to the BTRIEVE object |
182
|
|
|
|
|
|
|
#################################################################### |
183
|
|
|
|
|
|
|
sub nextbtr { |
184
|
0
|
|
|
0
|
1
|
0
|
my $save_btr=shift; |
185
|
0
|
|
|
|
|
0
|
my $increment=shift; |
186
|
0
|
|
|
|
|
0
|
my $totalrecord; |
187
|
0
|
0
|
|
|
|
0
|
if (not($save_btr->{'opt'}{'handle'})) {carp "There isn't a BTRIEVE SAVE file open"; return} |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
188
|
0
|
0
|
|
|
|
0
|
if ($increment) {$save_btr->{'opt'}{'increment'}=$increment} |
|
0
|
|
|
|
|
0
|
|
189
|
|
|
|
|
|
|
|
190
|
0
|
|
|
|
|
0
|
$totalrecord = $save_btr->parse_file(); |
191
|
|
|
|
|
|
|
|
192
|
0
|
|
|
|
|
0
|
return $totalrecord; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
#################################################################### |
196
|
|
|
|
|
|
|
# output() actually writes the file with a string version of |
197
|
|
|
|
|
|
|
# $save_btr unless no file is given, in which case it returns the string |
198
|
|
|
|
|
|
|
#################################################################### |
199
|
|
|
|
|
|
|
sub output { |
200
|
0
|
|
|
0
|
1
|
0
|
my $save_btr=shift; |
201
|
0
|
|
|
|
|
0
|
my $output = ""; |
202
|
0
|
|
|
|
|
0
|
my $outfile = shift; |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
|
205
|
0
|
|
|
|
|
0
|
$output = $save_btr->as_string(); |
206
|
0
|
0
|
|
|
|
0
|
if ($outfile) { |
207
|
0
|
0
|
|
|
|
0
|
if ($outfile !~ /^>/) {carp "Don't forget to use > or >>: $!"} |
|
0
|
|
|
|
|
0
|
|
208
|
0
|
|
|
|
|
0
|
local(*OUT); |
209
|
0
|
0
|
|
|
|
0
|
open (OUT, "$outfile") || carp "Couldn't open file: $!"; |
210
|
0
|
|
|
|
|
0
|
binmode OUT; |
211
|
0
|
|
|
|
|
0
|
print OUT $output; |
212
|
0
|
0
|
|
|
|
0
|
close OUT || carp "Couldn't close file: $!"; |
213
|
0
|
|
|
|
|
0
|
return 1; |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
#if no filename was specified return the output so it can be grabbed |
216
|
|
|
|
|
|
|
else { |
217
|
0
|
|
|
|
|
0
|
return $output; |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
#################################################################### |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
# as_string() returns a string version of $save_btr. Handles packing the |
225
|
|
|
|
|
|
|
# easily updateable version of %fixed. |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
#################################################################### |
228
|
|
|
|
|
|
|
sub as_string { |
229
|
0
|
|
|
0
|
1
|
0
|
my $output = ""; |
230
|
0
|
|
|
|
|
0
|
my $save_btr=shift; |
231
|
|
|
|
|
|
|
|
232
|
0
|
|
|
|
|
0
|
for (@{$save_btr->{'array'}}) { |
|
0
|
|
|
|
|
0
|
|
233
|
0
|
|
|
|
|
0
|
my $data = $_->data; |
234
|
0
|
|
|
|
|
0
|
my $packed_rec = $_->counted_rec($data); |
235
|
0
|
|
|
|
|
0
|
$output .=$packed_rec; |
236
|
|
|
|
|
|
|
} |
237
|
0
|
|
|
|
|
0
|
$output .="\cZ"; |
238
|
0
|
|
|
|
|
0
|
return $output; |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
#################################################################### |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
# Takes an rdb filename, save filename, error file name, and config |
244
|
|
|
|
|
|
|
# file name. Also takes the field name for unindexed fixed info and |
245
|
|
|
|
|
|
|
# var info, and strings to translate to tab and newline. Writes |
246
|
|
|
|
|
|
|
# an rdb file with that information; warns and writes to the error file |
247
|
|
|
|
|
|
|
# if there are problems in the data. |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
#################################################################### |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
sub rdb_to_save { |
252
|
1
|
|
|
1
|
1
|
6
|
my $save_btr = shift; |
253
|
1
|
|
|
|
|
5
|
my ($rdb,$save,$errs, |
254
|
|
|
|
|
|
|
$zzname,$varname,$tabtrans,$rettrans) = @_; |
255
|
|
|
|
|
|
|
|
256
|
1
|
|
|
|
|
2
|
local *RDB; |
257
|
1
|
|
|
|
|
3
|
local *SAVE; |
258
|
1
|
|
|
|
|
3
|
local *ERRS; |
259
|
|
|
|
|
|
|
|
260
|
1
|
50
|
|
|
|
37
|
open RDB,"$rdb" or die "Could not open $rdb:$!\n"; |
261
|
1
|
|
|
|
|
3
|
binmode RDB; |
262
|
1
|
50
|
|
|
|
101
|
open SAVE,">$save" or die "Could not open $save:$!\n"; |
263
|
1
|
|
|
|
|
2
|
binmode SAVE; |
264
|
1
|
50
|
|
|
|
60
|
open ERRS,">$errs" or die "Could not open $errs:$!\n"; |
265
|
1
|
|
|
|
|
2
|
binmode ERRS; |
266
|
|
|
|
|
|
|
|
267
|
1
|
|
|
|
|
22
|
my $fieldnames = ; |
268
|
1
|
|
|
|
|
15
|
print ERRS $fieldnames; |
269
|
|
|
|
|
|
|
|
270
|
1
|
|
|
|
|
3
|
chomp $fieldnames; |
271
|
|
|
|
|
|
|
|
272
|
1
|
|
|
|
|
5
|
my @rdbnames = split(/\t/,$fieldnames); |
273
|
|
|
|
|
|
|
|
274
|
1
|
|
|
|
|
4
|
my $proto_rec = $save_btr->{opt}{proto_rec}; |
275
|
|
|
|
|
|
|
|
276
|
1
|
|
|
|
|
2
|
my @names = @{$proto_rec->{opt}{names}}; |
|
1
|
|
|
|
|
9
|
|
277
|
|
|
|
|
|
|
|
278
|
1
|
|
|
|
|
2
|
my %fieldlen = (); #Gonna use this for lookup. |
279
|
1
|
|
|
|
|
3
|
my @fixed_defs = @{$proto_rec->{opt}{fixed_defs}}; |
|
1
|
|
|
|
|
3
|
|
280
|
1
|
|
|
|
|
2
|
for (@fixed_defs) { |
281
|
3
|
|
|
|
|
11
|
$fieldlen{ $_->{name}} = $_->{len}; |
282
|
|
|
|
|
|
|
}; |
283
|
|
|
|
|
|
|
|
284
|
1
|
|
|
|
|
4
|
my $dashline = ; |
285
|
1
|
|
|
|
|
2
|
print ERRS $dashline; |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
REC: |
289
|
1
|
|
|
|
|
5
|
while () { |
290
|
2
|
|
|
|
|
4
|
chomp; |
291
|
2
|
50
|
|
|
|
10
|
next unless /\S/; |
292
|
2
|
|
|
|
|
9
|
my @fields= split(/\t/); |
293
|
|
|
|
|
|
|
|
294
|
2
|
|
|
|
|
2
|
my $var; |
295
|
|
|
|
|
|
|
my $rhfixed; |
296
|
2
|
|
|
|
|
6
|
my @fieldnames = @rdbnames; |
297
|
2
|
50
|
|
|
|
6
|
if ($#fields != $#rdbnames) { |
298
|
0
|
|
|
|
|
0
|
warn "Paranoia 1: Number of fields do not match rdb spec at line $..\n"; |
299
|
0
|
|
|
|
|
0
|
print ERRS $_; |
300
|
0
|
|
|
|
|
0
|
next REC; |
301
|
|
|
|
|
|
|
} |
302
|
2
|
|
|
|
|
3
|
my $err_skip =0; |
303
|
|
|
|
|
|
|
FIELD: |
304
|
2
|
|
|
|
|
6
|
while (@fields) { |
305
|
8
|
|
|
|
|
10
|
my $field = shift @fields; |
306
|
8
|
|
|
|
|
28
|
$field=~s/$tabtrans/\t/; |
307
|
8
|
|
|
|
|
14
|
$field=~s/$rettrans/\n/; |
308
|
8
|
|
|
|
|
13
|
my $name = shift @fieldnames; |
309
|
|
|
|
|
|
|
|
310
|
8
|
100
|
|
|
|
16
|
if ($name eq $zzname) { |
311
|
2
|
|
|
|
|
4
|
$rhfixed->{'ZZ'} = $field; |
312
|
2
|
|
|
|
|
12
|
next FIELD; |
313
|
|
|
|
|
|
|
} |
314
|
6
|
100
|
|
|
|
19
|
if ($name eq $varname) { |
315
|
2
|
|
|
|
|
3
|
$var = $field; |
316
|
2
|
|
|
|
|
11
|
next FIELD; |
317
|
|
|
|
|
|
|
} |
318
|
4
|
50
|
|
|
|
14
|
if ($fieldlen{$name} != length($field)) { |
319
|
0
|
|
|
|
|
0
|
warn "Paranoia 2: Lengths do not match for $name at line $..\n"; |
320
|
0
|
|
|
|
|
0
|
print ERRS $_; |
321
|
0
|
|
|
|
|
0
|
next REC; |
322
|
|
|
|
|
|
|
} |
323
|
4
|
|
|
|
|
12
|
$rhfixed->{$name}=$field; |
324
|
|
|
|
|
|
|
} |
325
|
|
|
|
|
|
|
|
326
|
2
|
|
|
|
|
9
|
my $curr_rec = $proto_rec->copy_struct(); |
327
|
2
|
|
|
|
|
3
|
@{$curr_rec->{values}} = ($rhfixed,\"",\$var); |
|
2
|
|
|
|
|
7
|
|
328
|
2
|
|
|
|
|
6
|
my $counted_rec = $curr_rec->counted_rec_hash(); |
329
|
2
|
|
|
|
|
55
|
print SAVE $counted_rec; |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
|
332
|
1
|
|
|
|
|
3
|
print SAVE "\cZ"; |
333
|
|
|
|
|
|
|
|
334
|
1
|
50
|
|
|
|
17
|
close RDB or carp "Could not close $rdb:$!\n"; |
335
|
1
|
50
|
|
|
|
57
|
close ERRS or carp "Could not close $errs:$!\n"; |
336
|
1
|
50
|
|
|
|
42
|
close SAVE or carp "Could not close $save:$!\n"; |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
#################################################################### |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
# Takes an rdb filename, save filename, error file name, and config |
342
|
|
|
|
|
|
|
# file name. Also takes the field name for unindexed fixed info and |
343
|
|
|
|
|
|
|
# var info, and strings to translate to tab and newline. Writes |
344
|
|
|
|
|
|
|
# a rdb file with that information; warns and writes to the error file |
345
|
|
|
|
|
|
|
# if there are problems in the data. |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
#################################################################### |
348
|
|
|
|
|
|
|
sub save_to_rdb { |
349
|
1
|
|
|
1
|
1
|
945
|
my $save_btr = shift; |
350
|
1
|
|
|
|
|
8
|
my ($rdb,$save,$errs, |
351
|
|
|
|
|
|
|
$zzname,$varname,$tabtrans,$rettrans) = @_; |
352
|
|
|
|
|
|
|
|
353
|
1
|
|
|
|
|
7
|
local *RDB; |
354
|
1
|
|
|
|
|
3
|
local *ERRS; |
355
|
|
|
|
|
|
|
|
356
|
1
|
|
|
|
|
10
|
my $btr = BTRIEVE::SAVE->new($save_btr->{opt}{config},$save); |
357
|
1
|
|
|
|
|
6
|
$btr->parse_file(); |
358
|
1
|
|
|
|
|
2
|
my $proto_rec = $btr->{'opt'}{'proto_rec'}; |
359
|
1
|
|
|
|
|
2
|
my @names = @{$proto_rec->{'opt'}{'names'}}; |
|
1
|
|
|
|
|
3
|
|
360
|
1
|
|
|
|
|
2
|
my @rdbnames = @names; |
361
|
1
|
100
|
|
|
|
2
|
grep {$_ = $zzname if $_ eq 'ZZ'} @rdbnames; |
|
3
|
|
|
|
|
15
|
|
362
|
1
|
50
|
|
|
|
105
|
open RDB,">$rdb" or die "Could not open $rdb for write: $!\n"; |
363
|
1
|
|
|
|
|
3
|
binmode RDB; |
364
|
1
|
50
|
|
|
|
68
|
open ERRS,">$errs" or die "Could not open $errs for write: $!\n"; |
365
|
1
|
|
|
|
|
2
|
binmode ERRS; |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
|
368
|
1
|
|
|
|
|
3
|
foreach my $name (@names) { |
369
|
3
|
|
|
|
|
11
|
print RDB "$name\t"; # in /rdb systems, deleting an extra column is trivial. |
370
|
|
|
|
|
|
|
} |
371
|
1
|
|
|
|
|
3
|
print RDB "$varname\n"; |
372
|
|
|
|
|
|
|
|
373
|
1
|
|
|
|
|
3
|
for (@names) { |
374
|
3
|
|
|
|
|
5
|
my $name =$_; |
375
|
3
|
|
|
|
|
15
|
$name=~s/./-/g; |
376
|
3
|
|
|
|
|
8
|
print RDB $name."\t"; |
377
|
|
|
|
|
|
|
} |
378
|
1
|
|
|
|
|
3
|
my $dashvar = $varname; |
379
|
1
|
|
|
|
|
4
|
$dashvar=~s/./-/g; |
380
|
1
|
|
|
|
|
3
|
print RDB $dashvar."\n"; |
381
|
|
|
|
|
|
|
|
382
|
1
|
|
|
|
|
3
|
REC: |
383
|
1
|
|
|
|
|
2
|
foreach my $rec (@{$btr->{array}}) { |
384
|
2
|
|
|
|
|
3
|
my $rdbline = ""; |
385
|
2
|
|
|
|
|
3
|
foreach my $name (@names) { |
386
|
6
|
|
|
|
|
13
|
my $field = $rec->{values}[0]{$name}; |
387
|
6
|
50
|
|
|
|
56
|
if ($field=~/$tabtrans|$rettrans/) { |
388
|
0
|
|
|
|
|
0
|
print ERRS $rec->counted_rec($rec->fixed.$rec->var); |
389
|
0
|
|
|
|
|
0
|
next REC; |
390
|
|
|
|
|
|
|
} |
391
|
6
|
|
|
|
|
10
|
$field =~s/\t/$tabtrans/g; |
392
|
6
|
|
|
|
|
7
|
$field =~s/\n/$rettrans/g; |
393
|
6
|
|
|
|
|
13
|
$rdbline .= $field."\t"; |
394
|
|
|
|
|
|
|
} |
395
|
2
|
|
|
|
|
8
|
my $var = $rec->var(); |
396
|
2
|
|
|
|
|
3
|
$var =~s/\t/$tabtrans/; |
397
|
2
|
|
|
|
|
3
|
$var =~s/\n/$rettrans/; |
398
|
2
|
|
|
|
|
4
|
$rdbline.= $var."\n"; |
399
|
2
|
|
|
|
|
5
|
print RDB $rdbline; |
400
|
|
|
|
|
|
|
} |
401
|
1
|
50
|
|
|
|
49
|
close RDB or carp "Could not close $rdb:$!\n"; |
402
|
1
|
|
|
|
|
6
|
print ERRS "\cZ"; |
403
|
1
|
50
|
|
|
|
57
|
close ERRS or carp "Could not close $errs:$!\n";; |
404
|
|
|
|
|
|
|
} |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
#################################################################### |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
# BTRIEVE::SAVE::REC is responsible for internal representation of btrieve |
409
|
|
|
|
|
|
|
# records. It knows enough to parse the %fixed information from |
410
|
|
|
|
|
|
|
# a string and can generate string representations of data and |
411
|
|
|
|
|
|
|
# counted string. |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
#################################################################### |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
package BTRIEVE::SAVE::REC; |
416
|
|
|
|
|
|
|
|
417
|
1
|
|
|
1
|
|
19
|
use vars qw( %TYPEMAP %TYPE_SCALE $VERSION); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
3627
|
|
418
|
|
|
|
|
|
|
%TYPEMAP = (Zstring => 'a', Integer => 'V', RAW => 'a'); |
419
|
|
|
|
|
|
|
%TYPE_SCALE = (Zstring => 1, Integer => 0.25, RAW => 1 ); # Btrieve standard has byte counts. |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
$VERSION = '0.35'; |
422
|
|
|
|
|
|
|
#################################################################### |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
# This roughly specifies what real recs know: a template to pack and |
425
|
|
|
|
|
|
|
# unpack strings and a list of names for %fixed keys. The arrayref |
426
|
|
|
|
|
|
|
# stores [$rhfixed,$rfixed,$rrest] information. |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
#################################################################### |
429
|
|
|
|
|
|
|
sub new { |
430
|
2
|
|
|
2
|
|
5
|
my $proto = shift; |
431
|
2
|
|
33
|
|
|
11
|
my $class = ref($proto) || $proto; |
432
|
2
|
|
|
|
|
5
|
my ($ranames,$rtemplate,$packed_length,$rhfixed_defs) = @_; |
433
|
2
|
|
|
|
|
14
|
my $save_rec = {opt=>{names =>$ranames,template=>$rtemplate, |
434
|
|
|
|
|
|
|
len=>$packed_length,fixed_defs=>$rhfixed_defs }, |
435
|
|
|
|
|
|
|
values=>[]}; |
436
|
2
|
|
|
|
|
16
|
return bless $save_rec,$class; |
437
|
|
|
|
|
|
|
} |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
sub newconfig { |
440
|
2
|
|
|
2
|
|
5
|
my $proto = shift; |
441
|
2
|
|
33
|
|
|
11
|
my $class = ref($proto) || $proto; |
442
|
2
|
|
|
|
|
3
|
my $handle = shift; |
443
|
2
|
|
|
|
|
12
|
local $/="\n"; |
444
|
2
|
|
|
|
|
4
|
local(*F); |
445
|
2
|
50
|
|
|
|
82
|
open F,$handle or die "Could not open $handle:$!\n"; |
446
|
2
|
|
|
|
|
7
|
binmode *F; |
447
|
2
|
|
|
|
|
4
|
my $fixed_length = 0; |
448
|
|
|
|
|
|
|
|
449
|
2
|
|
|
|
|
3
|
my $langname_preamble; |
450
|
|
|
|
|
|
|
my $lang_len; |
451
|
2
|
|
|
|
|
4
|
my $rhfixed_defs = []; |
452
|
2
|
|
|
|
|
49
|
while () { |
453
|
88
|
100
|
|
|
|
173
|
if (/langname/i) { |
454
|
2
|
|
|
|
|
10
|
($langname_preamble) =/^(.*)langname/i ; |
455
|
2
|
|
|
|
|
5
|
$lang_len = length($langname_preamble) ; |
456
|
|
|
|
|
|
|
} |
457
|
88
|
100
|
|
|
|
164
|
($fixed_length) = /(\d+)/ if /Record Length/; |
458
|
88
|
100
|
|
|
|
306
|
if (/^\s+\d+/) { |
459
|
4
|
|
|
|
|
18
|
my ($len,$type) = /^\s+\d+\s+\d+\s+\d+\s+(\d+)\s+(\S+)/o; |
460
|
4
|
50
|
|
|
|
13
|
die "Type $type not understood" unless $TYPEMAP{$type}; |
461
|
4
|
|
|
|
|
41
|
my ($langname) = /^.{$lang_len}(.*)/o; |
462
|
4
|
|
|
|
|
30
|
$langname=~s/\W//og; |
463
|
4
|
50
|
|
|
|
9
|
die '"ZZ" is a reserved fieldname\n' if $langname eq "ZZ"; |
464
|
4
|
|
|
|
|
6
|
push @{$rhfixed_defs},{len=>$len,type=>$type,name=>$langname}; |
|
4
|
|
|
|
|
29
|
|
465
|
|
|
|
|
|
|
} |
466
|
|
|
|
|
|
|
} |
467
|
|
|
|
|
|
|
# We define the unmatched as "ZZ" |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
|
471
|
2
|
|
|
|
|
4
|
my $template=""; |
472
|
|
|
|
|
|
|
|
473
|
2
|
|
|
|
|
5
|
my $hashed_len = 0; |
474
|
2
|
|
|
|
|
11
|
for (@{$rhfixed_defs}) { |
|
2
|
|
|
|
|
5
|
|
475
|
4
|
|
|
|
|
21
|
$template.= $TYPEMAP{$_->{'type'}}.($_->{'len'}*$TYPE_SCALE{$_->{'type'}})." "; #works for ZString and Integer |
476
|
4
|
|
|
|
|
18
|
$hashed_len += $_->{'len'}; |
477
|
|
|
|
|
|
|
} |
478
|
2
|
|
|
|
|
6
|
my $ZZ_len = $fixed_length-$hashed_len; |
479
|
2
|
50
|
|
|
|
9
|
die "Sum of field lengths exceeds fixed length by ".-$ZZ_len." bytes\n" if $ZZ_len < 0; |
480
|
2
|
|
|
|
|
2
|
push @{$rhfixed_defs},{len=>$ZZ_len,type=>"RAW",name=>"ZZ"}; |
|
2
|
|
|
|
|
9
|
|
481
|
2
|
|
|
|
|
5
|
$template .= $TYPEMAP{'RAW'}.$ZZ_len; |
482
|
2
|
|
|
|
|
4
|
my @names = map {$_->{'name'} } @{$rhfixed_defs}; |
|
6
|
|
|
|
|
36
|
|
|
2
|
|
|
|
|
17
|
|
483
|
|
|
|
|
|
|
# Templates with "a0" in them return empty strings, so ok |
484
|
|
|
|
|
|
|
# to have $fixed_length= $hashed_len. Perl rules OK? |
485
|
|
|
|
|
|
|
|
486
|
2
|
|
|
|
|
6
|
$template=~s/(\D)1 /$1 /g; |
487
|
2
|
50
|
|
|
|
27
|
close F or die "Could not close config file:$!\n"; |
488
|
2
|
|
|
|
|
14
|
return $class->new(\@names,$template,$fixed_length,$rhfixed_defs); |
489
|
|
|
|
|
|
|
} |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
#################################################################### |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
# All_index returns true iff the structure of the record implies that |
494
|
|
|
|
|
|
|
# there are no extra bytes in the fixed portion that are not indexed. |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
#################################################################### |
497
|
|
|
|
|
|
|
sub all_indexed { |
498
|
0
|
|
|
0
|
|
0
|
my $save_rec = shift; |
499
|
0
|
|
|
|
|
0
|
my $rhfixed_defs = $save_rec->{'opt'}{'fixed_defs'}; |
500
|
0
|
|
|
|
|
0
|
my $hashed_len = 0; |
501
|
0
|
|
|
|
|
0
|
for (@{$rhfixed_defs}) { |
|
0
|
|
|
|
|
0
|
|
502
|
0
|
|
|
|
|
0
|
$hashed_len += $_->{'len'}; |
503
|
|
|
|
|
|
|
} |
504
|
0
|
0
|
|
|
|
0
|
return 1 if $hashed_len == $save_rec->{opt}{len}; |
505
|
0
|
|
|
|
|
0
|
return 0; |
506
|
|
|
|
|
|
|
} |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
#################################################################### |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
# This produces a clone with the same structure but no data. |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
#################################################################### |
513
|
|
|
|
|
|
|
sub copy_struct { |
514
|
4
|
|
|
4
|
|
8
|
my $proto = shift; |
515
|
4
|
|
33
|
|
|
13
|
my $class = ref($proto) || $proto; |
516
|
4
|
|
|
|
|
6
|
my ($btr) = @_; |
517
|
|
|
|
|
|
|
|
518
|
4
|
|
|
|
|
19
|
my $save_rec = {opt=>$proto->{'opt'}, values=>[{},\"",\""]}; |
519
|
|
|
|
|
|
|
|
520
|
4
|
|
|
|
|
14
|
return bless $save_rec,$class; |
521
|
|
|
|
|
|
|
} |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
#################################################################### |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
# This uses the {opt} information to fill in {values} from the string |
526
|
|
|
|
|
|
|
# passed as a parameter. {values} will look like |
527
|
|
|
|
|
|
|
# [$rhfixed,$rfixed,$rrest]. |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
#################################################################### |
530
|
|
|
|
|
|
|
sub parse_string { |
531
|
2
|
|
|
2
|
|
3
|
my $save_rec = shift; |
532
|
2
|
|
|
|
|
3
|
my $string = shift; |
533
|
2
|
|
|
|
|
4
|
my $fixed_len = $save_rec->{'opt'}{'len'}; |
534
|
|
|
|
|
|
|
# my($fixed,$rest)= $string=~/^(.{$save_rec->{'opt'}{'len'}})(.*)/os; |
535
|
2
|
|
|
|
|
6
|
my $fixed= substr($string,0,$fixed_len); |
536
|
2
|
|
|
|
|
4
|
my $rest = substr($string,$fixed_len); |
537
|
|
|
|
|
|
|
|
538
|
2
|
|
|
|
|
16
|
my @fixed=unpack($save_rec->{'opt'}{'template'},$fixed); |
539
|
2
|
|
|
|
|
3
|
my %fixed; |
540
|
2
|
|
|
|
|
4
|
for (@{$save_rec->{'opt'}{'names'}}) { |
|
2
|
|
|
|
|
653
|
|
541
|
|
|
|
|
|
|
#remove warnings about use of undefined value. |
542
|
6
|
50
|
66
|
|
|
23
|
if ($_ eq 'ZZ' and !defined($fixed[0])) { |
543
|
0
|
|
|
|
|
0
|
$fixed{$_} =''; |
544
|
0
|
|
|
|
|
0
|
next; |
545
|
|
|
|
|
|
|
} |
546
|
6
|
|
|
|
|
24
|
$fixed{$_}= shift @fixed; |
547
|
|
|
|
|
|
|
} |
548
|
2
|
|
|
|
|
8
|
$save_rec->{'values'}=[\%fixed,\$fixed,\$rest]; |
549
|
|
|
|
|
|
|
} |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
#################################################################### |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
# We know how to take a string and add the necessary appurtenances |
554
|
|
|
|
|
|
|
# for appending to the on-file btrieve set of records. |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
#################################################################### |
557
|
|
|
|
|
|
|
sub counted_rec { |
558
|
2
|
|
|
2
|
|
3
|
my ($save_rec,$data) = @_; |
559
|
2
|
|
|
|
|
9
|
return length($data).",".$data."\015\012"; # octal def for x-platform. |
560
|
|
|
|
|
|
|
} |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
#################################################################### |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
# We know how to use our hash to create a string |
565
|
|
|
|
|
|
|
# for appending to the on-file btrieve set of records. |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
#################################################################### |
568
|
|
|
|
|
|
|
sub counted_rec_hash { |
569
|
2
|
|
|
2
|
|
3
|
my ($save_rec) = @_; |
570
|
2
|
|
|
|
|
6
|
my $data = $save_rec->data(); |
571
|
2
|
|
|
|
|
6
|
return $save_rec->counted_rec($data); |
572
|
|
|
|
|
|
|
} |
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
#################################################################### |
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
# Looks up the fixed string component of self. |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
#################################################################### |
579
|
|
|
|
|
|
|
sub fixed { |
580
|
0
|
|
|
0
|
|
0
|
my $save_rec = shift; |
581
|
0
|
0
|
|
|
|
0
|
if (@_) { |
582
|
0
|
|
|
|
|
0
|
${$save_rec->{values}[1]} = shift; |
|
0
|
|
|
|
|
0
|
|
583
|
|
|
|
|
|
|
} |
584
|
0
|
|
|
|
|
0
|
return ${$save_rec->{values}[1]}; |
|
0
|
|
|
|
|
0
|
|
585
|
|
|
|
|
|
|
} |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
#################################################################### |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
# Looks up the var string component of self. |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
#################################################################### |
593
|
|
|
|
|
|
|
sub var { |
594
|
2
|
|
|
2
|
|
3
|
my $save_rec = shift; |
595
|
2
|
50
|
|
|
|
5
|
if (@_) { |
596
|
0
|
|
|
|
|
0
|
${$save_rec->{values}[2]} = shift; |
|
0
|
|
|
|
|
0
|
|
597
|
|
|
|
|
|
|
} |
598
|
2
|
|
|
|
|
3
|
return ${$save_rec->{values}[2]}; |
|
2
|
|
|
|
|
5
|
|
599
|
|
|
|
|
|
|
} |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
#################################################################### |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
# We know how to produce data from the hashed fixed info. |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
#################################################################### |
606
|
|
|
|
|
|
|
sub data { |
607
|
2
|
|
|
2
|
|
3
|
my ($save_rec) = @_; |
608
|
|
|
|
|
|
|
|
609
|
2
|
|
|
|
|
4
|
my $rrest = $save_rec->{'values'}[2]; |
610
|
2
|
|
|
|
|
5
|
my $fixed = $save_rec->fix_hash_to_string(); |
611
|
2
|
|
|
|
|
7
|
return $fixed.$$rrest; |
612
|
|
|
|
|
|
|
} |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
#################################################################### |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
# We know how to produce a fixed string from the hashed fixed info. |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
#################################################################### |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
sub fix_hash_to_string { |
621
|
2
|
|
|
2
|
|
4
|
my ($save_rec) = @_; |
622
|
|
|
|
|
|
|
|
623
|
2
|
|
|
|
|
3
|
my $rhfixed = $save_rec->{'values'}[0]; |
624
|
2
|
|
|
|
|
4
|
my $template = $save_rec->{'opt'}{'template'}; |
625
|
2
|
50
|
|
|
|
6
|
$rhfixed->{"ZZ"} = '' unless defined $rhfixed->{"ZZ"}; |
626
|
2
|
|
|
|
|
5
|
my @values = (); |
627
|
|
|
|
|
|
|
# ?? do we want to use an array slice: |
628
|
|
|
|
|
|
|
# my %fixed = %$rhfixed; |
629
|
|
|
|
|
|
|
# my @names = @{$save_rec->{opt}{names}} |
630
|
|
|
|
|
|
|
# @values = @fixed{@names}?? |
631
|
|
|
|
|
|
|
# |
632
|
2
|
|
|
|
|
3
|
for (@{$save_rec->{'opt'}{'names'}}) { |
|
2
|
|
|
|
|
6
|
|
633
|
6
|
|
|
|
|
18
|
push @values, $rhfixed->{$_}; |
634
|
|
|
|
|
|
|
} |
635
|
2
|
|
|
|
|
14
|
return pack($template,@values); |
636
|
|
|
|
|
|
|
} |
637
|
|
|
|
|
|
|
1; # so the require or use succeeds |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
__END__ |