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

#define HEXA_STRING "0123456789abcdef"

#ifdef WIN32
#include <io.h>
#include <ctype.h>
#define MKSTEMP mktemp
#else
#define MKSTEMP mkstemp
#endif

#define BIT(x) (1<<x)

char idx[1024], ind[1024];
int cho=-1, style_used=0;
int to_8bit(void);
int hangul_head(int);
int doublebyte(int, int);
int triplebyte(unsigned int, unsigned int, unsigned int);
int ucs(int);
void fputs_item(char *, FILE *);

main(int argc, char *argv[])
{
  int i, outfile_used=0;
  char prog[1024], args[1024], cmd[128], idx0[1024];
  char *t, *l;

  strcpy(prog, argv[0]);
#ifdef WIN32
  strcpy(args, "");
  strcpy(ind, "");
#else
  bzero(args, 1024);
  bzero(ind, 1024);
#endif

  printf("This is hmakeindex, version 1.0 (makeindex wrapper for Korean support).\n");

  for(i=1; i<argc; i++) {
    strcat(args, " ");
    t=argv[i];
    strcat(args, t);
    switch(*t) {
    case '-':
      t++;
      switch(*t) {
      case 'o':
	outfile_used=1;
	strcat(args, " ");
	strcat(args, argv[++i]);
	strcpy(ind, argv[i]);
	if((l=strrchr(ind, '.'))&&*(l+1)=='i'&&*(l+2)=='n'&&*(l+3)=='d')
	  *l=0;
	break;
      case 'p':
	strcat(args, " ");
	strcat(args, argv[++i]);
	break;
      case 's':
	strcat(args, " ");
	strcat(args, argv[++i]);
	style_used=1;
	break;
      case 't':
	strcat(args, " ");
	strcat(args, argv[++i]);
	break;
      default:
	break;
      }
      break;
    default:
      if((l=strrchr(argv[i], '.'))&&*(l+1)=='i'&&*(l+2)=='d'&&*(l+3)=='x')
	*l=0;
      strcpy(idx, argv[i]);
      strcpy(idx0, argv[i]);
      strcat(idx, ".idx");
      break;
    }
  }

  i=to_8bit();
  sprintf(cmd, "makeindex %s", args);
  system(cmd);

  if(outfile_used==0) {
    strcpy(ind, idx0);
    strcat(ind, ".ind");
  }
  hangul_head(i);

  exit(0);
}

int to_8bit() {
  FILE *in, *out;
  char line[1024], *h1, *h2, tempfile[9];
  unsigned char *l;
  int x, w=0, utf_seen=0, hangul_enc=0;

  in = fopen(idx, "r");
  if(!in) {
    printf("\tError opening index file \"%s\"!!!\n", idx);
    exit(1);
  }

  strcpy(tempfile, "IDXXXXXXX");
  MKSTEMP(tempfile);
  out = fopen(tempfile, "w");
  if(!out) {
    printf("\tError opening temporary file \"%s\"!!!\n", tempfile);
    exit(1);
  }

  while(fgets(line, 1024, in)) {
    l=line;
    while(*l) {
      if(*l=='^'&&*(l+1)=='^'
	 &&(h1=strchr(HEXA_STRING, *(l+2)))
	 &&(h2=strchr(HEXA_STRING, *(l+3)))) {
	if(*h1>'9') x=*h1-87;
	else x=*h1-48;
	x*=16;
	if(*h2>'9') x+=*h2-87;
	else x+=*h2-48;
	fputc(x, out);
	l+=4;
	hangul_enc=1;
	if(w<161 || x<161) utf_seen=1;
	w=x;
      }
      else {
	if(w>127 && *l>127) {
	  /* 이미 변환된 .idx 파일의 경우 */
	  hangul_enc=1;
	  if(w<161 || *l<161) utf_seen=1;
	}
	w=*l;
	/* 위치 표시 문자 '@'는 '\a'으로 변환하여 makeindex로 처리한 후
	   나중에 제거한다. \hindexhead{#}의 "#" 처리에서 오류가 발생 */
	if(*(l-1)!='"' && *l=='@') fputc('\a', out);
	else fputc(*l, out);
	l++;
      }
    }
  }
  fflush(NULL);
  fclose(in);
  fclose(out);

  rename(tempfile, idx);

  return(hangul_enc+utf_seen);
}

