+static unsigned long lookup_marc8(yaz_iconv_t cd,
+ unsigned long x, int *comb,
+ const char **page_chr)
+{
+ char utf8_buf[7];
+ char *utf8_outbuf = utf8_buf;
+ size_t utf8_outbytesleft = sizeof(utf8_buf)-1, r;
+
+ r = yaz_write_UTF8(cd, x, &utf8_outbuf, &utf8_outbytesleft, 0);
+ if (r == (size_t)(-1))
+ {
+ cd->my_errno = YAZ_ICONV_EILSEQ;
+ return 0;
+ }
+ else
+ {
+ unsigned char *inp;
+ size_t inbytesleft, no_read_sub = 0;
+ unsigned long x;
+
+ *utf8_outbuf = '\0';
+ inp = (unsigned char *) utf8_buf;
+ inbytesleft = strlen(utf8_buf);
+
+ x = yaz_marc8r_1_conv(inp, inbytesleft, &no_read_sub, comb);
+ if (x)
+ {
+ *page_chr = "\033(B";
+ return x;
+ }
+ x = yaz_marc8r_2_conv(inp, inbytesleft, &no_read_sub, comb);
+ if (x)
+ {
+ *page_chr = "\033g";
+ return x;
+ }
+ x = yaz_marc8r_3_conv(inp, inbytesleft, &no_read_sub, comb);
+ if (x)
+ {
+ *page_chr = "\033b";
+ return x;
+ }
+ x = yaz_marc8r_4_conv(inp, inbytesleft, &no_read_sub, comb);
+ if (x)
+ {
+ *page_chr = "\033p";
+ return x;
+ }
+ x = yaz_marc8r_5_conv(inp, inbytesleft, &no_read_sub, comb);
+ if (x)
+ {
+ *page_chr = "\033(2";
+ return x;
+ }
+ x = yaz_marc8r_6_conv(inp, inbytesleft, &no_read_sub, comb);
+ if (x)
+ {
+ *page_chr = "\033(N";
+ return x;
+ }
+ x = yaz_marc8r_7_conv(inp, inbytesleft, &no_read_sub, comb);
+ if (x)
+ {
+ *page_chr = "\033(3";
+ return x;
+ }
+ x = yaz_marc8r_8_conv(inp, inbytesleft, &no_read_sub, comb);
+ if (x)
+ {
+ *page_chr = "\033(S";
+ return x;
+ }
+ x = yaz_marc8r_9_conv(inp, inbytesleft, &no_read_sub, comb);
+ if (x)
+ {
+ *page_chr = "\033(1";
+ return x;
+ }
+ cd->my_errno = YAZ_ICONV_EILSEQ;
+ return x;
+ }
+}
+
+static size_t flush_combos(yaz_iconv_t cd,
+ char **outbuf, size_t *outbytesleft)
+{
+ unsigned long y = cd->write_marc8_last;
+ unsigned char byte, second_half = 0;
+ char out_buf[10];
+ size_t i, out_no = 0;
+
+ if (!y)
+ return 0;
+
+ byte = (unsigned char )((y>>16) & 0xff);
+ if (byte)
+ out_buf[out_no++] = byte;
+ byte = (unsigned char)((y>>8) & 0xff);
+ if (byte)
+ out_buf[out_no++] = byte;
+ byte = (unsigned char )(y & 0xff);
+ if (byte)
+ out_buf[out_no++] = byte;
+
+ if (out_no + cd->write_marc8_comb_no + 1 > *outbytesleft)
+ {
+ cd->my_errno = YAZ_ICONV_E2BIG;
+ return (size_t) (-1);
+ }
+
+ for (i = 0; i < cd->write_marc8_comb_no; i++)
+ {
+ /* all MARC-8 combined characters are simple bytes */
+ byte = (unsigned char )(cd->write_marc8_comb_ch[i]);
+ if (byte == 0xEB)
+ second_half = 0xEC;
+ else if (byte == 0xFA)
+ second_half = 0xFB;
+
+ *(*outbuf)++ = byte;
+ (*outbytesleft)--;
+ }
+ memcpy(*outbuf, out_buf, out_no);
+ *outbuf += out_no;
+ (*outbytesleft) -= out_no;
+ if (second_half)
+ {
+ *(*outbuf)++ = second_half;
+ (*outbytesleft)--;
+ }
+
+ cd->write_marc8_last = 0;
+ cd->write_marc8_comb_no = 0;
+ return 0;
+}
+
+static size_t yaz_write_marc8(yaz_iconv_t cd, unsigned long x,
+ char **outbuf, size_t *outbytesleft,
+ int last)
+{
+ int comb = 0;
+ const char *page_chr = 0;
+ unsigned long y = lookup_marc8(cd, x, &comb, &page_chr);
+
+ if (!y)
+ return (size_t) (-1);
+
+ if (comb)
+ {
+ if (cd->write_marc8_comb_no < 6)
+ cd->write_marc8_comb_ch[cd->write_marc8_comb_no++] = y;
+ }
+ else
+ {
+ size_t r = flush_combos(cd, outbuf, outbytesleft);
+ if (r)
+ return r;
+ if (strcmp(page_chr, cd->write_marc8_page_chr))
+ {
+ size_t plen = strlen(page_chr);
+
+ if (*outbytesleft < plen)
+ {
+ cd->my_errno = YAZ_ICONV_E2BIG;
+ return (size_t) (-1);
+ }
+ memcpy(*outbuf, page_chr, plen);
+ (*outbuf) += plen;
+ (*outbytesleft) -= plen;
+ cd->write_marc8_page_chr = page_chr;
+ }
+ cd->write_marc8_last = y;
+ }
+ if (last)
+ {
+ size_t r = flush_combos(cd, outbuf, outbytesleft);
+ if (r)
+ {
+ if (comb)
+ cd->write_marc8_comb_no--;
+ else
+ cd->write_marc8_last = 0;
+ return r;
+ }
+ }
+ return 0;
+}
+