/* ------------------------------------------------------------------- */ /* MARC2709 : Converts a "line format MARC record" into ISO 2709 */ /* */ /* Input string requirements: */ /* 1. New MARC tag is indicated by MARC tag in pos 1-3 */ /* (may be preceded by *). Indicator follows in next 2 */ /* bytes. */ /* 2. Continuation line is indicated by blank in col 1 */ /* 3. End-of-record (^) may or may not be present */ /* */ /* author : Ole Husby */ /* updated : 1998-09-30 */ /* ------------------------------------------------------------------- */ #include #include #include #include #define NORMARC 12 #define SUBFIELD_CODE "\x1f" #define FIELD_TERMINATOR "\x1e" #define RECORD_TERMINATOR "\x1d" #define INDICATOR_COUNT '2' #define SUBFIELD_CODE_COUNT '2' #define LENGTH_OF_LENGTH_OF_FIELD '4' #define LENGTH_OF_STARTING_CHARACTER_POSITION '5' #define UNUSED " " #define TAG001 "001" #define TAG008 "008" #define SKIP 41 static char out_record[10240], leader[24+1], directory[10240], field_001[32], field_008[40+2], data_field[10240]; static char logline[128]; static char rstr[6], dollar, dollarstring[2]; static int skip; static char direlem[300][12+1]; static int dircntr; union LDR { char ldr_string[24+1]; struct { char record_length[5], record_status, record_type, bibliographic_level, unused1[2], indicator_count, subfield_code_count, base_adress[5], unused2[3], entry1, entry2, entry3, entry4; } ltab; } ldr; static int startet = 0; /* ------------------------------------------------------------------- */ /* Compare function for qsort */ /* ------------------------------------------------------------------- */ int cmp(const void *a, const void *b) { return strcmp((char*)a, (char*)b); } /* ------------------------------------------------------------------- */ /* Convert integer to string of fixed length. Right justified padded */ /* with zeros. Returns NULL if error */ /* ------------------------------------------------------------------- */ char *itoal(int n, int len) { char *r; r = (char *) rstr; switch (len) { case 4 : sprintf(r, "%04d", n); break; case 5 : sprintf(r, "%05d", n); break; default : return NULL; } r[len] = '\0'; return r; } /* ------------------------------------------------------------------- */ /* One 001 subfield is put into field_001 */ /* ------------------------------------------------------------------- */ static int make_001(char *data, char subfield) { int len; startet = 0; switch (subfield) { case ' ' : break; case 'a' : break; default : return 1; } while (data[0] == ' ') data++; strcpy(field_001, data); len = strlen(data) + 1; skip = SKIP + len; sprintf(directory, "00100%2d000000080041000%2d", len, len); return 1; } /* ------------------------------------------------------------------- */ /* One subfield string is appended to data_field */ /* ------------------------------------------------------------------- */ static int out_subfield(char *data, char *ftag, char subfield, char nextsubfield) { int len, subint; char subreplace, *p, *up; while (data[strlen(data) -1] == ' ') data[strlen(data) -1] = '\0'; /* strip trailing blanks */ if (subfield == '3') /* always discard $3 */ return 1; if (strcmp(ftag, TAG001) == 0) /* 001 data treatment */ { make_001(data, subfield); return 1; } if (strcmp(ftag, TAG008) == 0) /* 008 data treatment */ { strncpy(field_008, data, strlen(data)); return 1; } if (subfield != ' ') /* handle subfield code */ { strcat(data_field, SUBFIELD_CODE); len = strlen(data_field); data_field[len] = subfield; data_field[len + 1] = '\0'; } while(data[0] == ' ') data++; /* strip leading blanks */ if (!data) return 0; strcat(data_field, data); /* append data */ return 1; } /* ------------------------------------------------------------------- */ /* One MARC field is split into subfields and given to output */ /* ------------------------------------------------------------------- */ static int out_field(char *data, char *ftag, char *find) { char lnumber[5], snumber[6]; int fStart, fLen, moresubs; char subfield[5120], *sub, subcode, *nextsub, nextsubcode; char *v, subfield_v[32]; if (!startet) return 1; if ((strncmp(ftag, "00", 2) == 0) && (strcmp(ftag, TAG001) != 0) && (strcmp(ftag, TAG008) != 0)) return 1; fStart = strlen(data_field); if (strncmp(data, " $", 3) == 0) data +=2; /* possible if 008 */ if (data[0] != dollar) /* Dollar sign missing */ { if (strncmp(ftag,"00",2) != 0) return 0; /* only allowed if tag=00x */ if (strcmp(ftag, TAG001) == 0) /* 001: skip leading blanks */ while (data[0] == ' ') data++; subcode = ' '; nextsubcode = ' '; if (!out_subfield(data, ftag, subcode, nextsubcode)) return 0; return 1; } else { data++; if (!data) return 0; if (strncmp(ftag,"00",2) != 0) /* append indicators */ strcat(data_field, find); sub = strtok(data, dollarstring); /* first subfield */ if (!sub) return 0; /* printf("--- %s\n", sub); */ subcode = sub[0]; sub++; moresubs = 1; while (moresubs) /* loop while more subflds */ { nextsub = strtok(NULL, dollarstring); /* next subfld */ if (nextsub) { /* printf("--- %s\n", nextsub); */ nextsubcode = nextsub[0]; nextsub++; } else nextsubcode = ' '; if (sub) { if (!out_subfield(sub, ftag, subcode, nextsubcode)) return 0; /* printf("Denne |%c| Neste |%c|\n", subcode, nextsubcode); */ } if (nextsub) { subcode = nextsubcode; sub = nextsub; } else moresubs = 0; } } if (strcmp(ftag,TAG001) == 0 || strcmp(ftag,TAG008) == 0) return 1; /* directory ready */ strcat(data_field, FIELD_TERMINATOR); /* terminate data field */ fLen = strlen(data_field) - fStart; /* length of field */ strcpy(lnumber,itoal(fLen,4)); /* convert to 4digit str */ if (!lnumber) return 0; strcpy(snumber,itoal(fStart + skip,5)); /* convert start */ if (!snumber) return 0; strcpy(direlem[dircntr], ftag); /* start direlem with tag */ strcat(direlem[dircntr], lnumber); /* append length to dir */ strcat(direlem[dircntr], snumber); /* append start to dir */ dircntr++; return 1; } /* ------------------------------------------------------------------- */ /* Main program */ /* ------------------------------------------------------------------- */ char *MARC2709(char *record, int last, int first, char recstatus, char rectype, char biblevel) { static char buffer[10240], field_data[5120], tag[4], ind[3]; char alen[3], *cp, *buf = buffer, *cq, logline[128]; int prelen, ii; int lastchar, Last, First, x, more; int SOF, digits, newField; char test[6]; strcpy(buf, record); Last = First = 0; /* initialize */ if (last > 0) /* Last : linelength if */ { /* fixed */ Last = last; /* First: starting col */ First = first; /* for cont. line */ } prelen = 5; dollar = '$'; strcpy(dollarstring, "$"); data_field[0] = '\0'; directory[0] = '\0'; strcpy(field_001, " "); strcpy(field_008, " "); out_record[0] = '\0'; dircntr = 0; startet = 0; /* initialize directory with 9 bytes for 001 */ sprintf(directory, "001001000000008004100010", alen, alen); skip = SKIP + 10; more = 1; while (more) /* loop until EOR */ { x = 0; /* x counts bytes */ for (cp = buf; *cp && *cp != '\n'; cp++) x++; /* read until LF */ if (!*cp) /* EOR */ more = 0; else cp++; SOF = 0; if (buf[0] == '^') break; /* "EOR-line" */ if (buf[0] == '*') /* skip leading * */ { buf++; x--; SOF = 1; } if (x == 0) continue; /* empty line */ digits = 1; /* test if first 3 */ for (ii = 0; ii < 3; ii++) /* bytes are digits */ if (!isdigit(buf[ii])) { digits = 0; break; } newField = 0; if (SOF) { if (!digits) continue; /* illegal line */ else newField = 1; } else if (digits) newField = 1; if (newField) /* start of new field */ { if (!out_field(field_data, tag, ind)) /* output prev. field */ return NULL; startet = 1; field_data[0] = '\0'; /* reset field buffer */ strncpy(tag, buf, 3); /* keep MARC tag */ buf += 3; x -=3; if (strncmp(tag, "00", 2) != 0) { strncpy(ind, buf, 2); /* keep indicator */ buf += 2; /* if not control field */ x -= 2; } strncat(field_data, buf, x); /* keep data */ /* strip trailing blanks */ while (field_data[strlen(field_data) -1] == ' ') { field_data[strlen(field_data) -1] = '\0'; x--; } if (Last && x == (Last - prelen)) /* full line */ lastchar = 1; else lastchar = 0; } else /* continuation line */ { if (Last) { cq = buf + First - 1; /* skip fixed nmbr chars */ x -= (First - 1); if (!lastchar && cq[0] != ' ' /* and insert one blank */ && cq[0] != dollar) strcat(field_data, " "); /* if needed */ } else { for (cq = buf; *cq == ' '; cq++) x--; /* skip leading blanks */ strcat(field_data, " "); /* insert one blank */ } strncat(field_data, cq, x); /* append data */ /* strip trail. blanks */ while (field_data[strlen(field_data) -1] == ' ') { field_data[strlen(field_data) -1] = '\0'; x--; } if (Last && x == (Last - 5)) /* full line */ lastchar = 1; else lastchar = 0; } while (field_data[strlen(field_data) -1] == ' ') field_data[strlen(field_data) - 1] = '\0'; /* rm trailing blanks */ buf = cp; } if (!out_field(field_data, tag, ind)) /* output last field */ return NULL; /* terminate field_001 */ strcat(field_001, FIELD_TERMINATOR); field_008[40] = '\0'; /* terminate field_008 */ strcat(field_008, FIELD_TERMINATOR); /* sort directory elem. */ qsort ((void *) direlem, dircntr, sizeof(direlem[0]), cmp); for (ii = 0; ii < dircntr; ii++) strcat(directory, direlem[ii]); /* append to directory */ strcat(directory, FIELD_TERMINATOR); /* terminate dictionary */ strcat(data_field, RECORD_TERMINATOR); /* terminate data */ x = 24 + strlen(directory); /* construct leader */ strcpy(test, itoal(x,5)); strncpy(ldr.ltab.base_adress, test, 5); x += (strlen(data_field) + strlen(field_001) + strlen(field_008)); strcpy(test, itoal(x,5)); strncpy(ldr.ltab.record_length, test, 5); ldr.ltab.record_status = recstatus; ldr.ltab.record_type = rectype; ldr.ltab.bibliographic_level = biblevel; ldr.ltab.indicator_count = INDICATOR_COUNT; ldr.ltab.subfield_code_count = SUBFIELD_CODE_COUNT; strncpy(ldr.ltab.unused1,UNUSED,2); strncpy(ldr.ltab.unused2,UNUSED,3); ldr.ltab.entry1 = LENGTH_OF_LENGTH_OF_FIELD; ldr.ltab.entry2 = LENGTH_OF_STARTING_CHARACTER_POSITION; ldr.ltab.entry3 = '0'; ldr.ltab.entry4 = '0'; ldr.ldr_string[24] = '\0'; strcpy(out_record, ldr.ldr_string); /* put together record */ strcat(out_record, directory); strcat(out_record, field_001); strcat(out_record, field_008); strcat(out_record, data_field); return out_record; }