/* ------------------------------------------------------------------- */
/* marc2line : Reads an ISO 2709 MARC record, converts to MARC         */
/*             "Line format"                                           */
/*                                                                     */
/* author    : Ole Husby, BIBSYS                                       */
/* updated   : 1998-09-30                                              */
/* ------------------------------------------------------------------- */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define DIRL                                   3600

#define LINEL                                  72 
#define SUBFIELD_CODE                          '\x1f'
#define SUBFIELD_STR                           "\x1f" 
#define FIELD_TERMINATOR                       '\x1e'
#define RECORD_TERMINATOR                      '\x1d'

#define BIBSYS_TYPE                            0
#define NORMARC_TYPE                           1

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 char out_record[10240];
static int out_type;



/* ------------------------------------------------------------------- */
/* One subfield string is split into output lines                      */
/* ------------------------------------------------------------------- */

static void out_subfield(data, prefix, slen)
char *data, *prefix;
int slen;

{
   char lineprefix[7], subprefix[4], *spre;
   int i, more, len, max;

   if (out_type == BIBSYS_TYPE)
      strcpy(lineprefix, prefix);
   else
   {
      if (prefix[0] == ' ') strcpy(lineprefix, " ");
      else                  strcpy(lineprefix, "*");
      strcat(lineprefix, prefix);
   }

   max = LINEL;

   if (slen)
   {
      spre = (char *) subprefix;
      strcpy(spre, "$");                       /* Construct subfield    */
      strncat(spre, data, 1);                  /* prefix                */
      if (out_type == BIBSYS_TYPE) 
	 strcat(spre, " ");
      data++;
      max = LINEL - 2; 
      if (out_type == BIBSYS_TYPE) 
	 max--;
   }
   else spre = NULL;  

   more = 1;

   while (more)
   {
      if (slen)
         while (data[0] == ' ') data++;    /* skip leading blanks    */

      strcat(out_record, lineprefix);      /* Start with prefix      */
      strcpy(lineprefix, "     ");
      if (out_type == NORMARC_TYPE) 
	 strcat(lineprefix, " ");

      len = strlen(data);
      if (len > max)                       /* Must fit into one line */
      {
	 len = max;
	 for (i = max; i > max - 15; i--)
	 {
	    if (data[i] == ' ')
	    {
	       len = i;
	       break;
	    }
	 }
      }
      else more = 0;

      if (spre)
      {
	 strcat(out_record, spre);         /* subfield pref needed  */
	 spre = NULL;                      /* only first line       */
	 max = LINEL;
      }

      strncat(out_record, data, len);      /* append data           */
      if (more) data += len;
      strcat(out_record, "\n");
   }
}



/* ------------------------------------------------------------------- */
/* One MARC field is split into subfields and given to output          */
/* ------------------------------------------------------------------- */

static int out_field(data, ftag, find)
char *data, *ftag, *find;

{
   char prefix[5];
   char subfield[5120], *sub = subfield;
   int subcode = 0;

   strcpy(prefix, ftag);

   if (!find)                                 /* output entire field   */ 
   {
      out_subfield(data, prefix, subcode);
      return 1;
   }

   strcat(prefix, find);

   if (data[0] != SUBFIELD_CODE) return 0;    /* requires subf code in */
   data++;                                    /*   first byte          */

   sub = strtok(data, SUBFIELD_STR);          /* find first subfield   */
   if (!sub) return 0;

   subcode = 1;
   out_subfield(sub, prefix, subcode);        /* output subfield       */
   strcpy(prefix, "     ");                   /* reset prefix          */

   while (sub = strtok(NULL, SUBFIELD_STR))   /* find and output rest  */
      out_subfield(sub, prefix, subcode);     /* of the subfields      */

   return 1;
}



/* ------------------------------------------------------------------- */
/* Main program                                                        */
/* ------------------------------------------------------------------- */

char *marc2line(record, type)          
char *record, *type;
{
   char buffer[10240], tag[4], indicators[3];
   char *cp, *fld, *buf = buffer, *cq;
   char directory[DIRL+1], *dir = directory, *ind;
   char sBase[6], fLen[5], fStart[6];
   int           dlen, base, x = 0, more = 1, len, start;

   if (!record || !*record)
     return (char *) NULL;

   strcpy(buf, record);
   *out_record = 0;                                 /* reset out area     */

   if (strcmp(type, "bibsys") == 0) out_type = BIBSYS_TYPE;
   else out_type = NORMARC_TYPE;

   strncpy(ldr.ldr_string, buf, 24);                 /* get leader         */
   ldr.ldr_string[24] = '\0';
   buf += 24;
  
   strncpy(sBase, ldr.ltab.base_adress, 5);
   sBase[5] = '\0';
   base = atoi(sBase);

   dlen = base - 24;                                 /* get directory      */
   strncpy(dir, buf, dlen);
   dir[dlen] = '\0';
   buf += dlen;

   cp = dir;

   while (more)                                      /* loop until EOdir   */ 
   {
      if (*cp == FIELD_TERMINATOR)  break;
      if (strlen(cp) < 13) return (char *) NULL;

      strncpy(tag, cp, 3);                           /* get tag            */
      tag[3] = '\0';
      cp +=3;

      strncpy(fLen, cp, 4);                         /* get length          */
      fLen[4] = '\0';
      len = atoi(fLen) -1;                          /* discard field term. */
      cp += 4;

      strncpy(fStart, cp, 5);                       /* get start of field  */
      fStart[5] = '\0';
      start = atoi(fStart);
      cp += 5;

      fld = buf + start;                            /* get field           */ 
      fld[len] = '\0';
      
      if (strncmp(tag, "00", 2) != 0)               /* get indicators      */
      {
	 indicators[0] = '\0';
	 strncat(indicators, fld, 2);
	 ind = (char *) indicators;
	 fld += 2;
      }
      else ind = NULL;

      if (!out_field(fld, tag, ind))                /* output field         */
	 return (char *) NULL;

   }

   return (char *) out_record;

}
