/**
 *
 * gra2prn.c
 *
 * This is a sample for an external driver of Ngraph. 
 * This is free software; you can redistribute it and/or modify it.
 *
 **/

/*

  draw(), main() を変更する。

 変換結果は stdin に対して出力する。
 -o オプションでファイルが指定された場合にはそのファイルに出力する。

 NGRAPH.EXE の中では -o オプションを使ってファイルに出力される。

 */

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

#define MPI 3.1415926535897932385
#define NSTRLEN 256
#define GRAF "%Ngraph GRAF"

#define TRUE  1
#define FALSE 0

/* オプション */
int intopt;
int boolopt;
char *charopt;

/*  'T' コマンド数が多いときに分割する */
#define LINETOLIMIT 500
int lineto=FALSE;
int linetonum=0;

/* 変数 */
char *outfilename;
FILE *outfp;
char *fontalias=NULL;
int loadfont=FALSE;
int cpx=0;
int cpy=0;

char *nstrnew(void)
{
  char *po;

  po=malloc(NSTRLEN);
  po[0]='\0';
  return po;
}

char *nstrccat(char *po,char ch)
{
  size_t len,num;

  if (po==NULL) return NULL;
  len=strlen(po);
  num=len/NSTRLEN;
  if (len%NSTRLEN==NSTRLEN-1) po=realloc(po,NSTRLEN*(num+2));
  po[len]=ch;
  po[len+1]='\0';
  return po;
}

int fgetline(FILE *fp,char **buf)
{
  char *s;
  int ch;

  *buf=NULL;
  s=nstrnew();
  ch=fgetc(fp);
  if (ch==EOF) return 1;
  while (TRUE) {
    if ((ch=='\0') || (ch=='\n') || (ch==EOF)) {
      *buf=s;
      return 0;
    }
    if (ch!='\r') s=nstrccat(s,ch);
    ch=fgetc(fp);
  }
}

int niskanji(unsigned int code)
{
  if (((0x81<=code) && (code<=0x9f))
   || ((0xe0<=code) && (code<=0xff))) return TRUE;
  return FALSE;
}

unsigned int njms2jis(unsigned int code)
{
  unsigned char dh,dl;

  dh=code >> 8;
  dl=code & 0xff;
  if (dh<=0x9f) dh-=0x70;
  else dh-=0xb0;
  dh=dh<<1;
  if (dl>=0x9f) dl-=0x7e;
  else {
    dh--;
    if (dl>=0x80) dl-=0x20;
    else dl-=0x1f;
  }
  return ((unsigned int)(dh << 8))+dl;
}

int getintpar(char *s,int num,int cpar[])
{
  int i,pos1,pos2;
  char s2[256];
  char *endptr;

  pos1=0;
  for (i=0;i<num;i++) {
	while ((s[pos1]!='\0') && (strchr(" \t,",s[pos1])!=NULL)) pos1++;
	if (s[pos1]=='\0') return FALSE;
	pos2=0;
	while ((s[pos1]!='\0') && (strchr(" \t,",s[pos1])==NULL)) {
	  s2[pos2]=s[pos1];
	  pos2++;
	  pos1++;
	}
	s2[pos2]='\0';
	cpar[i]=strtol(s2,&endptr,10);
	if (endptr[0]!='\0') return FALSE;
  }
  return TRUE;
}

int GRAinput(char *s,void (*draw)(char code,int *cpar,char *cstr))
{
  int pos,i;
  int num;
  char code;
  int *cpar;
  char *cstr;

  code='\0';
  cpar=NULL;
  cstr=NULL;
  for (i=0;s[i]!='\0';i++)
	if (strchr("\n\r",s[i])!=NULL) {
	  s[i]='\0';
	  break;
	}
  pos=0;
  while ((s[pos]==' ') || (s[pos]=='\t')) pos++;
  if (s[pos]=='\0') return TRUE;
  if (strchr("IE%VAGOMNLTCBPRDFHSK",s[pos])==NULL) return FALSE;
  code=s[pos];
  if (strchr("%FSK",code)==NULL) {
	if (!getintpar(s+pos+1,1,&num)) return FALSE;
    num++;
    cpar=malloc(sizeof(int)*num);
    if (!getintpar(s+pos+1,num,cpar)) goto errexit;
  } else {
    cpar=malloc(sizeof(int));
    cpar[0]=-1;
    cstr=malloc(strlen(s)-pos);
    strcpy(cstr,s+pos+1);
  }
  draw(code,cpar,cstr);
  free(cpar);
  free(cstr);
  return TRUE;

errexit:
  free(cpar);
  free(cstr);
  return FALSE;
}


