#include #include #include #include // ====================================================================== // 設定保持関係 // ====================================================================== struct Setting { int type; const char *key; double nval; char *sval; }; enum { STEnd, STNum, STStr, }; Setting settings[]={ {STNum, "step", 10, NULL}, {STNum, "lineheight", 10, NULL}, {STNum, "lineskip", 20, NULL}, {STNum, "capwidth", 40, NULL}, {STNum, "slant", 0.3, NULL}, {STNum, "rotate", 0, NULL}, {STStr, "signalline", 0,"0 0 0 setrgbcolor 5 setlinewidth"}, {STStr, "borderline", 0,"0.7 0.7 0.7 setrgbcolor 5 setlinewidth"}, {STStr, "gridline", 0,"1 0 0 setrgbcolor 2 setlinewidth"}, {STStr, "capfont", 0,"Helvetica"}, {STStr, "strfont", 0,"Helvetica"}, {STEnd, "",0,""}, }; double VN(const char *key) { int i; for(i=0;settings[i].type!=STEnd;i++) if(strcmp(key,settings[i].key)==0) return settings[i].nval; return 0; } int VI(const char *key) { return (int)VN(key); } char *VS(const char *key) { int i; for(i=0;settings[i].type!=STEnd;i++) if(strcmp(key,settings[i].key)==0) return settings[i].sval; return 0; } int SetSetting(const char *key,char *value) { int i; double d; if(key==NULL) return -1; for(i=0;settings[i].type!=STEnd;i++) if(strcmp(key,settings[i].key)==0) break; switch(settings[i].type) { case STEnd: return -1; case STNum: if(sscanf(value,"%lf",&d)==1) settings[i].nval=d; break; case STStr: settings[i].sval=strdup(value); // リーク覚悟 break; } return 0; } // ====================================================================== // 文字列保持 // ====================================================================== struct StringInfo { char *str; double x,y; StringInfo *next; }; StringInfo *si_root=NULL,*si_cur=NULL; void AddString(double x,double y,char *s) { StringInfo *si=new StringInfo; si->next=NULL; si->x=x; si->y=y; si->str=strdup(s); if(si_cur==NULL) { si_root=si; } else {si_cur->next=si; } si_cur=si; // fprintf(stderr,"%d %d %s\n",x,y,s); } // ====================================================================== // ファイルを読み込んで各行毎に char* にばらして 配列化。 // ====================================================================== char **LoadFileIntoStrings(const char *source,int &linecount) { struct stat st; if(stat(source,&st)<0) { fprintf(stderr,"Cannot stat '%s'. Probably, not found\n",source); return NULL; } FILE *fp=fopen(source,"rb"); if(fp==NULL) { fprintf(stderr,"Cannot open '%s'\n",source); return NULL; } char *buff=new char[st.st_size]; fread(buff,1,st.st_size,fp); fclose(fp); linecount=0; char *it=buff; while(*it) { while((*it)&&(strchr("\r\n",*it)==NULL)) it++; linecount++; if(!(*it)) break; while((*it)&&(strchr("\r\n",*it)!=NULL)) it++; } char **strs=new char *[linecount]; linecount=0; it=buff; while(*it) { strs[linecount]=it; while((*it)&&(strchr("\r\n",*it)==NULL)) it++; linecount++; if(!(*it)) break; while((*it)&&(strchr("\r\n",*it)!=NULL)) { *it='\0'; it++; } } return strs; } // ====================================================================== // 処理用関数 // ====================================================================== char *PointAfterSpace(char *s) { while((*s)&&(strchr(" \t",*s)==NULL)) s++; if(!(*s)) return ""; while((*s)&&(strchr(" \t",*s)!=NULL)) s++; return s; } int GetLength(char *s) { int r=0; char *tmp=strdup(s); char *t=tmp; while(1) { char *s1=strchr(t,'"'); if(!s1) break; char *s2=strchr(s1+1,'"'); if(!s2) break; for(s1++; *s1!='"'; s1++) *s1=' '; t=s2+1; } for(t=tmp; *t; t++) if(strchr("-=~_:X",*t)) r++; free(tmp); return r; } int Index(const char *s,char c) { int i; for(i=0;s[i];i++) if(s[i]==c) return i; return -1; } // ====================================================================== // グローバル // ====================================================================== FILE *dest; int linec; int w,h,step,capwidth,lineheight,lineskip; // ====================================================================== // 描画系関数 // ====================================================================== // -~_=: int GetChar(char *&it, int line, int pos, int extra, double &f, double &s) { int idx; while(*it) { char c=*it; it++; idx=Index("-~_=:",c); if(idx>=0) return idx; if(c=='X') // いれかえ { double t=f; f=s; s=t; return 3; // Index("-~_=:",'='); } // 文字列 if(c=='"') { char *p=strchr(it,'"'); if(p!=NULL) { *p='\0'; if(extra) AddString(pos,line,it); *p='"'; it=p+1; } continue; } if(!extra) continue; // 縦線出力 if(c=='|') { int x=pos*step+capwidth+20; fprintf(dest,"gsave %s\n",VS("gridline")); fprintf(dest,"newpath %d 0 moveto %d %d lineto stroke\n", x,x,lineskip*linec); fprintf(dest,"grestore\n"); continue; } // 文字列抽出 char *s=new char[strlen(it)+2]; char *si=s; *si=c; si++; while(*it) { if((*it=='\\')&&(it[1])) { *si=it[1]; si++; it+=2; continue; } if(strchr("=~_-:X",*it)) break; *si=*it; si++; it++; } *si='\0'; AddString(pos,line,s); delete s; } return 4; // Index(,':'); } inline int Iabs(double d) { if(d>0) return (int)d; return (int)(-d); } void DrawLevel(int line, int pos, double ll, double cl) { if((ll<0)&&(cl<0)) return; int sx=pos*step+capwidth+20; int ex=sx+step; int sy=(int)((line+0.5)*lineskip-(ll-0.5)*lineheight); int ey=(int)((line+0.5)*lineskip-(cl-0.5)*lineheight); if(ll==cl) return; if(ll<0) { fprintf(dest,"newpath %d %d moveto\n",sx,ey); return ; } if(cl<0) { fprintf(dest,"%d %d lineto stroke\n",sx,sy); return; } double delta=lineheight*VN("slant"); int deltap=Iabs(delta*(ll-0.5)); int deltan=Iabs(delta*(cl-0.5)); fprintf(dest,"%d %d lineto\n",sx-deltap,sy); fprintf(dest,"%d %d lineto\n",sx+deltan,ey); } // ====================================================================== // メイン(すぱげてぃ) // ====================================================================== char *EPSName(const char *src) { char *r=new char[strlen(src)+4]; strcpy(r,src); char *p=strrchr(r,'/'); if(p==NULL) p=strrchr(r,'\\'); if(p==NULL) p=r; if(strchr(p,'.')) *(strchr(p,'.'))='\0'; strcat(p,".eps"); return r; } int main(int argc, char **argv) { if(argc<2) { fprintf(stderr,"tchart []\n"); return 0; } if(argc<3) dest=fopen(EPSName(argv[1]),"w"); else dest=fopen(argv[2],"w"); if(dest==NULL) { fprintf(stderr,"Cannot open destination '%s'\n",argv[2]); return 1; } // ファイルの読み込み int linecount; char **lines=LoadFileIntoStrings(argv[1],linecount); if(lines==NULL) { return 1; } char tmp[200]; char **caption=new char *[linecount]; // linecount を越えることはない char **line=new char *[linecount]; // linecount を越えることはない linec=0; int maxlen=0; int maxslen=0; // 一次構文解析 int i,j; for(i=0;imaxlen) maxlen=GetLength(line[linec]); if(strlen(line[linec])>maxslen) maxslen=strlen(line[linec]); linec++; } fprintf(stderr,"%d lines\n",linec); // 出力開始 // プロローグ〜外枠 w=maxlen*VI("step")+VI("capwidth")+3; h=VI("lineskip")*linec; fprintf(dest,"%%!PS-Adobe-3.0 EPSF-3.0\n"); if(VN("rotate")) { fprintf(dest,"%%%%BoundingBox: 20 20 %d %d\n",h+22,w+22); fprintf(dest,"21 21 translate 90 rotate 0.1 -0.1 scale\n"); } else { fprintf(dest,"%%%%BoundingBox: 20 20 %d %d\n",w+22,h+22); fprintf(dest,"21 %d translate 0.1 -0.1 scale\n",h+21); } fprintf(dest,"/showright { dup stringwidth pop neg 0 rmoveto show } def\n"); fprintf(dest,"/showleft { show } def\n"); fprintf(dest,"/showcenter { dup stringwidth pop 2 div neg 0 rmoveto show } def\n"); step=VI("step")*10; capwidth=VI("capwidth")*10; lineheight=VI("lineheight")*10; lineskip=VI("lineskip")*10; w*=10; h*=10; fprintf(dest,"%s\n",VS("borderline")); fprintf(dest,"newpath -5 -5 moveto %d -5 lineto %d %d lineto ",w+5,w+5,h+5); fprintf(dest,"-5 %d lineto -5 -5 lineto stroke\n",h+5); // キャプション const char *ShowCap="showright"; int sz=(int)(lineheight*0.8+0.5); fprintf(dest,"/%s findfont [%d 0 0 -%d 0 0] makefont setfont\n", VS("capfont"),sz,sz); fprintf(dest,"%s\n",VS("signalline")); for(i=0;inext) { const char *showcmd=ShowSt; it=si->str; if(strncmp(it,"_<_",3)==0) { showcmd=ShowLeft; it+=3; } if(strncmp(it,"_>_",3)==0) { showcmd=ShowRight; it+=3; } fprintf(dest,"%d %d moveto\n", (int)((si->x)*step+capwidth+20), (int)(((si->y)+0.5)*lineskip+lineheight*0.2)); fprintf(dest,"(%s) %s\n",it,showcmd); } fprintf(dest,"showpage\n\n\n\n\n\n"); // 入力を事故防止のためにコメントとして保存 for(i=0;i