#define VERSION "0.99f" /* flow.c 22/1/93 (C) 2005 Terry Brown This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* flow - a flow-chart -> LaTeX generator. Parses a file in a flow-chart specification language, then produces a corresponding LaTeX pic environment. */ #include #include #include #include typedef int bool; #define TRUE 1 #define FALSE 0 typedef struct {float x,y;} coord; typedef struct {char name[80]; int Params; coord size; bool HasText; } FlowCom; #define ParamLen 120 #define LineLen 120 typedef char param[ParamLen]; #define MaxBoxes 2048 /* could not possibly have more than this */ #define Commands 16 FlowCom fcom[Commands] = { { "SetTrack", 1, {0,0}, FALSE }, { "Up", 1, {0,0}, FALSE }, { "Down", 1, {0,0}, FALSE }, { "Left", 1, {0,0}, FALSE }, { "Right", 1, {0,0}, FALSE }, { "Box", 0, {4,2}, TRUE }, { "Oval", 0, {4,2}, TRUE }, { "Choice", 4, {4,4}, TRUE }, { "Tag", 0, {0,0}, FALSE }, { "ToTag", 0, {0,0}, FALSE }, { "Scale", 2, {0,0}, FALSE }, { "Tilt", 0, {4,2}, TRUE }, { "Text", 0, {4,2}, TRUE }, { "TxtPos", 4, {0,0}, FALSE }, { "Skip", 2, {0,0}, FALSE }, { "%", 0, {0,0}, FALSE } }; typedef enum {SetTrack, Up, Down, Left, Right, Box, Oval, Choice, Tag, ToTag, Scale, Tilt, Text, TxtPos, Skip, Comment } TheCommands; typedef enum {ArrowS, LineS, NoneS} trackSymb; typedef enum {UpD, DownD, LeftD, RightD} direcs; typedef struct ATAG {coord pos; coord size; struct ATAG *next; } aTag; typedef struct { coord min; coord max; } boundingBox; /* state / position tracking variables */ boundingBox pic = {{0,0},{0,0}}; coord Coords[MaxBoxes] = {{0,0}}; /* just initialise first coord */ int CurCoord = 0; int CurTrack = ArrowS; int CurDirec = DownD; coord CurScale = {1.,1.}; coord CurSize = {0.,0.}; aTag *CurTag = NULL; char CurPos[20] = "[c]"; char CurBoxPos[20] = "[c]"; char leader[20]=""; char tailer[20]=""; float TrackX = 1.; float TrackY = 1.; int InputLine = 0; char line[LineLen]; float VertGap=1.; float HorzGap=1.; FILE *inFile, *outFile; /* global input output streams */ int doText(); void checkBounds(boundingBox *b, coord *c) { if (b->min.x > c->x) b->min.x = c->x; if (b->max.x < c->x) b->max.x = c->x; if (b->min.y > c->y) b->min.y = c->y; if (b->max.y < c->y) b->max.y = c->y; } void checkBoundsRng( boundingBox *b, float x, float y, float sx, float sy ) { if (b->min.x > x) b->min.x = x; if (b->max.x < x+sx) b->max.x = x+sx; if (b->min.y > y) b->min.y = y; if (b->max.y < y+sy) b->max.y = y+sy; } int getCommand(char line[], param plist) { /* tries to interpret the next line of inFile as a command, returns -1 if it can't */ int i=0, command = -1; while (iys) ? xs : ys; i>1; i--) { if ( (xs % i) == 0 && (ys % i) == 0 ) { xs /= i; ys /= i; i = (xs>ys) ? xs : ys; } } if (xs>6) { fprintf(stderr,"Flow warning - illegal Choice aspect ratio\n"); xs = 6; } if (ys>6) { fprintf(stderr,"Flow warning - illegal Choice aspect ratio\n"); ys = 6; } fprintf(outFile,"\\put(%3.4f,%3.4f){\\line(%d,%d){%3.4f}}\n", Coords[CurCoord].x, Coords[CurCoord].y-CurSize.y/2, xs,ys,CurSize.x/2 ); fprintf(outFile,"\\put(%3.4f,%3.4f){\\line(%d,%d){%3.4f}}\n", Coords[CurCoord].x, Coords[CurCoord].y-CurSize.y/2, xs,-ys,CurSize.x/2 ); fprintf(outFile,"\\put(%3.4f,%3.4f){\\line(%d,%d){%3.4f}}\n", Coords[CurCoord].x+CurSize.x, Coords[CurCoord].y-CurSize.y/2, -xs,-ys,CurSize.x/2 ); fprintf(outFile,"\\put(%3.4f,%3.4f){\\line(%d,%d){%3.4f}}\n", Coords[CurCoord].x+CurSize.x, Coords[CurCoord].y-CurSize.y/2, -xs,ys,CurSize.x/2 ); fprintf(outFile,"\\put(%3.4f,%3.4f){\\makebox(%3.4f,%3.4f)%s{\\shortstack%s{\n", Coords[CurCoord].x, Coords[CurCoord].y-CurSize.y, CurSize.x, CurSize.y, CurBoxPos, CurPos ); doText(); fprintf(outFile,"}}}\n"); sscanf(pList,"%s %s %s %s",params[0],params[1],params[2],params[3]); if (params[0][0] != '.') fprintf(outFile,"\\put(%3.4f,%3.4f){\\makebox(0,0)[lt]{%s}}\n", Coords[CurCoord].x+ CurSize.x*0.65, Coords[CurCoord].y, params[0] ); if (params[1][0] != '.') fprintf(outFile,"\\put(%3.4f,%3.4f){\\makebox(0,0)[rt]{%s}}\n", Coords[CurCoord].x, Coords[CurCoord].y- CurSize.y/2.*0.7, params[1] ); if (params[2][0] != '.') fprintf(outFile,"\\put(%3.4f,%3.4f){\\makebox(0,0)[lt]{%s}}\n", Coords[CurCoord].x+ CurSize.x, Coords[CurCoord].y- CurSize.y/2.*0.7, params[2] ); if (params[3][0] != '.') fprintf(outFile,"\\put(%3.4f,%3.4f){\\makebox(0,0)[lb]{%s}}\n", Coords[CurCoord].x+ CurSize.x*0.65, Coords[CurCoord].y- CurSize.y, params[3] ); checkBoundsRng( &pic, Coords[CurCoord].x, Coords[CurCoord].y-CurSize.y, CurSize.x, CurSize.y ); break; case SetTrack : sscanf(pList,"%s",params[0]); if ( strcmp("arrow",params[0]) == 0) CurTrack = ArrowS; if ( strcmp("line",params[0]) == 0) CurTrack = LineS; if ( strcmp("none",params[0]) == 0) CurTrack = NoneS; break; case Scale : sscanf(pList,"%f %f",&CurScale.x,&CurScale.y); break; case Tag : tempTag = (aTag*)malloc(sizeof(aTag)); tempTag->size.x = CurSize.x; tempTag->size.y = CurSize.y; tempTag->pos.x = Coords[CurCoord].x; tempTag->pos.y = Coords[CurCoord].y; tempTag->next = CurTag; CurTag = tempTag; break; case ToTag : if (CurTag == NULL) { fprintf(stderr,"flow error - Tag stack empty \n"); break; } tempTag = CurTag; CurSize.x = tempTag->size.x; CurSize.y = tempTag->size.y; Coords[CurCoord].x = tempTag->pos.x; Coords[CurCoord].y = tempTag->pos.y; CurTag = tempTag->next; free(tempTag); break; case Right : CurDirec = RightD; if (sscanf(pList,"%f %19s",&dimen,params[0])>=1) { init=1; dimen *= TrackX; if (CurTrack != NoneS) fprintf(outFile,"\\put(%3.4f,%3.4f){\\%s(%d,%d){%3.4f}}\n", Coords[CurCoord].x+CurSize.x, Coords[CurCoord].y-CurSize.y/2, (params[0][0]=='*')?"vector":"line", 1,0, dimen); Coords[CurCoord+1].x = Coords[CurCoord].x + CurSize.x + dimen; Coords[CurCoord+1].y = Coords[CurCoord].y - CurSize.y/2; CurCoord++; CurSize = fcom[command].size; } checkBounds(&pic,&(Coords[CurCoord])); break; case Down : CurDirec = DownD; if (sscanf(pList,"%f %19s",&dimen,params[0])>=1) { init=1; dimen *= TrackY; if (CurTrack != NoneS) fprintf(outFile,"\\put(%3.4f,%3.4f){\\%s(%d,%d){%3.4f}}\n", Coords[CurCoord].x+CurSize.x/2, Coords[CurCoord].y-CurSize.y, (params[0][0]=='*')?"vector":"line", 0,-1, dimen); Coords[CurCoord+1].x = Coords[CurCoord].x + CurSize.x/2 - fcom[command].size.x / 2; Coords[CurCoord+1].y = Coords[CurCoord].y - CurSize.y - dimen; CurCoord++; CurSize = fcom[command].size; } checkBounds(&pic,&(Coords[CurCoord])); break; case Left : CurDirec = LeftD; if (sscanf(pList,"%f %19s",&dimen,params[0])>=1) { init=1; dimen *= TrackX; if (CurTrack != NoneS) fprintf(outFile,"\\put(%3.4f,%3.4f){\\%s(%d,%d){%3.4f}}\n", Coords[CurCoord].x, Coords[CurCoord].y-CurSize.y/2, (params[0][0]=='*')?"vector":"line", -1,0, dimen); Coords[CurCoord+1].x = Coords[CurCoord].x - dimen; Coords[CurCoord+1].y = Coords[CurCoord].y - CurSize.y/2; CurCoord++; CurSize = fcom[command].size; } checkBounds(&pic,&(Coords[CurCoord])); break; case Up : CurDirec = UpD; if (sscanf(pList,"%f %19s",&dimen,params[0])>=1) { init=1; dimen *= TrackY; if (CurTrack != NoneS) fprintf(outFile,"\\put(%3.4f,%3.4f){\\%s(%d,%d){%3.4f}}\n", Coords[CurCoord].x+CurSize.x/2, Coords[CurCoord].y, (params[0][0]=='*')?"vector":"line", 0,1, dimen); Coords[CurCoord+1].x = Coords[CurCoord].x + CurSize.x/2 - fcom[command].size.x / 2; Coords[CurCoord+1].y = Coords[CurCoord].y + dimen; CurCoord++; CurSize = fcom[command].size; } checkBounds(&pic,&(Coords[CurCoord])); break; case Comment : break; default: fprintf(stderr,"flow error : unknown command %4d\n",command); return 0; } if (command != Scale) CurScale.x = CurScale.y = 1.; if (fcom[command].HasText == FALSE) { line[0]=0; fgets(line,LineLen,inFile); InputLine++; } return 1; } int doText() { /* output text for those commands that require it, spit out all lines that start with white space (0x20, 0x09) */ int i; line[0]=0; fgets(line,LineLen,inFile); InputLine++; while (!feof(inFile) && ( line[0] == 0x20 || line[0] == 0x09 ) ) { line[strlen(line)-1]=0; for (i=0; i 1) { inFile = fopen(argv[1],"r"); if (inFile == NULL) { fprintf(stderr,"Couldn't open input file %s\n",argv[1]); exit(0); } } line[0]=0; fgets(line,LineLen,inFile); InputLine++; fprintf(outFile,"%% picture environment flowchart generated by flow "); fprintf(outFile,"%s\n",VERSION); while (command != -1) { command = getCommand(line,params); if (command != -1) if (!doCommand(command, params)) return 10; } fclose(inFile); fclose(outFile); outFile = stdout; if (argc > 2) { outFile = fopen(argv[2],"w"); if (outFile == NULL) { fprintf(stderr,"Couldn't open output file %s\n",argv[2]); fclose(inFile); exit(0); } } inFile = fopen(tmpfileNm,"r"); applyPicWrapper(inFile,outFile); if (outFile != stdout) fclose(outFile); fclose(inFile); remove(tmpfileNm); exit(0); return 0; /* just to suppress the warning */ }