File Coverage

MARC.pm
Criterion Covered Total %
statement 1318 1626 81.0
branch 397 650 61.0
condition 118 216 54.6
subroutine 91 118 77.1
pod 34 40 85.0
total 1958 2650 73.8


line stmt bran cond sub pod time code
1             package MARC;
2              
3 5     5   1954836 use Carp;
  5         16  
  5         642  
4 5     5   30 use strict;
  5         14  
  5         191  
5 5     5   43 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $DEBUG $TEST);
  5         12  
  5         2454  
6              
7             $VERSION = '1.07';
8             $MARC::DEBUG = 0;
9             $MARC::TEST = 0;
10              
11             require Exporter;
12             require 5.004;
13              
14             @ISA = qw(Exporter);
15             @EXPORT= qw();
16             @EXPORT_OK= qw();
17              
18             #### Not using these yet
19              
20             #### %EXPORT_TAGS = (USTEXT => [qw( marc2ustext )]);
21             #### Exporter::export_ok_tags('USTEXT');
22             #### $EXPORT_TAGS{ALL} = \@EXPORT_OK;
23              
24              
25             # Preloaded methods go here.
26              
27             sub mycarp { # rec
28 4 50   4 0 14 Carp::carp (@_) unless $MARC::TEST;
29             }
30              
31             ####################################################################
32             # This is the constructor method that creates the MARC object. It #
33             # will call the appropriate read using the file and format #
34             # parameters that are passed. #
35             ####################################################################
36             sub new { # rec
37 5     5 1 3021 my $proto = shift;
38 5   33     46 my $class = ref($proto) || $proto;
39 5         13 my $file = shift;
40 5         13 my $marc = [];
41 5         14 my $totalrecord;
42 5         26 $marc->[0]{'increment'}=-1; #store the default increment in the object
43 5         9 my $proto_rec;
44             # print STDERR "foo\n";
45             {
46             # We are going to look for related classes in Perl's
47             # symbol table. This is a little tricky.
48             # Shoot me.
49            
50 5     5   34 no strict 'refs';
  5         9  
  5         44943  
  5         11  
51             # Next, we set up a symbolic reference.
52 5         11 my $g = $ {$class.'::Rec::VERSION'}; # space for emacs.
  5         38  
53             # That was a sample of Perl reflection. Yup, what Smalltalk
54             # does with Class and MetaClass, Perl does with strings.
55             # Not much structure, but also not much fuss.
56              
57 5 100       23 my $rec_class = $class."::Rec" if $g;
58             # Now we will use the related Rec class if it exists.
59 5   100     207 $rec_class ||= "MARC::Rec";
60            
61 5         55 $proto_rec = $rec_class->new();
62             }
63              
64 5         102 $marc->[0]{'proto_rec'}=$proto_rec; # Used for future manipulations.
65 5         15 bless ($marc, $class);
66             # bless early so _readxxx can use methods
67             #if file isn't defined then just return the empty MARC object
68 5 50       20 if ($file) {
69 5 50       76 unless (-e $file) {mycarp "File $file doesn't exist"; return}
  0         0  
  0         0  
70             #if the file doesn't exist return an error
71 5   100     38 my $format = shift || "usmarc";
72             # $format defaults to USMARC if undefined
73 5 50       308 open(*file, $file) or mycarp "Open Error: $file, $!";
74 5         19 binmode *file;
75 5         34 $marc->[0]{'handle'}=\*file;
76 5         17 $proto_rec->{'handle'} = $marc->[0]{'handle'};
77 5         19 $proto_rec->{'format'} = lc $format;
78 5 100       48 if ($format =~ /usmarc$/io) {
    50          
    50          
    0          
79 4         11 $marc->[0]{'format'}='usmarc';
80 4         35 $totalrecord = _readmarc($marc);
81 4 50       74 close *file or mycarp "Close Error: $file, $!";
82             }
83             elsif ($format =~ /unimarc$/io) {
84 0         0 $marc->[0]{'format'}='unimarc';
85 0         0 $totalrecord = _readmarc($marc);
86 0 0       0 close *file or mycarp "Close Error: $file, $!";
87             }
88             elsif ($format =~ /marcmaker$/io) {
89 1         3 $marc->[0]{'lineterm'}="\015\012"; # MS-DOS default for MARCMaker
90 1         5 $totalrecord = _readmarcmaker($marc);
91 1 50       46 close *file or mycarp "Close Error: $file, $!";
92             }
93             elsif ($format =~ /xml/oi) {
94 0         0 mycarp "XML formats are now handled by MARC::XML";
95 0         0 return;
96             }
97             else {
98 0         0 mycarp "I don't recognize format $format";
99 0         0 return;
100             }
101             }
102 5 50       120 print "read in $totalrecord records\n" if $MARC::DEBUG;
103 5         49 return $marc;
104             }
105             ####################################################################
106              
107             # clone returns a new MARC object with copies of the data.
108             # Admin information remains linked to original.
109              
110             ####################################################################
111              
112             sub clone {
113 0     0 0 0 my $marc = shift;
114 0   0     0 my $class = shift || ref $marc;
115 0         0 my $ans = $marc->new;
116 0         0 bless $ans, $class;
117 0         0 $ans->[0] = $marc->[0];
118 0         0 foreach my $i (1..$#$marc) {
119 0         0 my $rec = $marc->[$i];
120              
121 0         0 my $newrec = $rec->clone();
122 0         0 bless $newrec, $class."::Rec";
123 0         0 push @$ans, $newrec;
124             }
125 0         0 return $ans;
126             }
127              
128             ###################################################################
129             # _readmarc() reads in a MARC file into the $marc object #
130             ###################################################################
131             sub _readmarc { # also rec
132 8     8   16 my $marc = shift;
133 8         17 my $handle = $marc->[0]{'handle'};
134 8         14 my $proto_rec = $marc->[0]{'proto_rec'};
135 8         15 my $increment = $marc->[0]{'increment'}; #pick out increment from the object
136 8         12 my $recordcount = 0;
137              
138 8   100     42 while ($increment==-1 || $recordcount<$increment) {
139 17         53 my ($rec,$status)=$proto_rec->_readmarc();
140 17 100       49 last unless $status;
141 12 100       33 if ($status == -1) {
142 1         2 mycarp "Invalid record, size does not match leader";
143 1 50       4 return unless $recordcount; # undef if first
144 0         0 return -$recordcount; # if some are valid
145             }
146 11 100       30 if ($status == -2) {
147 1         4 mycarp "Invalid record, leader size not numeric";
148 1 50       3 return unless $recordcount; # undef if first
149 1         4 return -$recordcount; # if some are valid
150             }
151 10         24 push @$marc, $rec;
152 10         40 $recordcount++;
153             } #end processing this record
154 6         19 return $recordcount;
155             }
156              
157             ###################################################################
158             # readmarcmaker() reads a marcmaker file into the MARC object #
159             ###################################################################
160             sub _readmarcmaker { # rec
161 5     5   10 my $marc = shift;
162 5         10 my $handle = $marc->[0]{'handle'};
163 5         7 my $proto_rec = $marc->[0]{'proto_rec'};
164 5         10 my $increment = $marc->[0]{'increment'}; #pick out increment from the object
165 5 100       17 unless (exists $marc->[0]{'makerchar'}) {
166 1         5 $marc->[0]{'makerchar'} = usmarc_default(); # hash ref
167 1         3 $proto_rec->{'makerchar'} = $marc->[0]{'makerchar'};
168             }
169 5         6 my $recordcount = 0;
170              
171 5   100     26 while ($increment==-1 or $recordcount<$increment) {
172 15         45 my ($rec,$status) = $proto_rec->_readmarcmaker();
173 15 100       40 last unless $status;
174 14 100       30 if ($status == -1) {
175 2         6 mycarp 'Invalid record, prefix "=LDR " not found';
176 2 100       7 return unless $recordcount; # undef if first
177 1         4 return -$recordcount; # if some are valid
178             }
179 12         60 push @$marc, $rec;
180 12         43 $recordcount++;
181             } #end reading this record
182 3         9 return $recordcount;
183             }
184              
185             sub _maker2char { # rec
186 329     329   557 return MARC::Rec::_maker2char(@_);
187             }
188              
189             sub usmarc_default { # rec
190 1     1 1 5 return MARC::Rec::usmarc_default(@_);
191             }
192              
193             ####################################################################
194             # marc_count() returns the number of records in a #
195             # particular MARC object #
196             ####################################################################
197             sub marc_count {
198 10     10 1 24 my $marc=shift;
199 10         40 return $#$marc;
200             }
201              
202             ####################################################################
203             # openmarc() is a method for reading in a MARC file. It takes #
204             # several parameters: file (name of the marc file) ; format, ie. #
205             # usmarc ; and increment which defines how many records to read in #
206             ####################################################################
207             sub openmarc {
208 3     3 1 6 my $marc=shift;
209 3         5 my $params=shift;
210 3         65 my $file=$params->{'file'};
211 3 50       72 if (not(-e $file)) {mycarp "File \"$file\" doesn't exist"; return}
  0         0  
  0         0  
212 3         10 $marc->[0]{'format'}=$params->{'format'}; #store format in object
213 3         5 my $totalrecord;
214 3   100     21 $marc->[0]{'increment'}=$params->{'increment'} || 0;
215             #store increment in the object, default is 0
216 3 50       10 unless ($marc->[0]{'format'}) {$marc->[0]{'format'}="usmarc"}; #default to usmarc
  0         0  
217 3 50       116 open(*file, $file) or mycarp "Open Error: $file, $!";
218 3         10 binmode *file;
219 3         8 $marc->[0]{'handle'}=\*file; #store filehandle in object
220 3         8 my $proto_rec = $marc->[0]{'proto_rec'};
221 3         9 $proto_rec->{'handle'} = $marc->[0]{'handle'};
222 3         13 $proto_rec->{'format'} = lc $marc->[0]{'format'};
223 3 100       24 if ($marc->[0]{'format'} =~ /usmarc/oi) {
    50          
224 1         4 $totalrecord = _readmarc($marc);
225             }
226             elsif ($marc->[0]{'format'} =~ /marcmaker/oi) {
227 2 50       6 if (exists $params->{'charset'}) {
228 0         0 $marc->[0]{makerchar} = $params->{'charset'}; # hash ref
229             }
230             else {
231 2 50       7 unless (exists $marc->[0]{'makerchar'}) {
232 0         0 $marc->[0]{makerchar} = usmarc_default(); # hash ref
233             }
234             }
235 2   50     13 $marc->[0]{'lineterm'} = $params->{'lineterm'} || "\015\012";
236 2         6 $totalrecord = _readmarcmaker($marc);
237             }
238             else {
239 0         0 close *file;
240 0 0       0 if ($params->{'format'} =~ /xml/oi) {
241 0         0 mycarp "XML formats are now handled by MARC::XML";
242             }
243             else {
244 0         0 mycarp "Unrecognized format $marc->[0]{'format'}";
245             }
246 0         0 return;
247             }
248 3 50       11 print "read in $totalrecord records\n" if $MARC::DEBUG;
249 3 100       12 if ($totalrecord==0) {$totalrecord="0 but true"}
  2         5  
250 3         21 return $totalrecord;
251             }
252              
253             ####################################################################
254             # closemarc() will close a file-handle that was opened with #
255             # openmarc() #
256             ####################################################################
257             sub closemarc {
258 3     3 1 7 my $marc = shift;
259 3         7 $marc->[0]{'increment'}=0;
260 3 50       15 if (not($marc->[0]{'handle'})) {
261 0         0 mycarp "There isn't a MARC file to close";
262 0         0 return;
263             }
264 3         50 my $ok = close $marc->[0]{'handle'};
265 3         8 $marc->[0]{'handle'}=undef;
266 3         14 return $ok;
267             }
268              
269             ####################################################################
270             # nextmarc() will read in more records from a file that has #
271             # already been opened with openmarc(). the increment can be #
272             # adjusted if necessary by passing a new value as a parameter. the #
273             # new records will be APPENDED to the MARC object #
274             ####################################################################
275             sub nextmarc {
276 5     5 1 9 my $marc=shift;
277 5         7 my $increment=shift;
278 5         7 my $totalrecord;
279 5 50       17 if (not($marc->[0]{'handle'})) {
280 0         0 mycarp "There isn't a MARC file open";
281 0         0 return;
282             }
283 5 50       12 if ($increment) {$marc->[0]{'increment'}=$increment}
  5         10  
284 5 100       28 if ($marc->[0]{'format'} =~ /usmarc/oi) {
    50          
285 3         4 $totalrecord = _readmarc($marc);
286             }
287 0         0 elsif ($marc->[0]{'format'} =~ /marcmaker/oi) {
288 2         4 $totalrecord = _readmarcmaker($marc);
289             }
290             else {return}
291 5         28 return $totalrecord;
292             }
293              
294             ####################################################################
295              
296             # add_map() takes a recnum and a ref to a field in ($tag,
297             # $i1,$i2,a=>"bar",...) or ($tag, $field) formats and will append to
298             # the various indices that we have hanging off that record. It is
299             # intended for use in creating records de novo and as a component for
300             # rebuild_map(). It carefully does not copy subfield values or entire
301             # fields, maintaining some reference relationships. What this means
302             # for indices created with add_map that you can directly edit
303             # subfield values in $marc->[recnum]{array} and the index will adjust
304             # automatically. Vice-versa, if you edit subfield values in
305             # $marc->{recnum}{tag}{subfield_code} the fields in
306             # $marc->[recnum]{array} will adjust. If you change structural
307             # information in the array with such an index, you must rebuild the
308             # part of the index related to the current tag (and possibly the old
309             # tag if you change the tag).
310              
311             ####################################################################
312              
313             sub add_map { # rec
314 25     25 1 115 my $marc=shift;
315 25         36 my $recnum = shift;
316 25         31 my $rafield = shift;
317 25         72 $marc->[$recnum]->add_map($rafield);
318             }
319              
320             ####################################################################
321              
322             # rebuild_map() takes a recnum and a tag and will synchronize the
323             # index with all elements in the [recnum]{array} with that tag.
324              
325             ####################################################################
326             sub rebuild_map { # rec
327 2     2 1 114 my $marc=shift;
328 2         5 my $recnum = shift;
329 2         5 my $tag = shift;
330 2 50       9 return undef if $tag eq '000'; #currently ldr is different...
331 2         9 $marc->[$recnum]->rebuild_map($tag);
332             }
333              
334             ####################################################################
335              
336             # rebuild_map_all() takes a recnum and will synchronize the
337             # index with all elements in the [recnum]{array}
338              
339             ####################################################################
340             sub rebuild_map_all { # rec
341 0     0 1 0 my $marc=shift;
342 0         0 my $recnum = shift;
343 0         0 $marc->[$recnum]->rebuild_map_all();
344             }
345              
346             ####################################################################
347             # deletemarc() will delete entire records, specific fields, as #
348             # well as specific subfields depending on what parameters are #
349             # passed to it #
350             ####################################################################
351             sub deletemarc {
352 8     8 1 3584 my $marc=shift;
353 8         15 my $template=shift;
354              
355 8         24 my $params = _params($template,@_);
356              
357 8         26 my @delrecords= _records($marc,$params);
358 8         21 my %delrecords= map {$_=>1} @delrecords;
  12         48  
359             #if records parameter not passed set to all records in MARC object
360 8         23 my $field=$params->{field};
361 8         13 my $subfield=$params->{subfield};
362              
363 8         12 my $deletecount=0;
364 8         33 my @keepers = grep {!$delrecords{$_}} (0..$#$marc);
  27         72  
365              
366             #delete entire records
367 8 50 66     37 if (not($field) and not($subfield)) {
368 3         9 my $class = ref $marc;
369 3         9 my @newmarc = @$marc[@keepers]; # array slice, look it up.
370 3         371 @$marc=@newmarc;
371 3         9 bless $marc,$class;
372 3         18 return @delrecords;
373             }
374              
375             #delete fields and/or subfields. deletefirst takes care of the details.
376             # This may be slow. If so write a loop using deletesubfield, etc.
377              
378 5         19 foreach my $i (1..$#$marc) {
379 12 100       39 next unless $delrecords{$i};
380 5         13 my $rec=$marc->[$i];
381 5         17 my @newfields =();
382 5         7 while (1) {
383 16         50 my $has_subfield = $rec->deletefirst($template);
384 16 100       50 last unless $has_subfield;
385 11         16 $deletecount++;
386             }
387 5         24 $rec->rebuild_map($field);
388             }
389 5         37 return $deletecount;
390             }
391              
392             ####################################################################
393             # selectmarc() performs the opposite function of deletemarc(). It #
394             # will select specified elements of a MARC object and return them #
395             # as a MARC object. So if you wanted to select records 1-10 and 15 #
396             # of a MARC object you could say $x=$x->selectmarc(["1-10","15"]); #
397             ####################################################################
398             sub selectmarc {
399 1     1 1 29 my $marc=shift;
400 1         3 my $selarray=shift;
401              
402 1         2 my @keepers=(0); # so we have admin information.
403 1         3 foreach my $selelement (@$selarray) {
404 2 100       9 if ($selelement=~/(\d+)-(\d+)/) {
405 1         8 push @keepers,($1..$2);
406             } else {
407 1         3 push @keepers, $selelement;
408             }
409             }
410 1 50       15 if (not($selarray)) {@{$selarray}= (1..$#$marc)}
  0         0  
  0         0  
411 1         3 my $class = ref $marc;
412 1         4 my @newmarc = @$marc[@keepers]; # array slice, look it up.
413 1         220 @$marc=@newmarc;
414 1         4 bless $marc,$class;
415 1         5 return scalar(@keepers) -1; # minus off the $marc->[0]
416             }
417              
418             ####################################################################
419             # searchmarc() is method for searching a MARC object for specific #
420             # values. It will return an array which contains the record #
421             # numbers that matched. #
422             ####################################################################
423             sub searchmarc {
424 36     36 1 8905 my $marc=shift;
425 36         47 my $template=shift;
426 36 50       95 return unless (ref($template) eq "HASH");
427 36         80 my $params = _params($template,@_);
428              
429 36   50     113 my $field=$params->{field} || return;
430 36         51 my $subfield=$params->{subfield};
431 36         53 my $regex=$params->{regex};
432 36         44 my $notregex=$params->{notregex};
433 36         58 my @results;
434             my $searchtype;
435              
436             #determine the type of search
437 36 100 66     625 if ($field and not($subfield) and not($regex) and not($notregex)) {
    100 100        
    100 100        
    100 66        
    100 100        
    50 100        
      66        
      100        
      66        
      100        
      66        
      66        
      33        
      33        
438 15         37 $searchtype="fieldpresence"}
439             elsif ($field and $subfield and not($regex) and not($notregex)) {
440 13         19 $searchtype="subfieldpresence"}
441             elsif ($field and not($subfield) and $regex) {
442 2         4 $searchtype="fieldvalue"}
443             elsif ($field and $subfield and $regex) {
444 2         4 $searchtype="subfieldvalue"}
445             elsif ($field and not($subfield) and $notregex) {
446 2         5 $searchtype="fieldnotvalue"}
447             elsif ($field and $subfield and $notregex) {
448 2         4 $searchtype="subfieldnotvalue"}
449              
450             #do the search by cycling through each record
451 36         109 for (my $i=1; $i<=$#$marc; $i++) {
452              
453 76         89 my $flag=0;
454 76 100       256 if ($searchtype eq "fieldpresence") {
    100          
    100          
    100          
    100          
    50          
455 31 100       111 next unless exists $marc->[$i]{$field};
456 16         117 push(@results,$i);
457             }
458             elsif ($searchtype eq "subfieldpresence") {
459 29 100       94 next unless exists $marc->[$i]{$field};
460 20 100       59 next unless exists $marc->[$i]{$field}{$subfield};
461 14         42 push(@results,$i);
462             }
463             elsif ($searchtype eq "fieldvalue") {
464 4 50       17 next unless exists $marc->[$i]{$field};
465 4 50       21 next unless exists $marc->[$i]{$field}{field};
466 4         9 my $x=$marc->[$i]{$field}{field};
467 4         10 foreach my $y (@$x) {
468 4         12 my $z=_joinfield($y,$field);
469 4 100       334 if (eval qq("$z" =~ $regex)) {$flag=1}
  2         10  
470             }
471 4 100       27 if ($flag) {push (@results,$i)}
  2         10  
472             }
473             elsif ($searchtype eq "subfieldvalue") {
474 4 50       24 next unless exists $marc->[$i]{$field};
475 4 50       17 next unless exists $marc->[$i]{$field}{$subfield};
476 4         11 my $x=$marc->[$i]{$field}{$subfield};
477 4         10 foreach my $y (@$x) {
478 4 100       206 if (eval qq("$$y" =~ $regex)) {$flag=1}
  2         10  
479             }
480 4 100       18 if ($flag) {push (@results,$i)}
  2         9  
481             }
482             elsif ($searchtype eq "fieldnotvalue" ) {
483 4 50       14 next unless exists $marc->[$i]{$field};
484 4 50       27 next unless exists $marc->[$i]{$field}{field};
485 4         9 my $x=$marc->[$i]{$field}{field};
486 4 50       12 if (not($x)) {push(@results,$i); next}
  0         0  
  0         0  
487 4         9 foreach my $y (@$x) {
488 4         11 my $z=_joinfield($y,$field);
489 4 100       203 if (eval qq("$z" =~ $notregex)) {$flag=1}
  2         11  
490             }
491 4 100       17 if (not($flag)) {push (@results,$i)}
  2         9  
492             }
493             elsif ($searchtype eq "subfieldnotvalue") {
494 4 50       15 next unless exists $marc->[$i]{$field};
495 4 50       14 next unless exists $marc->[$i]{$field}{$subfield};
496 4         11 my $x=$marc->[$i]{$field}{$subfield};
497 4 50       13 if (not($x)) {push (@results,$i); next}
  0         0  
  0         0  
498 4         8 foreach my $y (@$x) {
499 4 100       245 if (eval qq("$$y" =~ $notregex)) {$flag=1}
  2         8  
500             }
501 4 100       17 if (not($flag)) {push (@results,$i)}
  2         8  
502             }
503             }
504 36         179 return @results;
505             }
506              
507             ####################################################################
508              
509             # getfirstvalue() will return the first value of a field or subfield
510             # or indicator or i12 in a particular record found in the MARC
511             # object. It does not depend on the index being up to date.
512              
513             ####################################################################
514             sub getfirstvalue { # rec
515 0     0 1 0 my $marc= shift;
516 0         0 my $template=shift;
517 0 0       0 return unless (ref($template) eq "HASH");
518 0         0 my $record = $template->{record};
519 0 0       0 if (not($record)) {mycarp "You must specify a record"; return}
  0         0  
  0         0  
520 0 0       0 if ($record > $#{$marc}) {mycarp "Invalid record specified"; return}
  0         0  
  0         0  
  0         0  
521 0         0 my $marcrec = $marc->[$record];
522 0         0 return $marcrec->getfirstvalue($template);
523              
524             }
525              
526             ####################################################################
527             # getvalue() will return the value of a field or subfield in a #
528             # particular record found in the MARC object #
529             ####################################################################
530             sub getvalue { # rec
531 63     63 1 4425 my $marc = shift;
532 63         78 my $template=shift;
533 63 50       147 return unless (ref($template) eq "HASH");
534 63         129 my $params = _params($template,@_);
535 63         105 my $record = $params->{record};
536 63 50       113 if (not($record)) {mycarp "You must specify a record"; return}
  0         0  
  0         0  
537 63 50       83 if ($record > $#{$marc}) {mycarp "Invalid record specified"; return}
  63         162  
  0         0  
  0         0  
538            
539 63         159 return $marc->[$record]->getvalue($params);
540             }
541              
542             ####################################################################
543             #Returns LDR at $record. #
544             ####################################################################
545             sub ldr { # rec
546 4     4 0 8 my ($self,$record)=@_;
547 4         14 return $self->[$record]->ldr();
548             }
549              
550              
551             ####################################################################
552             #Takes a record number and returns a hash of fields. #
553             #Needed to determine the format (BOOK, VIS, etc) of #
554             #the record. #
555             #Folk also like to know what Ctrl, Desc etc are. #
556             ####################################################################
557             sub unpack_ldr { # rec
558 2     2 1 9 my ($self,$record) = @_;
559 2         14 return $self->[$record]->unpack_ldr();
560             }
561              
562            
563             sub _unpack_ldr { # rec
564 0     0   0 my ($self,$ldr)=@_;
565 0         0 return $self->[0]{proto_rec}->unpack_ldr($ldr);
566             }
567              
568              
569             ####################################################################
570             #Takes a record number. #
571             #Returns the unpacked ldr as a ref to hash from the ref in $self. #
572             #Does not overwrite hash from ldr. #
573             ####################################################################
574             sub get_hash_ldr { # rec
575 0     0 1 0 my ($self,$record)=@_;
576 0         0 return $self->[$record]->get_hash_ldr();
577             }
578              
579             ####################################################################
580             # Takes a record number and updates the corresponding ldr if there
581             # is a hashed form. Returns undef unless there is a hash. Else
582             # returns $ldr.
583             ####################################################################
584             sub pack_ldr { # rec
585 1     1 1 3 my ($self,$record)=@_;
586 1         4 return $self->[$record]->pack_ldr();
587             }
588              
589             ####################################################################
590             #Takes a ref to hash version of the LDR and returns a string #
591             # version #
592             ####################################################################
593             sub _pack_ldr { # rec
594 4     4   1061 my ($self,$rhldr) = @_;
595 4         17 return $self->[0]{proto_rec}->_pack_ldr($rhldr);
596             }
597              
598             ####################################################################
599             #Takes a string record number. #
600             #Returns a the format necessary to pack/unpack 008 fields correctly#
601             ####################################################################
602             sub bib_format { # rec
603 0     0 1 0 my ($self,$record)=@_;
604 0         0 return $self->[$record]->bib_format();
605             }
606              
607             sub _bib_format { # rec
608 0     0   0 my ($self,$ldr)=@_;
609 0         0 return $self->[0]{proto_rec}->_bib_format($ldr);
610             }
611              
612             ####################################################################
613             #Takes a record number. #
614             #Returns the unpacked 008 as a ref to hash. Installs ref in $self. #
615             ####################################################################
616             sub unpack_008 { # rec
617 2     2 1 579 my ($self,$record) = @_;
618 2         11 return $self->[$record]->unpack_008();
619             }
620              
621             sub _unpack_008 { # rec
622 0     0   0 my ($self,$ff_string,$bib_format) = @_;
623 0         0 return $self->[0]{proto_rec}->_unpack_008($ff_string,$bib_format);
624             }
625              
626             ####################################################################
627             #Takes a record number. #
628             #Returns the unpacked 008 as a ref to hash from the ref in $self. #
629             #Does not overwrite hash from 008 field. #
630             ####################################################################
631             sub get_hash_008 { # rec
632 0     0 1 0 my ($self,$record)=@_;
633 0         0 return $self->[$record]->get_hash_008();
634             }
635              
636             ####################################################################
637             #Takes a record number. Flushes hashes to 008 and ldr. #
638             #Updates the 008 field from an installed fixed field hash.
639             #Returns undef unless there is a hash, else returns the 008 field #
640             ####################################################################
641             sub pack_008 { # rec
642 1     1 1 3 my ($self,$record) = @_;
643 1         5 return $self->[$record]->pack_008();
644             }
645              
646             ####################################################################
647             #Takes LDR and ref to hash of unpacked 008 #
648             #Returns string version of 008 *without* newlines. #
649             ####################################################################
650             sub _pack_008 { # rec
651 2     2   4 my ($self,$ldr,$rhff) = @_;
652 2         17 return $self->[0]{proto_rec}->_pack_008($ldr,$rhff);
653             }
654              
655             ####################################################################
656             # _joinfield() is an internal subroutine for creating a string out #
657             # of an array of subfields. It takes an optional delimiter #
658             # parameter which will print out subfields if defined #
659             ####################################################################
660             sub _joinfield { # rec
661 8     8   33 return MARC::Rec->_joinfield(@_);
662             }
663              
664             ####################################################################
665              
666             # _make_005 is a function: it returns the time formatted for the 005
667             # field.
668              
669             ####################################################################
670             sub _make_005 {
671 31     31   2081 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
672             # 1. Official specs for 005 are at
673             # lcweb.loc.gov/marc/bibliographic/ecbdcntr.html
674             # They refer to X3.30 ansi; a copy of that would be of interest.
675             # 2. Checked out some examples for existing practice.
676 31         79 $year += 1900;
677 31         42 $mon++; #$mon is counted from 1 when talking to humans.
678 31 100       120 return "19960221075055.7" if $MARC::TEST;
679 27         149 return sprintf("%0.4d%0.2d%0.2d%0.2d%0.2d%0.2d.0",$year,$mon,$mday,$hour,$min,$sec);
680             }
681              
682             ####################################################################
683              
684             # add_005s takes a template and adds current 005s to the elements of
685             # $marc mentioned in $template->{records}
686              
687             ####################################################################
688             sub add_005s {
689 31     31 1 45 my $marc=shift;
690 31         44 my $args = shift;
691 31         36 my @records;
692 31         102 @records= (1..$#$marc);
693 31 50 33     168 if ($args && $args->{'records'} ) {
694 0         0 @records =@{$args->{'records'}};
  0         0  
695             }
696              
697 31         75 my $time = MARC::_make_005() ;
698 31         66 foreach my $i (@records) {
699 86         344 $marc->[$i]->add_005($time);
700             }
701             }
702            
703             ####################################################################
704             # output() will call the appropriate output method using the marc #
705             # object and desired format parameters. #
706             ####################################################################
707             sub output {
708 39     39 1 181 my $marc=shift;
709 39         54 my $args=shift;
710 39         59 my $output = "";
711 39   50     353 my $newline = $args->{'lineterm'} || "\n";
712              
713 39 100 66     216 $marc->add_005s($args) if ($args->{'file'} or $args->{'add_005s'});
714              
715 39 100       136 unless (exists $args->{'format'}) {
716             # everything to string
717 1         3 $args->{'format'} = "marc";
718 1         3 $args->{'lineterm'} = $newline;
719             }
720 39 100       516 if ($args->{'format'} =~ /marc$/oi) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
721 2         10 $output = _writemarc($marc,$args);
722             }
723             elsif ($args->{'format'} =~ /marcmaker$/oi) {
724 6         41 $output = _marcmaker($marc,$args);
725             }
726             elsif ($args->{'format'} =~ /ascii$/oi) {
727 6         30 $output = _marc2ascii($marc,$args);
728             }
729             elsif ($args->{'format'} =~ /html$/oi) {
730 8         15 $output .= "";
731 8         25 $output .= _marc2html($marc,$args);
732 8         25 $output .="$newline$newline";
733             }
734             elsif ($args->{'format'} =~ /html_header$/oi) {
735 2         7 $output = "Content-type: text/html\015\012\015\012";
736             }
737             elsif ($args->{'format'} =~ /html_start$/oi) {
738 4 100       13 if ($args->{'title'}) {
739 1         5 $output = "$args->{'title'}";
740 1         3 $output .= "$newline";
741             }
742             else {
743 3         6 $output = "";
744             }
745             }
746             elsif ($args->{'format'} =~ /html_body$/oi) {
747 2         9 $output =_marc2html($marc,$args);
748             }
749             elsif ($args->{'format'} =~ /html_footer$/oi) {
750 3         12 $output = "$newline$newline";
751             }
752             elsif ($args->{'format'} =~ /urls$/oi) {
753 2   50     16 my $title = $args->{'title'} || "Untitled URLs";
754 2         9 $output .= "$title$newline$newline";
755 2         10 $output .= _urls($marc,$args);
756 2         6 $output .="";
757             }
758             elsif ($args->{'format'} =~ /isbd$/oi) {
759 2         8 $output = _isbd($marc,$args);
760             }
761             elsif ($args->{'format'} =~ /xml/oi) {
762 2 50       8 mycarp "XML formats are now handled by MARC::XML" if ($^W);
763 2         13 return;
764             }
765 37 100       137 if ($args->{'file'}) {
766 29 50       150 if ($args->{'file'} !~ /^>/) {
767 0         0 mycarp "Don't forget to use > or >> with output file name";
768 0         0 return;
769             }
770 29 50       34348 open (OUT, "$args->{file}") || mycarp "Couldn't open file: $!";
771             #above quote is bad if {file} is tainted. Is probably unecessary.dgl.
772 29         92 binmode OUT;
773 29         602 print OUT $output;
774 29 50       2222 close OUT || mycarp "Couldn't close file: $!";
775 29         271 return 1;
776             }
777             #if no filename was specified return the output so it can be grabbed
778             else {
779 8         65 return $output;
780             }
781             }
782              
783             ####################################################################
784             # _records unpacks it hashref arg or defaults to the entire list
785             ####################################################################
786             sub _records {
787 36     36   1311 my ($marc,$args)=@_;
788 36         66 my $trecs =[];
789 36         67 my @records = ();
790 36 100       168 $trecs= [$args->{record}] if exists($args->{record});
791 36 50       88 $trecs= $args->{records} if $args->{records};
792              
793 36 100       93 @records = @$trecs if @$trecs;
794 36 100       139 @records = (1..$#$marc) unless @$trecs;
795              
796 36         129 return @records;
797             }
798              
799             ####################################################################
800              
801             # params takes a hashref and does a one level deep copy of it.
802             # It uses the rest of the args to override elements of the hashref.
803             # Returns a hashref so that caller does'nt have to worry about
804             # crypto-context.
805              
806             ####################################################################
807              
808             sub _params {
809 107     107   270 return MARC::Rec::_params(@_);
810             }
811              
812             ####################################################################
813             # _writemarc() takes a MARC object as its input and returns the #
814             # the USMARC equivalent of the object as a string #
815             ####################################################################
816             sub _writemarc { #rec
817 2     2   5 my $marc=shift;
818 2         4 my $args=shift;
819             #Read in each individual MARC record in the file
820 2         9 my @records = _records($marc,$args);
821              
822 2         5 my $marcrecord="";
823 2         5 foreach my $i (@records) {
824 16         28 my $record = $marc->[$i];
825 16         39 $marcrecord .= $record->_writemarc($args);
826             }
827 2         47 return $marcrecord;
828             }
829              
830              
831             ####################################################################
832             # _marc2ascii() takes a MARC object as its input and returns the #
833             # ASCII equivalent of the object (field names, indicators, field #
834             # values and line-breaks) #
835             ####################################################################
836             sub _marc2ascii { # rec
837 6     6   13 my $marc=shift;
838 6         13 my $args=shift;
839 6         24 my @records = _records($marc,$args);
840 6   50     57 $args->{'lineterm'} ||= "\n";
841 6         11 my $output = "";
842 6         14 for my $i (@records) { #cycle through each record
843 18         38 my $record=$marc->[$i];
844 18         59 $output .= $record->_marc2ascii($args);
845             }
846 6         52 return $output;
847             }
848              
849             ####################################################################
850             # _marcmaker() takes a MARC object as its input and converts it #
851             # into MARCMaker format, which is returned as a string #
852             ####################################################################
853             sub _marcmaker { # rec
854 6     6   15 my @output = ();
855 6         16 my $marc=shift;
856 6         10 my $args=shift;
857 6         25 $args->{'proto_rec'} = $marc->[0]{'proto_rec'};
858 6         28 my @records = _records($marc,$args);
859              
860 6         32 local $^W = 0; # no warnings
861 6         13 my $breaker = "";
862 6         15 for my $i (@records) { #cycle through each record
863 24         62 my $record=$marc->[$i];
864 24         111 $breaker .= $record->_marcmaker($args);
865             }
866 6         71 return $breaker;
867             }
868              
869             sub _char2maker { # rec
870 0     0   0 return MARC::Rec::_char2maker(@_);
871             }
872              
873             sub ustext_default { # rec
874 0     0 1 0 return MARC::Rec::ustext_default(@_);
875             }
876              
877             ####################################################################
878             # _marc2html takes a MARC object as its input and converts it into #
879             # HTML. It is possible to specify which field you want to output #
880             # as well as field labels to be used instead of the MARC codes. #
881             # The HTML is returned as a string #
882             ####################################################################
883             sub _marc2html {
884 10     10   18 my $marc = shift;
885 10         14 my $args = shift;
886 10   50     44 my $newline = $args->{'lineterm'} || "\n";
887              
888 10         27 my @records = _records($marc,$args);
889 10         18 my $output = "";
890 10         20 foreach my $i (@records) {
891 20         33 my $marcrec=$marc->[$i];
892 20         62 $output.= $marcrec->_marc2html($args);
893             }
894 10         31 return $output;
895             }
896              
897              
898             ####################################################################
899             # _urls() takes a MARC object as its input, and then extracts the #
900             # control# (MARC 001) and URLs (MARC 856) and outputs them as #
901             # hypertext links in an HTML page. This could then be used with a #
902             # link checker to determine what URLs are broken. #
903             ####################################################################
904             sub _urls { # rec
905 2     2   6 my $marc = shift;
906 2         3 my $args = shift;
907              
908 2         4 my $output = "";
909 2         8 my @records = _records($marc,$args);
910              
911 2         9 local $^W = 0; # no warnings
912 2         7 foreach my $i (@records) {
913 4         8 my $marcrec=$marc->[$i];
914 4         15 $output .= $marcrec->_urls($args);
915             }
916 2         9 return $output;
917             }
918              
919             ####################################################################
920             # isbd() attempts to create a quasi ISBD output format #
921             ####################################################################
922             sub _isbd { # rec
923 2     2   4 my $marc=shift;
924 2         2 my $args=shift;
925 2   50     13 my $newline = $args->{'lineterm'} || "\n";
926 2         7 my @records = _records($marc,$args);
927 2         5 my $output ="";
928 2         5 for my $i (@records) { #cycle through each record
929 4         7 my $record=$marc->[$i];
930 4         14 $output .= $record->_isbd($args);
931             }
932 2         8 return $output;
933             }
934              
935             ####################################################################
936             # createrecord() appends a new record to the MARC object #
937             # and initializes the '000' field #
938             ####################################################################
939             sub createrecord { # rec
940 0     0 1 0 my $marc=shift;
941 0         0 local $^W = 0; # no warnings
942 0         0 my $params=shift;
943 0   0     0 my $leader=$params->{'leader'} || "00000nam 2200000 a 4500";
944             #default leader see MARC documentation http://lcweb.loc.gov/marc
945 0         0 my $number=$#$marc + 1;
946 0         0 my $marcrec = $marc->[0]{'proto_rec'}->createrecord($leader);
947 0         0 push @$marc, $marcrec;
948 0         0 return $number;
949             }
950              
951             ####################################################################
952             # addfield() appends/inserts a new field into an existing record #
953             ####################################################################
954              
955             sub addfield {
956 19     19 1 3732 my $marc=shift;
957 19         24 my $params=shift;
958 19         65 local $^W = 0; # no warnings
959 19         32 my $record=$params->{'record'};
960 19 50       50 unless ($record) {mycarp "You must specify a record"; return}
  0         0  
  0         0  
961 19 50       22 if ($record > $#{$marc}) {mycarp "Invalid record specified"; return}
  19         52  
  0         0  
  0         0  
962 19         38 my $field = $params->{'field'};
963 19 50       62 unless ($field) {mycarp "You must specify a field"; return}
  0         0  
  0         0  
964 19 50       76 unless ($field =~ /^\d{3}$/) {mycarp "Invalid field specified"; return}
  0         0  
  0         0  
965              
966 19         34 my $i1=$params->{'i1'};
967 19 100       51 $i1 = ' ' unless (defined $i1);
968 19         26 my $i2=$params->{'i2'};
969 19 100       40 $i2 = ' ' unless (defined $i2);
970 19   66     96 my @value=$params->{'value'} || @_;
971 19 100       61 if (ref($params->{'value'}) eq "ARRAY") { @value = @{$params->{'value'}}; }
  9         14  
  9         36  
972 19 50       51 unless (defined $value[0]) {mycarp "No value specified"; return}
  0         0  
  0         0  
973              
974 19 50       728 if ($field >= 10) {
975 19 100       112 if ($value[0] eq 'i1') {
976 10         13 shift @value;
977 10         19 $i1 = shift @value;
978             }
979 19 50       47 unless (1 == length($i1)) {
980 0         0 mycarp "invalid \'i1\' specified";
981 0         0 return;
982             }
983 19 100       3046 if ($value[0] eq 'i2') {
984 10         13 shift @value;
985 10         317 $i2 = shift @value;
986             }
987 19 50       54 unless (1 == length($i2)) {
988 0         0 mycarp "invalid \'i2\' specified";
989 0         0 return;
990             }
991             }
992              
993 19   100     54 my $ordered=$params->{'ordered'} || "y";
994 19         22 my $insertorder = $#{$marc->[$record]{array}} + 1;
  19         53  
995             #if necessary figure out the insert order to preserve tag order
996 19 100       73 if ($ordered=~/y/i) {
997 16         25 for (my $i=0; $i<=$#{$marc->[$record]{array}}; $i++) {
  249         622  
998 249 100       665 if ($marc->[$record]{array}[$i][0] > $field) {
999 16         23 $insertorder=$i;
1000 16         26 last;
1001             }
1002 233 50       592 if ($insertorder==0) {$insertorder=1}
  0         0  
1003             }
1004             }
1005 19         23 my @field;
1006 19 50       54 if ($field<10) {
1007 0         0 push (@field, $field, $value[0]);
1008 0 0       0 if ($ordered=~/y/i) {
1009 0         0 splice @{$marc->[$record]{array}},$insertorder,0,\@field;
  0         0  
1010             }
1011             else {
1012 0         0 push (@{$marc->[$record]{array}},\@field);
  0         0  
1013             }
1014             }
1015             else {
1016 19         49 push (@field, $field, $i1, $i2);
1017 19         24 my ($sub_id, $subfield);
1018 19         57 while ($sub_id = shift @value) {
1019 32 50       83 last if ($sub_id eq "\036");
1020 32         40 $subfield = shift @value;
1021 32         106 push (@field, $sub_id, $subfield);
1022             }
1023 19 100       63 if ($ordered=~/y/i) {
1024 16         21 splice @{$marc->[$record]{array}},$insertorder,0,\@field;
  16         51  
1025             }
1026             else {
1027 3         7 push (@{$marc->[$record]{array}},\@field);
  3         12  
1028             }
1029             }
1030 19         290 $marc->add_map($record,\@field);
1031             }
1032              
1033             ####################################################################
1034              
1035             # getfields() takes a template and returns an array of fieldrefs from
1036             # $marc->[$recnum]{'array'} including all with the appropriate tag
1037             # and having the property that they are a contiguous group. (So may
1038             # include fields with other tags.)
1039              
1040             ####################################################################
1041             sub getfields { # rec
1042 0     0 1 0 my $marc=shift;
1043 0         0 my $params=shift;
1044 0         0 my $record=$params->{'record'};
1045 0 0       0 unless ($record) {mycarp "You must specify a record"; return}
  0         0  
  0         0  
1046 0 0       0 if ($record > $#{$marc}) {mycarp "Invalid record specified"; return}
  0         0  
  0         0  
  0         0  
1047 0         0 return $marc->[$record]->getfields($params);
1048              
1049             }
1050              
1051             ####################################################################
1052             # getupdate() returns an array of key,value pairs formatted to #
1053             # pass to addfield(). For repeated tags, a "\036" element is used #
1054             # to delimit data for separate addfield() commands #
1055             ####################################################################
1056             sub getupdate {
1057 32     32 1 9809 my @output;
1058 32         111 my $marc=shift;
1059 32         37 my $params=shift;
1060 32         54 my $record=$params->{'record'};
1061 32 50       76 unless ($record) {mycarp "You must specify a record"; return}
  0         0  
  0         0  
1062 32 50       40 if ($record > $#{$marc}) {mycarp "Invalid record specified"; return}
  32         92  
  0         0  
  0         0  
1063 32         57 my $field = $params->{'field'};
1064 32 50       69 unless ($field) {mycarp "You must specify a field"; return}
  0         0  
  0         0  
1065 32 50       126 unless ($field =~ /^\d{3}$/) {mycarp "Invalid field specified"; return}
  0         0  
  0         0  
1066              
1067 32         37 foreach my $fields (@{$marc->[$record]{array}}) { #cycle each field
  32         93  
1068 738 100       1483 next unless ($field eq $fields->[0]);
1069 40 100       159 if ($field<10) {
1070 5         10 push @output,$fields->[1];
1071             }
1072             else {
1073 35         91 push @output,'i1',$fields->[1],'i2',$fields->[2];
1074 35         48 my @subfields = @{$fields}[3..$#{$fields}];
  35         177  
  35         74  
1075 35         92 while (@subfields) { #cycle through subfields incl. refs
1076 100         140 my $subfield = shift @subfields;
1077 100 50       230 last unless defined $subfield;
1078 100 50       166 if (ref($subfield) eq "ARRAY") {
1079 0         0 foreach my $subsub (@{$subfield}) {
  0         0  
1080 0         0 push @output, $subsub;
1081             }
1082             }
1083             else {
1084 100         270 push @output, $subfield;
1085             }
1086             } #finish cycling through subfields
1087             } #finish tag test < 10
1088 40         75 push @output,"\036";
1089             }
1090 32         255 return @output;
1091             }
1092             ####################################################################
1093              
1094             # deletefirst() takes a template and a boolean $do_rebuild_map to
1095             # rebuild the map. It deletes the field data for a first match, using
1096             # the template and leaves the rest alone. If the template has a
1097             # subfield element it deletes based on the subfield information in the
1098             # template. If the last subfield of a field is deleted, deletefirst()
1099             # also deletes the field. It complains about attempts to delete
1100             # indicators. If there is no match, it does nothing. Deletefirst also
1101             # rebuilds the map if $do_rebuild_map. Deletefirst returns the number
1102             # of matches deleted (that would be 0 or 1), or undef if it feels
1103             # grumpy (i.e. carps).
1104              
1105             ####################################################################
1106              
1107             sub deletefirst { # rec
1108 2   50 2 1 216 my $marc = shift || return;
1109 2         4 my $template = shift;
1110 2         6 my $recnum = $template->{'record'};
1111 2 50       7 if (!$recnum) {mycarp "Need a record to confine my destructive tendencies"; return undef}
  0         0  
  0         0  
1112 2         10 return $marc->[$recnum]->deletefirst($template);
1113             }
1114              
1115             ####################################################################
1116              
1117             # field_is_empty takes a ref to an array formatted like
1118             # an element of $marc->[$recnum]{array}. It returns 1 if there are
1119             # no "significant" elements of the array (e.g. nothing but indicators
1120             # if $tag>10), else 0. Override this if you want to delete fields
1121             # that have "insignificant" subfields inside deletefirst.
1122              
1123             ####################################################################
1124             sub field_is_empty { # rec
1125 0     0 0 0 my ($marc,$rfield) = @_;
1126 0         0 return $marc->[0]{proto_rec}->field_is_empty($rfield);
1127             }
1128              
1129             ####################################################################
1130              
1131             # field_updatehook takes a ref to an array formatted like
1132             # $marc->[$recnum]{'array'}. It is there so that
1133             # subclasses can override it to do something before calling
1134             # addfield(), e.g. store field-specific information in the affected
1135             # field or log information in an external file/database. One notes that
1136             # since this is a method, it can ignore its arguments and log global
1137             # information about $marc, e.g. order information in $marc->[$rnum]{'array'}
1138              
1139             ####################################################################
1140              
1141             sub field_updatehook { # rec
1142 0     0 0 0 my ($marc,$rfield)=@_;
1143 0         0 $marc->[0]{'proto_rec'}->field_updatehook($rfield);
1144             }
1145              
1146             ####################################################################
1147              
1148             # updatefirst() takes a template, a request to rebuild the index, and
1149             # an array from $marc->[recnum]{array}. It replaces/creates the field
1150             # data for a first match, using the template, and leaves the rest
1151             # alone. If the template has a subfield element, (this includes
1152             # indicators) it ignores all other information in the array and only
1153             # updates/creates based on the subfield information in the array. If
1154             # the template has no subfield information then indicators are left
1155             # untouched unless a new field needs to be created, in which case they
1156             # are left blank.
1157              
1158             ####################################################################
1159              
1160             sub updatefirst { # rec
1161 8   50 8 1 64 my $marc = shift || return;
1162 8         11 my $template = shift;
1163 8 50       21 return unless (ref($template) eq "HASH");
1164 8 50       17 return unless (@_);
1165 8 50       21 return if (defined $template->{'value'});
1166              
1167 8         12 my $recnum = $template->{'record'};
1168 8 50       18 if (!$recnum) {mycarp "Need a record to confine my changing needs."; return undef}
  0         0  
  0         0  
1169 8         24 return $marc->[$recnum]->updatefirst($template,@_);
1170             }
1171              
1172             ####################################################################
1173              
1174             # updatefields() takes a template which specifies recnum, a
1175             # $do_rebuild_map and a field (needs the field in case $rafields->[0]
1176             # is empty). It also takes a ref to an array of fieldrefs formatted
1177             # like the output of getfields(), and replaces/creates the field
1178             # data. It assumes that it should remove the fields with the first tag
1179             # in the fieldrefs. It calls rebuild_map() if $do_rebuild_map.
1180              
1181             ####################################################################
1182             sub updatefields { # rec
1183 0   0 0 1 0 my $marc = shift || return;
1184 0         0 my $template = shift;
1185              
1186 0         0 my $rafieldrefs = shift;
1187 0         0 my $recnum = $template->{'record'};
1188 0         0 return $marc->[$recnum]->updatefields($template,$rafieldrefs);
1189             }
1190              
1191             ####################################################################
1192              
1193             # getmatch() takes a subfield code (can be an indicator) and a fieldref
1194             # Returns 0 or a ref to the value to be updated.
1195              
1196             ####################################################################
1197             sub getmatch { # rec
1198 0   0 0 1 0 my $marc = shift || return;
1199 0         0 return $marc->[0]{proto_rec}->getmatch(@_);
1200             }
1201              
1202             ####################################################################
1203              
1204             # deletesubfield() takes a subfield code (can not be an indicator) and a
1205             # fieldref. Deletes the subfield code and its value in the fieldref at
1206             # the first match on subfield code. Assumes there is an exact
1207             # subfield match in $fieldref.
1208              
1209             ####################################################################
1210             sub deletesubfield { # rec
1211 0   0 0 0 0 my $marc = shift || return;
1212 0         0 return $marc->[0]{proto_rec}->deletesubfield(@_);
1213             }
1214              
1215             ####################################################################
1216              
1217             # insertpos() takes a subfield code (can not be an indicator), a
1218             # value, and a fieldref. Updates the fieldref with the first
1219             # place that the fieldref can match. Assumes there is no exact
1220             # subfield match in $fieldref.
1221              
1222             ####################################################################
1223             sub insertpos { # rec
1224 0   0 0 1 0 my $marc = shift || return;
1225 0         0 return $marc->[0]{proto_rec}->insertpos(@_);
1226             }
1227            
1228              
1229             ####################################################################
1230             # updaterecord() takes an array of key/value pairs, formatted like #
1231             # the output of getupdate(), and replaces/creates the field data. #
1232             # For repeated tags, a "\036" element is used to delimit data into #
1233             # separate addfield() commands. #
1234             ####################################################################
1235             sub updaterecord {
1236 0   0 0 1 0 my $marc = shift || return;
1237 0         0 my $template = shift;
1238 0 0       0 return unless (ref($template) eq "HASH");
1239 0 0       0 return unless (@_);
1240 0 0       0 return if (defined $template->{'value'});
1241 0         0 my $count = 0;
1242 0         0 my @records = ();
1243 0 0       0 unless ($marc->deletemarc($template)) {mycarp "not deleted\n"; return;}
  0         0  
  0         0  
1244 0         0 foreach my $y1 (@_) {
1245 0 0       0 unless ($y1 eq "\036") {
1246 0         0 push @records, $y1;
1247 0         0 next;
1248             }
1249 0 0       0 unless ($marc->addfield($template, @records)) {
1250 0         0 mycarp "not added\n";
1251 0         0 return;
1252             }
1253 0         0 @records = ();
1254 0         0 $count++;
1255             }
1256 0         0 return $count;
1257             }
1258              
1259             ####################################################################
1260             # _offset is an internal subroutine used by writemarc to offset #
1261             # number ie. making "34" into "00034". #
1262             ####################################################################
1263             sub _offset{
1264 0     0   0 return MARC::Rec::_offset(@_);
1265             }
1266              
1267             ####################################################################
1268              
1269             # MARC::Rec is responsible for the methods and representation of
1270             # a single MARC record. Its protocol is very close to that of MARC:
1271             # in fact, most MARC methods have been moved here without the record
1272             # number and re-implemented in standard form by delegation.
1273              
1274             ####################################################################
1275              
1276             package MARC::Rec;
1277 5     5   68 use Carp;
  5         8  
  5         553  
1278 5         1053392 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS
1279             @LDR_FIELDS $LDR_TEMPLATE %FF_FIELDS %FF_TEMPLATE
1280 5     5   29 );
  5         12  
1281              
1282             $VERSION = $MARC::VERSION;
1283              
1284             @ISA = qw(Exporter);
1285             @EXPORT= qw();
1286             @EXPORT_OK= qw();
1287              
1288             #### Not using these yet
1289              
1290             #### %EXPORT_TAGS = (USTEXT => [qw( marc2ustext )]);
1291             #### Exporter::export_ok_tags('USTEXT');
1292             #### $EXPORT_TAGS{ALL} = \@EXPORT_OK;
1293              
1294             # gotta know where to find leader information....
1295              
1296             @LDR_FIELDS = qw(rec_len RecStat Type BLvl Ctrl Undefldr base_addr
1297             ELvl Desc ln_rec len_len_field len_start_char len_impl Undef2ldr);
1298              
1299             $LDR_TEMPLATE = "a5aaaaa3a5aaaaaaa";
1300              
1301             #...And the 008 field has a special place in Librarians' hearts.
1302             %FF_FIELDS = (
1303             BOOKS =>
1304             [qw(Entered DtSt Date1 Date2 Ctry Ills Audn Form Cont
1305             GPub Conf Fest Indx Undef1 Fict Biog Lang MRec Srce)],
1306             COMPUTER_FILES =>
1307             [qw(Entered DtSt Date1 Date2 Ctry Undef1 Audn Undef2
1308             File Undef3 GPub Undef4 Lang MRec Srce)],
1309             MAPS =>
1310             [qw(Entered DtSt Date1 Date2 Ctry Relf Proj Prme CrTp
1311             Undef1 GPub Undef2 Indx Undef3 SpFm Lang MRec Srce)],
1312             MUSIC =>
1313             [qw(Entered DtSt Date1 Date2 Ctry Comp FMus Undef1 Audn
1314             Form AccM LTxt Undef2 Lang MRec Srce)],
1315             SERIALS =>
1316             [qw(Entered DtSt Date1 Date2 Ctry Freq Regl ISSN SrTp
1317             Orig Form EntW Cont GPub Conf Undef1 Alph S_L Lang MRec Srce)],
1318             VIS =>
1319             [qw(Entered DtSt Date1 Date2 Ctry Time Undef1
1320             Audn AccM GPub Undef2 TMat Tech Lang MRec Srce)],
1321             MIX =>
1322             [qw(Entered DtSt Date1 Date2
1323             Ctry Undef1 Form Undef2 Lang MRec Srce)]
1324             );
1325              
1326             %FF_TEMPLATE = (
1327             BOOKS => "a6a1a4a4a3a4a1a1a4a1a1a1a1a1a1a1a3a1a1",
1328             COMPUTER_FILES => "a6a1a4a4a3a4a1a3a1a1a1a6a3a1a1",
1329             MAPS => "a6a1a4a4a3a4a2a1a1a2a1a2a1a1a2a3a1a1",
1330             MUSIC => "a6a1a4a4a3a2a1a1a1a1a6a2a3a3a1a1",
1331             SERIALS => "a6a1a4a4a3a1a1a1a1a1a1a1a3a1a1a3a1a1a3a1a1",
1332             VIS => "a6a1a4a4a3a3a1a1a5a1a4a1a1a3a1a1",
1333             MIX => "a6a1a4a4a3a5a1a11a3a1a1"
1334             );
1335              
1336             # Preloaded methods go here.
1337             ####################################################################
1338             # _offset is an internal subroutine used by writemarc to offset #
1339             # number ie. making "34" into "00034". #
1340             ####################################################################
1341             sub _offset{
1342 592     592   627 my $value=shift;
1343 592         656 my $digits=shift;
1344 592 50       2464 print "DEBUG: _offset value = $value, digits = $digits\n" if $MARC::DEBUG;
1345 592         590 my $x=length($value);
1346 592         521 $x=$digits-$x;
1347 592         1273 $x="0"x$x."$value";
1348             }
1349              
1350             sub mycarp { # rec
1351 0 0   0   0 Carp::carp (@_) unless $MARC::TEST;
1352             }
1353              
1354             ####################################################################
1355              
1356             # This is the constructor method that creates the MARC::Rec object. It
1357             # sets up references and gets out. Any file it knows about will be an
1358             # already opened filehandle: do error checking and binmode on the file
1359             # outside MARC::Rec.
1360              
1361             ####################################################################
1362             sub new { # rec
1363 5     5   13 my $proto = shift;
1364 5   33     40 my $class = ref($proto) || $proto;
1365 5         12 my $filehandle = shift;
1366 5         11 my $marcrec = {};
1367 5         16 bless ($marcrec, $class);
1368 5   50     47 my $format = shift || "usmarc";
1369              
1370 5   50     73 $marcrec->{'handle'} ||= \*filehandle;
1371 5         13 $marcrec->{'format'}=$format;
1372 5 50       22 $marcrec->{'lineterm'}="\015\012" if $format eq 'marcmaker';
1373             # MS-DOS default for MARCMaker
1374 5         18 return $marcrec;
1375             }
1376              
1377             ####################################################################
1378              
1379             # Copy_struct returns a copy of the marcrec ($proto) without
1380             # {array} and map information. The copy shares references to
1381             # {handle} by design.
1382              
1383             ####################################################################
1384             sub copy_struct {
1385 23     23   37 my $proto = shift;
1386 23         41 my $class = ref($proto);
1387 23         24 my $newrec;
1388 23         279 for (keys %$proto) {
1389 72 100       675 $newrec->{$_} = $proto->{$_} if /^(handle|format|proto_rec)$/;
1390             }
1391 23         99 return bless $newrec,$class;
1392             }
1393              
1394             ####################################################################
1395              
1396             # clone returns a new MARC::Rec object with copies of the data.
1397             # Admin information remains linked to original.
1398              
1399             ####################################################################
1400             sub clone {
1401 0     0   0 my $marcrec=shift;
1402 0         0 my $ldr = $marcrec->ldr();
1403 0         0 my $ans = $marcrec->createrecord($ldr);
1404 0         0 for (@{$marcrec->{array}}) {
  0         0  
1405 0 0       0 next if $_->[0] eq '000';
1406 0         0 my @field = @$_;
1407 0         0 my $rfield = \@field;
1408 0         0 push @{$ans->{array}}, $rfield;
  0         0  
1409 0         0 $ans->add_map($rfield);
1410             }
1411 0         0 return $ans;
1412             }
1413              
1414             ####################################################################
1415              
1416             # field_is_empty takes a ref to an array formatted like
1417             # an element of $marc->[$recnum]{array}. It returns 1 if there are
1418             # no "significant" elements of the array (e.g. nothing but indicators
1419             # if $tag>10), else 0. Override this if you want to delete fields
1420             # that have "insignificant" subfields inside deletefirst.
1421              
1422             ####################################################################
1423             sub field_is_empty { # rec
1424 1     1   2 my ($marcrec,$rfield) = @_;
1425              
1426 1         2 my $tag = $rfield->[0];
1427 1         4 my @field = @$rfield;
1428 1 50 33     9 return 1 if ($tag > 10 and !defined($field[3]));
1429 1 50 33     6 return 1 if ($tag < 10 and !defined($field[1]) );
1430 1         5 return 0;
1431             }
1432              
1433             ####################################################################
1434              
1435             # field_updatehook echos the version in MARC without the recordnum.
1436              
1437             ####################################################################
1438 117     117   303 sub field_updatehook { # rec
1439             # nothing. Subclass may want to handle this.
1440             }
1441              
1442              
1443             ####################################################################
1444              
1445             # getfields() takes a template and returns an array of fieldrefs from
1446             # $marc->[$recnum]{'array'} including all with the appropriate tag
1447             # and having the property that they are a contiguous group. (So may
1448             # include fields with other tags.)
1449              
1450             ####################################################################
1451             sub getfields { # rec
1452              
1453 113     113   185 my $marcrec=shift;
1454 113         180 my $params=shift;
1455              
1456 113         151 my $field = $params->{'field'};
1457 113 50       242 unless ($field) {mycarp "You must specify a field"; return}
  0         0  
  0         0  
1458 113 50       9226 unless ($field =~ /^\d{3}$/) {mycarp "Invalid field specified"; return}
  0         0  
  0         0  
1459              
1460 113         164 my @ans=();
1461 113         134 my $first = undef;
1462 113         114 my $last = $first;
1463 113         123 my $pos = 0;
1464 113         119 for (@{$marcrec->{'array'}}) {
  113         281  
1465 2383 100 100     5516 $first = $pos if ($_->[0] eq $field && !defined($first)) ;
1466 2383 100       4316 $last = $pos if $_->[0] eq $field;
1467 2383         2802 $pos++;
1468             }
1469 113 100       388 return () unless defined($first);
1470 106         176 return @{$marcrec->{'array'}}[$first..$last]; # array slice. Look it up.
  106         403  
1471             }
1472              
1473             ####################################################################
1474              
1475             # deletefirst() takes a template and a boolean $do_rebuild_map to
1476             # rebuild the map. It deletes the field data for a first match, using
1477             # the template and leaves the rest alone. If the template has a
1478             # subfield element it deletes based on the subfield information in the
1479             # template. If the last subfield of a field is deleted, deletefirst()
1480             # also deletes the field. It complains about attempts to delete
1481             # indicators. If there is no match, it does nothing. Deletefirst also
1482             # rebuilds the map if $do_rebuild_map. Deletefirst returns the number
1483             # of matches deleted (that would be 0 or 1), or undef if it feels
1484             # grumpy (i.e. carps).
1485              
1486             ####################################################################
1487              
1488             sub deletefirst { # rec
1489 18   50 18   49 my $marcrec = shift || return;
1490 18         21 my $template = shift;
1491 18 50       55 return unless (ref($template) eq "HASH");
1492 18 50       46 return if (defined $template->{'value'});
1493              
1494 18         26 my $field = $template->{'field'};
1495              
1496 18         29 my $subfield = $template->{'subfield'};
1497 18         25 my $do_rebuild_map = $template->{'rebuild_map'};
1498 18 50 66     55 if (defined($subfield) and $subfield =~/^i[12]$/) {mycarp "Cannot delete indicators"; return undef}
  0         0  
  0         0  
1499             #I know that $marc->{$field}{field} is this information
1500             #But I don't want to depend on the map being up-to-date allways.
1501              
1502 18         51 my @fieldrefs = $marcrec->getfields($template); #helps with cjk.
1503              
1504 18 100       52 return 0 unless scalar(@fieldrefs);
1505            
1506 14 100 66     69 if ($field and not($subfield)) {
1507 12         18 shift @fieldrefs;
1508 12         38 $marcrec->updatefields($template,\@fieldrefs);
1509 12 50       30 $marcrec->rebuild_map($field) if $do_rebuild_map;
1510 12         40 return 1;
1511             }
1512              
1513              
1514             #Linear search for the field where deletion happens and the position
1515             #in that field.
1516 2         4 my $rvictim=0;
1517 2         3 my $fieldnum = 0;
1518 2         4 foreach my $fieldref (@fieldrefs) {
1519 2 100       7 if ($marcrec->getmatch($subfield,$fieldref)){
1520 1         2 $rvictim=$fieldref;
1521 1         2 last;
1522             }
1523 1         3 $fieldnum++;
1524             }
1525 2 100       6 if (!$rvictim) {
1526 1 50       3 $marcrec->rebuild_map($field) if $do_rebuild_map;
1527 1         4 return 0;
1528             }
1529              
1530             #Now we know that we have a field and subfield with a match.
1531             #Find the first one and kill it. Kill the enclosing field
1532             #if it is the last one.
1533 1         4 $marcrec->deletesubfield($subfield,$rvictim);
1534 1         3 $marcrec->field_updatehook($rvictim);
1535 1 50       4 if ($marcrec->field_is_empty($rvictim)) {
1536 0         0 splice @fieldrefs,$fieldnum,1;
1537 0         0 $marcrec->updatefields($template,\@fieldrefs);
1538             }
1539             #here we don't need to directly touch $marc->{array}
1540             # since we are not changing its structure.
1541 1 50       3 $marcrec->rebuild_map($field) if $do_rebuild_map;
1542 1         3 return 1;
1543             }
1544              
1545             sub _params {
1546 170     170   177 my $template =shift;
1547 170 100       561 return {} unless ref $template eq 'HASH';
1548 167         879 my %params = %$template;
1549 167         677 %params = (%params,@_);
1550 167         386 return \%params;
1551             }
1552              
1553             ####################################################################
1554             # _writemarc() takes a MARC object as its input and returns the #
1555             # the USMARC equivalent of the object as a string #
1556             ####################################################################
1557             sub _writemarc { # rec
1558 16     16   19 my $marcrec=shift;
1559 16         16 my $args=shift;
1560 16         18 my (@record, $fieldbase, $fielddata, $fieldlength, $fieldposition,
1561             $marcrecord, $recordlength);
1562            
1563 16         17 my $record = $marcrec;
1564             #Reset variables
1565 16         17 my $position=0; my $directory=""; my $fieldstream="";
  16         16  
  16         18  
1566 16         36 my $leader=$record->{'000'}[1];
1567 16         16 foreach my $field (@{$record->{'array'}}) {
  16         31  
1568 296         394 my $tag = $field->[0];
1569 296 100       495 if ($tag eq '000') {next}; #don't output the directory!
  16         25  
1570 280         277 my $fielddata="";
1571 280 100       411 if ($tag < 10) {
1572 64         87 $fielddata=$field->[1];
1573             }
1574             else {
1575 216         313 $fielddata.=$field->[1].$field->[2]; #add on indicators
1576 216         226 my @subfields=@{$field}[3..$#{$field}];
  216         601  
  216         412  
1577 216         451 while (@subfields) {
1578 426         539 $fielddata.="\037".shift(@subfields); #shift off subfield delimiter
1579 426         975 $fielddata.=shift(@subfields); #shift off subfield value
1580             }
1581             }
1582 280         304 $fielddata.="\036";
1583 280         469 $fieldlength=_offset(length($fielddata),4);
1584 280         1056 $fieldposition=_offset($position,5);
1585 280         380 $directory.=$tag.$fieldlength.$fieldposition;
1586 280         353 $position+=$fieldlength;
1587 280         453 $fieldstream.=$fielddata;
1588             }
1589 16         21 $directory.="\036";
1590 16         19 $fieldstream.="\035";
1591 16         21 $fieldbase=24+length($directory);
1592 16         24 $fieldbase=_offset($fieldbase,5);
1593 16         24 $recordlength=24+length($directory)+length($fieldstream);
1594 16         24 $recordlength=_offset($recordlength,5);
1595 16         118 $leader=~s/^.{5}(.{7}).{5}(.{7})/$recordlength$1$fieldbase$2/;
1596              
1597 16         52 $marcrecord ="$leader$directory$fieldstream";
1598              
1599 16         36 $record->{'000'}[1] = $leader; # save recomputed version
1600 16         125 return $marcrecord;
1601             }
1602            
1603             ####################################################################
1604             # _marc2ascii() takes a MARC object as its input and returns the #
1605             # ASCII equivalent of the object (field names, indicators, field #
1606             # values and line-breaks) #
1607             ####################################################################
1608             sub _marc2ascii {
1609              
1610 18     18   26 my $marcrec=shift;
1611 18         23 my $args=shift;
1612 18   50     48 my $newline = $args->{'lineterm'} || "\n";
1613 18         25 my $output = "";
1614 18         26 my $record=$marcrec;
1615 18         26 foreach my $fields (@{$record->{'array'}}) { #cycle each field
  18         35  
1616 373         471 my $tag=$fields->[0];
1617 373 50       8076 print "ASCII: tag = $tag\n" if $MARC::DEBUG;
1618 373 100       566 if ($tag<10) {
1619 95         184 $output.="$fields->[0] $fields->[1]";
1620             }
1621             else {
1622 278         465 $output.="$tag $fields->[1]$fields->[2] ";
1623 278         385 my @subfields = @{$fields}[3..$#{$fields}];
  278         743  
  278         632  
1624 278         632 while (@subfields) { #cycle through subfields
1625 495         1321 $output .= "\$".shift(@subfields).shift(@subfields);
1626             } #finish cycling through subfields
1627             } #finish tag test < 10
1628 373         589 $output .= $newline; #put a newline at the end of the field
1629             }
1630 18         35 $output.=$newline; #put an extra newline to separate records
1631 18         121 return $output;
1632             }
1633              
1634             ####################################################################
1635             # _marcmaker() takes a MARC object as its input and converts it #
1636             # into MARCMaker format, which is returned as a string #
1637             ####################################################################
1638             sub _marcmaker { # rec
1639 24     24   67 my @output = ();
1640 24         40 my $marcrec=shift;
1641 24         43 my $args=shift;
1642 24         53 my $proto_rec=$args->{'proto_rec'};
1643 24 100       1067081 unless (exists $args->{'charset'}) {
1644 6 100       60 unless (exists $proto_rec->{'brkrchar'}) {
1645 5         24 $proto_rec->{'brkrchar'} = ustext_default(); # hash ref
1646             }
1647 6         32 $args->{'charset'} = $proto_rec->{'brkrchar'};
1648 6         17 $proto_rec->{'charset'} = $proto_rec->{'brkrchar'};
1649             }
1650 24         90 local $^W = 0; # no warnings
1651              
1652 24         37 my $record=$marcrec;
1653 24         35 foreach my $fields (@{$record->{'array'}}) { #cycle each field
  24         75  
1654 476         847 my $tag=$fields->[0];
1655 476 50       1015 print "OUT: tag = $tag\n" if $MARC::DEBUG;
1656 476 100       1060 if ($tag eq '000') {
    100          
1657 24         43 my $value=$fields->[1];
1658 24         139 $value=~s/ /\\/go;
1659 24         74 push @output, "=LDR $value";
1660             }
1661             elsif ($tag<10) {
1662 100         313 my $value = _char2maker($fields->[1], $args->{'charset'});
1663 100         275 $value=~s/ /\\/go;
1664 100         275 push @output, "=$tag $value";
1665             }
1666             else {
1667 352         440 my $indicator1=$fields->[1];
1668 352         804 $indicator1=~s/ /\\/;
1669 352         495 my $indicator2=$fields->[2];
1670 352         826 $indicator2=~s/ /\\/;
1671 352         616 my $output="=$tag $indicator1$indicator2";
1672 352         390 my @subfields = @{$fields}[3..$#{$fields}];
  352         1025  
  352         572  
1673 352         839 while (@subfields) { #cycle through subfields
1674 650         881 my $subfield_id = shift(@subfields);
1675 650         1576 my $subfield = _char2maker( shift(@subfields),
1676             $args->{'charset'} );
1677 650         2719 $output .= "\$$subfield_id$subfield";
1678             } #finish cycling through subfields
1679 352         1018 push @output, $output;
1680             } #finish tag test < 10
1681             }
1682 24         53 push @output,""; #put an extra blank line to separate records
1683            
1684 24   50     155 my $newline = $args->{'lineterm'} || "\015\012";
1685 24 100       76 if ($args->{'nolinebreak'}) {
1686 8         84 my $breaker1 = join ($newline, @output) . $newline;
1687 8         103 return $breaker1;
1688             }
1689             # linebreak on by default
1690 16         27 my @output2 = ();
1691 16         31 foreach my $outline (@output) {
1692 344 100       518 if (length($outline) < 66) {
1693 302         319 push @output2, $outline;
1694 302         361 next;
1695             }
1696             else {
1697 42         1688 my @words = split (/\s{1,1}/, $outline);
1698 42         155 my $outline2 = shift @words;
1699 42         70 foreach my $word (@words) {
1700 2276 100       3508 if (length($outline2) + length($word) < 66) {
1701 2032         11874 $outline2 .= " $word";
1702             }
1703             else {
1704 244         293 push @output2, $outline2;
1705 244         355 $outline2 = " $word";
1706             }
1707             }
1708 42         261 push @output2, $outline2;
1709             }
1710             }
1711 16         256 my $breaker = join ($newline, @output2);
1712 16         244 return $breaker;
1713             }
1714              
1715             sub _char2maker {
1716 750     750   9990 my @marc_string = split (//, shift);
1717 750         1851 my $charmap = shift;
1718 750         2203 my $maker_string = join ('', map { ${$charmap}{$_} } @marc_string);
  32538         40553  
  32538         87057  
1719 750         5050 while ($maker_string =~ s/(&)([^ ]{1,7}?)(;)/{$2}/o) {}
1720 750         4806 return $maker_string;
1721             }
1722              
1723             sub ustext_default {
1724 5     5   85 my @hexchar = (0x00..0x1a,0x1c,0x7f..0x8c,0x8f..0xa0,0xaf,0xbb,
1725             0xbe,0xbf,0xc7..0xdf,0xfc,0xfd,0xff);
1726 5         17 my %outchar = map {chr($_), sprintf ("{%2.2X}",int $_)} @hexchar;
  460         1527  
1727              
1728 5         75 my @ascchar = map {chr($_)} (0x20..0x23,0x25..0x7a,0x7c,0x7e);
  460         876  
1729 5         30 foreach my $asc (@ascchar) { $outchar{$asc} = $asc; }
  460         1074  
1730              
1731 5         49 $outchar{chr(0x1b)} = '{esc}'; # escape
1732 5         40 $outchar{chr(0x24)} = '{dollar}'; # dollar sign
1733 5         143 $outchar{chr(0x5c)} = '{bsol}'; # back slash (reverse solidus)
1734 5         17 $outchar{chr(0x7b)} = '{lcub}'; # opening curly brace
1735 5         15 $outchar{chr(0x7d)} = '{rcub}'; # closing curly brace
1736 5         28 $outchar{chr(0x8d)} = '{joiner}'; # zero width joiner
1737 5         35 $outchar{chr(0x8e)} = '{nonjoin}'; # zero width non-joiner
1738 5         20 $outchar{chr(0xa1)} = '{Lstrok}'; # latin capital letter l with stroke
1739 5         17 $outchar{chr(0xa2)} = '{Ostrok}'; # latin capital letter o with stroke
1740 5         10 $outchar{chr(0xa3)} = '{Dstrok}'; # latin capital letter d with stroke
1741 5         11 $outchar{chr(0xa4)} = '{THORN}'; # latin capital letter thorn (icelandic)
1742 5         19 $outchar{chr(0xa5)} = '{AElig}'; # latin capital letter AE
1743 5         12 $outchar{chr(0xa6)} = '{OElig}'; # latin capital letter OE
1744 5         11 $outchar{chr(0xa7)} = '{softsign}'; # modifier letter soft sign
1745 5         14 $outchar{chr(0xa8)} = '{middot}'; # middle dot
1746 5         18 $outchar{chr(0xa9)} = '{flat}'; # musical flat sign
1747 5         10 $outchar{chr(0xaa)} = '{reg}'; # registered sign
1748 5         11 $outchar{chr(0xab)} = '{plusmn}'; # plus-minus sign
1749 5         12 $outchar{chr(0xac)} = '{Ohorn}'; # latin capital letter o with horn
1750 5         10 $outchar{chr(0xad)} = '{Uhorn}'; # latin capital letter u with horn
1751 5         11 $outchar{chr(0xae)} = '{mlrhring}'; # modifier letter right half ring (alif)
1752 5         11 $outchar{chr(0xb0)} = '{mllhring}'; # modifier letter left half ring (ayn)
1753 5         12 $outchar{chr(0xb1)} = '{lstrok}'; # latin small letter l with stroke
1754 5         11 $outchar{chr(0xb2)} = '{ostrok}'; # latin small letter o with stroke
1755 5         11 $outchar{chr(0xb3)} = '{dstrok}'; # latin small letter d with stroke
1756 5         12 $outchar{chr(0xb4)} = '{thorn}'; # latin small letter thorn (icelandic)
1757 5         19 $outchar{chr(0xb5)} = '{aelig}'; # latin small letter ae
1758 5         15 $outchar{chr(0xb6)} = '{oelig}'; # latin small letter oe
1759 5         12 $outchar{chr(0xb7)} = '{hardsign}'; # modifier letter hard sign
1760 5         10 $outchar{chr(0xb8)} = '{inodot}'; # latin small letter dotless i
1761 5         11 $outchar{chr(0xb9)} = '{pound}'; # pound sign
1762 5         11 $outchar{chr(0xba)} = '{eth}'; # latin small letter eth
1763 5         11 $outchar{chr(0xbc)} = '{ohorn}'; # latin small letter o with horn
1764 5         11 $outchar{chr(0xbd)} = '{uhorn}'; # latin small letter u with horn
1765 5         12 $outchar{chr(0xc0)} = '{deg}'; # degree sign
1766 5         12 $outchar{chr(0xc1)} = '{scriptl}'; # latin small letter script l
1767 5         10 $outchar{chr(0xc2)} = '{phono}'; # sound recording copyright
1768 5         20 $outchar{chr(0xc3)} = '{copy}'; # copyright sign
1769 5         11 $outchar{chr(0xc4)} = '{sharp}'; # sharp
1770 5         14 $outchar{chr(0xc5)} = '{iquest}'; # inverted question mark
1771 5         10 $outchar{chr(0xc6)} = '{iexcl}'; # inverted exclamation mark
1772 5         10 $outchar{chr(0xe0)} = '{hooka}'; # combining hook above
1773 5         12 $outchar{chr(0xe1)} = '{grave}'; # combining grave
1774 5         11 $outchar{chr(0xe2)} = '{acute}'; # combining acute
1775 5         25 $outchar{chr(0xe3)} = '{circ}'; # combining circumflex
1776 5         15 $outchar{chr(0xe4)} = '{tilde}'; # combining tilde
1777 5         101 $outchar{chr(0xe5)} = '{macr}'; # combining macron
1778 5         11 $outchar{chr(0xe6)} = '{breve}'; # combining breve
1779 5         11 $outchar{chr(0xe7)} = '{dot}'; # combining dot above
1780 5         9 $outchar{chr(0xe8)} = '{uml}'; # combining diaeresis (umlaut)
1781 5         11 $outchar{chr(0xe9)} = '{caron}'; # combining hacek
1782 5         16 $outchar{chr(0xea)} = '{ring}'; # combining ring above
1783 5         11 $outchar{chr(0xeb)} = '{llig}'; # combining ligature left half
1784 5         12 $outchar{chr(0xec)} = '{rlig}'; # combining ligature right half
1785 5         13 $outchar{chr(0xed)} = '{rcommaa}'; # combining comma above right
1786 5         12 $outchar{chr(0xee)} = '{dblac}'; # combining double acute
1787 5         9 $outchar{chr(0xef)} = '{candra}'; # combining candrabindu
1788 5         11 $outchar{chr(0xf0)} = '{cedil}'; # combining cedilla
1789 5         11 $outchar{chr(0xf1)} = '{ogon}'; # combining ogonek
1790 5         9 $outchar{chr(0xf2)} = '{dotb}'; # combining dot below
1791 5         13 $outchar{chr(0xf3)} = '{dbldotb}'; # combining double dot below
1792 5         29 $outchar{chr(0xf4)} = '{ringb}'; # combining ring below
1793 5         36 $outchar{chr(0xf5)} = '{dblunder}'; # combining double underscore
1794 5         31 $outchar{chr(0xf6)} = '{under}'; # combining underscore
1795 5         10 $outchar{chr(0xf7)} = '{commab}'; # combining comma below
1796 5         10 $outchar{chr(0xf8)} = '{rcedil}'; # combining right cedilla
1797 5         12 $outchar{chr(0xf9)} = '{breveb}'; # combining breve below
1798 5         11 $outchar{chr(0xfa)} = '{ldbltil}'; # combining double tilde left half
1799 5         16 $outchar{chr(0xfb)} = '{rdbltil}'; # combining double tilde right half
1800 5         21 $outchar{chr(0xfe)} = '{commaa}'; # combining comma above
1801 5 50       22 if ($MARC::DEBUG) {
1802 0         0 foreach my $num (sort keys %outchar) {
1803 0         0 printf "%x = %s\n", ord($num), $outchar{$num};
1804             }
1805             }
1806 5         82 return \%outchar;
1807             }
1808              
1809             ####################################################################
1810             # _marc2html takes a MARC object as its input and converts it into #
1811             # HTML. It is possible to specify which field you want to output #
1812             # as well as field labels to be used instead of the MARC codes. #
1813             # The HTML is returned as a string #
1814             ####################################################################
1815             sub _marc2html { # rec
1816 20     20   26 my $marcrec = shift;
1817 20         22 my $args = shift;
1818 20   50     88 my $newline = $args->{'lineterm'} || "\n";
1819 20         24 my $output = "";
1820 20         23 my $outputall = 1;
1821              
1822 20         27 my @tags =();
1823 20         25 @tags = grep /^[0-9]/, sort(keys(%{$args}));
  20         166  
1824              
1825 20 100       66 $outputall = 0 if (scalar(@tags));
1826 20 50       46 if (defined $args->{'fields'}) {
1827 0 0       0 if ($args->{'fields'} =~ /all$/oi) {$outputall=1} ## still needed ?????
  0         0  
1828             }
1829              
1830              
1831 20         33 my %tags =();
1832              
1833 20         29 %tags = map {$_=>1} @tags;
  16         53  
1834 20 100       45 %tags = map {$_->[0]=>1} @{$marcrec->{'array'}} if $outputall;
  90         208  
  4         13  
1835             #if 'all' fields are specified then set $outputall flag to yes
1836 20         95 local $^W = 0; # no warnings
1837              
1838 20         29 my $j=$marcrec;
1839 20         40 $output.= $newline."

";

1840            
1841 20         24 foreach my $rfield (@{$j->{'array'}}) {
  20         60  
1842 450 100       1051 $output.= $rfield->[0]." ".$j->_joinfield($rfield,$rfield->[0])."
".$newline
1843             if $tags{$rfield->[0]};
1844             }
1845 20         40 $output.="

";
1846 20         122 return $output;
1847             }
1848              
1849              
1850             ####################################################################
1851             # _urls() takes a MARC object as its input, and then extracts the #
1852             # control# (MARC 001) and URLs (MARC 856) and outputs them as #
1853             # hypertext links in an HTML page. This could then be used with a #
1854             # link checker to determine what URLs are broken. #
1855             ####################################################################
1856             sub _urls {
1857 4     4   6 my $marcrec = shift;
1858 4         6 my $args = shift;
1859 4   50     32 my $newline = $args->{'lineterm'} || "\n";
1860 4         7 my $output = "";
1861            
1862 4         5 my $controlnum=undef;
1863 4         6 foreach my $rfield (@{$marcrec->{'array'}}) {
  4         11  
1864 90 100       216 if ($rfield->[0] eq "001") {
    100          
1865 4         7 $controlnum= $rfield->[1];
1866             }
1867             elsif ($rfield->[0] eq "856") {
1868 2         9 for (my $k=3; $k< $#$rfield; $k++) {
1869 10 100       34 if ($rfield->[$k] eq "u") {
1870 2         17 $output.=qq{$controlnum :}.
1871             qq{$rfield->[$k+1]
$newline};
1872             }
1873             }
1874             }
1875             }
1876 4         15 return $output;
1877             }
1878              
1879             ####################################################################
1880             # isbd() attempts to create a quasi ISBD output format #
1881             ####################################################################
1882             sub _isbd { # rec
1883 4     4   4 my $marcrec=shift;
1884 4         15 my $args=shift;
1885              
1886 4         6 my $output = "";
1887 4   50     26 my $newline = $args->{'lineterm'} || "\n";
1888              
1889 90         242 my @reporting_fields = grep {$_->[0] =~/020|245|250|260|300|440|490|5../}
  4         9  
1890 4         6 @{$marcrec->{'array'}}; # optimization.
1891 4         10 my %tagfields = (); # This will allow random access to fields based on tags
1892 4         18 foreach my $rfield (@reporting_fields) {
1893 30         27 push @{$tagfields{$rfield->[0]}},$rfield;
  30         66  
1894             }
1895 4         14 $output .= $marcrec->_joinfield($tagfields{245}[0],"245");
1896 4         10 for (qw/250 260 300/) {
1897 12 100       42 $output .= " -- ". $marcrec->_joinfield($tagfields{$_}[0],$_) if $tagfields{$_};
1898             }
1899 4 50       12 if ($tagfields{'440'}) {
1900 0         0 $output .= " -- ";
1901 0         0 foreach my $rfield (@{$tagfields{'440'}}) {
  0         0  
1902 0         0 $output .= "(".$marcrec->_joinfield($rfield,"440").") ";
1903             }
1904             }
1905 4 50       12 if ($tagfields{'490'}) {
1906 0 0       0 $output .= " -- " unless $tagfields{'440'};
1907 0         0 foreach my $rfield (@{$tagfields{'490'}}) {
  0         0  
1908 0         0 $output .= "(".$marcrec->_joinfield($rfield,"490").") ";
1909             }
1910             }
1911 4         6 my @f500s = grep {$_->[0] =~/5../} @reporting_fields;
  30         76  
1912 4         8 foreach my $rfield (@f500s) {
1913 20         52 $output .= $newline.$marcrec->_joinfield($rfield,$rfield->[0]);
1914             }
1915 4 50       24 if ($tagfields{'020'}) {
1916 0         0 $output .= $newline.$marcrec->_joinfield($tagfields{'020'}[0]);
1917             }
1918 4         5 $output .= $newline.$newline;
1919 4         36 return $output;
1920             }
1921              
1922             ####################################################################
1923              
1924             # createrecord takes a string leader and returns a new record with
1925             # leader information at the appropriate place.
1926              
1927             ####################################################################
1928             sub createrecord { # rec
1929 22     22   31 my $marcrec = shift;
1930 22         63 local $^W = 0; # no warnings
1931 22   50     59 my $leader=shift || "00000nam 2200000 a 4500";
1932 22         63 my $newrec = $marcrec->copy_struct();
1933             #default leader see MARC documentation http://lcweb.loc.gov/marc
1934 22         58 my @ldrfield = ('000',$leader);
1935 22         86 $newrec->field_updatehook(\@ldrfield);
1936 22         27 push (@{$newrec->{'000'}},@ldrfield); #create map
  22         85  
1937 22         40 push(@{$newrec->{'array'}},$newrec->{'000'});
  22         122  
1938 22         77 return $newrec;
1939             }
1940              
1941             ####################################################################
1942             # nextrec() will read in a record from a filehandle
1943             # already been opened with openmarc(). the increment can be #
1944             # adjusted if necessary by passing a new value as a parameter. the #
1945             # new records will be APPENDED to the MARC object #
1946             ####################################################################
1947             sub nextrec {
1948 0     0   0 my $marcrec=shift;
1949 0 0       0 if (not($marcrec->{'handle'})) {
1950 0         0 mycarp "There isn't a MARC file open";
1951 0         0 return;
1952             }
1953 0 0       0 if ($marcrec->{'format'} =~ /usmarc/oi) {
    0          
1954 0         0 return _readmarc($marcrec);
1955             }
1956 0         0 elsif ($marcrec->{'format'} =~ /marcmaker/oi) {
1957 0         0 return _readmarcmaker($marcrec);
1958             }
1959             else {return (undef,-3)}
1960             }
1961              
1962             ####################################################################
1963              
1964             # Add_map is the rec equivalent of MARC::add_map (as usual, without
1965             # the record number).
1966              
1967             ####################################################################
1968             sub add_map { # rec
1969 460     460   706 my $marcrec=shift;
1970 460         528 my $rafield = shift;
1971 460         648 my $tag = $rafield->[0];
1972 460 50       4017 return undef if $tag eq '000'; #currently handle ldr yourself...
1973 460         1551 my @tmp = @$rafield;
1974 460         791 my $field_len = $#tmp;
1975 460         772 my $record = $marcrec;
1976 460 100       948 if ($tag > 10 ) {
1977 365         511 my $i1 = $rafield->[1];
1978 365         413 my $i2 = $rafield->[2];
1979 365         504 my $i12 = $i1.$i2;
1980              
1981 365         821 for(my $i=3;$i<$field_len;$i+=2) {
1982 652         1002 my $subf_code = $rafield->[$i];
1983 652         884 push(@{$record->{$tag}{$subf_code}}, \$rafield->[$i+1]);
  652         3732  
1984             }
1985 365         408 push(@{$record->{$tag}{'i1'}{$i1}},$rafield);
  365         1523  
1986 365         421 push(@{$record->{$tag}{'i2'}{$i2}},$rafield);
  365         1297  
1987 365         419 push(@{$record->{$tag}{'i12'}{$i12}},$rafield);
  365         1322  
1988             }
1989 460         533 push(@{$record->{$tag}{field}},$rafield);
  460         2708  
1990             }
1991              
1992             ####################################################################
1993              
1994             # rebuild_map() is the ::Rec version of MARC::rebuild_map().
1995              
1996             ####################################################################
1997             sub rebuild_map { # rec
1998 7     7   14 my $marcrec=shift;
1999 7         14 my $tag = shift;
2000 7 50       33 return undef if $tag eq '000'; #currently ldr is different...
2001 7         12 my @tagrefs = grep {$_->[0] eq $tag} @{$marcrec->{'array'}};
  144         290  
  7         23  
2002 7         59 delete $marcrec->{$tag};
2003 7         22 for (@tagrefs) {$marcrec->add_map($_)};
  6         18  
2004             }
2005              
2006             ####################################################################
2007              
2008             # rebuild_map_all() is the ::Rec version of MARC::rebuild_map_all()
2009              
2010             ####################################################################
2011             sub rebuild_map_all { # rec
2012 0     0   0 my $marcrec=shift;
2013 0         0 my %tags=();
2014 0         0 map {$tags{$_->[0]}++} @{$marcrec->{'array'}};
  0         0  
  0         0  
2015 0         0 foreach my $tag (keys %tags) {$marcrec->rebuild_map($tag)};
  0         0  
2016             }
2017              
2018              
2019              
2020             ####################################################################
2021              
2022             # Reads the next record out of the handle. Returns a pair (new
2023             # record,status). Status is 1 in the generic case. Status is -1 if
2024             # lengths do not match -2 if leader size is not numeric, undef if at
2025             # the last record. New record is undef if there is an error or at the
2026             # last record.
2027              
2028             ####################################################################
2029             sub _readmarc { # rec
2030 17     17   27 my $marcrec = shift;
2031 17         35 my $handle = $marcrec->{'handle'};
2032 17         22 my $string = shift;
2033 17         69 local $/ = "\035"; # cf. TPJ #14
2034 17         48 local $^W = 0; # no warnings
2035 17         29 my $line;
2036 17 50       41 $line = $string if $string;
2037 17 50 33     503 $line = <$handle> if $handle and !defined($string);
2038 17         47 my $recordlength = substr($line,0,5);
2039 17         27 my $octets = length ($line);
2040 17         112 $line=~s/[\n\r\cZ]//og;
2041 17 100       61 return (undef,undef) unless $line;
2042 12 100       58 if ($recordlength =~ /\d{5}/o) {
2043 11 50       31 print "recordlength = $recordlength, length = $octets\n"
2044             if $MARC::DEBUG;
2045 11 100       45 return (undef,-1) unless $recordlength == $octets;
2046             } else {
2047 1         5 return (undef,-2);
2048             }
2049 10         21 my @d = ();
2050 10         105 $line=~/^(.{24})([^\036]*)\036(.*)/o;
2051 10         34 my $leader=$1; my $dir=$2; my $data=$3;
  10         26  
  10         64  
2052 10         37 my $record = $marcrec->createrecord($leader);
2053              
2054 10         228 @d=$dir=~/(.{12})/go;
2055 10         27 for my $d(@d) {
2056 215         322 my @field=();
2057 215         1765 my $tag=substr($d,0,3);
2058 215         740 chop(my $field=substr($data,substr($d,7,5),substr($d,3,4)));
2059 215 100       460 if ($tag<10) {
2060 45         110 @field=($tag,$field);
2061             }
2062             else {
2063 170         897 my ($indi1, $indi2, $field_data) = unpack ("a1a1a*", $field);
2064            
2065 170         404 push (@field, $tag, $indi1, $indi2);
2066            
2067 170         537 my @subfields = split(/\037/,$field_data);
2068 170         278 foreach (@subfields) {
2069 450         610 my $delim = substr($_,0,1);
2070 450 100       2979 next unless $delim;
2071 280         398 my $subfield_data = substr($_,1);
2072 280         994 push(@field, $delim, $subfield_data);
2073            
2074             } #end parsing subfields
2075             } #end testing tag number
2076 215         277 push(@{$record->{'array'}},\@field);
  215         500  
2077 215         528 $record-> add_map(\@field);
2078             } #end processing this field
2079 10         103 return ($record,1);
2080             }
2081              
2082             ###################################################################
2083             # readmarcmaker() reads a marcmaker file into the MARC object #
2084             ###################################################################
2085             sub _readmarcmaker { # rec
2086 15     15   18 my $marcrec = shift;
2087 15         24 my $handle = $marcrec->{'handle'};
2088 15         14 my $string = shift;
2089 15         16 my $record;
2090              
2091 15 50       36 unless (exists $marcrec->{'makerchar'}) {
2092 0         0 $marcrec->{'makerchar'} = usmarc_default(); # hash ref
2093             }
2094 15         23 my $charset = $marcrec->{makerchar};
2095 15   50     62 my $lineterm = $marcrec->{'lineterm'} || "\015\012";
2096             # MS-DOS file default for MARCMaker
2097              
2098             #Set the file input separator to "\r\n\r\n", which is the same as
2099             #a blank line. A single blank line separates individual MARC records
2100             #in the MARCMakr format.
2101 15         78 local $/ = "$lineterm$lineterm"; # cf. TPJ #14
2102 15         33 local $^W = 0; # no warnings
2103 15 50       27 $record = $string if $string;
2104 15 50 33     302 $record = <$handle> if $handle and !defined($string);
2105              
2106 15 100       41 return (undef,undef) unless $record;
2107             #Split each record on the "\n=" into the @fields array
2108 14         235 my @lines=split "$lineterm=",$record;
2109 14         35 my $leader = shift @lines;
2110 14 100       54 unless ($leader =~ /^=LDR /o) {
2111 2         13 return (undef, -1);
2112             }
2113            
2114 12         612 $leader=~s/^=LDR //o; #Remove "=LDR "
2115 12         202 $leader=~s/[\n\r]//og;
2116 12         47 $leader=~s/\\/ /go; # substitute " " for \
2117 12         196 my $rec = $marcrec->createrecord($leader);
2118 12         2300 foreach my $line (@lines) {
2119             #Remove newlines from @fields ; and also substitute " " for \
2120 214         826 $line=~s/[\n\r]//og;
2121 214         819 $line=~s/\\/ /go;
2122             #get the tag name
2123 214         499 my $tag = substr($line,0,3);
2124 214         412 my @field=(); #this will be added to $marcrec and the map updated.
2125             #if the tag is less than 010 (has no indicators or subfields)
2126             #then push the data into @$field
2127 214 100       517 if ($tag < 10) {
2128 48         106 my $value = _maker2char (substr($line,5), $charset);
2129 48         311 @field=($tag,$value);
2130             }
2131             else {
2132             #elseif the tag is greater than 010 (has indicators and
2133             #subfields then add the data to the $marc object
2134 166         274 my $field_data=substr($line,7);
2135 166         240 my $i1=substr($line,5,1);
2136 166         186 my $i2=substr($line,6,1);
2137 166         359 @field = ($tag,$i1,$i2);
2138            
2139 166         4646 my @subfields=split /\$/, $field_data; #get the subfields
2140 166         252 foreach my $subfield (@subfields) {
2141 495         586 my $delim=substr($subfield,0,1); #extract subfield delimiter
2142 495 100       1014 next unless $delim;
2143 329         752 my $subfield_data= MARC::_maker2char (substr($subfield,1),
2144             $charset);
2145             #extract subfield value
2146 329         1233 push (@field, $delim, $subfield_data);
2147             } #end parsing subfields
2148             } #end tag>10
2149 214 50       434 print "DEBUG: tag = $tag\n" if $MARC::DEBUG;
2150 214         198 push @{$rec->{'array'}},\@field;
  214         728  
2151 214         510 $rec -> add_map(\@field);
2152             } #end reading this line
2153 12         98 return ($rec,1);
2154             } #end reading this record
2155              
2156             sub _maker2char { # rec
2157 377     377   1005 my $marc_string = shift;
2158 377         785 my $charmap = shift;
2159 377         1217 while ($marc_string =~ /{(\w{1,8}?)}/o) {
2160 189 100       198 if (exists ${$charmap}{$1}) {
  189         606  
2161 186         181 $marc_string = join ('', $`, ${$charmap}{$1}, $');
  186         2605  
2162             }
2163             else {
2164 3         16 $marc_string = join ('', $`, '&', $1, ';', $');
2165             }
2166             }
2167             # closing curly brace - part 2, permits {lcub}text{rcub} in input
2168 377         473 $marc_string =~ s/\}/\x7d/go;
2169 377         2346 return $marc_string;
2170             }
2171              
2172             sub usmarc_default { # rec
2173 1     1   35 my @hexchar = (0x00..0x1a,0x1c,0x7f..0x8c,0x8f..0xa0,0xaf,0xbb,
2174             0xbe,0xbf,0xc7..0xdf,0xfc,0xfd,0xff);
2175 1         3 my %inchar = map {sprintf ("%2.2X",int $_), chr($_)} @hexchar;
  92         293  
2176              
2177 1         14 $inchar{esc} = chr(0x1b); # escape
2178 1         2 $inchar{dollar} = chr(0x24); # dollar sign
2179 1         2 $inchar{curren} = chr(0x24); # dollar sign - alternate
2180 1         3 $inchar{24} = chr(0x24); # dollar sign - alternate
2181 1         3 $inchar{bsol} = chr(0x5c); # back slash (reverse solidus)
2182 1         2 $inchar{lcub} = chr(0x7b); # opening curly brace
2183 1         3 $inchar{rcub} = "}"; # closing curly brace - part 1
2184 1         2 $inchar{joiner} = chr(0x8d); # zero width joiner
2185 1         2 $inchar{nonjoin} = chr(0x8e); # zero width non-joiner
2186 1         2 $inchar{Lstrok} = chr(0xa1); # latin capital letter l with stroke
2187 1         2 $inchar{Ostrok} = chr(0xa2); # latin capital letter o with stroke
2188 1         3 $inchar{Dstrok} = chr(0xa3); # latin capital letter d with stroke
2189 1         1 $inchar{THORN} = chr(0xa4); # latin capital letter thorn (icelandic)
2190 1         2 $inchar{AElig} = chr(0xa5); # latin capital letter AE
2191 1         2 $inchar{OElig} = chr(0xa6); # latin capital letter OE
2192 1         1 $inchar{softsign} = chr(0xa7); # modifier letter soft sign
2193 1         2 $inchar{middot} = chr(0xa8); # middle dot
2194 1         3 $inchar{flat} = chr(0xa9); # musical flat sign
2195 1         2 $inchar{reg} = chr(0xaa); # registered sign
2196 1         1 $inchar{plusmn} = chr(0xab); # plus-minus sign
2197 1         2 $inchar{Ohorn} = chr(0xac); # latin capital letter o with horn
2198 1         8 $inchar{Uhorn} = chr(0xad); # latin capital letter u with horn
2199 1         2 $inchar{mlrhring} = chr(0xae); # modifier letter right half ring (alif)
2200 1         1 $inchar{mllhring} = chr(0xb0); # modifier letter left half ring (ayn)
2201 1         3 $inchar{lstrok} = chr(0xb1); # latin small letter l with stroke
2202 1         2 $inchar{ostrok} = chr(0xb2); # latin small letter o with stroke
2203 1         2 $inchar{dstrok} = chr(0xb3); # latin small letter d with stroke
2204 1         3 $inchar{thorn} = chr(0xb4); # latin small letter thorn (icelandic)
2205 1         1 $inchar{aelig} = chr(0xb5); # latin small letter ae
2206 1         2 $inchar{oelig} = chr(0xb6); # latin small letter oe
2207 1         2 $inchar{hardsign} = chr(0xb7); # modifier letter hard sign
2208 1         2 $inchar{inodot} = chr(0xb8); # latin small letter dotless i
2209 1         2 $inchar{pound} = chr(0xb9); # pound sign
2210 1         2 $inchar{eth} = chr(0xba); # latin small letter eth
2211 1         3 $inchar{ohorn} = chr(0xbc); # latin small letter o with horn
2212 1         9 $inchar{uhorn} = chr(0xbd); # latin small letter u with horn
2213 1         15 $inchar{deg} = chr(0xc0); # degree sign
2214 1         2 $inchar{scriptl} = chr(0xc1); # latin small letter script l
2215 1         2 $inchar{phono} = chr(0xc2); # sound recording copyright
2216 1         2 $inchar{copy} = chr(0xc3); # copyright sign
2217 1         2 $inchar{sharp} = chr(0xc4); # sharp
2218 1         1 $inchar{iquest} = chr(0xc5); # inverted question mark
2219 1         3 $inchar{iexcl} = chr(0xc6); # inverted exclamation mark
2220 1         1 $inchar{hooka} = chr(0xe0); # combining hook above
2221 1         2 $inchar{grave} = chr(0xe1); # combining grave
2222 1         2 $inchar{acute} = chr(0xe2); # combining acute
2223 1         2 $inchar{circ} = chr(0xe3); # combining circumflex
2224 1         9 $inchar{tilde} = chr(0xe4); # combining tilde
2225 1         2 $inchar{macr} = chr(0xe5); # combining macron
2226 1         3 $inchar{breve} = chr(0xe6); # combining breve
2227 1         2 $inchar{dot} = chr(0xe7); # combining dot above
2228 1         1 $inchar{diaer} = chr(0xe8); # combining diaeresis
2229 1         8 $inchar{uml} = chr(0xe8); # combining umlaut
2230 1         3 $inchar{caron} = chr(0xe9); # combining hacek
2231 1         2 $inchar{ring} = chr(0xea); # combining ring above
2232 1         2 $inchar{llig} = chr(0xeb); # combining ligature left half
2233 1         3 $inchar{rlig} = chr(0xec); # combining ligature right half
2234 1         2 $inchar{rcommaa} = chr(0xed); # combining comma above right
2235 1         2 $inchar{dblac} = chr(0xee); # combining double acute
2236 1         2 $inchar{candra} = chr(0xef); # combining candrabindu
2237 1         1 $inchar{cedil} = chr(0xf0); # combining cedilla
2238 1         2 $inchar{ogon} = chr(0xf1); # combining ogonek
2239 1         2 $inchar{dotb} = chr(0xf2); # combining dot below
2240 1         2 $inchar{dbldotb} = chr(0xf3); # combining double dot below
2241 1         7 $inchar{ringb} = chr(0xf4); # combining ring below
2242 1         3 $inchar{dblunder} = chr(0xf5); # combining double underscore
2243 1         2 $inchar{under} = chr(0xf6); # combining underscore
2244 1         2 $inchar{commab} = chr(0xf7); # combining comma below
2245 1         2 $inchar{rcedil} = chr(0xf8); # combining right cedilla
2246 1         3 $inchar{breveb} = chr(0xf9); # combining breve below
2247 1         2 $inchar{ldbltil} = chr(0xfa); # combining double tilde left half
2248 1         2 $inchar{rdbltil} = chr(0xfb); # combining double tilde right half
2249 1         3 $inchar{commaa} = chr(0xfe); # combining comma above
2250 1 50       4 if ($MARC::DEBUG) {
2251 0         0 foreach my $str (sort keys %inchar) {
2252 0         0 printf "%s = %x\n", $str, ord($inchar{$str});
2253             }
2254             }
2255 1         7 return \%inchar;
2256             }
2257              
2258             ####################################################################
2259              
2260             # updatefirst() takes a template, a request to rebuild the index, and
2261             # an array from $marc->[recnum]{array}. It replaces/creates the field
2262             # data for a first match, using the template, and leaves the rest
2263             # alone. If the template has a subfield element, (this includes
2264             # indicators) it ignores all other information in the array and only
2265             # updates/creates based on the subfield information in the array. If
2266             # the template has no subfield information then indicators are left
2267             # untouched unless a new field needs to be created, in which case they
2268             # are left blank.
2269              
2270             ####################################################################
2271              
2272             sub updatefirst { # rec
2273 95   50 95   234 my $marcrec = shift || return;
2274 95         108 my $template = shift;
2275 95 50       290 return unless (ref($template) eq "HASH");
2276 95 50       183 return unless (@_);
2277 95 50       262 return if (defined $template->{'value'});
2278              
2279              
2280 95         203 my @ufield = @_;
2281 95         162 my $field = $template->{'field'};
2282 95         125 my $subfield = $template->{'subfield'};
2283 95         132 my $do_rebuild_map = $template->{'rebuild_map'};
2284              
2285 95         142 $ufield[0]= $field;
2286 95         159 my $ufield_lt_10_value = $ufield[1];
2287 95         208 my $ftemplate = {field=>$field};
2288 95 50       208 if (!$field) {mycarp "Need a field to configure my changing needs."; return undef}
  0         0  
  0         0  
2289              
2290 95         216 my @fieldrefs = $marcrec->getfields($template);
2291              
2292             # An invariant is that at most one element of @fieldrefs is affected.
2293 95 100 66     428 if ($field and not($subfield)) {
2294             #save the indicators! Yes! Yes!
2295 91         144 my ($i1,$i2) = (" "," ");
2296 91 100       198 if (defined($fieldrefs[0])) {
2297 89         142 $i1 = $fieldrefs[0][1];
2298 89         159 $i2 = $fieldrefs[0][2];
2299             }
2300 91         120 $ufield[1]=$i1;
2301 91         114 $ufield[2]=$i2;
2302 91 100       224 if ($field <10) {@ufield = ($field,$ufield_lt_10_value)}
  87         215  
2303 91         118 my $rafieldrefs = \@fieldrefs;
2304 91         221 $marcrec->field_updatehook(\@ufield);
2305 91         166 $rafieldrefs->[0] = \@ufield;
2306 91 50       234 if (!scalar(@fieldrefs)) {
2307 0         0 $marcrec->updatefields($template,$rafieldrefs);
2308 0         0 return;
2309             }
2310 91         127 $fieldrefs[0]=\@ufield;
2311             #There is no issue with $fieldrefs being taken over by the splice in updatefields.
2312             # in current testing. Perl may change its behavior later...
2313 91         221 $marcrec->updatefields($template,\@fieldrefs);
2314 91         484 return;
2315             } #end field.
2316             # The case of adding first subfields is hard. (Not too bad with
2317             # indicators since every non-control field has them.)
2318             # OK, we have field, and subfield.
2319 4 50 33     26 if ($field and $subfield) {
2320 4 100       12 if ($field <10) {croak "Cannot update subfields of control fields"; return undef}
  1         251  
  0         0  
2321              
2322 3         5 my $rvictim=0;
2323 3         5 my $fieldnum = 0;
2324 3         4 my $rval = 0;
2325 3         6 foreach my $fieldref (@fieldrefs) {
2326 7         32 $rval = $marcrec->getmatch($subfield,$fieldref);
2327 7 100       17 if ($rval){
2328 1         1 $rvictim=$fieldref;
2329 1         2 last;
2330             }
2331 6         9 $fieldnum++;
2332             }
2333             # At this stage we have the number of the field $fieldnum,
2334             # whether there is a match, $rvictim,
2335             # and what to update if there is, $rval.
2336              
2337 3 50 66     18 if (!$rvictim and $subfield =~/^i[12]$/) {
2338 0         0 mycarp "Field $field does not exist. Can only add indicator $subfield to existing fields.";
2339 0         0 return undef;
2340             }
2341             #Now we need to find first match in @ufield.
2342 3         5 my $usub = undef;
2343 3 50       10 $usub=$ufield[1] if $subfield eq 'i1';
2344 3 50       13 $usub=$ufield[2] if $subfield eq 'i2';
2345              
2346 3         11 for(my $i=3;$i<@ufield;$i = $i+2) {
2347 5         8 my $sub = $ufield[$i];
2348 5 100       16 if ($sub eq $subfield) {
2349 3         6 $usub = $ufield[$i+1];
2350 3         5 last;
2351             }
2352             }
2353 3 50       9 mycarp(
2354             "Did not find $subfield in spec (".
2355             join " ",@ufield . ")"
2356             ) if !defined($usub);
2357              
2358 3 50       10 if (!scalar(@fieldrefs)) {
2359 0         0 my @newfield = ($field, ' ',' ', $subfield =>$usub);
2360 0         0 my $rafields;
2361 0         0 $marcrec->field_updatehook(\@newfield);
2362 0         0 $rafields->[0] = \@newfield;
2363 0         0 return $marcrec->updatefields($template,$rafields);
2364             }
2365             #The general insert case.
2366 3 50 100     56 if (!$rvictim and scalar(@fieldrefs)) {
2367 2         4 $rvictim = $fieldrefs[0];
2368 2         8 $marcrec->insertpos($subfield,$usub,$rvictim);
2369 2         6 $marcrec->field_updatehook($rvictim);
2370 2 50       6 $marcrec->rebuild_map($field) if $do_rebuild_map;
2371 2         13 return 1; # $rvictim is now defined, so can't depend on future
2372             # control logic.
2373             }
2374             #The general replace case.
2375 1 50       3 if ($rvictim) {
2376 1         2 $$rval = $usub;
2377 1         3 $marcrec->field_updatehook($rvictim);
2378              
2379             # The following line is unecessary for this class:
2380             # everything updates due to hard-coded ref
2381             # relationships in the index. Left so that subclasses
2382             # can do their thing with less over-ruling.
2383              
2384 1 50       3 $marcrec->rebuild_map($field) if $do_rebuild_map;
2385 1         5 return 1;
2386             }
2387             } #end $field and $subfield
2388             }
2389              
2390             ####################################################################
2391              
2392             # updatefields() takes a template which specifies a
2393             # $do_rebuild_map and a field (needs the field in case $rafields->[0]
2394             # is empty). It also takes a ref to an array of fieldrefs formatted
2395             # like the output of getfields(), and replaces/creates the field
2396             # data. It assumes that it should remove the fields with the first tag
2397             # in the fieldrefs. It calls rebuild_map() if $do_rebuild_map.
2398              
2399             ####################################################################
2400             sub updatefields { # rec
2401 103   50 103   245 my $marcrec = shift || return;
2402 103         129 my $template = shift;
2403              
2404 103         146 my $do_rebuild_map = $template->{'rebuild_map'};
2405 103         193 my $tag = $template->{'field'};
2406 103         114 my $rafieldrefs = shift;
2407 103         186 my @fieldrefs = @$rafieldrefs;
2408              
2409              
2410 103         117 my $pos = 0;
2411 103         116 my $first=undef;
2412 103         119 my $last = $first; # Should be "Let the first be last". Misbegotten Perl syntax.
2413 103         96 my $firstpast = undef;
2414 103         170 my $len = 0;
2415 103         102 my @mfields = @{$marcrec->{'array'}};
  103         401  
2416 103         130 my $insertpos = undef;
2417 103         157 for (@mfields) {
2418 2182 100 100     17073 $first = $pos if ($_->[0] eq $tag and !defined($first)) ;
2419 2182 100       4002 $last = $pos if $_->[0] eq $tag;
2420 2182 100 100     7541 $firstpast = $pos if ($_->[0] >= $tag and !defined($firstpast)) ;
2421 2182         2704 $pos++;
2422             }
2423 103 100       274 $len = $last - $first +1 if defined($first);
2424 103 50       198 $insertpos = scalar(@mfields) if !defined($firstpast);
2425 103 100       201 $insertpos = $first if (defined($first));
2426 103 100       173 $insertpos = $firstpast unless $insertpos;
2427 103         113 splice @{$marcrec->{'array'}},$insertpos,$len,@fieldrefs;
  103         283  
2428 103 50       459 $marcrec->rebuild_map($tag) if $do_rebuild_map;
2429             }
2430              
2431             ####################################################################
2432             # output() will call the appropriate output method using the marc #
2433             # object and desired format parameters. #
2434             ####################################################################
2435             sub output {
2436 0     0   0 my $marcrec=shift;
2437 0         0 my $args=shift;
2438 0         0 my $output = "";
2439 0   0     0 my $newline = $args->{'lineterm'} || "\n";
2440              
2441 0 0 0     0 $marcrec->add_005($args) if ($args->{'file'} or $args->{'add_005s'});
2442              
2443 0 0       0 unless (exists $args->{'format'}) {
2444             # everything to string
2445 0         0 $args->{'format'} = "usmarc";
2446 0         0 $args->{'lineterm'} = $newline;
2447             }
2448 0 0       0 if ($args->{'format'} =~ /marc$/oi) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2449 0         0 $output = _writemarc($marcrec,$args);
2450             }
2451             elsif ($args->{'format'} =~ /marcmaker$/oi) {
2452 0         0 $output = _marcmaker($marcrec,$args);
2453             }
2454             elsif ($args->{'format'} =~ /ascii$/oi) {
2455 0         0 $output = _marc2ascii($marcrec,$args);
2456             }
2457             elsif ($args->{'format'} =~ /html$/oi) {
2458 0         0 $output .= _marc2html($marcrec,$args);
2459             }
2460             elsif ($args->{'format'} =~ /html_header$/oi) {
2461 0         0 $output = "Content-type: text/html\015\012\015\012";
2462             }
2463             elsif ($args->{'format'} =~ /html_start$/oi) {
2464 0 0       0 if ($args->{'title'}) {
2465 0         0 $output = "$args->{'title'}";
2466 0         0 $output .= "$newline";
2467             }
2468             else {
2469 0         0 $output = "";
2470             }
2471             }
2472             elsif ($args->{'format'} =~ /html_body$/oi) {
2473 0         0 $output =_marc2html($marcrec,$args);
2474             }
2475             elsif ($args->{'format'} =~ /html_footer$/oi) {
2476 0         0 $output = "$newline$newline";
2477             }
2478             elsif ($args->{'format'} =~ /urls$/oi) {
2479 0         0 $output .= _urls($marcrec,$args);
2480             }
2481             elsif ($args->{'format'} =~ /isbd$/oi) {
2482 0         0 $output = _isbd($marcrec,$args);
2483             }
2484             elsif ($args->{'format'} =~ /xml/oi) {
2485 0 0       0 mycarp "XML formats are now handled by MARC::XML" if ($^W);
2486 0         0 return;
2487             }
2488 0 0       0 if ($args->{'file'}) {
2489 0 0       0 if ($args->{'file'} !~ /^>/) {
2490 0         0 mycarp "Don't forget to use > or >> with output file name";
2491 0         0 return;
2492             }
2493 0 0       0 open (OUT, $args->{file}) || mycarp "Couldn't open file: $!";
2494             #above quote is bad if {file} is tainted. Is probably unecessary.dgl.
2495 0         0 binmode OUT;
2496 0         0 print OUT $output;
2497 0 0       0 close OUT || mycarp "Couldn't close file: $!";
2498 0         0 return 1;
2499             }
2500             #if no filename was specified return the output so it can be grabbed
2501             else {
2502 0         0 return $output;
2503             }
2504             }
2505              
2506             ####################################################################
2507              
2508             # add_005s takes a template and adds current 005s to the elements of
2509             # $marc mentioned in $template->{records}
2510              
2511             ####################################################################
2512             sub add_005 {
2513 86     86   193 my $marcrec=shift;
2514 86         99 my $time = shift;
2515 86         168 my @m005 = ('005', $time );
2516 86         329 $marcrec->updatefirst({field=>'005'},@m005);
2517             }
2518              
2519             ##############################################################
2520             sub _joinfield { # rec
2521 163     163   182 my $marcrec=shift;
2522 163         232 my ($rfield,$field,$delim)=@_;
2523 163         145 my $result;
2524 163 100       402 return $rfield->[1] if $field<10;
2525              
2526 125 100       196 if ($delim) {
2527 2         7 foreach (my $i=3; $i<$#$rfield; $i+=2) {
2528 3         13 $result.=$delim.$rfield->[$i].$rfield->[$i+1];
2529             }
2530 2         9 return $result;
2531             }
2532              
2533 123         292 for (my $i=4; $i<=$#$rfield; $i=$i+2) {
2534 225         295 $result.=$rfield->[$i];
2535 225 50       768 $result.=" " unless $result=~/ $/;
2536             }
2537 123         4666 return $result;
2538             }
2539              
2540             ####################################################################
2541              
2542             # getmatch() takes a subfield code (can be an indicator) and a fieldref
2543             # Returns 0 or a ref to the value to be updated.
2544              
2545             ####################################################################
2546             sub getmatch { # rec
2547 9   50 9   25 my $marcrec = shift || return;
2548 9         13 my $subf = shift;
2549 9         11 my $rfield = shift;
2550 9         14 my $tag = $rfield->[0];
2551 9 50       24 if ($tag < 10) {mycarp "can't find subfields or indicators for control fields"; return undef}
  0         0  
  0         0  
2552 9 50       23 return \$rfield->[1] if $subf eq 'i1';
2553 9 50       16 return \$rfield->[2] if $subf eq 'i2';
2554              
2555 9         45 for (my $i=3;$i<@$rfield;$i+=2) {
2556 11 100       44 return \$rfield->[$i+1] if $rfield->[$i] eq $subf;
2557             }
2558 7         16 return 0;
2559             }
2560              
2561             ####################################################################
2562              
2563             # deletesubfield() takes a subfield code (can not be an indicator) and a
2564             # fieldref. Deletes the subfield code and its value in the fieldref at
2565             # the first match on subfield code. Assumes there is an exact
2566             # subfield match in $fieldref.
2567              
2568             ####################################################################
2569             sub deletesubfield { # rec
2570 1   50 1   4 my $marcrec = shift || return;
2571 1         2 my $subf = shift;
2572 1         2 my $rfield = shift;
2573 1         3 my $tag = $rfield->[0];
2574 1 50       4 if ($tag < 10) {mycarp "Can't use subfields or indicators for control fields"; return undef}
  0         0  
  0         0  
2575              
2576 1 50       4 if ($subf =~/i[12]/) {mycarp "Can't delete an indicator."; return undef}
  0         0  
  0         0  
2577 1         2 my $i=3;
2578 1         5 for ($i=3;$i<@$rfield;$i+=2) {
2579 2 100       8 last if $rfield->[$i] eq $subf;
2580             }
2581 1         3 splice @$rfield,$i,2;
2582            
2583             }
2584              
2585             ####################################################################
2586              
2587             # insertpos() takes a subfield code (can not be an indicator), a
2588             # value, and a fieldref. Updates the fieldref with the first
2589             # place that the fieldref can match. Assumes there is no exact
2590             # subfield match in $fieldref.
2591              
2592             ####################################################################
2593             sub insertpos { # rec
2594 2   50 2   18 my $marcrec = shift || return;
2595 2         4 my $subf = shift;
2596 2         3 my $value = shift;
2597 2         4 my $rfield = shift;
2598 2         4 my $tag = $rfield->[0];
2599 2 50       6 if ($tag < 10) {mycarp "Can't use subfields or indicators for control fields"; return undef}
  0         0  
  0         0  
2600              
2601 2 50       6 if ($subf =~/i[12]/) {mycarp "Can't insert past an indicator."; return undef}
  0         0  
  0         0  
2602 2         3 my $i=3;
2603 2         6 for ($i=3;$i<@$rfield;$i+=2) {
2604 3 50       13 last if $rfield->[$i] gt $subf;
2605             }
2606 2         8 splice @$rfield,$i,0,$subf,$value;
2607             }
2608              
2609             ####################################################################
2610              
2611             # getfirstvalue() will return the first value of a field or subfield
2612             # or indicator or i12 in a particular record found in the MARC
2613             # object. It does not depend on the index being up to date.
2614              
2615             ####################################################################
2616             sub getfirstvalue { # rec
2617 2     2   5 my $marcrec= shift;
2618 2         3 my $template=shift;
2619 2 50       11 return unless (ref($template) eq "HASH");
2620 2         6 my $field = $template->{'field'};
2621 2         4 my $delim = $template->{'delimiter'};
2622 2         5 my $subfield;
2623 2 50       11 $subfield = $template->{'subfield'} if $template->{'subfield'};
2624            
2625 2 50       7 if (not($field)) {mycarp "You must specify a field"; return}
  0         0  
  0         0  
2626 2 50       15 unless ($field =~ /^\d{3}$/) {mycarp "Invalid field specified"; return}
  0         0  
  0         0  
2627 2         4 my @fieldrefs = grep {$_->[0] eq $field} @{$marcrec->{'array'}};
  38         71  
  2         6  
2628 2 50       20 return unless @fieldrefs;
2629 2 50 33     18 if ($field and not $subfield) {
    0 0        
2630 2         9 return $marcrec->_joinfield($fieldrefs[0],$field,$delim);
2631             } elsif ($field and $subfield) {
2632 0 0       0 if ($field <10) {mycarp "There are no subfields or indicators for control fields";return}
  0         0  
  0         0  
2633 0 0       0 return $fieldrefs[0][1].$fieldrefs[0][2] if $subfield eq 'i12';
2634 0         0 my $rsubf = undef;
2635 0         0 foreach my $fieldref (@fieldrefs) {
2636 0         0 $rsubf =$marcrec->getmatch($subfield,$fieldref);
2637 0 0       0 return $$rsubf if $rsubf;
2638             }
2639 0 0       0 return undef unless $rsubf;
2640             }
2641             }
2642             ####################################################################
2643             # getvalue() will return the value of a field or subfield in a #
2644             # particular record found in the MARC object #
2645             ####################################################################
2646             sub getvalue { # rec
2647 63     63   75 my $marcrec = shift;
2648 63         78 my $template=shift;
2649 63 50       190 return unless (ref($template) eq "HASH");
2650 63         104 my $params = _params($template,@_);
2651              
2652 63         102 my $field = $params->{field};
2653 63 50       117 if (not($field)) {mycarp "You must specify a field"; return}
  0         0  
  0         0  
2654 63 50       197 unless ($field =~ /^\d{3}$/) {mycarp "Invalid field specified"; return}
  0         0  
  0         0  
2655 63         93 my $subfield = $params->{subfield};
2656 63         77 my $delim = $params->{delimiter};
2657 63         64 my @values;
2658 63 100 66     402 if ($field and not($subfield)) {
    50 33        
2659 25 100       77 return unless exists $marcrec->{$field};
2660 20 100       44 if ($field eq '000') { return $marcrec->{'000'}[1] };
  3         31  
2661 17         24 foreach my $rfield (@{$marcrec->{$field}{field}}) {
  17         44  
2662 17         55 push @values,
2663             $marcrec->_joinfield($rfield,$field,$delim);
2664             }
2665 17         93 return @values;
2666             }
2667             elsif ($field and $subfield) {
2668 38 50       319 return unless exists $marcrec->{$field};
2669 38 100       117 return unless exists $marcrec->{$field}{$subfield};
2670 34 100 100     209 if ($subfield eq "i1" || $subfield eq "i2" || $subfield eq "i12") {
      100        
2671 15         16 my @shortone = @{$marcrec->{$field}{field}};
  15         44  
2672 15         26 foreach my $rfield (@shortone) {
2673 19 100       53 if ($subfield eq 'i1') {
    100          
2674 5         15 push @values, $rfield->[1];
2675             }
2676             elsif ($subfield eq 'i2') {
2677 5         14 push @values, $rfield->[2];
2678             }
2679             else {
2680 9         31 push @values, $rfield->[1].$rfield->[2];
2681             }
2682             }
2683 15         92 return @values;
2684             }
2685 19         21 foreach my $rval (@{$marcrec->{$field}{$subfield}}) {
  19         50  
2686 27         60 push @values, $$rval;
2687             }
2688 19         170 return @values;
2689             }
2690             }
2691              
2692             ####################################################################
2693             #Returns LDR at $record. #
2694             ####################################################################
2695             sub ldr { # rec
2696 9     9   12 my $marcrec = shift;
2697 9         45 return $marcrec->{array}[0][1];
2698             }
2699              
2700              
2701             ####################################################################
2702             #Takes a record number and returns a hash of fields. #
2703             #Needed to determine the format (BOOK, VIS, etc) of #
2704             #the record. #
2705             #Folk also like to know what Ctrl, Desc etc are. #
2706             ####################################################################
2707             sub unpack_ldr { # rec
2708 2     2   4 my $marcrec = shift;
2709              
2710 2         7 my $ldr = $marcrec->ldr();
2711 2         11 my $rhldr = $marcrec->_unpack_ldr($ldr);
2712 2         7 $marcrec->{unp_ldr}=$rhldr;
2713 2         7 return $rhldr;
2714             }
2715              
2716            
2717             sub _unpack_ldr { # rec
2718 7     7   12 my ($marcrec,$ldr) = @_;
2719              
2720 7         13 my %ans=();
2721              
2722 7         94 my @fields=unpack($LDR_TEMPLATE,$ldr);
2723 7         43 for (@LDR_FIELDS) {
2724 98         175 $ans{$_}=shift @fields;
2725             }
2726 7         22 return \%ans;
2727             }
2728              
2729              
2730             ####################################################################
2731             #Takes a record number. #
2732             #Returns the unpacked ldr as a ref to hash from the ref in $self. #
2733             #Does not overwrite hash from ldr. #
2734             ####################################################################
2735             sub get_hash_ldr { # rec
2736 0     0   0 my $marcrec = shift;
2737 0 0       0 return undef unless exists($marcrec->{unp_ldr});
2738 0         0 return $marcrec->{unp_ldr};
2739             }
2740              
2741             ####################################################################
2742             # Takes a record number and updates the corresponding ldr if there
2743             # is a hashed form. Returns undef unless there is a hash. Else
2744             # returns $ldr.
2745             ####################################################################
2746             sub pack_ldr { # rec
2747 4     4   9 my $marcrec = shift;
2748 4 50       15 return undef unless exists($marcrec->{unp_ldr});
2749 4         8 my $rhldr = $marcrec->{unp_ldr};
2750 4         13 my $ldr = $marcrec -> _pack_ldr($rhldr);
2751 4         12 $marcrec->{array}[0][1] = $ldr;
2752 4         8 return $ldr;
2753             }
2754              
2755             ####################################################################
2756             #Takes a ref to hash version of the LDR and returns a string #
2757             # version #
2758             ####################################################################
2759             sub _pack_ldr { # rec
2760              
2761 8     8   13 my ($marcrec,$rhldr) = @_;
2762 8         12 my @fields=();
2763              
2764 8         18 for (@LDR_FIELDS) {
2765 112         181 push @fields,$rhldr->{$_};
2766             }
2767 8         41 my $ans = pack($LDR_TEMPLATE,@fields);
2768 8         39 return $ans;
2769             }
2770              
2771             ####################################################################
2772             #Takes a string record number. #
2773             #Returns a the format necessary to pack/unpack 008 fields correctly#
2774             ####################################################################
2775             sub bib_format { # rec
2776 2     2   4 my ($marcrec)=@_;
2777 2         51 $marcrec->pack_ldr();
2778 2         6 my $ldr = $marcrec->ldr();
2779 2         10 return $marcrec->_bib_format($ldr);
2780             }
2781              
2782             sub _bib_format { # rec
2783 5     5   8 my ($marcrec,$ldr)=@_;
2784 5         12 my $rldr=$marcrec->_unpack_ldr($ldr);
2785 5         13 my ($type,$bib_lvl) = ($rldr->{'Type'},$rldr->{'BLvl'});
2786 5 50 33     70 return "UNKNOWN (Type $type Bib_Lvl $bib_lvl)" unless ($type=~/[abcdefgijkmprot]/ &&
      33        
2787             (($bib_lvl eq "") or
2788             $bib_lvl=~/[abcdms]/)
2789             );
2790              
2791 5 0 33     53 return "BOOKS" if (
      33        
      33        
2792             (
2793             ($type eq "a") && !($bib_lvl =~/[bs]/)
2794             )
2795             or $type eq "t" or $type eq "b"
2796             ); #$type b is obsolete, 'tho.
2797 0 0 0     0 return "SERIALS" if (
2798             ($type eq "a") &&
2799             ($bib_lvl =~/[bs]/)
2800             );
2801 0 0       0 return "COMPUTER_FILES" if ($type =~/m/);
2802 0 0       0 return "MAPS" if ($type =~/[ef]/);
2803 0 0       0 return "MUSIC" if ($type =~/[cdij]/);
2804 0 0       0 return "VIS" if ($type =~/[gkro]/);
2805 0 0       0 return "MIX" if ($type =~/p/);
2806 0         0 return "UNKNOWN (Type $type Bib_Lvl $bib_lvl) ??"; # Shouldn't happen
2807             }
2808              
2809             ####################################################################
2810             #Takes a record number. #
2811             #Returns the unpacked 008 as a ref to hash. Installs ref in $self. #
2812             ####################################################################
2813             sub unpack_008 { # rec
2814 2     2   5 my ($marcrec) = @_;
2815 2         14 my ($ff_string) = $marcrec->getfirstvalue({field=>'008'});
2816 2         12 my $bib_format = $marcrec->bib_format();
2817 2         12 my $rh008= $marcrec->_unpack_008($ff_string,$bib_format);
2818 2         6 $marcrec->{unp_008}=$rh008;
2819 2         9 return $rh008;
2820             }
2821              
2822             sub _unpack_008 { # rec
2823 2     2   6 my ($marcrec,$ff_string,$bib_format) = @_;
2824 2         5 my %ans=();
2825              
2826 2         8 my $ff_templ=$FF_TEMPLATE{$bib_format};
2827 2         6 my $raff_fields=$FF_FIELDS{$bib_format};
2828 2 50       27 if ($bib_format =~/UNKNOWN/) {
2829 0         0 mycarp "Format is $bib_format";
2830 0         0 return;
2831             }
2832 2         18 my @fields=unpack($ff_templ,$ff_string);
2833 2         5 for (@{$raff_fields}) {
  2         6  
2834 38         100 $ans{$_}=shift @fields;
2835             }
2836 2         8 return \%ans;
2837             }
2838              
2839             ####################################################################
2840             #Takes a record number. #
2841             #Returns the unpacked 008 as a ref to hash from the ref in $self. #
2842             #Does not overwrite hash from 008 field. #
2843             ####################################################################
2844             sub get_hash_008 { # rec
2845 1     1   2 my ($marcrec)=@_;
2846 1 50       5 return undef unless exists($marcrec->{unp_008});
2847 1         3 return $marcrec->{unp_008};
2848             }
2849              
2850             ####################################################################
2851             #Takes a record number. Flushes hashes to 008 and ldr. #
2852             #Updates the 008 field from an installed fixed field hash.
2853             #Returns undef unless there is a hash, else returns the 008 field #
2854             ####################################################################
2855             sub pack_008 { # rec
2856 1     1   18 my ($marcrec) = @_;
2857 1         3 $marcrec->pack_ldr();
2858 1         19 my $ldr = $marcrec->ldr();
2859 1         5 my $rhff = $marcrec->get_hash_008();
2860 1 50       4 return undef unless $rhff;
2861 1         3 my $ff_string = $marcrec->_pack_008($ldr,$rhff);
2862 1         8 $marcrec->updatefirst({field=>'008'},$ff_string);
2863 1         4 return $ff_string;
2864             }
2865              
2866             ####################################################################
2867             #Takes LDR and ref to hash of unpacked 008 #
2868             #Returns string version of 008 *without* newlines. #
2869             ####################################################################
2870             sub _pack_008 { # rec
2871 3     3   6 my ($marcrec,$ldr,$rhff) = @_;
2872 3         9 my $bib_format = $marcrec->_bib_format($ldr);
2873 3         6 my $ans = "";
2874 3         8 my @fields = ();
2875 3         5 for (@{$FF_FIELDS{$bib_format}}) {
  3         10  
2876 57         87 push @fields, $rhff->{$_};
2877             }
2878 3         18 $ans = pack($FF_TEMPLATE{$bib_format},@fields);
2879 3         18 return $ans;
2880             }
2881              
2882             ####################################################################
2883              
2884             # as_string returns a newline-\c^ separated version of the record.
2885             # Subclasses may need to override this. If so, to make Tie happy,
2886             # they should override from_string. 000 is ldr.
2887              
2888             ####################################################################
2889              
2890             sub as_string {
2891 1     1   403 my $marcrec=shift;
2892 1         2 my $SEP = "\cJ"; #unix newline
2893 1         2 my $ans = "";
2894 1         2 for (@{$marcrec->{'array'}}) {
  1         4  
2895 21         24 my $tag = $_->[0];
2896 21 100       35 if ($tag < 10) {
2897 5         14 $ans .= "$tag $_->[1]$SEP";
2898 5         6 next;
2899             }
2900 16         26 $ans .= "$tag $_->[1]$_->[2] ";
2901 16         36 foreach (my $i=3; $i<$#$_; $i+=2) {
2902 32         88 $ans .="\c_$_->[$i]$_->[$i+1]";
2903             }
2904 16         30 $ans .=$SEP;
2905             }
2906 1         4 return $ans;
2907             }
2908              
2909             ####################################################################
2910              
2911             # from_string takes a newline-\c^ separated version of the record
2912             # and replaces the {array} information from that information.
2913             # Subclasses may need to override this. If so, to make Tie happy,
2914             # they should override as_string. 000 is ldr.
2915              
2916             ####################################################################
2917             sub from_string {
2918 1     1   5 my $marcrec=shift;
2919 1         2 my $string = shift;
2920 1         2 my $do_rebuild_map = shift;
2921 1         1 my $SEP = "\cJ"; #unix newline
2922 1         29 my @lines = split /$SEP/,$string;
2923 1         3 @{$marcrec->{'array'}}=();
  1         4  
2924 1         2 for (@lines) {
2925 21 50       59 next if /^\s*$/;
2926 21         28 my $tag = substr($_,0,3);
2927 21 100       46 if ($tag < 10) {
2928 5         8 my $contents = substr($_,4);
2929 5         6 push @{$marcrec->{'array'}}, [$tag, $contents];
  5         13  
2930 5         7 next;
2931             }
2932 16         35 my ($i1,$i2,$sub_string) = (substr($_,4,1),substr($_,5,1),substr($_,7));
2933 16         29 my @field = ($tag,$i1,$i2);
2934 16         79 my @subfields = split /\c_(.)/,$sub_string;
2935 16 50       36 shift @subfields if $subfields[0] eq ''; # feature of split.
2936 16         32 push @field,@subfields;
2937 16         16 push @{$marcrec->{'array'}}, [@field];
  16         84  
2938             }
2939 1 50       7 $marcrec->rebuild_map_all() if $do_rebuild_map;
2940             }
2941              
2942             1; # so the require or use succeeds
2943              
2944             __END__