budd@bu-cs.BU.EDU (Philip Budne) (03/13/89)
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@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