void draw(char code,int *cpar,char *cstr)
{
  int i;
  unsigned int jis;
  char ch;

  if (lineto) {
    if (code!='T') {
      /*  'T' コマンド終了 線出力 */
      lineto=FALSE;
      linetonum=0;
    } else if (linetonum>LINETOLIMIT) {
      /*  'T' コマンド分割 線出力 */
      /* (cpx,cpy) にカレントポイントを移動すること */
      lineto=FALSE;
	  linetonum=1;
    }
  }
  switch (code) {
  case 'X':
    break;
  case 'I':
    break;
  case 'E':
    break;
  case '%':
    break;
  case 'V':
    break;
  case 'A':
    break;
  case 'G':
    break;
  case 'M':
    cpx=cpar[1];
    cpy=cpar[2];
    break;
  case 'N':
    cpx+=cpar[1];
    cpy+=cpar[2];
    break;
  case 'L':
    break;
  case 'T':
    cpx=cpar[1];
    cpy=cpar[2];
    lineto=TRUE;
    linetonum++;
    break;
  case 'C':
    break;
  case 'B':
    break;
  case 'P':
    break;
  case 'R':
    for (i=0;i<cpar[1];i++) {
      /* (cpar[i*2+2],cpar[i*2+3]) が点の座標 */
    }
    break;
  case 'D':
    for (i=0;i<cpar[1];i++) {
      /* (cpar[i*2+3],cpar[i*2+4]) が点の座標 */
    }
    break;
  case 'F':
    free(fontalias);
    fontalias=malloc(strlen(cstr)+1);
    strcpy(fontalias,cstr);
    break;
  case 'H':
    if (fontalias==NULL) {
      loadfont=FALSE;
      break;
    }
    /* fontname のフォントを選択する */
	loadfont=TRUE;
    break;
  case 'S':
    if (!loadfont) break;
	i=0;
    while (i<strlen(cstr)) {
	  if (cstr[i]=='\\') {
		if (cstr[i+1]=='x') {
          if (toupper(cstr[i+2])>='A') ch=toupper(cstr[i+2])-'A'+10;
          else ch=cstr[i+2]-'0';
          if (toupper(cstr[i+3])>='A') ch=ch*16+toupper(cstr[i+3])-'A'+10;
          else ch=ch*16+cstr[i+3]-'0';
		  i+=4;
        } else if (cstr[i+1]=='\\') {
          ch=cstr[i+1];
          i+=2;
        } else {
          ch='\0';
          i++;
        }
      } else {
        ch=cstr[i];
        i++;
      }
      /* ch が '\0'でない時に ch を出力 */
	}
	break;
  case 'K':
    if (!loadfont) break;
    i=0;
    while (i<strlen(cstr)) {
      if (niskanji((unsigned char)cstr[i]) && (cstr[i+1]!='\0')) {
        jis=njms2jis(((unsigned char)cstr[i] << 8)+(unsigned char)cstr[i+1]);
        /* jis を出力 */
        i+=2;
      } else i++;
    }
    break;
  }
}


int main(int argc,char **argv)
{
  int i;
  char *endptr;
  char *filename;
  FILE *fp;
  char *buf;

  fprintf(stderr,"GRA2XXX sample program ver. 0.00.00\n");

  outfilename=NULL;
  for (i=1;(i<argc) && (argv[i][0]=='-') && (argv[i][1]!='\0') ;i++) {
    switch (argv[i][1]) {
    case 'o':
      if (((i+1)<argc) && (argv[i+1][0]!='-')) {
        outfilename=argv[i+1];
        i++;
      }
      break;
    case 'c':
      if (((i+1)<argc) && (argv[i+1][0]!='-')) {
        charopt=argv[i+1];
        i++;
      }
      break;
    case 'i':
      if (((i+1)<argc) && (argv[i+1][0]!='-')) {
        intopt=strtol(argv[i+1],&endptr,10);
        i++;
      }
      break;
    case 'b':
      boolopt=TRUE;
      break;
    default:
      fprintf(stderr,"unknown option `%s'.\n",argv[i]);
      exit(1);
    }
  }

  if (i>=argc) {
    fprintf(stderr,"Usage: gra2xxx[-i intopt] [-b boolopt] [-c charopt] grafile\n");
    fprintf(stderr," -o output file\n");
    fprintf(stderr," -i integer option\n");
    fprintf(stderr," -b bool option\n");
    fprintf(stderr," -c string option\n");
    exit(1);
  }

  if (outfilename!=NULL) {
    if ((outfp=fopen(outfilename,"wt"))==NULL) {
      fprintf(stderr,"error: file open `%s'.\n",outfilename);
      exit(1);
    }
  } else outfp=stdout;

  filename=argv[i];

  if ((filename[0]=='-') && (filename[1]=='\0')) fp=stdin;
  else {
    if ((fp=fopen(filename,"rt"))==NULL) {
      fprintf(stderr,"file not found `%s'.\n",filename);
      exit(1);
    }
  }
  if (fgetline(fp,&buf)==1) {
    fprintf(stderr,"illegal GRA format.\n");
    exit(1);
  }
  if (strcmp(buf,GRAF)!=0) {
    fprintf(stderr,"illegal GRA format.\n");
    exit(1);
  }
  free(buf);
  while (fgetline(fp,&buf)!=1) {
    if (!GRAinput(buf,draw)) {
      fprintf(stderr,"illegal GRA format.\n");
      exit(1);
    }
    free(buf);
  }
  fclose(fp);
  fclose(outfp);
  return 0;
}

