wolffd@0: # wolffd@0: # dotty_layout: layout functions and data structures wolffd@0: # wolffd@0: dotty.grablserver = function (lserver) { wolffd@0: local fd; wolffd@0: wolffd@0: if (~dotty.lservers[lserver] | tablesize (dotty.lservers[lserver]) == 0) { wolffd@0: if (~((fd = openio ('pipe', lserver, 'r+', '%e -Txdot')) >= 0)) { wolffd@0: dotty.message (0, concat ('cannot start ', lserver)); wolffd@0: return null; wolffd@0: } wolffd@0: dotty.lservers[lserver][fd] = [ wolffd@0: 'fd' = fd; wolffd@0: 'count' = 0; wolffd@0: ]; wolffd@0: } wolffd@0: for (fd in dotty.lservers[lserver]) { wolffd@0: dotty.lservers[lserver][fd].count = dotty.lservers[ wolffd@0: lserver wolffd@0: ][fd].count + 1; wolffd@0: dotty.lservers.inuse[fd] = dotty.lservers[lserver][fd]; wolffd@0: remove (fd, dotty.lservers[lserver]); wolffd@0: return fd; wolffd@0: } wolffd@0: }; wolffd@0: dotty.releaselserver = function (lserver, fd, state) { wolffd@0: if (state == 'bad' | dotty.lservers.inuse[fd].count > 40) { wolffd@0: closeio (fd, 'kill'); wolffd@0: remove (fd, dotty.lservers.inuse); wolffd@0: return; wolffd@0: } wolffd@0: dotty.lservers[lserver][fd] = dotty.lservers.inuse[fd]; wolffd@0: remove (fd, dotty.lservers.inuse); wolffd@0: }; wolffd@0: dotty.protogt.startlayout = function (gt) { wolffd@0: local lpt, fd; wolffd@0: wolffd@0: if (gt.layoutpending >= 1) { wolffd@0: lpt = dotty.layoutpending[gt.gtid]; wolffd@0: if (gt.layoutmode == 'async') wolffd@0: monitor ('off', lpt.fd); wolffd@0: dotty.releaselserver (gt.lserver, lpt.fd, 'bad'); wolffd@0: remove (gt.gtid, dotty.layoutpending); wolffd@0: gt.layoutpending = 0; wolffd@0: gt.haveinput = 0; wolffd@0: dotty.popbusy (gt, gt.views); wolffd@0: } wolffd@0: if (~((fd = dotty.grablserver (gt.lserver)) >= 0)) wolffd@0: return null; wolffd@0: dotty.pushbusy (gt, gt.views); wolffd@0: writegraph (fd, gt.graph, 1); wolffd@0: gt.layoutpending = 1; wolffd@0: dotty.layoutpending[gt.gtid] = [ wolffd@0: 'fd' = fd; wolffd@0: 'gtid' = gt.gtid; wolffd@0: ]; wolffd@0: if (gt.layoutmode == 'async') wolffd@0: monitor ('on', fd); wolffd@0: return 1; wolffd@0: }; wolffd@0: dotty.protogt.finishlayout = function (gt) { wolffd@0: local graph, lpt, fd; wolffd@0: wolffd@0: if (~(gt.layoutpending >= 1)) { wolffd@0: dotty.message (0, concat ('no layout pending for graph ', gt.gtid)); wolffd@0: return null; wolffd@0: } wolffd@0: lpt = dotty.layoutpending[gt.gtid]; wolffd@0: if (~(graph = readgraph (lpt.fd))) { wolffd@0: if (gt.layoutmode == 'async') wolffd@0: monitor ('off', lpt.fd); wolffd@0: dotty.releaselserver (gt.lserver, lpt.fd, 'bad'); wolffd@0: if (gt.layoutpending == 2) { wolffd@0: dotty.message (0, concat ('giving up on ', gt.lserver)); wolffd@0: if ((fd = openio ('file', 'dottybug.dot', 'w+')) >= 0) { wolffd@0: writegraph (fd, gt.graph, 0); wolffd@0: closeio (fd); wolffd@0: dotty.message ( wolffd@0: 0, concat ('graph that causes ', gt.lserver) wolffd@0: ); wolffd@0: dotty.message ( wolffd@0: 0, 'to fail has been saved in file dottybug.dot' wolffd@0: ); wolffd@0: dotty.message ( wolffd@0: 0, 'please fill out a bug report at' wolffd@0: ); wolffd@0: dotty.message ( wolffd@0: 0, 'http://www.graphviz.org/bugs/bugform.html' wolffd@0: ); wolffd@0: } wolffd@0: dotty.popbusy (gt, gt.views); wolffd@0: gt.layoutpending = 0; wolffd@0: gt.haveinput = 0; wolffd@0: return 1; wolffd@0: } wolffd@0: dotty.message ( wolffd@0: 1, concat ('lost connection to ', gt.lserver, ', restarting...') wolffd@0: ); wolffd@0: lpt.fd = dotty.grablserver (gt.lserver); wolffd@0: writegraph (lpt.fd, gt.graph, 1); wolffd@0: if (gt.layoutmode == 'async') wolffd@0: monitor ('on', lpt.fd); wolffd@0: gt.layoutpending = 2; wolffd@0: gt.haveinput = 0; wolffd@0: return null; wolffd@0: } wolffd@0: if (gt.layoutmode == 'async') wolffd@0: monitor ('off', lpt.fd); wolffd@0: dotty.releaselserver (gt.lserver, lpt.fd, null); wolffd@0: remove (gt.gtid, dotty.layoutpending); wolffd@0: gt.layoutpending = 0; wolffd@0: gt.haveinput = 0; wolffd@0: gt.unpacklayout (gt, graph); wolffd@0: dotty.popbusy (gt, gt.views); wolffd@0: return 1; wolffd@0: }; wolffd@0: dotty.protogt.cancellayout = function (gt) { wolffd@0: local lpt, vid; wolffd@0: wolffd@0: if (gt.layoutpending >= 1) { wolffd@0: lpt = dotty.layoutpending[gt.gtid]; wolffd@0: if (gt.layoutmode == 'async') wolffd@0: monitor ('off', lpt.fd); wolffd@0: dotty.releaselserver (gt.lserver, lpt.fd, 'bad'); wolffd@0: remove (gt.gtid, dotty.layoutpending); wolffd@0: gt.layoutpending = 0; wolffd@0: gt.haveinput = 0; wolffd@0: dotty.popbusy (gt, gt.views); wolffd@0: } wolffd@0: }; wolffd@0: dotty.protogt.unpacklayout = function (gt, graph2) { wolffd@0: local graph, gid, sgraph1, sgraph2, nid, node1, node2, eid, edge1, edge2; wolffd@0: local t1, pos, size; wolffd@0: wolffd@0: graph = gt.graph; wolffd@0: for (gid in graph2.graphdict) { wolffd@0: if (~(sgraph1 = graph.graphs[graph.graphdict[gid]])) wolffd@0: continue; wolffd@0: sgraph2 = graph2.graphs[graph2.graphdict[gid]]; wolffd@0: sgraph1.draws = gt.unpackalldraw (gt, sgraph2.graphattr); wolffd@0: } wolffd@0: for (nid in graph2.nodedict) { wolffd@0: if (~(node1 = graph.nodes[graph.nodedict[nid]])) wolffd@0: continue; wolffd@0: node2 = graph2.nodes[graph2.nodedict[nid]]; wolffd@0: node1.draws = gt.unpackalldraw (gt, node2.attr); wolffd@0: t1 = split (node2.attr.pos, ','); wolffd@0: pos = ['x' = ston (t1[0]); 'y' = ston (t1[1]);]; wolffd@0: size = [ wolffd@0: 'x' = ston (node2.attr.width) * 72; wolffd@0: 'y' = ston (node2.attr.height) * 72; wolffd@0: ]; wolffd@0: node1.pos = pos; wolffd@0: node1.size = size; wolffd@0: node1.rect = [ wolffd@0: 0 = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;]; wolffd@0: 1 = ['x' = pos.x + size.x / 2; 'y' = pos.y + size.y / 2;]; wolffd@0: ]; wolffd@0: } wolffd@0: for (eid in graph2.edges) { wolffd@0: edge2 = graph2.edges[eid]; wolffd@0: if (edge2.attr.id) { wolffd@0: if (~(edge1 = graph.edges[ston (edge2.attr.id)])) wolffd@0: continue; wolffd@0: } else if (graph == graph2) wolffd@0: edge1 = edge2; wolffd@0: edge1.draws = gt.unpackalldraw (gt, edge2.attr); wolffd@0: } wolffd@0: graph.draws = gt.unpackalldraw (gt, graph2.graphattr); wolffd@0: t1 = split (graph2.graphattr.bb, ','); wolffd@0: graph.rect[0].x = ston (t1[0]); wolffd@0: graph.rect[0].y = ston (t1[1]); wolffd@0: graph.rect[1].x = ston (t1[2]); wolffd@0: graph.rect[1].y = ston (t1[3]); wolffd@0: if (gt.graph ~= graph2) wolffd@0: return; wolffd@0: # strip position and size info from the attributes wolffd@0: for (gid in graph2.graphdict) { wolffd@0: sgraph2 = graph2.graphs[graph2.graphdict[gid]]; wolffd@0: gt.removealldraw (gt, sgraph2.graphattr); wolffd@0: if (sgraph2.graphattr.bb) wolffd@0: remove ('bb', sgraph2.graphattr); wolffd@0: } wolffd@0: for (nid in graph2.nodedict) { wolffd@0: node2 = graph2.nodes[graph2.nodedict[nid]]; wolffd@0: gt.removealldraw (gt, node2.attr); wolffd@0: if (node2.attr.rects) wolffd@0: remove ('rects', node2.attr); wolffd@0: remove ('pos', node2.attr); wolffd@0: remove ('width', node2.attr); wolffd@0: remove ('height', node2.attr); wolffd@0: } wolffd@0: for (eid in graph2.edges) { wolffd@0: edge2 = graph2.edges[eid]; wolffd@0: gt.removealldraw (gt, edge2.attr); wolffd@0: if (edge2.attr.pos) wolffd@0: remove ('pos', edge2.attr); wolffd@0: if (edge2.attr.lp) wolffd@0: remove ('lp', edge2.attr); wolffd@0: } wolffd@0: gt.removealldraw (gt, graph2.graphattr); wolffd@0: remove ('bb', graph2.graphattr); wolffd@0: if (graph2.graphattr.lp) wolffd@0: remove ('lp', graph2.graphattr); wolffd@0: }; wolffd@0: # wolffd@0: # draw directive parsing wolffd@0: # wolffd@0: dotty.protogt.unpackalldraw = function (gt, attr) { wolffd@0: local o, did; wolffd@0: wolffd@0: o = []; wolffd@0: if (attr._draw_) wolffd@0: o._draw_ = gt.unpackdraw (gt, attr._draw_); wolffd@0: if (attr._ldraw_) wolffd@0: o._ldraw_ = gt.unpackdraw (gt, attr._ldraw_); wolffd@0: if (attr._hdraw_) wolffd@0: o._hdraw_ = gt.unpackdraw (gt, attr._hdraw_); wolffd@0: if (attr._tdraw_) wolffd@0: o._tdraw_ = gt.unpackdraw (gt, attr._tdraw_); wolffd@0: if (attr._hldraw_) wolffd@0: o._hldraw_ = gt.unpackdraw (gt, attr._hldraw_); wolffd@0: if (attr._tldraw_) wolffd@0: o._tldraw_ = gt.unpackdraw (gt, attr._tldraw_); wolffd@0: for (did in o) wolffd@0: if (o[did].ep) { wolffd@0: o.ep = o[did].ep; wolffd@0: break; wolffd@0: } wolffd@0: return o; wolffd@0: }; wolffd@0: dotty.protogt.removealldraw = function (gt, attr) { wolffd@0: if (attr._draw_) wolffd@0: remove ('_draw_', attr); wolffd@0: if (attr._ldraw_) wolffd@0: remove ('_ldraw_', attr); wolffd@0: if (attr._hdraw_) wolffd@0: remove ('_hdraw_', attr); wolffd@0: if (attr._tdraw_) wolffd@0: remove ('_tdraw_', attr); wolffd@0: if (attr._hldraw_) wolffd@0: remove ('_hldraw_', attr); wolffd@0: if (attr._tldraw_) wolffd@0: remove ('_tldraw_', attr); wolffd@0: }; wolffd@0: dotty.protogt.unpackdraw = function (gt, attr) { wolffd@0: local oo, o, tt, t, n, i, j, s, l, ep; wolffd@0: wolffd@0: oo = []; wolffd@0: t = split (attr, ' ', 0); wolffd@0: n = tablesize (t); wolffd@0: if (t[n - 1] == '') { wolffd@0: remove (n - 1, t); wolffd@0: n = n - 1; wolffd@0: } wolffd@0: i = 0; wolffd@0: while (i < n) { wolffd@0: o = []; wolffd@0: if (t[i] == 'E') { wolffd@0: o.type = t[i]; wolffd@0: o.c.x = ston (t[i + 1]); wolffd@0: o.c.y = ston (t[i + 2]); wolffd@0: o.s.x = ston (t[i + 3]); wolffd@0: o.s.y = ston (t[i + 4]); wolffd@0: i = i + 5; wolffd@0: } else if (t[i] == 'e') { wolffd@0: o.type = t[i]; wolffd@0: o.c.x = ston (t[i + 1]); wolffd@0: o.c.y = ston (t[i + 2]); wolffd@0: o.s.x = ston (t[i + 3]); wolffd@0: o.s.y = ston (t[i + 4]); wolffd@0: i = i + 5; wolffd@0: } else if (t[i] == 'P') { wolffd@0: o.type = t[i]; wolffd@0: o.n = ston (t[i + 1]); wolffd@0: for (j = 0; j < o.n; j = j + 1) { wolffd@0: o.ps[j].x = ston (t[i + 2 + j * 2]); wolffd@0: o.ps[j].y = ston (t[i + 2 + j * 2 + 1]); wolffd@0: } wolffd@0: i = i + 2 + o.n * 2; wolffd@0: o.ps[o.n] = o.ps[0]; wolffd@0: o.n = o.n + 1; wolffd@0: } else if (t[i] == 'p') { wolffd@0: o.type = t[i]; wolffd@0: o.n = ston (t[i + 1]); wolffd@0: for (j = 0; j < o.n; j = j + 1) { wolffd@0: o.ps[j].x = ston (t[i + 2 + j * 2]); wolffd@0: o.ps[j].y = ston (t[i + 2 + j * 2 + 1]); wolffd@0: } wolffd@0: i = i + 2 + o.n * 2; wolffd@0: o.ps[o.n] = o.ps[0]; wolffd@0: o.n = o.n + 1; wolffd@0: } else if (t[i] == 'L') { wolffd@0: o.type = t[i]; wolffd@0: o.n = ston (t[i + 1]); wolffd@0: for (j = 0; j < o.n; j = j + 1) { wolffd@0: o.ps[j].x = ston (t[i + 2 + j * 2]); wolffd@0: o.ps[j].y = ston (t[i + 2 + j * 2 + 1]); wolffd@0: } wolffd@0: i = i + 2 + o.n * 2; wolffd@0: if (~ep) wolffd@0: ep = copy (o.ps[1]); wolffd@0: } else if (t[i] == 'B') { wolffd@0: o.type = t[i]; wolffd@0: o.n = ston (t[i + 1]); wolffd@0: for (j = 0; j < o.n; j = j + 1) { wolffd@0: o.ps[j].x = ston (t[i + 2 + j * 2]); wolffd@0: o.ps[j].y = ston (t[i + 2 + j * 2 + 1]); wolffd@0: } wolffd@0: i = i + 2 + o.n * 2; wolffd@0: if (~ep) wolffd@0: ep = copy (o.ps[1]); wolffd@0: } else if (t[i] == 'b') { wolffd@0: o.type = t[i]; wolffd@0: o.n = ston (t[i + 1]); wolffd@0: for (j = 0; j < o.n; j = j + 1) { wolffd@0: o.ps[j].x = ston (t[i + 2 + j * 2]); wolffd@0: o.ps[j].y = ston (t[i + 2 + j * 2 + 1]); wolffd@0: } wolffd@0: i = i + 2 + o.n * 2; wolffd@0: if (~ep) wolffd@0: ep = copy (o.ps[1]); wolffd@0: } else if (t[i] == 'T') { wolffd@0: o.type = t[i]; wolffd@0: o.p.x = ston (t[i + 1]); wolffd@0: o.p.y = ston (t[i + 2]); wolffd@0: o.j = ston (t[i + 3]); wolffd@0: if (o.j == -1) wolffd@0: o.j = 'lb'; wolffd@0: else if (o.j == 1) wolffd@0: o.j = 'rb'; wolffd@0: else if (o.j == 0) wolffd@0: o.j = 'cb'; wolffd@0: o.w = ston (t[i + 4]); wolffd@0: o.n = ston (t[i + 5]); wolffd@0: i = i + 6; wolffd@0: s = t[i]; wolffd@0: i = i + 1; wolffd@0: l = strlen (s) - 1; wolffd@0: while (l < o.n) { wolffd@0: s = concat (s, ' ', t[i]); wolffd@0: l = l + 1 + strlen (t[i]); wolffd@0: i = i + 1; wolffd@0: } wolffd@0: tt = split (s, ''); wolffd@0: l = tablesize (tt); wolffd@0: s = ''; wolffd@0: for (j = 1; j < l; j = j + 1) wolffd@0: s = concat (s, tt[j]); wolffd@0: o.s = s; wolffd@0: } else if (t[i] == 'C') { wolffd@0: o.type = t[i]; wolffd@0: o.n = ston (t[i + 1]); wolffd@0: i = i + 2; wolffd@0: s = t[i]; wolffd@0: i = i + 1; wolffd@0: l = strlen (s) - 1; wolffd@0: while (l < o.n) { wolffd@0: s = concat (s, ' ', t[i]); wolffd@0: l = l + 1 + strlen (t[i]); wolffd@0: i = i + 1; wolffd@0: } wolffd@0: tt = split (s, ''); wolffd@0: l = tablesize (tt); wolffd@0: s = ''; wolffd@0: for (j = 1; j < l; j = j + 1) wolffd@0: s = concat (s, tt[j]); wolffd@0: o.fillcolor = gt.getcolor (gt.views, s); wolffd@0: } else if (t[i] == 'c') { wolffd@0: o.type = t[i]; wolffd@0: o.n = ston (t[i + 1]); wolffd@0: i = i + 2; wolffd@0: s = t[i]; wolffd@0: i = i + 1; wolffd@0: l = strlen (s) - 1; wolffd@0: while (l < o.n) { wolffd@0: s = concat (s, ' ', t[i]); wolffd@0: l = l + 1 + strlen (t[i]); wolffd@0: i = i + 1; wolffd@0: } wolffd@0: tt = split (s, ''); wolffd@0: l = tablesize (tt); wolffd@0: s = ''; wolffd@0: for (j = 1; j < l; j = j + 1) wolffd@0: s = concat (s, tt[j]); wolffd@0: o.drawcolor = gt.getcolor (gt.views, s); wolffd@0: } else if (t[i] == 'F') { wolffd@0: o.type = t[i]; wolffd@0: o.fs = ston (t[i + 1]); wolffd@0: o.n = ston (t[i + 2]); wolffd@0: i = i + 3; wolffd@0: s = t[i]; wolffd@0: i = i + 1; wolffd@0: l = strlen (s) - 1; wolffd@0: while (l < o.n) { wolffd@0: s = concat (s, ' ', t[i]); wolffd@0: l = l + 1 + strlen (t[i]); wolffd@0: i = i + 1; wolffd@0: } wolffd@0: tt = split (s, ''); wolffd@0: l = tablesize (tt); wolffd@0: s = ''; wolffd@0: for (j = 1; j < l; j = j + 1) wolffd@0: s = concat (s, tt[j]); wolffd@0: o.ofn = s; wolffd@0: o.fn = dotty.fontmap[s]; wolffd@0: } else if (t[i] == 'S') { wolffd@0: o.type = t[i]; wolffd@0: o.n = ston (t[i + 1]); wolffd@0: i = i + 2; wolffd@0: s = t[i]; wolffd@0: i = i + 1; wolffd@0: l = strlen (s) - 1; wolffd@0: while (l < o.n) { wolffd@0: s = concat (s, ' ', t[i]); wolffd@0: l = l + 1 + strlen (t[i]); wolffd@0: i = i + 1; wolffd@0: } wolffd@0: tt = split (s, ''); wolffd@0: l = tablesize (tt); wolffd@0: s = ''; wolffd@0: for (j = 1; j < l; j = j + 1) wolffd@0: s = concat (s, tt[j]); wolffd@0: if ( wolffd@0: s == 'solid' | s == 'dashed' | s == 'dotted' | wolffd@0: s == 'longdashed' | s == 'shortdashed' wolffd@0: ) wolffd@0: o.style = s; wolffd@0: else if (s == 'bold') wolffd@0: o.width = 3; wolffd@0: else { wolffd@0: tt = split (s, '('); wolffd@0: if (tt[0] == 'setlinewidth') { wolffd@0: tt = split (tt[1], ')'); wolffd@0: o.width = ston (tt[0]); wolffd@0: } else wolffd@0: continue; wolffd@0: } wolffd@0: } else if (t[i] == 'I') { wolffd@0: i = i + 7; wolffd@0: } else { wolffd@0: dotty.message (0, concat ('draw language parser error: ', t[i])); wolffd@0: return null; wolffd@0: } wolffd@0: oo[tablesize (oo)] = o; wolffd@0: } wolffd@0: oo.ep = ep; wolffd@0: return oo; wolffd@0: };