/*
 * bdfindex.c  -  Make an index file of BDF font
 *
 *  Programmmed by Hirotsugu Kakugawa, Hiroshima University
 *  E-Mail:  kakugawa@se.hiroshima-u.ac.jp
 *
 *  Edition History
 *  27 Dec 1995  Index version 1.
 *  19 Feb 1996  Index version 2. Character Set (as defined in the
 *               BDF file) and encoding value added. (WL)
 *  14 Mar 1996  bug fix: ENCODING property must be used instead of
 *               STARTCHAR. (WL)
 */


/* This file is part of VFlib
 *
 * Copyright (C) 1995 Hirotsugu KAKUGAWA.   All rights reserved.
 *
 * VFlib is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
 * to anyone for the consequences of using it or for whether it serves any
 * particular purpose or works at all, unless he says so in writing.  Refer
 * to the GNU General Public License for full details.
 *
 * Everyone is granted permission to copy, modify and redistribute
 * VFlib, but only under the conditions described in the GNU
 * General Public License.  A copy of this license is supposed to have been
 * given to you along with VFlib so you can know your rights and
 * responsibilities.  It should be in a file named COPYING.  Among other
 * things, the copyright notice and this notice must be preserved on all
 * copies. 
 */

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

#include "VFenc.h"
#include "bdf.h"

#ifndef SEEK_SET
#  define SEEK_SET 0
#endif

struct s_ch_table {
  int   ccode;    /* char code */
  long  f_pos;    /* file position */
};
typedef struct s_ch_table  bdf_char_table;

struct s_bdf {
  int            bdf_enc;
  int            bdf_chset;
  int            bdf_width; 
  int            bdf_height; 
  bdf_char_table *bdf_chars;
  int            bdf_nchar; 
};
typedef struct s_bdf  bdf;

bdf  *bdf_table = NULL;

char *user_enc = NULL;
char *user_chset = NULL;

int Usage();
int ReadBDF();
int MakeBDFIndex();
int BDF_ReadProp();
int BDF_CountChars();
int BDF_ReadIndex();
int _BDF_ReadIndex();
int BDF_SortIndex();
int BDF_Partition();
int BDF_GetEnc();
int WriteIndex();



int
main(argc, argv)
     int argc;
     char **argv;
{
  char  *fname, *bdf_name, *idx_name;
  FILE  *ifp;
  FILE  *ofp;

  if (argc < 2)
    Usage();
  fname = argv[1];
  if (argc >= 3)
    user_enc = argv[2];
  if (argc == 4)
    user_chset = argv[3];

  if ((bdf_name = malloc(strlen(fname)+strlen(BDF_SUFFIX)+1)) == NULL){
    fprintf(stderr, "No memory\n");
    exit(1);
  }
  if ((idx_name = malloc(strlen(fname)+strlen(IDX_SUFFIX)+1)) == NULL){
    fprintf(stderr, "No memory\n");
    exit(1);
  }
  
  strcpy(bdf_name, fname);
  strcat(bdf_name, BDF_SUFFIX);
  if ((ifp = fopen(bdf_name, "r")) == NULL){
    fprintf(stderr, "Cannot open %s\n", bdf_name);
    exit(1);
  }
  strcpy(idx_name, fname);
  strcat(idx_name, IDX_SUFFIX);
  if ((ofp = fopen(idx_name, "wb")) == NULL){
    fprintf(stderr, "Cannot open %s\n", idx_name);
    exit(1);
  }

  (void) ReadBDF(ifp);
  (void) WriteIndex(ofp);

  return 0;
}

int
Usage()
{
  fprintf(stderr, "Usage: bdfindex bdf-file [encoding [charset]]\n");
  fprintf(stderr, "  Index file of `bdf-file'.bdf is generated %s",
	          "as `bdf-file'.bdx\n");
  fprintf(stderr, "  (`bdf-file' should not contain .bdf extension.)\n");
  fprintf(stderr, "  Use `encoding' string to force a certain encoding.\n");
  fprintf(stderr, "  Use `charset' string to force %s",
	          "a certain character set.\n");
  fprintf(stderr, "Examples:  bdfindex jiskan16\n");
  exit(1);
}

int
ReadBDF(fp)
     FILE  *fp;
{
  if ((bdf_table = (bdf*)malloc(sizeof(bdf))) == NULL)
    goto Err3; 
  bdf_table->bdf_width  = 0; 
  bdf_table->bdf_height = 0;

  if (BDF_ReadProp(fp) < 0)
    goto Err2;
  bdf_table->bdf_nchar = BDF_CountChars(fp);
  if (bdf_table->bdf_nchar < 0)
    goto Err2;
  bdf_table->bdf_chars  = 
    (bdf_char_table*) calloc(bdf_table->bdf_nchar, sizeof(bdf_char_table));
  if (bdf_table->bdf_chars == NULL)
    goto Err2;
  if (BDF_ReadIndex(fp) < 0)
    goto Err1;
  return 0;

Err1:
  free(bdf_table->bdf_chars);
Err2:
  bdf_table = NULL;
Err3:
  exit(1);
}

