diff options
Diffstat (limited to 'support/flow/flow.c')
-rw-r--r-- | support/flow/flow.c | 846 |
1 files changed, 846 insertions, 0 deletions
diff --git a/support/flow/flow.c b/support/flow/flow.c new file mode 100644 index 0000000000..525cfb96f8 --- /dev/null +++ b/support/flow/flow.c @@ -0,0 +1,846 @@ +#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 <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <string.h> + +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 (i<Commands) { + + if ( strncmp(fcom[i].name,line,strlen(fcom[i].name)) == 0) { + command = i; + break; + } + i++; + } + + if (command == -1) { + if (!feof(inFile) && line[0] != '\n') + fprintf(stderr,"flow error : can't interpret line %d\n",InputLine); + return command; + } + + strncpy(plist, line+strlen(fcom[command].name), ParamLen); + + return command; + +} + + +int doCommand(int command, param pList) { +/* +output the LaTeX bits for this command, updating the coords, coord list +etc. as required +*/ + + static int init = 0; + aTag *tempTag; + char params[10][80]; + char *trackStr = "vector"; + float dimen,x,y,x1,y1; + int i,xs,ys; + coord t; + + dimen = 0.; + + params[0][0]=0; /* so Up / Down / Left / Right can find *'s for line + drawing */ + + + if (CurTrack == LineS) trackStr = "line"; + + if (fcom[command].HasText) { + if ((command != Choice && sscanf(pList,"%f %f",&x,&y) == 2) || + (command == Choice && sscanf(pList,"%s %s %s %s %f %f", + params[0], + params[0], + params[0], + params[0], + &x,&y) == 6)) { + fcom[command].size.x = x; + fcom[command].size.y = y; + } + } + + if (!init && CurSize.x == 0. && CurSize.y == 0.) { + CurSize.x = fcom[command].size.x*CurScale.x; + CurSize.y = fcom[command].size.y*CurScale.y; + } + + if ( init && (fcom[command].size.x != 0 || fcom[command].size.y != 0 )) { + + switch (CurDirec) { + + case DownD : + + t.x = Coords[CurCoord].x+CurSize.x/2; + t.y = Coords[CurCoord].y-CurSize.y; + + if (CurTrack != NoneS) + fprintf(outFile,"\\put(%3.4f,%3.4f){\\%s(%d,%d){%3.4f}}\n", + t.x, + t.y, + trackStr, + 0,-1, + VertGap); + + checkBounds(&pic,&t); + + Coords[CurCoord+1].x = Coords[CurCoord].x + CurSize.x/2 - + fcom[command].size.x*CurScale.x / 2; + + Coords[CurCoord+1].y = Coords[CurCoord].y - CurSize.y + - VertGap; + + checkBounds(&pic,Coords+CurCoord+1); + + break; + + case UpD : + + t.x = Coords[CurCoord].x+CurSize.x/2; + t.y = Coords[CurCoord].y; + + if (CurTrack != NoneS) + fprintf(outFile,"\\put(%3.4f,%3.4f){\\%s(%d,%d){%3.4f}}\n", + t.x, + t.y, + trackStr, + 0,1, + VertGap); + + checkBounds(&pic,&t); + + Coords[CurCoord+1].x = Coords[CurCoord].x + CurSize.x/2 - + fcom[command].size.x*CurScale.x / 2; + + Coords[CurCoord+1].y = Coords[CurCoord].y + + fcom[command].size.y*CurScale.y + + VertGap; + checkBounds(&pic,Coords+CurCoord+1); + + break; + + case RightD : + + t.x = Coords[CurCoord].x+CurSize.x; + t.y = Coords[CurCoord].y-CurSize.y/2; + + if (CurTrack != NoneS) + fprintf(outFile,"\\put(%3.4f,%3.4f){\\%s(%d,%d){%3.4f}}\n", + t.x, + t.y, + trackStr, + 1,0, + HorzGap); + + checkBounds(&pic,&t); + + Coords[CurCoord+1].x = Coords[CurCoord].x + CurSize.x + + HorzGap; + Coords[CurCoord+1].y = Coords[CurCoord].y - CurSize.y/2 + + fcom[command].size.y*CurScale.y / 2; + + checkBounds(&pic,Coords+CurCoord+1); + + break; + + case LeftD : + + t.x = Coords[CurCoord].x; + t.y = Coords[CurCoord].y-CurSize.y/2; + + if (CurTrack != NoneS) + fprintf(outFile,"\\put(%3.4f,%3.4f){\\%s(%d,%d){%3.4f}}\n", + t.x, + t.y, + trackStr, + -1,0, + HorzGap); + + checkBounds(&pic,&t); + + Coords[CurCoord+1].x = Coords[CurCoord].x - + fcom[command].size.x*CurScale.x + - HorzGap; + Coords[CurCoord+1].y = Coords[CurCoord].y - CurSize.y/2 + + fcom[command].size.y*CurScale.y / 2; + + checkBounds(&pic,Coords+CurCoord+1); + + break; + + default: + break; + } + CurCoord++; + CurSize.x = fcom[command].size.x*CurScale.x; + CurSize.y = fcom[command].size.y*CurScale.y; + + } + + switch (command) { + + case Skip : + if (sscanf(pList,"%f %f %f %f",&x,&y,&x1,&y1) == 4) { + VertGap = y; + HorzGap = x; + TrackX = x1; + TrackY = y1; + } + break; + + case TxtPos : + CurPos[0]=CurBoxPos[0]=leader[0]=tailer[0]=0; + sscanf(pList,"%s %s %s %s",CurPos,CurBoxPos,leader,tailer); + break; + + case Box : + init=1; + fprintf(outFile,"\\put(%3.4f,%3.4f){\\framebox(%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"); + + checkBoundsRng( + &pic, + Coords[CurCoord].x, + Coords[CurCoord].y-CurSize.y, + CurSize.x, + CurSize.y + ); + + break; + + case Tilt : + init=1; + 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"); + + fprintf(outFile,"\\put(%3.4f,%3.4f){\\line(%d,%d){%3.4f}}\n", + Coords[CurCoord].x+1./6.*CurSize.y, + Coords[CurCoord].y, + 1,0, + CurSize.x); + fprintf(outFile,"\\put(%3.4f,%3.4f){\\line(%d,%d){%3.4f}}\n", + Coords[CurCoord].x-1./6.*CurSize.y, + Coords[CurCoord].y-CurSize.y, + 1,0, + CurSize.x); + fprintf(outFile,"\\put(%3.4f,%3.4f){\\line(%d,%d){%3.4f}}\n", + Coords[CurCoord].x-1./6.*CurSize.y, + Coords[CurCoord].y-CurSize.y, + 1,3, + CurSize.y*1./3.); + fprintf(outFile,"\\put(%3.4f,%3.4f){\\line(%d,%d){%3.4f}}\n", + Coords[CurCoord].x-1./6.*CurSize.y+CurSize.x, + Coords[CurCoord].y-CurSize.y, + 1,3, + CurSize.y*1./3.); + + checkBoundsRng( + &pic, + Coords[CurCoord].x-1./6.*CurSize.y, + Coords[CurCoord].y-CurSize.y, + CurSize.x + 1./6.*CurSize.y, + CurSize.y + ); + + break; + + case Text : + init=1; + 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"); + + checkBoundsRng( + &pic, + Coords[CurCoord].x, + Coords[CurCoord].y-CurSize.y, + CurSize.x, + CurSize.y + ); + break; + + case Oval : + init=1; + fprintf(outFile,"\\put(%3.4f,%3.4f){\\oval(%3.4f,%3.4f)}\n", + Coords[CurCoord].x+CurSize.x/2, + Coords[CurCoord].y-CurSize.y/2, + CurSize.x, + CurSize.y ); + 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"); + checkBoundsRng( + &pic, + Coords[CurCoord].x, + Coords[CurCoord].y-CurSize.y, + CurSize.x, + CurSize.y + ); + + break; + + case Choice : + + init=1; + + xs = (int)CurSize.x; ys = (int)CurSize.y; + + for (i = (xs>ys) ? 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<strlen(line) && + (line[i] == 0x09 || line[i] == 0x20); i++); + + fprintf(outFile,"%s%s%s",leader,line+i,tailer); + line[0]=0; + fgets(line,LineLen,inFile); + InputLine++; + + if (line[0] == 0x20 || line[0] == 0x09 ) + fprintf(outFile,"\\\\\n"); + else + fprintf(outFile,"\n"); + + } + + return 1; +} + +void applyPicWrapper(FILE *inFile, FILE *outFile) { + + char buf[1024]; + + fprintf(outFile,"\\begin{picture}(%f,%f)(%f,%f)\n", + pic.max.x - pic.min.x, + pic.max.y - pic.min.y, + pic.min.x, + pic.min.y + ); + + while (!feof(inFile)) { + + fwrite(buf,fread(buf,1,1024,inFile),1,outFile); + + } + + fprintf(outFile,"\\end{picture}\n"); +} + +int main(int argc, char **argv) { + + param params; + int command=0; + char tmpfileNm[80]; + + + inFile = stdin; outFile = stdout; + + tmpnam(tmpfileNm); + outFile = fopen(tmpfileNm,"w"); + + if (argc > 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 */ + +} |