|
|
1.1 ! root 1: /* DAG - draw a directed graph ! 2: * Gansner North Vo ! 3: */ ! 4: ! 5: const char* Version = "\n@(#)Version M-03/31/89\0\n"; ! 6: ! 7: #include "draw_dag.h" ! 8: #include "dag.h" ! 9: #include "parsedag.h" ! 10: #include "TrieFA.ins.c" ! 11: ! 12: /* useful constants */ ! 13: const double Pi = 3.1415926537; ! 14: const double IPP = .01; // real inches per point of type ! 15: const int Resolution = 72; // points per virtual inch ! 16: ! 17: /*** globals ***/ ! 18: Infile Current_file; ! 19: boolean Uselib = true; // user specified lib with -l option ! 20: char* Lib_path; // library directory ! 21: int N; // number of nodes ! 22: int Extent; // extent of node and edge array including spares ! 23: DAG_node_t** Node; // node list ! 24: DAG_edge_t** Edge; // edge list ! 25: user_info_t User; // user options from .GS line ! 26: options_t Options; // user options from graph input (for draw_dag) ! 27: char* Cmd_name; // from command line ! 28: output_lang_t Output_type; ! 29: int Xmax,Ymax; ! 30: Point Page_size; ! 31: Point Margin = {36,36}; ! 32: ! 33: void dumprank(int * rank) { ! 34: if (rank) ! 35: while (*rank >= 0) fprintf(stderr,"%d ",*rank++); ! 36: fprintf(stderr,"\n"); ! 37: } ! 38: ! 39: void dumpgraph() { ! 40: fprintf(stderr,"global ranksep %d nodesep %d\n",Options.ranksep,Options.nodesep); ! 41: for (int i = 0; i < N; i++) { ! 42: fprintf(stderr,"%s -> ",Node[i]->name); ! 43: for (DAG_edge_t *e = Edge[i]; e; e = e->nextof()) ! 44: fprintf(stderr,"%s ",Node[e->node]->name); ! 45: fprintf(stderr,"\n size %d %d\n",Node[i]->height,Node[i]->width); ! 46: } ! 47: fprintf(stderr,"min rank: "); dumprank(Options.source_nodes); ! 48: fprintf(stderr,"max rank: "); dumprank(Options.sink_nodes); ! 49: for (i = 0; i < Options.n_same_nodes; i++) { ! 50: fprintf(stderr,"rank %d: ",i); ! 51: dumprank(Options.same_nodes[i]); ! 52: } ! 53: } ! 54: ! 55: /* ! 56: * translate draw_dag coordinates to preferred system. ! 57: */ ! 58: ! 59: void translate() { ! 60: int node; ! 61: if (!User.rotated) { ! 62: switch(Output_type) { ! 63: case Pic: ! 64: case Cip: ! 65: case Postscript: ! 66: case Graphdraw: ! 67: for (node = 0; node < N; node++) { ! 68: Node[node]->pos.y = Ymax - Node[node]->pos.y; ! 69: for (DAG_edge_t *e = Edge[node]; e; e = e->nextof()) { ! 70: for (int sp = 0; e->splinept[sp].x >= 0; sp++) ! 71: e->splinept[sp].y = Ymax - e->splinept[sp].y; ! 72: e->top.y = Ymax - e->top.y; ! 73: e->bottom.y = Ymax - e->bottom.y; ! 74: } ! 75: } ! 76: break; ! 77: } ! 78: } ! 79: else { ! 80: swap(Xmax,Ymax); ! 81: switch(Output_type) { ! 82: case Pic: ! 83: case Cip: ! 84: case Postscript: ! 85: case Graphdraw: ! 86: for (node = 0; node < N; node++) { ! 87: swap(Node[node]->pos.x,Node[node]->pos.y); ! 88: for (DAG_edge_t *e = Edge[node]; e; e = e->nextof()) { ! 89: for (int sp = 0; e->splinept[sp].x >= 0; sp++) ! 90: swap(e->splinept[sp].x,e->splinept[sp].y); ! 91: swap(e->top.x,e->top.y); ! 92: swap(e->bottom.x,e->bottom.y); ! 93: } ! 94: } ! 95: break; ! 96: } ! 97: } ! 98: } ! 99: ! 100: /* ! 101: * compute Xmax, Ymax of drawing region ! 102: */ ! 103: void find_drawing_size() { ! 104: int node; ! 105: Xmax = 0; Ymax = 0; ! 106: ! 107: /* find extent of drawing region */ ! 108: for (node = 0; node < N; node++) { ! 109: Xmax = max(Xmax,Node[node]->pos.x + (Node[node]->width + 1) / 2); ! 110: Ymax = max(Ymax,Node[node]->pos.y + (Node[node]->height + 1) / 2); ! 111: for (DAG_edge_t *e = Edge[node]; e; e = e->nextof()) { ! 112: for (int sp = 0; e->splinept[sp].x >= 0; sp++) { ! 113: Xmax = max(Xmax,e->splinept[sp].x); ! 114: Ymax = max(Ymax,e->splinept[sp].y); ! 115: } ! 116: } ! 117: } ! 118: } ! 119: ! 120: void make_drawing() { ! 121: if (N <= 0) return; ! 122: ! 123: draw_dag(N,(node_t**)Node,(edge_t**)Edge,Options); ! 124: find_drawing_size(); ! 125: translate(); ! 126: ! 127: switch (Output_type) { ! 128: case Pic: ! 129: case Cip: ! 130: emit_pic(); ! 131: break; ! 132: case Postscript: ! 133: emit_ps(); ! 134: break; ! 135: case Graphdraw: ! 136: emit_graphdraw(); ! 137: break; ! 138: } ! 139: } ! 140: ! 141: void global_init(char *cmdname) { ! 142: Node = new DAG_node_t*[Init_extent]; ! 143: Edge = new DAG_edge_t*[Init_extent]; ! 144: Extent = Init_extent; ! 145: Cmd_name = cmdname; ! 146: Options = reset_options(); ! 147: } ! 148: ! 149: void graph_init() { ! 150: N = 0; ! 151: Syntax_error = 0; ! 152: User = user_info_t(); ! 153: Default_node = Reset_node; ! 154: Default_edge = Reset_edge; ! 155: } ! 156: ! 157: void reclaim_nodes() { ! 158: for (int i = 0; i < N; i++) delete Node[i]; ! 159: } ! 160: ! 161: void reclaim_edges() { ! 162: DAG_edge_t *e,*f; ! 163: for (int node = 0; node < N; node++) { ! 164: if (e = Edge[node]) { ! 165: if (e->splinept) delete e->splinept; ! 166: while (e) { ! 167: f = e->nextof(); ! 168: delete e; ! 169: e = f; ! 170: } ! 171: Edge[node] = 0; ! 172: } ! 173: } ! 174: } ! 175: ! 176: void reclaim_samenodesets() { ! 177: delete Options.source_nodes; ! 178: Options.source_nodes = 0; ! 179: delete Options.sink_nodes; ! 180: Options.sink_nodes = 0; ! 181: for (int i = 0; i < Options.n_same_nodes; i++) { ! 182: delete Options.same_nodes[i]; ! 183: Options.same_nodes[i] = 0; ! 184: } ! 185: Options.same_nodes = 0; ! 186: Options.n_same_nodes = 0; ! 187: } ! 188: ! 189: void reclaim_storage() { ! 190: reclaim_nodes(); ! 191: reclaim_edges(); ! 192: reclaim_hashtable(); ! 193: reclaim_samenodesets(); ! 194: freestrings(); ! 195: } ! 196: ! 197: main(int argc, char**argv) { ! 198: char **args = argv; ! 199: int nfiles = 0; ! 200: boolean use_stdin = true; ! 201: ! 202: global_init(argv[0]); ! 203: for (int arg = 1; arg < argc; arg++) { ! 204: if (*argv[arg] == '-') { ! 205: switch(argv[arg][1]) { ! 206: case 'O': ! 207: Options.quick = false; ! 208: break; ! 209: case 'l': ! 210: Uselib = false; ! 211: break; ! 212: case 'v': ! 213: Options.verbose = true; ! 214: break; ! 215: case 'T': // type of output ! 216: set_output_type(&argv[arg][2]); ! 217: break; ! 218: case 'p': ! 219: set_page_size(&argv[arg][2]); ! 220: break; ! 221: } ! 222: } ! 223: else {nfiles++; use_stdin = false;} ! 224: } ! 225: if (use_stdin) nfiles = 1; ! 226: ! 227: for (int file = 0; file < nfiles; file++) { ! 228: char buf[BUFSIZ]; ! 229: if (!use_stdin) Current_file = nextfile(args); ! 230: if (!Current_file.fp) continue; ! 231: if (Output_type == Pic) printf(".lf 1 %s\n",Current_file.name); ! 232: while (Current_file.gets(buf,sizeof(buf))) { ! 233: if (buf[0] == '.' && buf[1] == 'G' &&((buf[2] == 'D')||(buf[2] == 'R'))) { ! 234: /* they're playing our song */ ! 235: graph_init(); ! 236: if (buf[2] == 'R') User.set_rotate(); ! 237: double userwidth = 0., userheight = 0.; ! 238: char fill[80]; fill[0] = 0; ! 239: sscanf(&buf[3],"%lf %lf %s",&userwidth,&userheight,fill); ! 240: User.set_size(userwidth,userheight); ! 241: if (!strcmp(fill,"fill")) ! 242: set_bounds(userwidth,userheight); ! 243: yyparse(); ! 244: reclaim_storage(); ! 245: } ! 246: else if ((Output_type == Pic) && buf[0] == '.' && buf[1] == 'l' && buf[2] == 'f') { ! 247: char auxbuf[BUFSIZ]; ! 248: int line_number; ! 249: if (sscanf(buf + 3,"%d %s",&line_number,auxbuf) == 2) { ! 250: free(Current_file.name); ! 251: printf(".lf %d %s\n",Current_file.line_number = line_number, ! 252: Current_file.name = strcpy(new char[strlen(auxbuf)+1],auxbuf)); ! 253: } ! 254: else ! 255: printf(".lf %d\n",Current_file.line_number = line_number); ! 256: } ! 257: else fputs(buf,stdout); ! 258: } ! 259: if (!use_stdin) { ! 260: free(Current_file.name); ! 261: fclose(Current_file.fp); ! 262: } ! 263: } ! 264: } ! 265: ! 266: /*** the lexer ***/ ! 267: ! 268: static char tokenbuf[BUFSIZ]; ! 269: static char lexbuf[BUFSIZ]; ! 270: static char *lexbufptr; ! 271: ! 272: static char *eatwhitespace(char *p) { ! 273: while (isspace(*p)) p++; ! 274: return p; ! 275: } ! 276: ! 277: /* grab drawing-code enclosed in matching curly braces. strip braces. */ ! 278: static char *scandesc() { ! 279: char sidebuf[BUFSIZ],*p; ! 280: int left = BUFSIZ - 1; ! 281: int depth = 1; // eat opening curlybrace ! 282: ! 283: p = sidebuf; ! 284: while (left) { ! 285: if (!*lexbufptr) { ! 286: lexbufptr = Current_file.gets(lexbuf,sizeof(lexbuf)); ! 287: if (!lexbufptr) { ! 288: yyerror("unmatched '{' in drawing information"); ! 289: return 0; ! 290: } ! 291: } ! 292: if (*lexbufptr == '}') { ! 293: depth--; ! 294: if (depth == 0) { ! 295: *p = 0; ! 296: lexbufptr++; ! 297: return newstring(sidebuf); ! 298: } ! 299: } ! 300: else if (*lexbufptr == '{') depth++; ! 301: *p++ = *lexbufptr++; ! 302: left--; ! 303: } ! 304: yyerror("overran buffer for drawing info"); ! 305: return 0; ! 306: } ! 307: ! 308: /* bump p and return pointer to (static) null delimited copy of name token */ ! 309: char *delimitname(char* &p) { ! 310: char *q = tokenbuf; ! 311: ! 312: p = eatwhitespace(p); ! 313: if (!*p) return 0; ! 314: while ((*p) && !isspace(*p) && (*p != ';') && (*p != '{') && (*p != '}') ! 315: && (*p != ',') && (*p != '\"')) ! 316: *q++ = *p++; ! 317: *q = 0; ! 318: return tokenbuf; ! 319: } ! 320: ! 321: /* delimit a quoted string */ ! 322: char *quotelimit(char* &p) { ! 323: char *q = tokenbuf; ! 324: ! 325: ++p; ! 326: while ((*p) && *p != '\"') { ! 327: if ((*p == '\\') && (*(p + 1) == '\"')) p++; ! 328: *q++ = *p++; ! 329: } ! 330: if (!*p) yyerror("quoted string ran off end of line"); ! 331: p++; ! 332: *q = 0; ! 333: return tokenbuf; ! 334: } ! 335: ! 336: int squirrelbufinuse,squirrelbufsize; ! 337: char *squirrelbuf; ! 338: void squirrel(const char*p) ! 339: { ! 340: int l = strlen(p); ! 341: if (l > squirrelbufsize - squirrelbufinuse) { ! 342: if (!squirrelbuf) squirrelbuf = (char*)malloc(BUFSIZ); ! 343: else squirrelbuf = (char*)realloc(squirrelbuf,squirrelbufsize += BUFSIZ); ! 344: } ! 345: strcpy(squirrelbuf + squirrelbufinuse,p); ! 346: squirrelbufinuse += l; ! 347: } ! 348: void unsquirrel() ! 349: { ! 350: if (squirrelbuf) fputs(squirrelbuf,stdout); ! 351: squirrelbufinuse = 0; ! 352: } ! 353: ! 354: void copyPS() ! 355: { ! 356: char buf[BUFSIZ]; ! 357: char *p; ! 358: while (p = Current_file.gets(buf,sizeof(buf))) { ! 359: if (p[0] == '.' && p[1] == 'P' && p[2] == 'E') return; ! 360: else squirrel(buf); ! 361: } ! 362: yyerror("unmatched .PS inside .GS"); ! 363: } ! 364: ! 365: int myyylex() ! 366: { ! 367: int rv = myyylex(); ! 368: fprintf(stderr,"returning %d\n",rv); ! 369: if (rv == STRING || rv == DESC ) fprintf(stderr,"string val is %s\n",yylval.s); ! 370: return rv; ! 371: } ! 372: ! 373: int yylex() ! 374: { ! 375: if (lexbufptr) lexbufptr = eatwhitespace(lexbufptr); ! 376: while (!lexbufptr || !*lexbufptr) { ! 377: while ((lexbufptr = Current_file.gets(lexbuf,sizeof(lexbuf))) ! 378: && (lexbuf[0] == '.')) { ! 379: if (lexbuf[1] == 'P' && lexbuf[2] == 'S') copyPS(); ! 380: else { ! 381: if (lexbuf[1] == 'G' && lexbuf[2] == 'E') {lexbufptr = 0;return EOF;} ! 382: else squirrel(lexbuf); // assume it's a troff control ! 383: } ! 384: } ! 385: if (!lexbufptr) { ! 386: yyerror("unmatched .GS"); ! 387: return EOF; ! 388: } ! 389: lexbufptr = eatwhitespace(lexbufptr); ! 390: } ! 391: ! 392: switch(*lexbufptr) { ! 393: case ',': ! 394: case ';': ! 395: return *lexbufptr++; ! 396: case '\"': ! 397: yylval.s = newstring(quotelimit(lexbufptr)); ! 398: return STRING; ! 399: case '}': ! 400: yyerror("unexpected '}'"); ! 401: lexbufptr++; ! 402: return ';'; ! 403: case '{' : ! 404: lexbufptr++; ! 405: yylval.s = scandesc(); ! 406: return DESC; ! 407: } ! 408: char *tokenptr = delimitname(lexbufptr); ! 409: char *p = tokenptr; ! 410: ! 411: TFA_Init(); ! 412: while (*p) { ! 413: TFA_Advance(*p); ! 414: p++; ! 415: } ! 416: int token = TFA_Definition(); ! 417: if (token != -1) return token; ! 418: yylval.s = newstring(tokenptr); ! 419: return STRING; ! 420: } ! 421: ! 422: void error_context() ! 423: { ! 424: char *p,*q; ! 425: if (!lexbufptr) return; ! 426: fprintf(stderr,"context is: "); ! 427: for (p = lexbufptr - 1; (p > lexbuf) && (!isspace(*p)); p--); ! 428: for (q = lexbuf; q < p; q++) fputc(*q,stderr); ! 429: fputs(" >>> ",stderr); ! 430: for (; q < lexbufptr; q++)fputc(*q,stderr); ! 431: fputs(" <<< ",stderr); ! 432: fputs(lexbufptr,stderr); ! 433: } ! 434: void yyerror(char*s,char *s1, char* s2, char *s3, char *s4) { ! 435: extern void error_context(); ! 436: ! 437: if (Syntax_error) return; ! 438: Syntax_error = 1; ! 439: fprintf(stderr, "%s: ", Cmd_name); ! 440: fprintf(stderr, s, s1, s2, s3, s4); ! 441: fprintf(stderr, " near line %d, file %s\n",Current_file.line_number, ! 442: Current_file.name); ! 443: error_context(); ! 444: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.