LC MARC FORMAT-UNLABELLED
Philip Budne
budd at bu-cs.BU.EDU
Mon Mar 13 17:56:19 AEST 1989
Enclosed is code I wrote to prove the viability of producing fiche for
emergency use if our online catalog was not available. The reference
provided to me by our library systems manager was "OCLC-MARK Tape
Format" ISBN: 0-933418-62-0; 1984, OCLC
The encoding format is interesting, with variable length strings. To
someone who had never looked into the world of catalogging I was blown
away by the number of fields used to fully describe a work!
-Phil
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of shell archive."
# Contents: Makefile disk.c mdisplay.c ndisplay.c oclc.c oclc.h
# Wrapped by budd at buit2 on Mon Mar 13 02:45:24 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f Makefile -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(226 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
XCFLAGS=-g
X
Xall: oclc noclc
X
XOCLC=oclc.o disk.o mdisplay.o
Xoclc: $(OCLC)
X $(CC) $(CFLAGS) -o oclc $(OCLC)
X
XNOCLC=oclc.o disk.o ndisplay.o
Xnoclc: $(NOCLC)
X $(CC) $(CFLAGS) -o noclc $(NOCLC)
X
Xmdisplay.o ndisplay.o oclc.o: oclc.h
END_OF_Makefile
if test 226 -ne `wc -c <Makefile`; then
echo shar: \"Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f disk.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"disk.c\"
else
echo shar: Extracting \"disk.c\" \(1743 characters\)
sed "s/^X//" >disk.c <<'END_OF_disk.c'
X/*
X * disk.c -- read oclc mark tape records from disk
X *
X * Philip L. Budne, Boston University, Distributed Systems Group
X * Copyright 1988, 1989, Philip L. Budne
X * May be used in not-for-profit applications provided this
X * notice and the above copyright are not removed. No warranty
X * is expressed or implied.
X */
X
X# include "oclc.h"
X
X/*
X * assumes we are reading from a file unblocked to disk.
X * ie; dd if=/dev/rmt0 of=datafile ibs=2048
X *
X * reading from a real MARC tape the first file will be the
X * ANSI label.
X *
X * To read from tape all reads must be of size 2048.
X */
X
Xint
Xgetrec( fd, record )
X int fd;
X char *record;
X{
X int cc, llen;
X
X /*
X * would like to read 2048 here, but if any records are less
X * than 2048, we might read past the end, into the next
X * record.
X *
X * It might be better to have the tape reader always write
X * 2048 bytes to disk??
X *
X * reading from tape this is not a problem, as the read would
X * just return "short".
X */
X
X /* read just lrec len (this only works on disks) */
X if( (cc = read( fd, record, 5 )) != 5 ) /* not what we expected? */
X if( cc > 0 ) /* but got some??? */
X lose("premature eof (read %d)\n", cc ); /* premature eof */
X else /* got nothing */
X return( -1 ); /* EOF on time! */
X
X llen = getint( record, 5 ); /* get integer value */
X /* of logical record length */
X
X if( llen < 5 || llen > MAXLREC ) /* is it sane? */
X lose("bad llen %d", llen ); /* no. give up. */
X
X cc = read( fd, record+5, llen - 5 ); /* read rest of logical record */
X if( cc != llen - 5 )
X lose("read %d, expected %d", cc, llen-5 );
X
X record[ llen ] = EOS; /* blast char past end */
X return( llen );
X} /* getrec */
END_OF_disk.c
if test 1743 -ne `wc -c <disk.c`; then
echo shar: \"disk.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f mdisplay.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"mdisplay.c\"
else
echo shar: Extracting \"mdisplay.c\" \(2621 characters\)
sed "s/^X//" >mdisplay.c <<'END_OF_mdisplay.c'
X/*
X * mdisplay.c -- display records in TOMAS "marc" format
X *
X * Philip L. Budne, Boston University, Distributed Systems Group
X * Copyright 1988, 1989, Philip L. Budne
X * May be used in not-for-profit applications provided this
X * notice and the above copyright are not removed. No warranty
X * is expressed or implied.
X */
X
X# include <stdio.h> /* get standard i/o library defns */
X# include "oclc.h" /* get our defns */
X
Xstatic int record_count;
X
Xvoid
Xpdata( dp, len ) /* print data */
X char *dp;
X int len;
X{
X while( len-- > 0 ) {
X char c;
X
X c = *dp++; /* get next character */
X
X if( c == RS ) /* field terminator? (RS) */
X break; /* break loop */
X
X if( c == US ) { /* subfield delim (doub dag) (US) */
X len--; /* account for subsection letter */
X if( len < 0 ) /* no more data? */
X lose("bad subfield"); /* quit. */
X
X /* print next char too (sub section letter) */
X printf(" %c%c ", SCHAR, *dp++); /* dont' use putchar(*dp++); */
X /* as putchar is a macro!! */
X continue; /* continue printing data */
X } /* found US */
X
X if( c >= ' ' && c <= '~' ) /* printing ascii? */
X putchar( c ); /* just copy to stdout */
X# ifdef DISPLAY_DIACRITICS
X else
X printf("<%02x>", c & 0xff); /* print hex code. */
X /* interpret? (output troff?) */
X# endif /* DISPLAY_DIACRITICS defined */
X } /* while */
X} /* pdata */
X
Xdisplay( code, record, offset, length )
X int code, offset, length;
X char *record;
X{
X if( code < 10 ) { /* process 001...009 */
X process( code, record, offset, length );
X return;
X }
X else if( record_count == 0 )
X dump_header_info();
X
X record_count++;
X printf("%3d %03d ", record_count, code );
X pdata( record+offset, length ); /* give pointer to data */
X putchar('\n'); /* output newline char */
X
X} /* display */
X
Xend_record() {
X putchar('\n');
X} /* end */
X
X/****************************************************************/
X
Xstatic long oclc_id;
X
Xstart_record() {
X record_count = 0;
X oclc_id = -1;
X} /* start */
X
Xstatic
Xdump_header_info() {
X if( oclc_id != -1 )
X printf("OCLC: %8d\n", oclc_id );
X}
X
Xstatic
Xprocess( code, record, offset, length )
X int code, offset, length;
X char *record;
X{
X char bib_lvl;
X
X switch( code ) {
X case 1: /* careful!! 001 is octal! */
X if( record[offset] != 'o' || record[offset+1] != 'c' ||
X record[offset+2] != 'm' )
X lose( "Bad info in cols 0-2 of 001 record" );
X oclc_id = getint( record+offset+3, 8 );
X break;
X
X case 8:
X /* check record[7] (bib level) for interpretation!? */
X bib_lvl = record[7];
X
X } /* switch on code */
X} /* process */
END_OF_mdisplay.c
if test 2621 -ne `wc -c <mdisplay.c`; then
echo shar: \"mdisplay.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ndisplay.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"ndisplay.c\"
else
echo shar: Extracting \"ndisplay.c\" \(3335 characters\)
sed "s/^X//" >ndisplay.c <<'END_OF_ndisplay.c'
X/*
X * ndisplay.c -- display records in "normal" format (TOMAS D/DN)
X *
X * Philip L. Budne, Boston University, Distributed Systems Group
X * Copyright 1988, 1989, Philip L. Budne
X * May be used in not-for-profit applications provided this
X * notice and the above copyright are not removed. No warranty
X * is expressed or implied.
X *
X */
X
X# include <stdio.h> /* get standard i/o library defns */
X# include "oclc.h" /* get our defns */
X
Xvoid
Xcopy( dp, sp, len )
X register char *dp, *sp;
X register len;
X{
X while( len-- > 0 ) {
X register c;
X
X c = *sp++; /* get next character */
X if( c == RS ) /* field terminator? (RS) */
X break; /* break loop */
X else if( c == US ) { /* subfield delim (doub dag) (US) */
X len--; /* account for subsection letter */
X if( len < 0 ) /* no more data? */
X lose("bad subfield"); /* quit. */
X
X sp++; /* toss section letter */
X *dp++ = ' '; /* insert space */
X
X } /* found US */
X else if( c >= ' ' && c <= '~' ) /* printing ascii? */
X *dp++ = c;
X } /* while */
X *dp = EOS;
X} /* copy */
X
X/****************************************************************/
X
Xtypedef char str[ 1024 ];
Xstr auth, title, publ, descr, notes, subj, other, loc, call;
Xint authtype, titletype, publtype, descrtype, notestype,
X subjtype, othertype, loctype, calltype;
X
Xstart_record() {
X authtype = titletype = publtype = descrtype = notestype =
X subjtype = othertype = loctype = calltype = -1;
X} /* start */
X
Xend_record() {
X int n;
X
X# define MUMBLE(data,type,name) \
X if( type != -1 ) { printf("%-16s %s\n", name, data ); n++; }
X
X n = 0;
X MUMBLE(auth, authtype, "AUTHOR" );
X MUMBLE(title,titletype, "TITLE" );
X MUMBLE(publ, publtype, "PUBLICATION" );
X MUMBLE(descr,descrtype, "DESCRIPTION" );
X MUMBLE(notes,notestype, "NOTES" ); /* NEVER SET! */
X MUMBLE(subj, subjtype, "SUBJECTS" ); /* NEVER SET! */
X MUMBLE(other,othertype, "OTHER" ); /* NEVER SET! */
X MUMBLE(loc, loctype, "LOCATION" ); /* need to expand! */
X MUMBLE(call, calltype, "CALL NUMBER" ); /* clean up? */
X
X if( n > 0 )
X putchar('\n'); /* blank line */
X} /* end */
X
Xdisplay( code, record, offset, length )
X int code, offset, length;
X char *record;
X{
X char bib_lvl;
X
X record += offset+2; /* skip 2 indicators */
X
X /* MUST PRIORITIZE MULTIPLE RECORD TYPES */
X
X switch( code ) {
X case 49:
X if( loctype != -1 )
X puts("second location");
X copy( loc, record, length );
X loctype = code;
X break;
X
X case 50:
X case 90:
X case 99:
X if( calltype != -1 )
X printf("second call %03d (was %03d)\n", code, calltype );
X copy( call, record, length );
X calltype = code;
X break;
X
X
X case 100:
X case 110:
X case 130:
X if( authtype != -1 )
X printf("second author %03d (was %03d)\n", code, authtype );
X copy( auth, record, length );
X authtype = code;
X break;
X
X case 240:
X case 245:
X if( titletype != -1 )
X printf("second title %03d (was %03d)\n", code, titletype );
X copy( title, record, length );
X titletype = code;
X break;
X
X case 260:
X if( publtype != -1 )
X puts("second publication");
X copy( publ, record, length );
X publtype = code;
X break;
X
X case 300:
X if( descrtype != -1 )
X puts("second description");
X copy( descr, record, length );
X descrtype = code;
X break;
X
X } /* switch on code */
X} /* process */
END_OF_ndisplay.c
if test 3335 -ne `wc -c <ndisplay.c`; then
echo shar: \"ndisplay.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f oclc.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"oclc.c\"
else
echo shar: Extracting \"oclc.c\" \(5031 characters\)
sed "s/^X//" >oclc.c <<'END_OF_oclc.c'
X/*
X * oclc.c -- read oclc mark tape records
X *
X * Philip L. Budne, Boston University, Distributed Systems Group
X * Copyright 1988, 1989, Philip L. Budne
X * May be used in not-for-profit applications provided this
X * notice and the above copyright are not removed. No warranty
X * is expressed or implied.
X *
X * Coded as per "OCLC-MARK Tape Format" ISBN: 0-933418-62-0
X * 1984, OCLC
X */
X
X# include <stdio.h> /* get standard i/o library defns */
X# include "oclc.h" /* get our defns */
X
Xvoid lose(), holdings(), bibliographic(), pdata(); /* forward defn. */
X
Xint
Xmain() {
X char record[ MAXLREC+1 ]; /* entire logical record */
X int llen; /* 0-4 logical record length */
X int fd = 0; /* input file descr. */
X /* 0 is "standard input" opened */
X /* for us by the shell */
X
X while( (llen = getrec( fd, record )) > 0 ) {
X if( record[6] == 'y' ) /* check if a holdings record */
X holdings( record, llen ); /* it is???? */
X else
X bibliographic( record, llen );
X } /* while getrec */
X} /* main */
X
Xvoid
Xlose(f, a, b, c ) /* dangerous... should use varargs */
X char *f, *a, *b, *c;
X{
X printf(f, a, b, c );
X putchar('\n');
X exit( 1 );
X} /* lose */
X
Xvoid
Xholdings( record, llen ) /* print a holdings record */
X char *record;
X int llen;
X{
X if( llen < MINH || llen > MAXH )
X lose("invalid llen for holdings rec %d", llen );
X
X puts("holdings records nyi"); /* never seen one!! */
X /* (not fatal) */
X} /* holdings */
X
Xvoid
Xbibliographic( record, llen )
X char *record;
X int llen;
X{
X int baseaddr, p;
X
X if( llen < MINB || llen > MAXB )
X lose("invalid llen for bib rec %d", llen );
X
X baseaddr = getint( record+12, 5 ); /* 12-16 base address */
X if( baseaddr < 24 || baseaddr > llen )
X lose("bad baseaddr %d (llen %d)", baseaddr, llen );
X
X# ifdef DISPLAY_LEADER
X pr_bib_fixed( record ); /* print fixed leader */
X# endif /* DISPLAY_LEADER defined */
X
X start_record();
X p = 24; /* data starts in column 24 */
X while( p < baseaddr && record[p] != RS ) {
X int code, offset, length, lensiz, offsiz;
X
X# define CODELEN 3
X code = getint( record+p, CODELEN );
X p += CODELEN;
X
X lensiz = record[20] - '0'; /* get numer of columns in length */
X if( lensiz != 4 )
X lose("%03d: unusual size of length field (column 20): %d",
X code, lensiz );
X length = getint( record+p, lensiz ); /* get length */
X p += lensiz; /* advance pointer */
X
X offsiz = record[21] - '0'; /* get number of columns for offset */
X if( offsiz != 5 )
X lose("%03d: unusual size of offset field (column 21): %d",
X code, offsiz );
X offset = getint( record+p, offsiz ); /* get offset */
X p += offsiz; /* advance pointer */
X
X /* baseaddr+offset is first char of data */
X /* baseaddr+offset+length-1 is last char of data */
X if( offset+baseaddr+length-1 > llen ) /* end of data */
X lose("data out of bounds"); /* past end of logical record?? */
X
X /****************************************************************
X * perform record type dependant processing here!!
X */
X display( code, record, offset+baseaddr, length );
X /*
X ****************************************************************/
X } /* while */
X end_record();
X} /* bib record */
X
Xint
Xgetint( cp, cc ) /* get a fixed length integer */
X register char *cp; /* pointer */
X register int cc; /* length */
X{
X register c, i;
X
X i = 0;
X while( cc-- ) {
X c = *cp++;
X if( c < '0' || c > '9' )
X lose("bad digit '%c'", c );
X i = (i * 10) + c - '0';
X } /* while */
X return( i );
X} /* getint */
X
Xpr_bib_fixed( record ) /* print bib record fixed leader */
X char *record;
X{
X switch( record[5] ) { /* record status */
X case 'n':
X puts("new record");
X break;
X case 'c':
X puts("corrected record");
X break;
X case 'p':
X puts("previously prepublication record");
X break;
X case 'a':
X puts("increase in coding level");
X break;
X default:
X printf("** unknown bib rec stat '%c'\n", record[5] );
X break;
X } /* rec stat */
X
X printf("record type '%c'\n", record[6] );
X printf("bib level '%c'\n", record[7] );
X
X if( record[8] != ' ' || record[9] != ' ' ||
X record[10] != '2' || record[11] != '2' )
X lose("invalid contents in 8, 9, 10, or 11 of bib record");
X
X /* 12-16 base address */
X printf("encoding level '%c'\n", record[17] );
X printf("desc catalogging form '%c'\n", record[18] );
X /* 19 blank */
X /* 20, 21 size of length and offset */
X
X switch( record[22] ) { /* transaction type */
X case 0x01:
X puts("produce");
X break;
X case 0x02:
X puts("update");
X break;
X case 0x03:
X puts("cancel update");
X break;
X case 0x11:
X puts("replace");
X break;
X case 0x50:
X puts("all produce");
X break;
X case 0x90:
X puts("offline retrieve");
X break;
X case 0x92:
X puts("offline update");
X break;
X case 0x93:
X puts("offline cancel update");
X break;
X case 0x94:
X puts("microcon update");
X break;
X default:
X lose("bad transaction code %#02x\n", record[22] );
X break;
X } /* transaction code */
X
X /* 23 '0' */
X} /* pr_bib_fixed */
END_OF_oclc.c
if test 5031 -ne `wc -c <oclc.c`; then
echo shar: \"oclc.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f oclc.h -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"oclc.h\"
else
echo shar: Extracting \"oclc.h\" \(817 characters\)
sed "s/^X//" >oclc.h <<'END_OF_oclc.h'
X/*
X * oclc.h -- defns oclc mark tape records
X *
X * Philip L. Budne, Boston University, Distributed Systems Group
X * Copyright 1988, 1989, Philip L. Budne
X * May be used in not-for-profit applications provided this
X * notice and the above copyright are not removed. No warranty
X * is expressed or implied.
X */
X
X# define EOS '\0' /* End of String Char */
X
X# define MAXB 6114 /* Max length for bib record */
X# define MINB 124 /* Min length for bib record */
X
X# define MAXH 6114 /* Max length for holdings record */
X# define MINH 112 /* Min length for holdings record */
X
X# define MAXLREC MAXB /* Max length for any logical record */
X
X# define RS '\036' /* record sep */
X# define US '\037' /* start of subsection */
X
X# define SCHAR '|' /* char to output for subsection */
X /* could also use '$' */
END_OF_oclc.h
if test 817 -ne `wc -c <oclc.h`; then
echo shar: \"oclc.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0
More information about the Comp.unix.wizards
mailing list