#include <stdio.h>
#include <string.h>
#include <stdarg.h>

#define nonempty(X) ((X) != NULL && (X)[0] != '\0')
#define endof(X) ((X)+(int)strlen(X))

void split(char *s, int num, ...)
{
  va_list vl ;
  char *t, **ptr ;
  int i, quoted ;

  t = s ;
  va_start(vl, num) ;

  for (i=0 ; i < num ; i++) {
    ptr = va_arg(vl, char **) ;
    quoted = va_arg(vl, int) ;
    if (quoted) t++ ; /* skip first quote */
    if (ptr != NULL) *ptr = t ;
    if (quoted) {
      while (*t != '"') t++ ;  /* skip to second quote */
      *t = '\0' ; /* null out the second quote */
      t++ ; /* skip to space which is either comma or null */
      if (*t == ',') t++ ; /* skip over comma */
    }
    else {
      while (*t != '\0' && *t != ',') t++ ;
      if (*t == ',') {
	*t = '\0' ;
	t++ ;
      }
    }
  }
}

void capitalize(char *s)
{
  int len, i ;
  len = strlen(s) ;
  if (len > 0) s[0] = toupper(s[0]) ;
  for (i=1 ; i < len ; i++) s[i] = tolower(s[i]) ;
}

void auth_convert(char *old, char *new) 
{
  unsigned char *s ;
  char *t ;

  for (s = (unsigned char *)old, t=new ; *s != '\0' ; s++) {
    switch(*s) {
    case '&':
      sprintf(t, "&amp;") ;
      for (;*t != '\0' ; t++) ;
      break ;
    case 0x81: 
      sprintf(t, "&uuml;") ;
      for (;*t != '\0' ; t++) ;
      break ;
    case 0x82: 
      sprintf(t, "&eacute;") ;
      for (;*t != '\0' ; t++) ;
      break ;
    case 0x84: 
      sprintf(t, "&auml;") ;
      for (;*t != '\0' ; t++) ;
      break ;
    case 0x89:
      sprintf(t, "&euml;") ;
      for (;*t != '\0' ; t++) ;
      break ;
    case 0x8A: 
      sprintf(t, "&egrave;") ;
      for (;*t != '\0' ; t++) ;
      break ;
    case 0x93: 
      sprintf(t, "&ocirc;") ;
      for (;*t != '\0' ; t++) ;
      break ;
    case 0x94: 
      sprintf(t, "&ouml;") ;
      for (;*t != '\0' ; t++) ;
      break ;
    case 0x98:
      sprintf(t, "&yuml;") ;
      for (;*t != '\0' ; t++) ;
      break ;
    case 0xA0: 
      sprintf(t, "&aacute;") ;
      for (;*t != '\0' ; t++) ;
      break ;
    case 0xA1: 
      sprintf(t, "&iacute;") ;
      for (;*t != '\0' ; t++) ;
      break ;
    case 0xA2:
      sprintf(t, "&oacute;") ;
      for (;*t != '\0' ; t++) ;
      break ;
    default:
      *t = *s ;
      t++ ;
    }
  }
  *t = '\0' ;
}

