/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  backend-teix.c defines the TEI XML output backend of refdbd
  markus@mhoenicka.de 2002-08-27

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, see <http://www.gnu.org/licenses/>

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include <stdio.h>
#include <string.h>
#include <syslog.h> /* for definitions of log message priorities */
#include <dbi/dbi.h>

#include "refdb.h"
#include "backend.h"
#include "backend-teix.h"
#include "strfncs.h"
#include "linklist.h"
#include "refdbd.h"
#include "dbfncs.h"
#include "risdb.h"
#include "authorinfo.h"
#include "connect.h" /* for get_status_msg() */
#include "xmlhelper.h"

/* some globals */
extern int n_log_level; /* numeric version of log_level */

/* forward declarations of local functions */
static char* add_author_info_teix(struct renderinfo* ptr_rendinfo, int author_type, int n_refdb_id, char** ptr_chunk_buf, size_t* ptr_chunk_buf_len, struct xmlindent* ptr_indent, int n_ref_format);
static char* add_analytic_teix(struct renderinfo* ptr_rendinfo, int n_refdb_id, char **ptr_chunk_buf, size_t *ptr_chunk_buf_len, const char* type, struct xmlindent* ptr_indent, int n_ref_format);
static char* add_monogr_teix(struct renderinfo* ptr_rendinfo, int n_refdb_id, char **ptr_chunk_buf, size_t *ptr_chunk_buf_len, const char* type, struct xmlindent* ptr_indent, int n_ref_format);
static char* add_series_teix(struct renderinfo* ptr_rendinfo, int n_refdb_id, char **ptr_chunk_buf, size_t *ptr_chunk_buf_len, const char* type, struct xmlindent* ptr_indent, int n_ref_format);
static char* add_notes_teix(struct renderinfo* ptr_rendinfo, int n_refdb_id, char **ptr_chunk_buf, size_t *ptr_chunk_buf_len, struct xmlindent* ptr_indent);
static char* add_abstract_teix(struct renderinfo* ptr_rendinfo, int n_refdb_id, char **ptr_chunk_buf, size_t *ptr_chunk_buf_len, struct xmlindent* ptr_indent);
static int indent_notbelow_teix(const char* name);
static int is_entry_teix(const char* name);

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  prepare_render_teix(): writes a header for the TEI XML P4 output of a
                         query

  int prepare_render_teix returns 0 if successful, >0 if failed

  struct renderinfo* ptr_rendinfo ptr to a structure with the info
                             how the reference should be rendered

 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int prepare_render_teix(struct renderinfo* ptr_rendinfo) {
  char encodingstring[64] = ""; /* todo: is this enough? */

  if (*((ptr_rendinfo->ptr_biblio_info)->encoding)) {
    sprintf(encodingstring, " encoding=\"%s\"", (ptr_rendinfo->ptr_biblio_info)->encoding);
  }

  if (*(ptr_rendinfo->ptr_clrequest->namespace)) {
    sprintf(*(ptr_rendinfo->ptr_ref), "<!-- <?xml version=\"1.0\"%s?>\n<!DOCTYPE listBibl PUBLIC \"-//TEI P4//DTD Main Document Type//EN\" \"http://www.tei-c.org/P4X/DTD/tei2.dtd\" [\n<!ENTITY %% TEI.general \'INCLUDE\'>\n<!ENTITY %% TEI.names.dates \'INCLUDE\'>\n<!ENTITY %% TEI.linking \'INCLUDE\'>\n<!ENTITY %% TEI.XML \'INCLUDE\'>\n]> -->\n<%s:listBibl xmlns:%s=\"http://www.tei-c.org/ns/1.0\">\n  <%s:head>Bibliography</%s:head>\n", encodingstring, ptr_rendinfo->ptr_clrequest->namespace, ptr_rendinfo->ptr_clrequest->namespace, ptr_rendinfo->ptr_clrequest->namespace, ptr_rendinfo->ptr_clrequest->namespace);
  }
  else {
    sprintf(*(ptr_rendinfo->ptr_ref), "<!-- <?xml version=\"1.0\"%s?>\n<!DOCTYPE listBibl PUBLIC \"-//TEI P4//DTD Main Document Type//EN\" \"http://www.tei-c.org/P4X/DTD/tei2.dtd\" [\n<!ENTITY %% TEI.general \'INCLUDE\'>\n<!ENTITY %% TEI.names.dates \'INCLUDE\'>\n<!ENTITY %% TEI.linking \'INCLUDE\'>\n<!ENTITY %% TEI.XML \'INCLUDE\'>\n]> -->\n<listBibl xmlns=\"http://www.tei-c.org/ns/1.0\">\n<head>Bibliography</head>\n", encodingstring);
  }

  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  finish_render_teix(): writes a footer for the TEI XML P4 output of a query

  int finish_render_ris returns 0 if successful, >0 if failed

  struct renderinfo* ptr_rendinfo ptr to a structure with the info
                             how the reference should be rendered

 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int finish_render_teix(struct renderinfo* ptr_rendinfo) {
  char* new_ref;
  char ns[PREFS_BUF_LEN+32];

  if (*(ptr_rendinfo->ptr_clrequest->namespace)) {
    sprintf(ns, "\n</%s:listBibl>\n", ptr_rendinfo->ptr_clrequest->namespace);
  }
  else {
    strcpy(ns, "\n</listBibl>\n");
  }
  if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), ns, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    return 801;
  }
  *(ptr_rendinfo->ptr_ref) = new_ref;

  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  render_teix() renders a RIS dataset for TEI XML P4 export

  int render_teix returns 0 if successful, >0 if not

  struct renderinfo* ptr_rendinfo ptr to a structure with the info
                             how the reference should be rendered

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int render_teix(struct renderinfo* ptr_rendinfo) {
  char *new_ref; /* used for reallocating buffer ref */
  char *chunk;
  char *chunk_buf;
  const char *type;
  size_t chunk_buf_len;
  unsigned long long n_refdb_id;
  dbi_conn conn;
  struct xmlindent xindent;

  /*initialize xindent */
  initialize_xmlindent(&xindent, 2, indent_notbelow_teix, is_entry_teix);

  /* rendering bibliographic information takes up to three levels of
     information:
     analytic: author and title of the article or chapter
     monographic: name of the journal/book, vol/issue/page info, editors
     series: series title, series editors
  */

  chunk_buf_len = 1024;

  if ((chunk_buf = malloc(chunk_buf_len)) == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    return 801;
  }

  conn = dbi_result_get_conn(ptr_rendinfo->dbires);

  if ((type = get_refdb_type(ptr_rendinfo->dbires)) == NULL) {
    free(chunk_buf);
    LOG_PRINT(LOG_WARNING, get_status_msg(234));
    return 234;
  }

  n_refdb_id = my_dbi_result_get_idval(ptr_rendinfo->dbires, "refdb_id");

  if ((ptr_rendinfo->ptr_biblio_info)->entry_id != NULL) {
    if (print_elstart_x(ptr_rendinfo->ptr_ref, ptr_rendinfo->ptr_ref_len, "biblStruct", "id", (ptr_rendinfo->ptr_biblio_info)->entry_id, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      free(chunk_buf);
      return 801;
    }
  }
  else {
    if (print_elstart_x(ptr_rendinfo->ptr_ref, ptr_rendinfo->ptr_ref_len, "biblStruct", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      free(chunk_buf);
      return 801;
    }
  }
  
  if (has_part_data(type)) {
    chunk = add_analytic_teix(ptr_rendinfo, n_refdb_id, &chunk_buf, &chunk_buf_len, type, &xindent, REFTEIX);

    if (chunk && *chunk) {
      if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), chunk, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	free(chunk_buf);
	return 801;
      }
      else {
	*(ptr_rendinfo->ptr_ref) = new_ref;
      }
    }
  }

  chunk = add_monogr_teix(ptr_rendinfo, n_refdb_id, &chunk_buf, &chunk_buf_len, type, &xindent, REFTEIX);

  if (chunk && *chunk) {
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), chunk, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      free(chunk_buf);
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
  }

  if (has_set_data(type)) {
    chunk = add_series_teix(ptr_rendinfo, n_refdb_id, &chunk_buf, &chunk_buf_len, type, &xindent, REFTEIX);

    if (chunk && *chunk) {
      if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), chunk, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	free(chunk_buf);
	return 801;
      }
      else {
	*(ptr_rendinfo->ptr_ref) = new_ref;
      }
    }
  }

  /* add notes and abstract if requested */

  /* notes */
  if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "N1") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
    chunk = add_notes_teix(ptr_rendinfo, n_refdb_id, &chunk_buf, &chunk_buf_len, &xindent);

    if (chunk && *chunk) {
      if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), chunk, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	free(chunk_buf);
	return 801;
      }
      else {
	*(ptr_rendinfo->ptr_ref) = new_ref;
      }
    }
  }

  /*----------------------------------------------------------------*/
  /* abstract */
  if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "N2") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "AB") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
    chunk = add_abstract_teix(ptr_rendinfo, n_refdb_id, &chunk_buf, &chunk_buf_len, &xindent);

    if (chunk && *chunk) {
      if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), chunk, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	free(chunk_buf);
	return 801;
      }
      else {
	*(ptr_rendinfo->ptr_ref) = new_ref;
      }
    }
  }

  /* finish bibliography entry */
  if (print_elend_x(ptr_rendinfo->ptr_ref, ptr_rendinfo->ptr_ref_len, "biblStruct", &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    free(chunk_buf);
    return 801;
  }

  free(chunk_buf);

  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  prepare_render_teix5(): writes a header for the TEI P5 XML output of a
                         query

  int prepare_render_teix returns 0 if successful, >0 if failed

  struct renderinfo* ptr_rendinfo ptr to a structure with the info
                             how the reference should be rendered

 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int prepare_render_teix5(struct renderinfo* ptr_rendinfo) {
  char encodingstring[64] = ""; /* todo: is this enough? */

  if (*((ptr_rendinfo->ptr_biblio_info)->encoding)) {
    sprintf(encodingstring, " encoding=\"%s\"", (ptr_rendinfo->ptr_biblio_info)->encoding);
  }

  if (*(ptr_rendinfo->ptr_clrequest->namespace)) {
    sprintf(*(ptr_rendinfo->ptr_ref), "<?xml version=\"1.0\"%s?>\n<%s:listBibl xmlns:%s=\"http://www.tei-c.org/ns/1.0\">\n  <%s:head>Bibliography</%s:head>\n", encodingstring, ptr_rendinfo->ptr_clrequest->namespace, ptr_rendinfo->ptr_clrequest->namespace, ptr_rendinfo->ptr_clrequest->namespace, ptr_rendinfo->ptr_clrequest->namespace);
  }
  else {
    sprintf(*(ptr_rendinfo->ptr_ref), "<?xml version=\"1.0\"%s?>\n<listBibl xmlns=\"http://www.tei-c.org/ns/1.0\">\n<head>Bibliography</head>\n", encodingstring);
  }

  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  finish_render_teix5(): writes a footer for the TEI XML P5 output of a query

  int finish_render_ris returns 0 if successful, >0 if failed

  struct renderinfo* ptr_rendinfo ptr to a structure with the info
                             how the reference should be rendered

 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int finish_render_teix5(struct renderinfo* ptr_rendinfo) {
  char* new_ref;
  char ns[PREFS_BUF_LEN+32];

  if (*(ptr_rendinfo->ptr_clrequest->namespace)) {
    sprintf(ns, "\n</%s:listBibl>\n", ptr_rendinfo->ptr_clrequest->namespace);
  }
  else {
    strcpy(ns, "\n</listBibl>\n");
  }
  if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), ns, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    return 801;
  }
  *(ptr_rendinfo->ptr_ref) = new_ref;

  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  render_teix5() renders a RIS dataset for TEI XML P5 export

  int render_teix returns 0 if successful, >0 if not

  struct renderinfo* ptr_rendinfo ptr to a structure with the info
                             how the reference should be rendered

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int render_teix5(struct renderinfo* ptr_rendinfo) {
  char *new_ref; /* used for reallocating buffer ref */
  char *chunk;
  char *chunk_buf;
  const char *type;
  size_t chunk_buf_len;
  unsigned long long n_refdb_id;
  dbi_conn conn;
  struct xmlindent xindent;

  /*initialize xindent */
  initialize_xmlindent(&xindent, 2, indent_notbelow_teix, is_entry_teix);

  /* rendering bibliographic information takes up to three levels of
     information:
     analytic: author and title of the article or chapter
     monographic: name of the journal/book, vol/issue/page info, editors
     series: series title, series editors
  */

  chunk_buf_len = 1024;

  if ((chunk_buf = malloc(chunk_buf_len)) == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    return 801;
  }

  conn = dbi_result_get_conn(ptr_rendinfo->dbires);

  if ((type = get_refdb_type(ptr_rendinfo->dbires)) == NULL) {
    free(chunk_buf);
    LOG_PRINT(LOG_WARNING, get_status_msg(234));
    return 234;
  }

  n_refdb_id = my_dbi_result_get_idval(ptr_rendinfo->dbires, "refdb_id");

  if ((ptr_rendinfo->ptr_biblio_info)->entry_id != NULL) {
    if (print_elstart_x(ptr_rendinfo->ptr_ref, ptr_rendinfo->ptr_ref_len, "biblStruct", "id", (ptr_rendinfo->ptr_biblio_info)->entry_id, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      free(chunk_buf);
      return 801;
    }
  }
  else {
    if (print_elstart_x(ptr_rendinfo->ptr_ref, ptr_rendinfo->ptr_ref_len, "biblStruct", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      free(chunk_buf);
      return 801;
    }
  }
  
  if (has_part_data(type)) {
    chunk = add_analytic_teix(ptr_rendinfo, n_refdb_id, &chunk_buf, &chunk_buf_len, type, &xindent, REFTEIX5);

    if (chunk && *chunk) {
      if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), chunk, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	free(chunk_buf);
	return 801;
      }
      else {
	*(ptr_rendinfo->ptr_ref) = new_ref;
      }
    }
  }

  chunk = add_monogr_teix(ptr_rendinfo, n_refdb_id, &chunk_buf, &chunk_buf_len, type, &xindent, REFTEIX5);

  if (chunk && *chunk) {
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), chunk, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      free(chunk_buf);
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
  }

  if (has_set_data(type)) {
    chunk = add_series_teix(ptr_rendinfo, n_refdb_id, &chunk_buf, &chunk_buf_len, type, &xindent, REFTEIX5);

    if (chunk && *chunk) {
      if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), chunk, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	free(chunk_buf);
	return 801;
      }
      else {
	*(ptr_rendinfo->ptr_ref) = new_ref;
      }
    }
  }

  /* add notes and abstract if requested */

  /* notes */
  if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "N1") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
    chunk = add_notes_teix(ptr_rendinfo, n_refdb_id, &chunk_buf, &chunk_buf_len, &xindent);

    if (chunk && *chunk) {
      if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), chunk, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	free(chunk_buf);
	return 801;
      }
      else {
	*(ptr_rendinfo->ptr_ref) = new_ref;
      }
    }
  }

  /*----------------------------------------------------------------*/
  /* abstract */
  if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "N2") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "AB") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
    chunk = add_abstract_teix(ptr_rendinfo, n_refdb_id, &chunk_buf, &chunk_buf_len, &xindent);

    if (chunk && *chunk) {
      if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), chunk, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	free(chunk_buf);
	return 801;
      }
      else {
	*(ptr_rendinfo->ptr_ref) = new_ref;
      }
    }
  }

  /* finish bibliography entry */
  if (print_elend_x(ptr_rendinfo->ptr_ref, ptr_rendinfo->ptr_ref_len, "biblStruct", &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    free(chunk_buf);
    return 801;
  }

  free(chunk_buf);

  return 0;
}
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  add_analytic_teix() adds analytic level info to a TEI XML bibliography

  static char* add_analytic_teix returns ptr to ref if successful, NULL if not

  struct renderinfo* ptr_rendinfo ptr to a structure with the info
                             how the reference should be rendered

  int n_refdb_id ID of the current dataset

  char **ptr_chunk_buf ptr to an allocated string, may be resized

  size_t *ptr_chunk_buf_len ptr to length of ptr_chunk_buf

  const char* type ptr to string containing reference type

  struct xmlindent* ptr_indent ptr to structure with indentation info

  int n_ref_format REFTEIX or REFTEIX5

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static char* add_analytic_teix(struct renderinfo* ptr_rendinfo, int n_refdb_id, char **ptr_chunk_buf, size_t *ptr_chunk_buf_len, const char* type, struct xmlindent* ptr_indent, int n_ref_format) {
  int n_have_data = 0; /* set to 1 if we have some data */
  char *new_ref;
  char *entitize_buf;
  char *author_buf;
  char *author_result;
  const char *item;
  size_t author_buf_len;

  **ptr_chunk_buf = '\0';

  author_buf_len = 1024;

  if ((author_buf = malloc(author_buf_len)) == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    return NULL;
  }
    
  /* start analytic information */
  if (print_elstart_x(ptr_chunk_buf, ptr_chunk_buf_len, "analytic", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    free(author_buf);
    return NULL;
  }

  /* add authors, if any */
  author_result = add_author_info_teix(ptr_rendinfo, 1, n_refdb_id, &author_buf, &author_buf_len, ptr_indent, n_ref_format);

  if (!author_result) {
    free(author_buf);
    return NULL;
  }
  else if (*author_result) {
    n_have_data++;
    if ((new_ref = mstrcat(*ptr_chunk_buf, author_result, ptr_chunk_buf_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      free(author_buf);
      return NULL;
    }
    else {
      *ptr_chunk_buf = new_ref;
    }
  }

  free(author_buf);

  /* get the article or book title */
  item = get_refdb_title_copy(ptr_rendinfo->dbires);

  if (item != NULL && *item) {
    n_have_data++;
    if ((entitize_buf = mstrdup((char*)item)) == NULL) {
      free((char*)item);
      return NULL;
    }

    if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
      free((char*)item);
      free(entitize_buf);
      return NULL;
    }

    if (print_element_x(entitize_buf, ptr_chunk_buf, ptr_chunk_buf_len, "title", "level", "a", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free((char*)item);
      free(entitize_buf);
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return NULL;
    }

    free(entitize_buf);
    free((char*)item);
  }

  /* finish analytic information */
  if (print_elend_x(ptr_chunk_buf, ptr_chunk_buf_len, "analytic", ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    return NULL;
  }

  if (!n_have_data) {
    **ptr_chunk_buf = '\0';
  }

  return *ptr_chunk_buf;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  add_monogr_teix() adds monography level info to a TEI XML bibliography

  static char* add_monogr_teix returns ptr to ref if successful, NULL if not

  struct renderinfo* ptr_rendinfo ptr to a structure with the info
                             how the reference should be rendered

  int n_refdb_id ID of the current dataset

  char **ptr_chunk_buf ptr to an allocated string, may be resized

  size_t *ptr_chunk_buf_len ptr to length of ptr_chunk_buf

  const char* type ptr to string containing reference type

  struct xmlindent* ptr_indent ptr to structure with indentation info

  int n_ref_format REFTEIX or REFTEIX5

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static char* add_monogr_teix(struct renderinfo* ptr_rendinfo, int n_refdb_id, char **ptr_chunk_buf, size_t *ptr_chunk_buf_len, const char* type, struct xmlindent* ptr_indent, int n_ref_format) {
  int n_have_data = 0; /* set to 1 if we have some data */
  int i;
  int errcode; /* receives error code for periodical requests */
  char periodical[256];
  char *new_ref;
  char *entitize_buf;
  char *author_buf;
  char *author_result;
  const char *item;
  size_t author_buf_len;
  dbi_conn conn;

  
  **ptr_chunk_buf = '\0';

  author_buf_len = 1024;

  if ((author_buf = malloc(author_buf_len)) == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    return NULL;
  }
    
  conn = dbi_result_get_conn(ptr_rendinfo->dbires);

  /* start monographic information */
  if (print_elstart_x(ptr_chunk_buf, ptr_chunk_buf_len, "monogr", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    free(author_buf);
    return NULL;
  }

  /* add editors, if any */
  author_result = add_author_info_teix(ptr_rendinfo, 2, n_refdb_id, &author_buf, &author_buf_len, ptr_indent, n_ref_format);

  if (!author_result) {
    free(author_buf);
    return NULL;
  }
  else if (*author_result) {
    n_have_data++;
    if ((new_ref = mstrcat(*ptr_chunk_buf, author_result, ptr_chunk_buf_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      free(author_buf);
      return NULL;
    }
    else {
      *ptr_chunk_buf = new_ref;
    }
  }

  free(author_buf);

  if (has_periodical_data(type)) {
    /* journal information, if any */
    for (i = 0; i < 4; i++) {
      /* request journal */
      item = get_periodical(conn, periodical, /*ptr_rendinfo->database*/NULL, i, &errcode, 0, my_dbi_result_get_idval(ptr_rendinfo->dbires, "refdb_id"), NULL /* no frequency required */);
      if (item != NULL) {
	if (!*item) {
	  continue;
	}
	if ((entitize_buf = mstrdup((char*)item)) == NULL) {
	  return NULL;
	}
    
	if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
	  free(entitize_buf);
	  return NULL;
	}
      
/*       if ((new_ref = mstrcat(*ptr_chunk_buf, journaltype[i], ptr_chunk_buf_len, 0)) == NULL) { */
/* 	free(entitize_buf); */
/* 	LOG_PRINT(LOG_CRIT, get_status_msg(801)); */
/* 	return NULL; */
/*       } */
/*       else { */
/* 	*ptr_chunk_buf = new_ref; */
/*       } */

	if (print_element_x(entitize_buf, ptr_chunk_buf, ptr_chunk_buf_len, "title", "level", "j", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	  free(entitize_buf);
	  LOG_PRINT(LOG_CRIT, get_status_msg(801));
	  return NULL;
	}

	free(entitize_buf);
	n_have_data++;
      }
    }
  }

  /* monographic title */
  item = get_refdb_booktitle_copy(ptr_rendinfo->dbires);

  if (item != NULL) {
    if ((entitize_buf = mstrdup((char*)item)) == NULL) {
      free((char*)item);
      return NULL;
    }

    if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
      free((char*)item);
      free(entitize_buf);
      return NULL;
    }

    if (print_element_x(entitize_buf, ptr_chunk_buf, ptr_chunk_buf_len, "title", "level", "m", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(entitize_buf);
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return NULL;
    }
    free(entitize_buf);
    free((char*)item);
    n_have_data++;
  }

  if (print_elstart_x(ptr_chunk_buf, ptr_chunk_buf_len, "imprint", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    return NULL;
  }

  /* ISBN/ISSN */
  if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "SN") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
    if ((item = get_refdb_issn(ptr_rendinfo->dbires)) != NULL) {
      if ((entitize_buf = mstrdup((char*)item)) == NULL) {
	return NULL;
      }

      if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
	free(entitize_buf);
	return NULL;
      }

      if (print_element_x(entitize_buf, ptr_chunk_buf, ptr_chunk_buf_len, "idno", "type", "isbn", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	free(entitize_buf);
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	return NULL;
      }
      free(entitize_buf);
      n_have_data++;
    }
  }

  /* volume/issue info */
  if ((item = get_refdb_volume(ptr_rendinfo->dbires)) != NULL) {
    if ((entitize_buf = mstrdup((char*)item)) == NULL) {
      return NULL;
    }

    if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
      free(entitize_buf);
      return NULL;
    }
    
    /* volume */
    if (print_element_x(entitize_buf, ptr_chunk_buf, ptr_chunk_buf_len, "biblScope", "type", "vol", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(entitize_buf);
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return NULL;
    }

    free(entitize_buf);
    n_have_data++;
  }

  /* issue */
  if ((item = get_refdb_issue(ptr_rendinfo->dbires)) != NULL) {
    if ((entitize_buf = mstrdup((char*)item)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return NULL;
    }

    if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
      free(entitize_buf);
      return NULL;
    }

    if (print_element_x(entitize_buf, ptr_chunk_buf, ptr_chunk_buf_len, "biblScope", "type", "issue", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(entitize_buf);
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return NULL;
    }

    free(entitize_buf);
    n_have_data++;
  }

  /* pages */
  if ((item = get_refdb_startpage(ptr_rendinfo->dbires)) != NULL) {
    char* entitized_endpage;
    size_t entitize_buf_len;

    if ((entitize_buf = mstrdup((char*)item)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return NULL;
    }

    if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
      free(entitize_buf);
      return NULL;
    }

    entitize_buf_len = strlen(entitize_buf);

    /* end page */
    if ((item = get_refdb_endpage(ptr_rendinfo->dbires)) != NULL) {
      if ((entitized_endpage = mstrdup((char*)item)) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	return NULL;
      }

      if (sgml_entitize(&entitized_endpage, ptr_rendinfo->ref_format) == NULL) {
	free(entitize_buf);
	free(entitized_endpage);
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	return NULL;
      }

      if ((new_ref = mstrcat(entitize_buf, "-", &entitize_buf_len, 0)) == NULL) {
	free(entitize_buf);
	free(entitized_endpage);
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	return NULL;
      }
      else {
	entitize_buf = new_ref;
      }

      if ((new_ref = mstrcat(entitize_buf, entitized_endpage, &entitize_buf_len, 0)) == NULL) {
	free(entitize_buf);
	free(entitized_endpage);
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	return NULL;
      }
      else {
	entitize_buf = new_ref;
      }
      free(entitized_endpage);
    }

    if (print_element_x(entitize_buf, ptr_chunk_buf, ptr_chunk_buf_len, "biblScope", "type", "pages", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free((char*)item);
      free(entitize_buf);
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return NULL;
    }

    free(entitize_buf);
    n_have_data++;
  }

  /* reuse periodical buffer for date*/
  if ((item = get_refdb_pubyear(ptr_rendinfo->dbires, periodical)) != NULL) {
    if (print_element_x(periodical, ptr_chunk_buf, ptr_chunk_buf_len, "date", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free((char*)item);
      free(entitize_buf);
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return NULL;
    }
    n_have_data++;
  }

  /* publisher and city */
  if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "PB") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
    if ((item = get_refdb_publisher(ptr_rendinfo->dbires)) != NULL) {
      if ((entitize_buf = mstrdup((char*)item)) == NULL) {
	return NULL;
      }

      if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
	free(entitize_buf);
	return NULL;
      }

      if (print_element_x(entitize_buf, ptr_chunk_buf, ptr_chunk_buf_len, "publisher", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	return NULL;
      }

      free(entitize_buf);
      if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "CY") != NULL
	  || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
	/* pubplace - use only if publisher is known */
	if ((item = get_refdb_city(ptr_rendinfo->dbires)) != NULL) {
	  if ((entitize_buf = mstrdup((char*)item)) == NULL) {
	    return NULL;
	  }

	  if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
	    free(entitize_buf);
	    return NULL;
	  }

	  if (print_element_x(entitize_buf, ptr_chunk_buf, ptr_chunk_buf_len, "pubplace", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	    LOG_PRINT(LOG_CRIT, get_status_msg(801));
	    return NULL;
	  }

	  free(entitize_buf);
	}
      }
      
      n_have_data++;
    }
  }
  
  if (print_elend_x(ptr_chunk_buf, ptr_chunk_buf_len, "imprint", ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    return NULL;
  }

  /* finish monographic information */
  if (print_elend_x(ptr_chunk_buf, ptr_chunk_buf_len, "monogr", ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    return NULL;
  }

  if (!n_have_data) {
    **ptr_chunk_buf = '\0';
  }

  return *ptr_chunk_buf;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  add_series_teix() adds series level info to a TEI XML bibliography

  static char* add_series_teix returns ptr to ref if successful, NULL if not

  struct renderinfo* ptr_rendinfo ptr to a structure with the info
                             how the reference should be rendered

  int n_refdb_id ID of the current dataset

  char **ptr_chunk_buf ptr to an allocated string, may be resized

  size_t *ptr_chunk_buf_len ptr to length of ptr_chunk_buf

  const char* type ptr to string containing reference type

  struct xmlindent* ptr_indent ptr to structure with indentation info

  int n_ref_format REFTEIX or REFTEIX5

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static char* add_series_teix(struct renderinfo* ptr_rendinfo, int n_refdb_id, char **ptr_chunk_buf, size_t *ptr_chunk_buf_len, const char* type, struct xmlindent* ptr_indent, int n_ref_format) {
  int n_have_data = 0; /* set to 1 if we have some data */
  char *new_ref;
  char *entitize_buf;
  char *author_buf;
  char *author_result;
  const char *item;
  size_t author_buf_len;

  **ptr_chunk_buf = '\0';

  author_buf_len = 1024;

  if ((author_buf = malloc(author_buf_len)) == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    return NULL;
  }
    
  /* start series info */
  if (print_elstart_x(ptr_chunk_buf, ptr_chunk_buf_len, "series", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    free(author_buf);
    return NULL;
  }

  /* add editors, if any */
  author_result = add_author_info_teix(ptr_rendinfo, 3, n_refdb_id, &author_buf, &author_buf_len, ptr_indent, n_ref_format);

  if (!author_result) {
    free(author_buf);
    return NULL;
  }
  else if (*author_result) {
    n_have_data++;
    if ((new_ref = mstrcat(*ptr_chunk_buf, author_result, ptr_chunk_buf_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      free(author_buf);
      return NULL;
    }
    else {
      *ptr_chunk_buf = new_ref;
    }
  }

  free(author_buf);

  /* series title, if any */
  item = get_refdb_title_series_copy(ptr_rendinfo->dbires);

  if (item != NULL) {
    if ((entitize_buf = mstrdup((char*)item)) == NULL) {
      free((char*)item);
      return NULL;
    }

    if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
      free((char*)item);
      free(entitize_buf);
      return NULL;
    }

    if (print_element_x(entitize_buf, ptr_chunk_buf, ptr_chunk_buf_len, "title", "level", "s", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free((char*)item);
      free(entitize_buf);
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return NULL;
    }

    free(entitize_buf);
    free((char*)item);
    n_have_data++;
  }

  /* finish series information */
  if (print_elend_x(ptr_chunk_buf, ptr_chunk_buf_len, "series", ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    return NULL;
  }

  if (!n_have_data) {
    **ptr_chunk_buf = '\0';
  }

  return *ptr_chunk_buf;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  add_author_info_teix() adds author info to a TEI XML bibliography

  static char* add_author_info_teix returns ptr to ref if successful, NULL if not

  struct renderinfo* ptr_rendinfo ptr to a structure with the info
                             how the reference should be rendered

  int author_type 1=author 2=editor 3=series editor

  int n_refdb_id ID of the current dataset

  struct xmlindent* ptr_indent ptr to structure with indentation info

  int n_ref_format REFTEIX or REFTEIX5

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static char* add_author_info_teix(struct renderinfo* ptr_rendinfo, int author_type, int n_refdb_id, char** ptr_chunk_buf, size_t* ptr_chunk_buf_len, struct xmlindent* ptr_indent, int n_ref_format) {
  int n_have_data = 0;
  char *entitize_buf;
  char *item;
  char author_start[3][9] = {"author",
			     "editor",
			     "editor"};
  dbi_conn conn;
  dbi_result dbires;
  struct AUTHOR_INFO ainfo;

  **ptr_chunk_buf = '\0';

  conn = dbi_result_get_conn(ptr_rendinfo->dbires);

  /* get authors */
  dbires = request_authors(conn, author_type, NULL /* all roles */, NULL, 0, n_refdb_id);
  if (dbires == NULL) {
    return NULL;
  }

  /* fetch all authors of this article */
  while ((get_author_parts(dbires, &ainfo)) != NULL) {

    if (!*(ainfo.lastname) && !*(ainfo.firstname)
      && !*(ainfo.middlename) && !*(ainfo.suffix)) {
      if (*(ainfo.name)) {
 	n_have_data++;
	if (print_elstart_x(ptr_chunk_buf, ptr_chunk_buf_len, "author", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	  LOG_PRINT(LOG_CRIT, get_status_msg(801));
	  clean_request(dbires);
	  return NULL;
	}

	if ((entitize_buf = mstrdup(ainfo.name)) == NULL) {
	  clean_request(dbires);
	  return NULL;
	}

	if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
	  clean_request(dbires);
	  free(entitize_buf);
	  return NULL;
	}

	if (print_element_x(entitize_buf, ptr_chunk_buf, ptr_chunk_buf_len, "orgName", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	  free(entitize_buf);
	  LOG_PRINT(LOG_CRIT, get_status_msg(801));
	  return NULL;
	}

	free(entitize_buf);

	if (print_elend_x(ptr_chunk_buf, ptr_chunk_buf_len, "author", ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	  LOG_PRINT(LOG_CRIT, get_status_msg(801));
	  return NULL;
	}
      }
    }
    else {
      if (print_elstart_x(ptr_chunk_buf, ptr_chunk_buf_len, author_start[author_type-1], NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	clean_request(dbires);
	return NULL;
      }

      if (print_elstart_x(ptr_chunk_buf, ptr_chunk_buf_len, "persName", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	clean_request(dbires);
	return NULL;
      }

      if (*(ainfo.firstname)) {
 	n_have_data++;

	if ((entitize_buf = mstrdup(ainfo.firstname)) == NULL) {
	  clean_request(dbires);
	  return NULL;
	}

	if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
	  clean_request(dbires);
	  free(entitize_buf);
	  return NULL;
	}

	if (n_ref_format == REFTEIX5) {
	  if (print_element_x(entitize_buf, ptr_chunk_buf, ptr_chunk_buf_len, "forename", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	    free(entitize_buf);
	    LOG_PRINT(LOG_CRIT, get_status_msg(801));
	    return NULL;
	  }
	}
	else {
	  if (print_element_x(entitize_buf, ptr_chunk_buf, ptr_chunk_buf_len, "foreName", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	    free(entitize_buf);
	    LOG_PRINT(LOG_CRIT, get_status_msg(801));
	    return NULL;
	  }
	}
	free(entitize_buf);
      }

      if (*(ainfo.middlename)) {
 	n_have_data++;
	for (item = strtok(ainfo.middlename, " "); item; item = strtok(NULL, " ")) {
	  if ((entitize_buf = mstrdup(item)) == NULL) {
	    clean_request(dbires);
	    return NULL;
	  }
	  
	  if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
	    clean_request(dbires);
	    free(entitize_buf);
	    return NULL;
	  }

	  if (print_element_x(entitize_buf, ptr_chunk_buf, ptr_chunk_buf_len, "addName", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	    free(entitize_buf);
	    LOG_PRINT(LOG_CRIT, get_status_msg(801));
	    return NULL;
	  }
	  free(entitize_buf);
	}
      }

      if (*(ainfo.lastname)) {
 	n_have_data++;

	if ((entitize_buf = mstrdup(ainfo.lastname)) == NULL) {
	  clean_request(dbires);
	  return NULL;
	}

	if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
	  clean_request(dbires);
	  free(entitize_buf);
	  return NULL;
	}

	if (print_element_x(entitize_buf, ptr_chunk_buf, ptr_chunk_buf_len, "surname", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	  free(entitize_buf);
	  LOG_PRINT(LOG_CRIT, get_status_msg(801));
	  return NULL;
	}
	free(entitize_buf);
      }

      if (*(ainfo.suffix)) {
 	n_have_data++;
	if ((entitize_buf = mstrdup(ainfo.firstname)) == NULL) {
	  clean_request(dbires);
	  return NULL;
	}

	if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
	  clean_request(dbires);
	  free(entitize_buf);
	  return NULL;
	}

	if (print_element_x(entitize_buf, ptr_chunk_buf, ptr_chunk_buf_len, "genName", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	  free(entitize_buf);
	  LOG_PRINT(LOG_CRIT, get_status_msg(801));
	  return NULL;
	}
	free(entitize_buf);
      }

      if (print_elend_x(ptr_chunk_buf, ptr_chunk_buf_len, "persName", ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	return NULL;
      }

      if (print_elend_x(ptr_chunk_buf, ptr_chunk_buf_len, author_start[author_type-1], ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	return NULL;
      }
    }
  }

  if (!n_have_data) {
    **ptr_chunk_buf = '\0';
  }

  clean_request(dbires);

  /* if there was no author info, chunk_buf is returned unaltered */
  return *ptr_chunk_buf;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  add_notes_teix() adds notes info to a TEI bibliography

  static char* add_notes_teix returns ptr to ref if successful, NULL if not

  struct renderinfo* ptr_rendinfo ptr to a structure with the info
                             how the reference should be rendered

  int n_refdb_id ID of the current dataset

  char **ptr_chunk_buf ptr to an allocated string, may be resized

  size_t *ptr_chunk_buf_len ptr to length of ptr_chunk_buf

  struct xmlindent* ptr_indent ptr to structure with indentation info

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static char* add_notes_teix(struct renderinfo* ptr_rendinfo, int n_refdb_id, char **ptr_chunk_buf, size_t *ptr_chunk_buf_len, struct xmlindent* ptr_indent) {
  int n_have_data = 0; /* set to 1 if we have some data */
  char *entitize_buf;
  const char *item;

  **ptr_chunk_buf = '\0';

  /* note of current user, if any */
  item = get_notes_copy(ptr_rendinfo->dbires, ptr_rendinfo->username);

  if (item && *item) {
    n_have_data++;
    if ((entitize_buf = mstrdup((char*)item)) == NULL) {
      free((char*)item);
      return NULL;
    }

    if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
      free((char*)item);
      free(entitize_buf);
      return NULL;
    }

    if (print_element_x(entitize_buf, ptr_chunk_buf, ptr_chunk_buf_len, "note", "type", "annotation", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(entitize_buf);
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return NULL;
    }
  }

  if (!n_have_data) {
    **ptr_chunk_buf = '\0';
  }

  return *ptr_chunk_buf;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  add_abstract_teix() adds abstract to a TEI bibliography

  static char* add_abstract_db returns ptr to ref if successful, NULL if not

  struct renderinfo* ptr_rendinfo ptr to a structure with the info
                             how the reference should be rendered

  int n_refdb_id ID of the current dataset

  char **ptr_chunk_buf ptr to an allocated string, may be resized

  size_t *ptr_chunk_buf_len ptr to length of ptr_chunk_buf

  struct xmlindent* ptr_indent ptr to structure with indentation info

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static char* add_abstract_teix(struct renderinfo* ptr_rendinfo, int n_refdb_id, char **ptr_chunk_buf, size_t *ptr_chunk_buf_len, struct xmlindent* ptr_indent) {
  int n_have_data = 0; /* set to 1 if we have some data */
  char *entitize_buf;
  const char *item;

  **ptr_chunk_buf = '\0';

  /* abstract, if any */
  item = get_refdb_abstract_copy(ptr_rendinfo->dbires);

  if (item != NULL) {
    n_have_data++;
    if ((entitize_buf = mstrdup((char*)item)) == NULL) {
      free((char*)item);
      return NULL;
    }

    if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
      free((char*)item);
      free(entitize_buf);
      return NULL;
    }

    if (print_element_x(entitize_buf, ptr_chunk_buf, ptr_chunk_buf_len, "abstract", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free((char*)item);
      free(entitize_buf);
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return NULL;
    }

    free(entitize_buf);
    free((char*)item);
  }

  if (!n_have_data) {
    **ptr_chunk_buf = '\0';
  }

  return *ptr_chunk_buf;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  indent_notbelow_teix(): checks whether or not to indent below the current
                     element

  static int indent_notbelow_teix returns 1 if not to indent, 0 if to indent

  const char* name ptr to element name

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static int indent_notbelow_teix(const char* name)
{
  if (!strcmp(name, "date")) {
    return 1;
  }
  else {
    return 0;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  is_entry_teix(): checks whether an element starts a new entry

  static int is_entry_teix returns 1 if entry starts, 0 if not

  const char* name ptr to element name

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static int is_entry_teix(const char* name) {
  if (!strcmp(name, "biblStruct")) {
    return 1;
  }
  else {
    return 0;
  }
}