int 
BDF_ReadProp(fp)
     FILE *fp;
{
  int    found;
  char   buf[160];
  char   prop_name[160];
  char   prop_string[160];
  char   *p;
  int    s_len;
  int    prop_val;

  if (bdf_table == NULL){
    printf("bdfindex: BDF_ReadProp - ILL ARG\n");
    return -1;
  }

  found = 0;
  for (;;){
    if (fgets(buf, sizeof(buf), fp) == NULL)
      break;
    if (strncmp(buf, "ENDPROPERTIES", 13) == 0)
      break;
    if (strncmp(buf, "PIXEL_SIZE", 10) == 0){
      sscanf(buf, "%s %d", prop_name, &prop_val);
      found = 1;
      bdf_table->bdf_width  = prop_val;
      bdf_table->bdf_height = prop_val;
      continue;
    }  
    /* we do not consider spaces in the charset registry string */
    p = prop_string;
    if (strncmp(buf, "CHARSET_REGISTRY", 16) == 0){
      if (user_chset == NULL){
        sscanf(buf, "%s %s", prop_name, p);
        /* remove the leading and trailing `"' */
	p++;
	s_len = strlen(p);
	p[s_len - 1] = '\0';
	if ((bdf_table->bdf_chset = VFE_SearchCharSet(p)) < 0){
	  printf("bdfindex: BDF_ReadProp - ILL CHAR SET\n");
	  return -1;
	}
      }
      continue;
    }
  }

  if (user_chset){
    if ((bdf_table->bdf_chset = VFE_SearchCharSet(user_chset)) < 0){
      printf("bdfindex: illegal char set parameter on command line.\n");
      return -1;
    }
  }
  if (user_enc){
    if ((bdf_table->bdf_enc = VFE_SearchEncoding(user_enc)) < 0){
      printf("bdfindex: illegal encoding parameter on command line.\n");
      return -1;
    }
  } else
    bdf_table->bdf_enc = BDF_GetEnc(bdf_table->bdf_chset);


  if (found == 0)
    return -1; 
  return 0; 
}

int 
BDF_CountChars(fp)
     FILE *fp;
{
  return _BDF_ReadIndex(fp, 1);
}

int 
BDF_ReadIndex(fp)
     FILE *fp;
{
  return _BDF_ReadIndex(fp, 0);
}

int 
_BDF_ReadIndex(fp, count_only)
     FILE *fp;
     int count_only;
{
  int    ch_code, ch_index, last_ch, need_sorting;
  char   buf[160];
  char   prop_name[160];

  if (bdf_table == NULL){
    printf("bdfindex: BDF_ReadIndex - ILL ARG\n");
    return -1;
  }

  fseek(fp, 0, SEEK_SET);
  ch_index = 0;
  last_ch = 0;
  need_sorting = 0;
  for (;;){
    if (fgets(buf, sizeof(buf), fp) == NULL)
      break;
    if (strncmp(buf, "ENDFONT", 7) == 0)
      break;
    if (strncmp(buf, "ENCODING", 8) == 0){
      /**sscanf(buf, "%s %i", prop_name, &ch_code);**/
      sscanf(buf, "%s %d", prop_name, &ch_code);
      if (last_ch > ch_code)
	need_sorting = 1;   /* Must sort for binary search in VF_Bdf.c */
      for (;;){
	if (fgets(buf, sizeof(buf), fp) == NULL)
	  goto End;
	if (strncmp(buf, "ENDCHAR", 7) == 0)
	  break;
	if (strncmp(buf, "BITMAP", 6) == 0){
	  if (count_only == 0){
	    bdf_table->bdf_chars[ch_index].f_pos = (long) ftell(fp);
	    bdf_table->bdf_chars[ch_index].ccode = ch_code;
	    /*printf("%04d: %ld\n", ch_code, 
	      bdf_table->bdf_chars[ch_index].f_pos);*/
	  }
	  last_ch = ch_code;
	  ch_index++;
	}
      }
    }
  }
End:
  /*printf("XXX nchar = %d\n", ch_index);*/    /*XXX*/
  if ((count_only == 0) && (need_sorting == 1)){
    /* Must sort the index table for binary search in VF_Bdf.c */
    BDF_SortIndex(bdf_table->bdf_chars, 0, ch_index-1);
  }
  return ch_index; 
}


int
BDF_SortIndex(bdfchp, x, y)
     bdf_char_table *bdfchp;
     int x, y;
{
  int  z;

  if (x < y){
    z = BDF_Partition(bdfchp, x, y);
    (void) BDF_SortIndex(bdfchp, x,   z-1);
    (void) BDF_SortIndex(bdfchp, z+1, y); 
  }
  return 0;
}
int
BDF_Partition(bdfchp, x, y)
     bdf_char_table *bdfchp;
     int x, y;
{
  int  t, i, p, itmp;
  long ltmp;

  t = bdfchp[x].ccode;
  i = x+1; 
  p = x;
  for (;;){
    if (y < i){
      return p;
    } else if (bdfchp[i].ccode < t){
      itmp = bdfchp[i].ccode;
      ltmp = bdfchp[i].f_pos;
      bdfchp[i].ccode = bdfchp[p+1].ccode;
      bdfchp[i].f_pos = bdfchp[p+1].f_pos;
      bdfchp[p+1].ccode = itmp;
      bdfchp[p+1].f_pos = ltmp;
      i++;
      p++;
    } else {
      i++;
    }
  }
}


int
BDF_GetEnc(entry)
  int entry;
{
  int i;

  for (i = 0; ChSetTable[i].CharSetValue != entry; i++)
    ;
  return ChSetTable[i].DefEncValue;
}


int
WriteIndex(fp)
     FILE  *fp;
{
  int i;

  fprintf(fp, "%d %d %d\n",
          BDX_VERSION, bdf_table->bdf_chset, bdf_table->bdf_enc);
  fprintf(fp, "%d %d\n", bdf_table->bdf_width, bdf_table->bdf_height); 
  fprintf(fp, "%d\n", bdf_table->bdf_nchar);
  i = 0;
  while (i < bdf_table->bdf_nchar){
    fprintf(fp, "%04x %lx\n", 
	    bdf_table->bdf_chars[i].ccode, bdf_table->bdf_chars[i].f_pos);
    i++;
  }
  return 0;
}