main(int argc, char *argv[])
{
  FILE *fp ;
  int i ;
  char *ncode, *tcode, *acsy, *rank_str, *fam, *genhyb, *gen ;
  char *spechyb, *spec, *trirank, *tri, *quadrank, *quad, *auth ;
  char new_auth[256] ;
  int rank ;
  char cur_name[256], cur_spec[256], cur_tri[256], cur_quad[256] ;
  char pp_gen[256], pp_spec[256], pp_auth[256] ;
  char **sy_gens, **sy_specs, **sy_auths ;
  int num_sy_names, max_sy_names ;
  char ac_gen[256], ac_spec[256], ac_spec_auth[256] ;
  char ac_tri[256], ac_tri_auth[256] ;
  char ac_fam_code[10], ac_gen_code[10], ac_spec_code[10], ac_tri_code[10] ;

  fp = fopen(argv[1], "r") ;

  max_sy_names = 0 ;

  do {
    char s[256] ;

    fgets(s, 256, fp) ;
    if (!feof(fp)) {
      int len ;
      len = strlen(s) ;
      if (s[len-1] == '\n') s[len-1] = '\0' ;
      split(s, 14, &ncode, 1,
	    &tcode, 1,
	    &acsy, 1, 
	    &rank_str, 0,
	    &fam, 1, 
	    &genhyb, 1,
	    &gen, 1,
	    &spechyb, 1,
	    &spec, 1,
	    &trirank, 1,
	    &tri, 1,
	    &quadrank, 1,
	    &quad, 1,
	    &auth, 1) ;

      for (i=1 ; ncode[i] != '\0' ; i++) ncode[i] += 'A' - '0' ;
      for (i=1 ; tcode[i] != '\0' ; i++) tcode[i] += 'A' - '0' ;

      rank = atoi(rank_str) ;

      auth_convert(auth, new_auth) ;
      auth = new_auth ;

      capitalize(fam) ;

      if (rank == 1 && strcmp(acsy, "PP")) 
	num_sy_names = 0 ;

      else {
	if (nonempty(spechyb))
	  sprintf(cur_spec, "%s<i>%s</i> X <i>%s</i>",
		  nonempty(genhyb) ? "X " : "", gen, spec) ;
	else
	  sprintf(cur_spec, "%s<i>%s %s</i>",
		  nonempty(genhyb) ? "X " : "", gen, spec) ;
	if (rank >= 3)
	  sprintf(cur_tri, "%s. <i>%s</i>", trirank, tri) ;
	if (rank == 4)
	  sprintf(cur_quad, "%s. <i>%s</i>", quadrank, quad) ;
      }

      if (!strcmp(acsy, "PP")) {
	strcpy(pp_gen, gen) ;
	strcpy(pp_spec, spec) ;
	strcpy(pp_auth, auth) ;
      }
      else if (!strcmp(acsy, "SY") && rank == 2) {
	if (num_sy_names == max_sy_names) {
	  sy_gens = (char **)
	    (max_sy_names == 0 ? 
	     malloc(sizeof(char *)) :
	     realloc(sy_gens, sizeof(char *) * (max_sy_names+1))) ;
	  sy_gens[max_sy_names] = (char *)malloc(sizeof(char) * 256) ;

	  sy_specs = (char **)
	    (max_sy_names == 0 ? 
	     malloc(sizeof(char *)) :
	     realloc(sy_specs, sizeof(char *) * (max_sy_names+1))) ;
	  sy_specs[max_sy_names] = (char *)malloc(sizeof(char) * 256) ;

	  sy_auths = (char **)
	    (max_sy_names == 0 ? 
	     malloc(sizeof(char *)) :
	     realloc(sy_auths, sizeof(char *) * (max_sy_names+1))) ;
	  sy_auths[max_sy_names] = (char *)malloc(sizeof(char) * 256) ;
	  max_sy_names++ ;
	}
	strcpy(sy_gens[num_sy_names], gen) ;
	strcpy(sy_specs[num_sy_names], spec) ;
	strcpy(sy_auths[num_sy_names], auth) ;
	num_sy_names++ ;
      }
      else if (!strcmp(acsy, "AC"))
	if (rank == 0) {
	  strcpy(ac_fam_code, ncode) ;
	}
	else if (rank == 1) {
	  strcpy(ac_gen_code, ncode) ;
	}
	else if (rank == 2) {
	  strcpy(ac_spec_code, ncode) ;
	  strcpy(ac_gen, gen) ;
	  strcpy(ac_spec, spec) ;
	  strcpy(ac_spec_auth, auth) ;
	}
	else if (rank == 3) {
	  strcpy(ac_tri_code, ncode) ;
	  strcpy(ac_tri, tri) ;
	  strcpy(ac_tri_auth, auth) ;
	}

      
      if (strcmp(acsy, "PP")) {
	cur_name[0] = '\0' ;

	printf("qqrnk%c\n", 'a'+rank) ;
	if (!strcmp(acsy, "AC")) 
	  printf("qqacc\n") ;
	else printf("qqsyn\n") ;

	printf("qqbnn%s\n", ncode+1) ;
	printf("qqbtn%s\n", tcode+1) ;

	switch (rank) {
	case 0:
	  printf("qqfam%s\n", fam) ;
	  printf("qqnam %s\n", fam) ;
	  break ;
	case 1:
	  printf("qqfco%s\n", ac_fam_code+1) ;
	  printf("qqfam%s\n", fam) ;
	  printf("qqgen%s\n", gen) ;
	  if (nonempty(genhyb)) printf("qqghy\n") ;
	  printf("qqnam <i>%s</i>\n", gen) ;
	  printf("qqaut <i>%s</i> %s", gen, auth) ;
	  break ;
	case 2:
	  printf("qqfco%s\n", ac_fam_code+1) ;
	  printf("qqgco%s\n", ac_gen_code+1) ;
	  printf("qqfam%s\n", fam) ;
	  printf("qqgen%s\n", gen) ;
	  if (nonempty(genhyb)) printf("qqghy\n") ;
	  printf("qqspe%s\n", spec) ;
	  if (nonempty(spechyb)) printf("qqshy\n") ;
	  printf("qqnam %s\n", cur_spec);
	  printf("qqaut %s %s\n", cur_spec, auth) ;
	  break ;
	case 3:
	  printf("qqfco%s\n", ac_fam_code+1) ;
	  printf("qqgco%s\n", ac_gen_code+1) ;
	  printf("qqsco%s\n", ac_spec_code+1) ;
	  printf("qqfam%s\n", fam) ;
	  printf("qqgen%s\n", gen) ;
	  if (nonempty(genhyb)) printf("qqghy\n") ;
	  printf("qqspe%s\n", spec) ;
	  if (nonempty(spechyb)) printf("qqshy\n") ;
	  printf("qqtrr%s\n", trirank) ;
	  printf("qqtri%s\n", tri) ;
	  printf("qqnam %s %s\n", cur_spec, cur_tri) ;

	  if (!strcmp(acsy, "AC")) 
	    printf("qqaut %s %s %s %s\n", cur_spec, ac_spec_auth,
		   cur_tri, auth) ;
	  else {
	    if (!strcmp(gen, pp_gen) &&
		!strcmp(spec, pp_spec))
	      printf("qqaut %s %s %s %s\n",
		     cur_spec, pp_auth, cur_tri, auth) ;
	    else if (!strcmp(gen, ac_gen) &&
		     !strcmp(spec, ac_spec))
	      printf("qqaut %s %s %s %s\n",
		     cur_spec, ac_spec_auth, cur_tri, auth) ;
	    else {
	      int i ;
	      for (i=0 ; i < num_sy_names ; i++) 
		if (!strcmp(gen, sy_gens[i]) &&
		    !strcmp(spec, sy_specs[i])) {
		  printf("qqaut %s %s %s %s\n",
			 cur_spec, sy_auths[i], cur_tri, auth) ;
		  break ;
		}
	      if (i == num_sy_names) {
		printf("qqaut %s ??? %s %s\n",
		       cur_spec, cur_tri, auth) ;
	      }
	    }
	  }
	  break ;
	case 4:
	  printf("qqfco%s\n", ac_fam_code+1) ;
	  printf("qqgco%s\n", ac_gen_code+1) ;
	  printf("qqsco%s\n", ac_spec_code+1) ;
	  printf("qqtco%s\n", ac_tri_code+1) ;
	  printf("qqfam%s\n", fam) ;
	  printf("qqgen%s\n", gen) ;
	  if (nonempty(genhyb)) printf("qqghy\n") ;
	  printf("qqspe%s\n", spec) ;
	  if (nonempty(spechyb)) printf("qqshy\n") ;
	  printf("qqtrr%s\n", trirank) ;
	  printf("qqtri%s\n", tri) ;
	  printf("qqqur%s\n", quadrank) ;
	  printf("qqqua%s\n", quad) ;
	  printf("qqnam %s %s %s\n", cur_spec, cur_tri, cur_quad) ;
	  if (!strcmp(gen, ac_gen) &&
	      !strcmp(spec, ac_spec) &&
	      !strcmp(tri, ac_tri))
	    printf("qqaut %s %s %s %s %s %s\n",
		   cur_spec, ac_spec_auth,
		   cur_tri, ac_tri_auth,
		   cur_quad, auth) ;

	  break ;

	}
	printf("%c", (char)2) ;
      }
    }
  } while (!feof(fp)) ;
  
  fclose(fp) ; 
}