int hangul_head(encoding) {
  FILE *in, *out;
  char tempfile[9];
  unsigned char line[1024], *l;
  unsigned int cho=20, x;

  strcpy(tempfile, "INDXXXXXX");
  MKSTEMP(tempfile);
  in=fopen(ind, "r");
  out=fopen(tempfile, "w");

  while(fgets(line, 1024, in)) {
    l=line;
    while(isspace(*l)) l++;
    if(strncmp(l, "\\item", 5)==0) {
      l+=5;
      while(isspace(*l)) l++;
      if(*l<128) {
	fputs_item(line, out);
	continue;
      }
      switch(encoding) {
      case 1: /* EUC-KR */
	x=doublebyte(*l, *(l+1));
	break;
      case 2: /* UTF-8 */
	x=triplebyte(*l, *(l+1), *(l+2));
	break;
      default:
	fprintf(stderr, "Encoding error in the ind file\n");
	fputs(line, out);
	break;
      }
      if(x!=cho && x<20) {
	cho=x;
	fprintf(out, "\n\\hindexhead{%d}\n", cho);
      }
      fputs_item(line, out);
    }
    else if(strncmp(l, "\\indexspace", 11)==0) {
      if(cho<0 || cho>19) fputs(line, out);
    }
    else if(!(strncmp(l, "\\indexhead{", 11)==0&&*(l+11)>128)) {
      fputs(line, out);
    }
  }

  fflush(NULL);
  fclose(in);
  fclose(out);

  rename(tempfile, ind);

  return(1);
}

void fputs_item(char *item, FILE *fp) {
  char *s;

  if((s=strchr(item, '\a'))) fprintf(fp, "  \\item %s", ++s);
  else fputs(item, fp);
}

int doublebyte(int first, int second) {
  unsigned int ksc;

  if(first<0xa1) return(21);
  else if(first<0xb1) return(0);
  else if(first>0xc8) return(20);
  ksc=(first<<8)+second;
  if(ksc<0xb1ee) return(1);
  else if(ksc<0xb3aa) return(2);
  else if(ksc<0xb4d9) return(3);
  else if(ksc<0xb5fb) return(4);
  else if(ksc<0xb6f3) return(5);
  else if(ksc<0xb8b6) return(6);
  else if(ksc<0xb9d9) return(7);
  else if(ksc<0xbafc) return(8);
  else if(ksc<0xbbe7) return(9);
  else if(ksc<0xbdce) return(10);
  else if(ksc<0xbec6) return(11);
  else if(ksc<0xc0da) return(12);
  else if(ksc<0xc2a5) return(13);
  else if(ksc<0xc2f7) return(14);
  else if(ksc<0xc4ab) return(15);
  else if(ksc<0xc5b8) return(16);
  else if(ksc<0xc6c4) return(17);
  else if(ksc<0xc7cf) return(18);
  else if(ksc<0xc8ff) return(19);
  else return(-1);
}

int triplebyte(unsigned int first, unsigned int second, unsigned int third) {
  unsigned int utf;
  int i;

  if(first<=0x7f) utf=first;
  else {
    i=0;
    while(first & BIT((6-i))) i++;
    switch(i) {
    case 1:
      utf=((first - BIT(7) - BIT(6))<<6);
      utf+=(second - BIT(7));
      break;
    case 2:
      utf=((first - BIT(7) - BIT(6) - BIT(5))<<12);
      utf+=((second - BIT(7))<<6);
      utf+=(third - BIT(7));
      break;
    default:
      break;
    }
  }

  if(0xac00<=utf && utf<=0xd7a3)
    return((utf-0xac00)/(21*28)+1);
  else if((0x4e00<=utf && utf>=0x9fff) ||
	  (0xf900<=utf && utf>=0xfaff)) return(20);
  else if(utf==first) return(21);
  else return(0);
}