| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Clarion; |
|
2
|
|
|
|
|
|
|
|
|
3
|
4
|
|
|
4
|
|
106318
|
use 5.006; |
|
|
4
|
|
|
|
|
15
|
|
|
|
4
|
|
|
|
|
145
|
|
|
4
|
4
|
|
|
4
|
|
25
|
use strict; |
|
|
4
|
|
|
|
|
6
|
|
|
|
4
|
|
|
|
|
133
|
|
|
5
|
4
|
|
|
4
|
|
20
|
use warnings; |
|
|
4
|
|
|
|
|
12
|
|
|
|
4
|
|
|
|
|
129
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
4
|
|
|
4
|
|
4479
|
use FileHandle; |
|
|
4
|
|
|
|
|
59548
|
|
|
|
4
|
|
|
|
|
23
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our $VERSION = '1.02'; |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 NAME |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
Clarion - Perl module for reading CLARION 2.1 data files |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
This is a perl module to access CLARION 2.1 files. |
|
18
|
|
|
|
|
|
|
At the moment only read access to the files is implemented. |
|
19
|
|
|
|
|
|
|
"Encrypted" (owned) files are processed transparently, |
|
20
|
|
|
|
|
|
|
there is no need to specify the password of a file. |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
use Clarion; |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
my $dbh=new Clarion "customer.dat"; |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
print $dbh->file_struct; |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
for ( 1 .. $dbh->last_record ) { |
|
31
|
|
|
|
|
|
|
my $r=$dbh->get_record_hash($_); |
|
32
|
|
|
|
|
|
|
next if $r->{_DELETED}; |
|
33
|
|
|
|
|
|
|
print $r->{CODE}." ".$r->{NAME}." ".$r->{PHONE}."\n"; |
|
34
|
|
|
|
|
|
|
} |
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
$dbh->close(); |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=head1 METHODS |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=over 4 |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=cut |
|
43
|
|
|
|
|
|
|
|
|
44
|
0
|
|
|
0
|
0
|
0
|
sub FILLOCK { 0x01; } # file is locked |
|
45
|
16
|
|
|
16
|
0
|
50
|
sub FILOWN { 0x02; } # file is owned |
|
46
|
48
|
|
|
48
|
0
|
122
|
sub FILCRYP { 0x04; } # records are encrypted |
|
47
|
13
|
|
|
13
|
0
|
56
|
sub FILMEMO { 0x08; } # memo file exists |
|
48
|
0
|
|
|
0
|
0
|
0
|
sub FILCOMP { 0x10; } # file is compressed |
|
49
|
6
|
|
|
6
|
0
|
18
|
sub FILRCLM { 0x20; } # reclaim deleted records |
|
50
|
6
|
|
|
6
|
0
|
15
|
sub FILREAD { 0x40; } # file is read only |
|
51
|
6
|
|
|
6
|
0
|
27
|
sub FILCRET { 0x80; } # file may be created |
|
52
|
|
|
|
|
|
|
|
|
53
|
0
|
|
|
0
|
0
|
0
|
sub RECNEW { 0x01; } # bit 0 - new record |
|
54
|
0
|
|
|
0
|
0
|
0
|
sub RECOLD { 0x02; } # bit 1 - old record |
|
55
|
0
|
|
|
0
|
0
|
0
|
sub RECREV { 0x04; } # bit 2 - revised record |
|
56
|
49
|
|
|
49
|
0
|
83
|
sub RECDEL { 0x10; } # bit 4 - deleted record |
|
57
|
0
|
|
|
0
|
0
|
0
|
sub RECHLD { 0x40; } # bit 6 - record held |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=item $h=new Clarion ["file.dat" [, 1]] |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
Create object for reading Clarion file. If file name is specified then |
|
62
|
|
|
|
|
|
|
associate the DAT file with the object. "Encrypted" files are processed |
|
63
|
|
|
|
|
|
|
transparently, you do not need to specify the password of a file. |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
If the third argument (skipMemo) specified, memo field will not be |
|
66
|
|
|
|
|
|
|
processed at all. |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=cut |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
sub new { |
|
71
|
11
|
|
|
11
|
0
|
281
|
my $self={}; |
|
72
|
11
|
|
|
|
|
24
|
bless $self, shift; |
|
73
|
|
|
|
|
|
|
|
|
74
|
11
|
100
|
|
|
|
97
|
$self->open(@_) if @_; |
|
75
|
11
|
|
|
|
|
32
|
return $self; |
|
76
|
|
|
|
|
|
|
} |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
=item $h->close |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
Close all open file handles. |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
=cut |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
sub close { |
|
85
|
17
|
|
|
17
|
1
|
2931
|
my $self=shift; |
|
86
|
17
|
100
|
|
|
|
55
|
if($self->{fh}) { |
|
87
|
10
|
|
|
|
|
103
|
$self->{fh}->close(); |
|
88
|
10
|
|
|
|
|
199
|
delete $self->{fh}; |
|
89
|
|
|
|
|
|
|
} |
|
90
|
17
|
100
|
|
|
|
258
|
if($self->{fhMemo}) { |
|
91
|
4
|
|
|
|
|
15
|
$self->{fhMemo}->close(); |
|
92
|
4
|
|
|
|
|
288
|
delete $self->{fhMemo}; |
|
93
|
|
|
|
|
|
|
} |
|
94
|
|
|
|
|
|
|
} |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
sub DESTROY { |
|
97
|
11
|
|
|
11
|
|
3101
|
shift->close; |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=item $h->open('file.dat' [, 1]) |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
Read and parse header of Clarion file. |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
If second argument given, skip processing of memo field. |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
=cut |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
sub open { |
|
109
|
10
|
|
|
10
|
1
|
22
|
my ($self, $fileName, $skipMemo)=@_; |
|
110
|
|
|
|
|
|
|
|
|
111
|
10
|
50
|
|
|
|
66
|
my $fh=new FileHandle $fileName |
|
112
|
|
|
|
|
|
|
or die("Cannot open '$fileName': $!\n"); |
|
113
|
10
|
|
|
|
|
1075
|
binmode($fh); |
|
114
|
10
|
|
|
|
|
38
|
$self->{fh}=$fh; |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# Read file signature & header |
|
117
|
10
|
|
|
|
|
37
|
my ($filesig, $sfatr)=unpack('a2 S', $self->readData(4, 'header')); |
|
118
|
10
|
50
|
|
|
|
33
|
die "Not a Clarion 2.1 file '$fileName'!\n" if $filesig ne 'C3'; |
|
119
|
10
|
|
|
|
|
22
|
$self->{name}=$fileName; |
|
120
|
10
|
|
|
|
|
20
|
$self->{sfatr}=$sfatr; |
|
121
|
10
|
|
|
|
|
25
|
my $header=$self->readData(2*9+31+9*4-4, 'header'); |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
# File is encrypted? |
|
124
|
10
|
100
|
|
|
|
138
|
if($sfatr & FILOWN) { |
|
125
|
|
|
|
|
|
|
# Looking for key; 4 variants exist |
|
126
|
7
|
|
|
|
|
29
|
$self->{Key}=[unpack('x8 CX2C', $header)]; # numdels, high word |
|
127
|
|
|
|
|
|
|
# $self->{Key}=[unpack('x68 CX2C', $header)]; # reserved, low word |
|
128
|
|
|
|
|
|
|
# $self->{Key}=[unpack('x70 CX2C', $header)]; # reserved, high word |
|
129
|
|
|
|
|
|
|
# $self->{Key}=[unpack('x68 CC', $header)]; # reserved, middle word |
|
130
|
7
|
|
|
|
|
24
|
$header=$self->decrypt($header); |
|
131
|
|
|
|
|
|
|
} |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# Parse header itself |
|
134
|
10
|
|
|
|
|
111
|
my @X=unpack('C L L S S S S L L L L A12 A12 A3 A3 S S L L L S', $header); |
|
135
|
10
|
|
|
|
|
35
|
foreach my $f(qw(numbkeys numrecs numdels numflds numpics nummars reclen offset |
|
136
|
|
|
|
|
|
|
logeof logbof freerec recname memnam filpre recpre memolen memowid |
|
137
|
|
|
|
|
|
|
reserved chgtime chgdate reserved2)) { |
|
138
|
210
|
|
|
|
|
450
|
$self->{header}{$f}=shift @X; |
|
139
|
|
|
|
|
|
|
} |
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
# Read field descriptions & build record template |
|
142
|
10
|
|
|
|
|
30
|
$self->{fields}=[]; |
|
143
|
10
|
|
|
|
|
20
|
$self->{decimal_fields}=[]; |
|
144
|
10
|
|
|
|
|
31
|
$self->{record}{unpack}=''; |
|
145
|
10
|
|
|
|
|
33
|
$self->{record}{No}=0; |
|
146
|
10
|
|
|
|
|
46
|
for(my $i=0; $i<$self->{header}{numflds}; $i++) { |
|
147
|
74
|
|
|
|
|
178
|
@X=unpack('C A16 S S C C S S', $self->readData(3+16+2*4, 'field descriptor', 1)); |
|
148
|
74
|
|
|
|
|
288
|
my $fd={}; |
|
149
|
74
|
|
|
|
|
315
|
foreach my $f(qw(fldtype fldname foffset length decsig decdec arrnum picnum)) { |
|
150
|
592
|
|
|
|
|
1120
|
$fd->{$f}=shift @X; |
|
151
|
|
|
|
|
|
|
} |
|
152
|
74
|
|
|
|
|
109
|
push @{$self->{fields}}, $fd; |
|
|
74
|
|
|
|
|
152
|
|
|
153
|
74
|
100
|
|
|
|
181
|
push @{$self->{decimal_fields}}, $fd if 8==$fd->{fldtype}; |
|
|
17
|
|
|
|
|
32
|
|
|
154
|
74
|
|
|
|
|
107
|
my $n=$fd->{fldname}; |
|
155
|
74
|
|
|
|
|
341
|
$n=~s/^.+?://; |
|
156
|
74
|
|
|
|
|
160
|
$fd->{Name}=$n; |
|
157
|
74
|
|
|
|
|
187
|
$self->{field_map}{$n}=$fd->{No}=$i; |
|
158
|
74
|
|
|
|
|
135
|
my $c=qw(a l d A A C s G)[$fd->{fldtype}]; |
|
159
|
74
|
100
|
|
|
|
140
|
$c='a' unless $c; |
|
160
|
74
|
100
|
|
|
|
375
|
$c.=$fd->{length} if uc($c)eq 'A'; |
|
161
|
74
|
100
|
|
|
|
180
|
$c='a'.$fd->{length}.' X'.$fd->{length}.' ' if 'G' eq $c; |
|
162
|
74
|
|
|
|
|
297
|
$self->{record}{unpack}.=$c.' '; |
|
163
|
|
|
|
|
|
|
} |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
# Read key descriptions |
|
166
|
10
|
|
|
|
|
41
|
$self->{keys}=[]; |
|
167
|
10
|
|
|
|
|
44
|
for(my $i=$self->{header}{numbkeys}; $i>0; $i--) { |
|
168
|
21
|
|
|
|
|
50
|
@X=unpack('C A16 C C', $self->readData(1+16+1+1, 'key descriptor', 1)); |
|
169
|
21
|
|
|
|
|
45
|
my $kd={}; |
|
170
|
21
|
|
|
|
|
33
|
foreach my $f(qw(numcomps keynams comptype complen)) { |
|
171
|
84
|
|
|
|
|
172
|
$kd->{$f}=shift @X; |
|
172
|
|
|
|
|
|
|
} |
|
173
|
21
|
|
|
|
|
31
|
push @{$self->{keys}}, $kd; |
|
|
21
|
|
|
|
|
41
|
|
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
# Read key parts |
|
176
|
21
|
|
|
|
|
38
|
$kd->{parts}=[]; |
|
177
|
21
|
|
|
|
|
61
|
for(my $j=$kd->{numcomps}; $j>0; $j--) { |
|
178
|
28
|
|
|
|
|
60
|
@X=unpack('C S S C', $self->readData(1+2+2+1, 'key element', 1)); |
|
179
|
28
|
|
|
|
|
58
|
my $kp={}; |
|
180
|
28
|
|
|
|
|
41
|
foreach my $f(qw(fldtype fldnum elmoff elmlen)) { |
|
181
|
112
|
|
|
|
|
226
|
$kp->{$f}=shift @X; |
|
182
|
|
|
|
|
|
|
} |
|
183
|
28
|
|
|
|
|
39
|
push @{$kd->{parts}}, $kp; |
|
|
28
|
|
|
|
|
122
|
|
|
184
|
|
|
|
|
|
|
} |
|
185
|
|
|
|
|
|
|
} |
|
186
|
|
|
|
|
|
|
|
|
187
|
10
|
100
|
100
|
|
|
46
|
return if defined($skipMemo) or !($sfatr & FILMEMO); |
|
188
|
|
|
|
|
|
|
# Reading memo... |
|
189
|
4
|
|
|
|
|
24
|
$fileName=~s/\.[^\.\\\/]*$//; |
|
190
|
4
|
|
|
|
|
8
|
$fileName.='.mem'; |
|
191
|
4
|
50
|
|
|
|
96
|
$fh=new FileHandle $fileName |
|
192
|
|
|
|
|
|
|
or die("Cannot open memo '$fileName': $!\n"); |
|
193
|
4
|
|
|
|
|
392
|
binmode($fh); |
|
194
|
4
|
|
|
|
|
9
|
$self->{fhMemo}=$fh; |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
# Read memo file signature |
|
197
|
4
|
|
|
|
|
76
|
read($fh, $filesig, 2); |
|
198
|
4
|
50
|
|
|
|
18
|
die "Not a Clarion 2.1 memo '$fileName'!\n" if $filesig ne 'M3'; |
|
199
|
4
|
|
|
|
|
43
|
my $m={ |
|
200
|
|
|
|
|
|
|
isMemo=>1, |
|
201
|
4
|
|
|
|
|
12
|
No=>scalar @{$self->{fields}}, |
|
202
|
|
|
|
|
|
|
Name=>$self->{header}{memnam}, |
|
203
|
|
|
|
|
|
|
fldname=>$self->{header}{memnam}.':'.$self->{header}{filpre}, |
|
204
|
|
|
|
|
|
|
length=>$self->{header}{memolen}, |
|
205
|
|
|
|
|
|
|
}; |
|
206
|
4
|
|
|
|
|
7
|
push @{$self->{fields}}, $m; |
|
|
4
|
|
|
|
|
11
|
|
|
207
|
4
|
|
|
|
|
17
|
$self->{field_map}{$m->{Name}}=$m->{No}; |
|
208
|
|
|
|
|
|
|
} |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
=item $n=$dbh->last_record; |
|
211
|
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
Returns the number of records in the database file. |
|
213
|
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
=cut |
|
215
|
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sub last_record { |
|
217
|
3
|
|
|
3
|
1
|
1329
|
return shift->{header}{numrecs}; |
|
218
|
|
|
|
|
|
|
} |
|
219
|
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
=item $n=$dbh->bof; |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
Returns the physical number of first logical record. |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=cut |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
sub bof { |
|
227
|
0
|
|
|
0
|
1
|
0
|
return shift->{header}{logbof}; |
|
228
|
|
|
|
|
|
|
} |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=item $n=$dbh->eof; |
|
231
|
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
Returns the physical number of last logical record. |
|
233
|
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=cut |
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
sub eof { |
|
237
|
0
|
|
|
0
|
1
|
0
|
return shift->{header}{logeof}; |
|
238
|
|
|
|
|
|
|
} |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
# Internal function to read a record |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
sub readRecord { |
|
243
|
38
|
|
|
38
|
0
|
42
|
my ($self, $n)=@_; |
|
244
|
38
|
|
66
|
|
|
108
|
$n||=$self->{record}{No}+1; |
|
245
|
38
|
100
|
66
|
|
|
177
|
return if $n<1 or $n>$self->{header}{numrecs}; |
|
246
|
35
|
|
|
|
|
94
|
$self->{record}{data}=[]; |
|
247
|
35
|
|
|
|
|
71
|
$self->{record}{No}=$n; |
|
248
|
35
|
|
|
|
|
295
|
seek($self->{fh}, $self->{header}{offset}+$self->{header}{reclen}*($n-1), 0); |
|
249
|
|
|
|
|
|
|
|
|
250
|
35
|
|
|
|
|
76
|
($self->{record}{rhd}, $self->{record}{rptr})=unpack('C L', $self->readData(5, 'record')); |
|
251
|
35
|
|
|
|
|
114
|
my @Data=unpack($self->{record}{unpack}, |
|
252
|
|
|
|
|
|
|
$self->readData($self->{header}{reclen}-5, 'record', $self->{sfatr} & FILCRYP)); |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
# Convert decimal() fields, if any |
|
255
|
35
|
|
|
|
|
58
|
foreach my $f(@{$self->{decimal_fields}}) { |
|
|
35
|
|
|
|
|
62
|
|
|
256
|
49
|
|
|
|
|
121
|
$Data[$f->{No}]=unpackBCD($Data[$f->{No}], $f->{decsig}, $f->{decdec}); |
|
257
|
|
|
|
|
|
|
} |
|
258
|
35
|
|
|
|
|
74
|
$self->{record}{data}=\@Data; |
|
259
|
|
|
|
|
|
|
|
|
260
|
35
|
100
|
|
|
|
101
|
return 1 unless $self->{fhMemo}; |
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
# Read memo... |
|
263
|
14
|
|
|
|
|
16
|
my $memo; |
|
264
|
14
|
50
|
|
|
|
29
|
$n=($self->{record}{rhd} & RECDEL)? 0 : $self->{record}{rptr}; |
|
265
|
14
|
|
|
|
|
41
|
while($n) { |
|
266
|
7
|
|
|
|
|
54
|
seek($self->{fhMemo}, ($n-1)*256+6, 0); |
|
267
|
7
|
|
|
|
|
25
|
$n=unpack('L', $self->readMemo(4)); |
|
268
|
7
|
|
|
|
|
18
|
my $m=$self->readMemo(252); |
|
269
|
7
|
100
|
|
|
|
19
|
$m=$self->decrypt($m) if $self->{sfatr} & FILCRYP; |
|
270
|
7
|
50
|
|
|
|
20
|
$memo='' unless defined($memo); |
|
271
|
7
|
|
|
|
|
21
|
$memo.=$m; |
|
272
|
|
|
|
|
|
|
} |
|
273
|
14
|
100
|
|
|
|
104
|
$memo=~s/( +|\00+)\z// if $memo; |
|
274
|
14
|
|
|
|
|
26
|
push @Data, $memo; |
|
275
|
|
|
|
|
|
|
|
|
276
|
14
|
|
|
|
|
57
|
return 1; |
|
277
|
|
|
|
|
|
|
} |
|
278
|
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
=item @r=$dbh->get_record([ $n [, @fields]]); |
|
280
|
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
Returns a list of data (field values) from the specified record. |
|
282
|
|
|
|
|
|
|
The first parameter in the call is the number of the physical |
|
283
|
|
|
|
|
|
|
record. If you do not specify any other parameters, all fields are |
|
284
|
|
|
|
|
|
|
returned in the same order as they appear in the file. You can also |
|
285
|
|
|
|
|
|
|
put list of field names after the record number and then only those |
|
286
|
|
|
|
|
|
|
will be returned. The first value of the returned list is always the |
|
287
|
|
|
|
|
|
|
logical (0 or not 0) value saying whether the record is deleted or not. |
|
288
|
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
If first argument is omited (or undef) then reads next record from file. |
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
=cut |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
sub get_record { |
|
294
|
36
|
|
|
36
|
1
|
2634
|
my ($self, $n, @fields)=@_; |
|
295
|
|
|
|
|
|
|
|
|
296
|
36
|
100
|
|
|
|
64
|
$self->readRecord($n) or return; |
|
297
|
|
|
|
|
|
|
|
|
298
|
33
|
50
|
|
|
|
105
|
return ($self->{record}{rhd} & RECDEL, @{$self->{record}{data}}) |
|
|
33
|
|
|
|
|
155
|
|
|
299
|
|
|
|
|
|
|
unless @fields; |
|
300
|
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
return |
|
302
|
0
|
|
|
|
|
0
|
$self->{record}{rhd} & RECDEL, |
|
303
|
|
|
|
|
|
|
map($self->{record}{data}[$self->{field_map}{$_}], @fields); |
|
304
|
|
|
|
|
|
|
} |
|
305
|
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
=item $r=$dbh->get_record_hash([ $n [, @fields]]); |
|
307
|
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
Returns reference to hash containing field values indexed by field names. |
|
309
|
|
|
|
|
|
|
The name of the deleted flag is C<_DELETED>. The first parameter in the call |
|
310
|
|
|
|
|
|
|
is the number of the physical record (can be omited to read next record if |
|
311
|
|
|
|
|
|
|
avaialable). If you do not specify any other parameters, all fields are returned. |
|
312
|
|
|
|
|
|
|
You can also put list of field names after the record number and then only those |
|
313
|
|
|
|
|
|
|
will be returned. |
|
314
|
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
=cut |
|
316
|
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
sub get_record_hash { |
|
318
|
2
|
|
|
2
|
1
|
8
|
my ($self, $n, @fields)=@_; |
|
319
|
|
|
|
|
|
|
|
|
320
|
2
|
50
|
|
|
|
8
|
$self->readRecord($n) or return; |
|
321
|
|
|
|
|
|
|
|
|
322
|
2
|
|
|
|
|
48
|
my %res= @fields ? |
|
323
|
|
|
|
|
|
|
map(($_, $self->{record}{data}[$self->{field_map}{$_}]), @fields) : |
|
324
|
2
|
50
|
|
|
|
5
|
map(($_->{Name}, $self->{record}{data}[$_->{No}]), @{$self->{fields}}); |
|
325
|
|
|
|
|
|
|
|
|
326
|
2
|
|
|
|
|
10
|
$res{_DELETED}=$self->{record}{rhd} & RECDEL; |
|
327
|
2
|
|
|
|
|
26
|
return \%res; |
|
328
|
|
|
|
|
|
|
} |
|
329
|
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
=item $struct = $dbh->file_struct; |
|
331
|
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
This returns CLARION file structure as a string. |
|
333
|
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
=cut |
|
335
|
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
sub file_struct { |
|
337
|
6
|
|
|
6
|
1
|
1029
|
my $self=shift; |
|
338
|
|
|
|
|
|
|
|
|
339
|
6
|
|
|
|
|
12
|
my $res=$self->{name}; |
|
340
|
6
|
|
|
|
|
25
|
$res=~s/\.dat$//i; |
|
341
|
6
|
|
|
|
|
20
|
$res=~s/^.*[\/\\]//; |
|
342
|
6
|
|
|
|
|
11
|
$res=uc($res); |
|
343
|
|
|
|
|
|
|
|
|
344
|
6
|
|
|
|
|
23
|
$res.="\tFILE,NAME('$res'),PRE('$self->{header}{filpre}')"; |
|
345
|
|
|
|
|
|
|
|
|
346
|
6
|
100
|
|
|
|
16
|
$res.=",OWNER('???')" if $self->{sfatr} & FILOWN; |
|
347
|
6
|
100
|
|
|
|
18
|
$res.=",ENCRYPT" if $self->{sfatr} & FILCRYP; |
|
348
|
6
|
100
|
|
|
|
15
|
$res.=",CREATE" if $self->{sfatr} & FILCRET; |
|
349
|
6
|
50
|
|
|
|
55
|
$res.=",RECLAIM" if $self->{sfatr} & FILRCLM; |
|
350
|
6
|
100
|
|
|
|
24
|
$res.=",PROTECT" if $self->{sfatr} & FILREAD; |
|
351
|
6
|
100
|
|
|
|
14
|
$res.="\n$self->{header}{memnam}\tMEMO($self->{header}{memolen})" |
|
352
|
|
|
|
|
|
|
if $self->{sfatr} & FILMEMO; |
|
353
|
|
|
|
|
|
|
|
|
354
|
6
|
|
|
|
|
15
|
$res.="\n$self->{header}{recname}\tRECORD\n"; |
|
355
|
|
|
|
|
|
|
|
|
356
|
6
|
|
|
|
|
8
|
for my $f(@{$self->{fields}}) { |
|
|
6
|
|
|
|
|
14
|
|
|
357
|
45
|
100
|
|
|
|
85
|
next if $f->{isMemo}; |
|
358
|
42
|
|
|
|
|
59
|
$res.=$f->{Name}."\t"; |
|
359
|
42
|
|
|
|
|
52
|
my $t=qw(? LONG REAL . . BYTE SHORT . DECIMAL)[$f->{fldtype}]; |
|
360
|
42
|
50
|
33
|
|
|
177
|
if(!$t or '?' eq $t) { |
|
361
|
0
|
|
|
|
|
0
|
$t='UNKNOWN TYPE'; |
|
362
|
0
|
|
|
|
|
0
|
$res.='!'; |
|
363
|
|
|
|
|
|
|
} |
|
364
|
42
|
100
|
|
|
|
63
|
if('.' eq $t){ |
|
365
|
9
|
|
|
|
|
14
|
$res.="STRING($f->{length})"; |
|
366
|
9
|
100
|
|
|
|
22
|
$res.="\t!GROUP" if 7==$f->{fldtype}; |
|
367
|
|
|
|
|
|
|
} else { |
|
368
|
33
|
|
|
|
|
34
|
$res.=$t; |
|
369
|
33
|
100
|
|
|
|
81
|
$res.="(".($f->{decsig}+$f->{decdec}).",$f->{decdec})" |
|
370
|
|
|
|
|
|
|
if 8==$f->{fldtype}; |
|
371
|
|
|
|
|
|
|
} |
|
372
|
42
|
|
|
|
|
55
|
$res.="\n"; |
|
373
|
|
|
|
|
|
|
} |
|
374
|
6
|
|
|
|
|
41
|
return $res."\t. .\n"; |
|
375
|
|
|
|
|
|
|
} |
|
376
|
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
# Clarion "decryption" |
|
378
|
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
sub decrypt { |
|
380
|
146
|
|
|
146
|
0
|
230
|
my ($self, $str)=@_; |
|
381
|
146
|
100
|
|
|
|
469
|
return $str unless defined($self->{Key}); |
|
382
|
110
|
|
|
|
|
132
|
my $res=''; |
|
383
|
110
|
|
|
|
|
112
|
do{ |
|
384
|
1858
|
|
|
|
|
2718
|
my($c1, $c2)=unpack('C2', $str); |
|
385
|
1858
|
100
|
|
|
|
3756
|
defined($c2) or return $res.$str; |
|
386
|
1748
|
|
|
|
|
3485
|
$res.=pack('C2', $c1^$self->{Key}[0], $c2^$self->{Key}[1]); |
|
387
|
1748
|
|
|
|
|
4187
|
$str=unpack('x2 a*', $str); |
|
388
|
|
|
|
|
|
|
}while(1); |
|
389
|
|
|
|
|
|
|
} |
|
390
|
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
sub readData { |
|
392
|
213
|
|
|
213
|
0
|
330
|
my ($self, $len, $what, $decrypt)=@_; |
|
393
|
213
|
|
50
|
|
|
1037
|
my $rc=read($self->{fh}, my $buf, $len)||0; |
|
394
|
213
|
50
|
|
|
|
481
|
die "Read error Clarion file ($what) ($rc bytes read instead of $len)!\n" |
|
395
|
|
|
|
|
|
|
if $rc!=$len; |
|
396
|
213
|
100
|
|
|
|
717
|
return $decrypt? $self->decrypt($buf) : $buf; |
|
397
|
|
|
|
|
|
|
} |
|
398
|
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
sub readMemo { |
|
400
|
14
|
|
|
14
|
0
|
18
|
my ($self, $len)=@_; |
|
401
|
14
|
|
50
|
|
|
144
|
my $rc=read($self->{fhMemo}, my $buf, $len)||0; |
|
402
|
14
|
50
|
|
|
|
30
|
die "Read error Clarion memo ($rc bytes read instead of $len)!\n" |
|
403
|
|
|
|
|
|
|
if $rc!=$len; |
|
404
|
14
|
|
|
|
|
31
|
return $buf; |
|
405
|
|
|
|
|
|
|
} |
|
406
|
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
# Convert BCD to string |
|
408
|
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
sub unpackBCD { |
|
410
|
49
|
|
|
49
|
0
|
70
|
my ($bcd, $decsig, $decdec)=@_; |
|
411
|
49
|
|
|
|
|
94
|
$bcd=unpack('H*', $bcd); |
|
412
|
|
|
|
|
|
|
|
|
413
|
49
|
100
|
|
|
|
107
|
my $sign=substr($bcd, 0, 1) eq '0' ? '' : '-'; |
|
414
|
49
|
|
|
|
|
63
|
$bcd=substr($bcd, 1); |
|
415
|
49
|
50
|
|
|
|
112
|
$bcd=~s/\D/9/g and |
|
416
|
|
|
|
|
|
|
warn "Incorrect DECIMAL value!\n"; |
|
417
|
|
|
|
|
|
|
|
|
418
|
49
|
|
|
|
|
66
|
my $sig=substr($bcd, 0, $decsig); |
|
419
|
49
|
|
|
|
|
122
|
$sig=~s/^0+//; |
|
420
|
49
|
100
|
|
|
|
84
|
$sig='0' if !length($sig); |
|
421
|
|
|
|
|
|
|
|
|
422
|
49
|
|
|
|
|
62
|
my $dec=substr($bcd, $decsig, $decdec); |
|
423
|
49
|
|
|
|
|
85
|
$dec=~s/0+$//; |
|
424
|
49
|
100
|
|
|
|
101
|
$sig.='.' if length($dec); |
|
425
|
|
|
|
|
|
|
|
|
426
|
49
|
|
|
|
|
178
|
return $sign.$sig.$dec; |
|
427
|
|
|
|
|
|
|
} |
|
428
|
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
1; |
|
430
|
|
|
|
|
|
|
__END__ |