示例#1
0
static void 
xd_set_style (char **s)
{
    unsigned char buf[BUFSIZ];
    agxbuf xbuf;
    char* p;
    int more;

    agxbinit(&xbuf, BUFSIZ, buf);
    while ((p = *s++)) {
	agxbput(&xbuf, p);
	while (*p)
	    p++;
	p++;
	if (*p) {  /* arguments */
	    agxbputc(&xbuf, '(');
            more = 0;
	    while (*p) {
		if (more)
		    agxbputc(&xbuf, ',');
		agxbput(&xbuf, p);
	        while (*p) p++;
		p++;
		more++;
	    }
	    agxbputc(&xbuf, ')');
	}
	xd_str ("S ", agxbuse(&xbuf));
    }
    agxbfree(&xbuf);
}
示例#2
0
char *gvUsername(void)
{
    char *user = NULL;
#ifndef MSWIN32
    static int first = 1;
    struct passwd *p;
    if (first) {
	agxbinit(&xb, SMALLBUF, userbuf);
	atexit(cleanup);
	first = 0;
    }
    p = (struct passwd *) getpwuid(getuid());
    if (p) {
	agxbputc(&xb, '(');
	agxbput(&xb, p->pw_name);
	agxbput(&xb, ") ");
#ifdef SVR4
	agxbput(&xb, p->pw_comment);
#else
	agxbput(&xb, p->pw_gecos);
#endif
	user = agxbuse(&xb);
    }
#endif
    if (user == NULL)
	user = "******"; //maks
    return user;
}
示例#3
0
/* clustNode:
 * Generate a special cluster node representing the end node
 * of an edge to the cluster cg. n is a node whose name is the same
 * as the cluster cg. clg is the subgraph of all of
 * the original nodes, which will be deleted later.
 */
static node_t *clustNode(node_t * n, graph_t * cg, agxbuf * xb,
			 graph_t * clg)
{
    node_t *cn;
    static int idx = 0;
    char num[100];

    agxbput(xb, "__");
    sprintf(num, "%d", idx++);
    agxbput(xb, num);
    agxbputc(xb, ':');
    agxbput(xb, cg->name);

    cn = agnode(cg->root, agxbuse(xb));
    SET_CLUST_NODE(cn);
    aginsert(cg, cn);
    aginsert(clg, n);

    /* set attributes */
    N_label = setAttr(cn->graph, cn, "label", "", N_label);
    N_style = setAttr(cn->graph, cn, "style", "invis", N_style);
    N_shape = setAttr(cn->graph, cn, "shape", "box", N_shape);
    /* N_width = setAttr (cn->graph, cn, "width", "0.0001", N_width); */

    return cn;
}
示例#4
0
/* clustNode:
 * Generate a special cluster node representing the end node
 * of an edge to the cluster cg. n is a node whose name is the same
 * as the cluster cg. clg is the subgraph of all of
 * the original nodes, which will be deleted later.
 */
static node_t *clustNode(node_t * n, graph_t * cg, agxbuf * xb,
			 graph_t * clg)
{
    node_t *cn;
    static int idx = 0;
    char num[100];

    agxbput(xb, "__");
    sprintf(num, "%d", idx++);
    agxbput(xb, num);
    agxbputc(xb, ':');
    agxbput(xb, agnameof(cg));

    cn = agnode(agroot(cg), agxbuse(xb), 1);
    agbindrec(cn, "Agnodeinfo_t", sizeof(Agnodeinfo_t), TRUE);

    SET_CLUST_NODE(cn);
	agsubnode(cg,cn,1);
	//aginsert(cg, cn);
	agsubnode(clg,n,1);
	//aginsert(clg, n);

    /* set attributes */
    N_label = setAttr(agraphof(cn), cn, "label", "", N_label);
    N_style = setAttr(agraphof(cn), cn, "style", "invis", N_style);
    N_shape = setAttr(agraphof(cn), cn, "shape", "box", N_shape);
    /* N_width = setAttr (cn->graph, cn, "width", "0.0001", N_width); */

    return cn;
}
static void xdot_point(agxbuf *xbuf, pointf p)
{
    char buf[BUFSIZ];
    xdot_fmt_num (buf, p.x);
    agxbput(xbuf, buf);
    xdot_fmt_num (buf, yDir(p.y));
    agxbput(xbuf, buf);
}
示例#6
0
static void xd_str (char* pfx, char* s)
{
    char buf[BUFSIZ];

    sprintf (buf, "%s%d -", pfx, (int)strlen(s));
    agxbput(xbufs[gvc->emit_state], buf);
    agxbput(xbufs[gvc->emit_state], s);
    agxbputc(xbufs[gvc->emit_state], ' ');
}
static void xdot_str_xbuf (agxbuf* xb, char* pfx, char* s)
{
    char buf[BUFSIZ];

    sprintf (buf, "%s%d -", pfx, (int)strlen(s));
    agxbput(xb, buf);
    agxbput(xb, s);
    agxbputc(xb, ' ');
}
void core_loadimage_xdot(GVJ_t * job, usershape_t *us, boxf b, boolean filled)
{
    emit_state_t emit_state = job->obj->emit_state;
    char buf[BUFSIZ];
    
    agxbput(xbufs[emit_state], "I ");
    xdot_point(xbufs[emit_state], b.LL);
    xdot_fmt_num (buf, b.UR.x - b.LL.x);
    agxbput(xbufs[emit_state], buf);
    xdot_fmt_num (buf, b.UR.y - b.LL.y);
    agxbput(xbufs[emit_state], buf);
    xdot_str (job, "", (char*)(us->name));
}
static void xdot_style (GVJ_t *job)
{
    unsigned char buf0[BUFSIZ];
    char buf [128]; /* enough to hold a double */
    agxbuf xbuf;
    char* p, **s;
    int more;

    agxbinit(&xbuf, BUFSIZ, buf0);

    /* First, check if penwidth state is correct */
    if (job->obj->penwidth != penwidth[job->obj->emit_state]) {
	penwidth[job->obj->emit_state] = job->obj->penwidth;
	agxbput (&xbuf, "setlinewidth(");
	sprintf (buf, "%.3f", job->obj->penwidth);
	xdot_trim_zeros (buf, 0);
	agxbput(&xbuf, buf);
	agxbputc (&xbuf, ')');
        xdot_str (job, "S ", agxbuse(&xbuf));
    }

    /* now process raw style, if any */
    s = job->obj->rawstyle;
    if (!s)
	return;

    while ((p = *s++)) {
	if (streq(p, "filled") || streq(p, "bold") || streq(p, "setlinewidth")) continue;
        agxbput(&xbuf, p);
        while (*p)
            p++;
        p++;
        if (*p) {  /* arguments */
            agxbputc(&xbuf, '(');
            more = 0;
            while (*p) {
                if (more)
                    agxbputc(&xbuf, ',');
                agxbput(&xbuf, p);
                while (*p) p++;
                p++;
                more++;
            }
            agxbputc(&xbuf, ')');
        }
        xdot_str (job, "S ", agxbuse(&xbuf));
    }

    agxbfree(&xbuf);

}
示例#10
0
static void xd_points(char c, point * A, int n)
{
    char buf[BUFSIZ];
    int i;
    point p;

    agxbputc(xbufs[gvc->emit_state], c);
    sprintf(buf, " %d ", n);
    agxbput(xbufs[gvc->emit_state], buf);
    for (i = 0; i < n; i++) {
	p = A[i];
	sprintf(buf, "%d %d ", p.x, YDIR(p.y));
	agxbput(xbufs[gvc->emit_state], buf);
    }
}
示例#11
0
int savefiledlg(int filtercnt, char **filters, agxbuf * xbuf)
{
    GtkWidget *dialog;
    GtkFileFilter *filter;
    int id, rv;
    filter = gtk_file_filter_new();
    if (filtercnt >= 1) {
	for (id = 0; id < filtercnt; id++) {
	    gtk_file_filter_add_pattern(filter, filters[id]);
	}
    }

    dialog = gtk_file_chooser_dialog_new("Save File",
					 NULL,
					 GTK_FILE_CHOOSER_ACTION_OPEN,
					 GTK_STOCK_CANCEL,
					 GTK_RESPONSE_CANCEL,
					 GTK_STOCK_OPEN,
					 GTK_RESPONSE_ACCEPT, NULL);

    if (filtercnt >= 1)
	gtk_file_chooser_set_filter((GtkFileChooser *) dialog, filter);
    if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
	agxbput(xbuf,
		gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)));
	rv = 1;
    } else
	rv = 0;

    gtk_widget_destroy(dialog);
    return rv;
}
示例#12
0
static void xd_ellipse(point p, int rx, int ry, int filled)
{
    char buf[BUFSIZ];

    agxbputc(xbufs[gvc->emit_state], (filled ? 'E' : 'e'));
    sprintf(buf, " %d %d %d %d ", p.x, YDIR(p.y), rx, ry);
    agxbput(xbufs[gvc->emit_state], buf);
}
示例#13
0
/* initAnchor:
 * Save current map values
 * Initialize fields in job->obj pertaining to anchors.
 * In particular, this also sets the output rectangle.
 * If there is something to do, close current anchor if
 * necessary, start the anchor and returns 1.
 * Otherwise, it returns 0.
 *
 * FIX: Should we provide a tooltip if none is set, as is done
 * for nodes, edges, etc. ?
 */
static int
initAnchor (GVJ_t* job, htmlenv_t* env, htmldata_t* data, boxf b, htmlmap_data_t* save,
    int closePrev)
{
    obj_state_t *obj = job->obj;
    int changed;
    char* id;
    static int anchorId;
    int internalId = 0;
    agxbuf xb;
    char intbuf[30];  /* hold 64-bit decimal integer */
    unsigned char buf[SMALLBUF];

    save->url = obj->url; 
    save->tooltip = obj->tooltip;
    save->target = obj->target;
    save->id = obj->id;
    save->explicit_tooltip = obj->explicit_tooltip;
    id = data->id;
    if (!id || !*id) { /* no external id, so use the internal one */
	agxbinit(&xb, SMALLBUF, buf);
	if (!env->objid) {
	    env->objid = strdup (getObjId (job, obj->u.n, &xb));
	    env->objid_set = 1;
	}
	agxbput (&xb, env->objid);
	sprintf (intbuf, "_%d", anchorId++);
	agxbput (&xb, intbuf);
	id = agxbuse (&xb);
	internalId = 1;
    }
    changed = initMapData (job, NULL, data->href, data->title, data->target, id, obj->u.g);
    if (internalId)
	agxbfree (&xb);

    if (changed) {
	if (closePrev && (save->url || save->explicit_tooltip))
	    gvrender_end_anchor(job);
	if (obj->url || obj->explicit_tooltip) {
	    emit_map_rect(job, b);
	    gvrender_begin_anchor(job,
		obj->url, obj->tooltip, obj->target, obj->id);
	}
    }
    return changed;
}
示例#14
0
static void 
xd_set_font (char *fontname, double fontsize)
{
    char buf[BUFSIZ];

    sprintf(buf, "F %f ", fontsize);
    agxbput(xbufs[gvc->emit_state], buf);
    xd_str ("", fontname);
}
/* Construct the list of font faces */
static char *get_avail_faces(int faces, agxbuf* xb)
{
    int i;
    for (i = 0; i < FACELIST_SZ; i++) {
	if (faces & facelist[i].flag) {
	    agxbput (xb, facelist[i].name); 
	    agxbputc(xb, ' ');
	}
    }
    return agxbuse (xb);
}
示例#16
0
/* stoj:
 * Convert dot string to a valid json string embedded in double quotes.
 */
static char* stoj (char* ins, state_t* sp)
{
    char* s;
    char* input;
    static agxbuf xb;
    unsigned char c;

    if (sp->isLatin)
	input = latin1ToUTF8 (ins);
    else
	input = ins;

    if (xb.buf == NULL)
	agxbinit(&xb, BUFSIZ, NULL);
    for (s = input; (c = *s); s++) {
	switch (c) {
	case '"' :
	    agxbput(&xb, "\\\"");
	    break;
	case '\\' :
	    agxbput(&xb, "\\\\");
	    break;
	case '/' :
	    agxbput(&xb, "\\/");
	    break;
	case '\b' :
	    agxbput(&xb, "\\b");
	    break;
	case '\f' :
	    agxbput(&xb, "\\f");
	    break;
	case '\n' :
	    agxbput(&xb, "\\n");
	    break;
	case '\r' :
	    agxbput(&xb, "\\r");
	    break;
	case '\t' :
	    agxbput(&xb, "\\t");
	    break;
	default :
	    agxbputc(&xb, c);
	    break;
	}
    }
    s = agxbuse(&xb);

    if (sp->isLatin)
	free (input);
    return s;
}
static void xdot_points(GVJ_t *job, char c, pointf * A, int n)
{
    emit_state_t emit_state = job->obj->emit_state;
    char buf[BUFSIZ];
    int i, rc;

    rc = agxbputc(xbufs[emit_state], c);
    sprintf(buf, " %d ", n);
    agxbput(xbufs[emit_state], buf);
    for (i = 0; i < n; i++)
        xdot_point(xbufs[emit_state], A[i]);
}
示例#18
0
static char *nameOf(void *obj, agxbuf * xb)
{
    Agedge_t *ep;
    switch (agobjkind(obj)) {
#ifndef WITH_CGRAPH
    case AGGRAPH:
#else
    case AGRAPH:
#endif
	agxbput(xb, agnameof(((Agraph_t *) obj)));
	break;
    case AGNODE:
	agxbput(xb, agnameof(((Agnode_t *) obj)));
	break;
    case AGEDGE:
	ep = (Agedge_t *) obj;
	agxbput(xb, agnameof(agtail(ep)));
	agxbput(xb, agnameof(aghead(ep)));
	if (agisdirected(agraphof(aghead(ep))))
	    agxbput(xb, "->");
	else
	    agxbput(xb, "--");
	break;
    }
    return agxbuse(xb);
}
示例#19
0
/*
	this function is designed to return a GtkTextView object's text in agxbuf
	send an initialized agxbuf and a GtkTextView object
	null termination is taken care by agxbuf
*/
void get_gtktextview_text(GtkTextView * w, agxbuf * xbuf)
{
    int charcnt;
    GtkTextBuffer *gtkbuf;
    GtkTextIter startit;
    GtkTextIter endit;
    gtkbuf = gtk_text_view_get_buffer(w);
    charcnt = gtk_text_buffer_get_char_count(gtkbuf);
    gtk_text_buffer_get_start_iter(gtkbuf, &startit);
    gtk_text_buffer_get_end_iter(gtkbuf, &endit);

    agxbput(xbuf, gtk_text_buffer_get_text(gtkbuf, &startit, &endit, 0));
}
/* xdot_begin_anchor:
 * The encoding of which fields are present assumes that one of the fields is present,
 * so there is never a 0 after the H.
 */
static void xdot_begin_anchor(GVJ_t * job, char *href, char *tooltip, char *target, char *id)
{
    emit_state_t emit_state = job->obj->emit_state;
    char buf[3];  /* very small integer */
    unsigned int flags = 0;

    agxbput(xbufs[emit_state], "H ");
    if (href)
	flags |= 1;
    if (tooltip)
	flags |= 2;
    if (target)
	flags |= 4;
    sprintf (buf, "%d ", flags);
    agxbput(xbufs[emit_state], buf);
    if (href)
	xdot_str (job, "", href);
    if (tooltip)
	xdot_str (job, "", tooltip);
    if (target)
	xdot_str (job, "", target);
}
/* Returns the font corresponding to a Graphviz PS font. 
   AvantGarde-Book may return URW Gothic L, book
   Returns NULL if no appropriate font found.
*/
static char *gv_get_font(availfont_t* gv_af_p,
		  PostscriptAlias * ps_alias, agxbuf* xb, agxbuf *xb2)
{
    char *avail_faces;
    int i;

    for (i = 0; i < GV_FONT_LIST_SIZE; i++) {
	/* Searches the array of available system fonts for the one that
	   corresponds to the current Graphviz PS font name. Sets up the
	   font string with the available font name and the installed font 
	   faces that match what are required by the Graphviz PS font.
	 */
	if (gv_af_p[i].faces && strstr(ps_alias->name, gv_af_p[i].gv_ps_fontname)) {
	    agxbput(xb2, gv_af_p[i].fontname);
	    agxbput(xb2, ", ");
	    avail_faces = get_avail_faces(gv_af_p[i].faces, xb);
	    if (ps_alias->weight) {
		if (strcasestr(avail_faces, ps_alias->weight)) {
		    agxbputc(xb2, ' ');
		    copyUpper(xb2, ps_alias->weight);
		}
	    } else if (strcasestr(avail_faces, "REGULAR")) {
		agxbputc(xb2, ' ');
		agxbput(xb2, "REGULAR");
	    } else if (strstr(avail_faces, "ROMAN")) {
		agxbputc(xb2, ' ');
		agxbput(xb2, "ROMAN");
	    }
	    if (ps_alias->stretch) {
		if (strcasestr(avail_faces, ps_alias->stretch)) {
		    agxbputc(xb2, ' ');
		    copyUpper(xb2, ps_alias->stretch);
		}
	    }
	    if (ps_alias->style) {
		if (strcasestr(avail_faces, ps_alias->style)) {
		    agxbputc(xb2, ' ');
		    copyUpper(xb2, ps_alias->style);
		} else if (!strcasecmp(ps_alias->style, "ITALIC")) {
                    /* try to use ITALIC in place of OBLIQUE & visa versa */
		    if (strcasestr(avail_faces, "OBLIQUE")) {
			agxbputc(xb2, ' ');
			agxbput(xb2, "OBLIQUE");
		    }
		} else if (!strcasecmp(ps_alias->style, "OBLIQUE")) {
		    if (strcasestr(avail_faces, "ITALIC")) {
			agxbputc(xb2, ' ');
			agxbput(xb2, "ITALIC");
		    }
		}
	    }
	    return strdup(agxbuse(xb2));
	}
    }
    return NULL;
}
static void xdot_ellipse(GVJ_t * job, pointf * A, int filled)
{
    emit_state_t emit_state = job->obj->emit_state;

    char buf[BUFSIZ];

    xdot_style (job);
    xdot_pencolor (job);
    if (filled) {
	if ((filled == GRADIENT) || (filled == RGRADIENT)) {
	   xdot_gradient_fillcolor (job, filled, A, 2);
	}
        else 
	    xdot_fillcolor (job);
        agxbput(xbufs[emit_state], "E ");
    }
    else
        agxbput(xbufs[emit_state], "e ");
    xdot_point(xbufs[emit_state], A[0]);
    xdot_fmt_num (buf, A[1].x - A[0].x);
    agxbput(xbufs[emit_state], buf);
    xdot_fmt_num (buf, A[1].y - A[0].y);
    agxbput(xbufs[emit_state], buf);
}
示例#23
0
static void global_def(agxbuf* xb, char *dcl, int kind,
         attrsym_t * ((*dclfun) (Agraph_t *, int kind, char *, char *)) )
{
    char *p;
    char *rhs = "true";

    attrsym_t *sym;
    if ((p = strchr(dcl, '='))) {
	agxbput_n (xb, dcl, p-dcl);
        rhs = p+1;
    }
    else
	agxbput (xb, dcl);
    sym = dclfun(NULL, kind, agxbuse (xb), rhs);
    sym->fixed = 1;
}
示例#24
0
文件: output.c 项目: Chaduke/bah.mod
static void set_record_rects(node_t * n, field_t * f, agxbuf * xb)
{
    int i;
    char buf[BUFSIZ];

    if (f->n_flds == 0) {
	sprintf(buf, "%d,%d,%d,%d ",
		f->b.LL.x + ND_coord_i(n).x,
		YDIR(f->b.LL.y + ND_coord_i(n).y),
		f->b.UR.x + ND_coord_i(n).x,
		YDIR(f->b.UR.y + ND_coord_i(n).y));
	agxbput(xb, buf);
    }
    for (i = 0; i < f->n_flds; i++)
	set_record_rects(n, f->fld[i], xb);
}
示例#25
0
static void xd_textline(point p, textline_t * line)
{
    char buf[BUFSIZ];
    int j;

    switch (line->just) {
    case 'l':
	j = -1;
	break;
    case 'r':
	j = 1;
	break;
    default:
    case 'n':
	j = 0;
	break;
    }
    sprintf(buf, "T %d %d %d %d ", p.x, YDIR(p.y), j, (int) line->width);
    agxbput(xbufs[gvc->emit_state], buf);
    xd_str ("", line->str);
}
static void xdot_textspan(GVJ_t * job, pointf p, textspan_t * span)
{
    emit_state_t emit_state = job->obj->emit_state;
    int flags;
    char buf[BUFSIZ];
    int j;
    
    agxbput(xbufs[emit_state], "F ");
    xdot_fmt_num (buf, span->font->size);
    agxbput(xbufs[emit_state], buf);
    xdot_str (job, "", span->font->name);
    xdot_pencolor(job);

    switch (span->just) {
    case 'l':
        j = -1; 
        break;
    case 'r':
        j = 1;
        break;
    default:
    case 'n':
        j = 0;
        break;
    }
    if (span->font)
	flags = span->font->flags;
    else
	flags = 0;
    if (xd->version >= 15) {
	unsigned int mask = (xd->version >= 16?0x3F:0x1F);
	unsigned int bits = flags & mask;
	if (textflags[emit_state] != bits) {
	    sprintf (buf, "t %d ", bits);
	    agxbput(xbufs[emit_state], buf);
	    textflags[emit_state] = bits;
	}
    }

    p.y += span->yoffset_centerline;
    agxbput(xbufs[emit_state], "T ");
    xdot_point(xbufs[emit_state], p);
    sprintf(buf, "%d ", j);
    agxbput(xbufs[emit_state], buf);
    xdot_fmt_num (buf, span->size.x);
    agxbput(xbufs[emit_state], buf);
    xdot_str (job, "", span->str);
}
示例#27
0
/* scanEntity:
 * Scan non-numeric entity, convert to &#...; form and store in xbuf.
 * t points to first char after '&'. Return after final semicolon.
 * If unknown, we return t and let libexpat flag the error.
 *     */
char* scanEntity (char* t, agxbuf* xb)
{
    char*  endp = strchr (t, ';');
    struct entities_s key, *res;
    int    len;
    char   buf[MAXENTLEN+1];

    agxbputc(xb, '&');
    if (!endp) return t;
    if (((len = endp-t) > MAXENTLEN) || (len < 2)) return t;
    strncpy (buf, t, len);
    buf[len] = '\0';
    key.name =  buf;
    res = bsearch(&key, entities, NR_OF_ENTITIES,
        sizeof(entities[0]), comp_entities);
    if (!res) return t;
    sprintf (buf, "%d", res->value);
    agxbputc(xb, '#');
    agxbput(xb, buf);
    agxbputc(xb, ';');
    return (endp+1);
}
示例#28
0
static char *nameOf(void *obj, agxbuf * xb)
{
    Agedge_t *ep;
    switch (agobjkind(obj)) {
    case AGGRAPH:
	agxbput(xb, ((Agraph_t *) obj)->name);
	break;
    case AGNODE:
	agxbput(xb, ((Agnode_t *) obj)->name);
	break;
    case AGEDGE:
	ep = (Agedge_t *) obj;
	agxbput(xb, ep->tail->name);
	agxbput(xb, ep->head->name);
	if (AG_IS_DIRECTED(ep->tail->graph))
	    agxbput(xb, "->");
	else
	    agxbput(xb, "--");
	break;
    }
    return agxbuse(xb);
}
示例#29
0
文件: output.c 项目: Chaduke/bah.mod
void output_point(agxbuf *xbuf, pointf p)
{
    char buf[BUFSIZ];
    sprintf(buf, "%d %d ", ROUND(p.x), YDIR(ROUND(p.y)));
    agxbput(xbuf, buf);
}
示例#30
0
文件: output.c 项目: Chaduke/bah.mod
void attach_attrs_and_arrows(graph_t* g, int* sp, int* ep)
{
    int e_arrows;		/* graph has edges with end arrows */
    int s_arrows;		/* graph has edges with start arrows */
    int i, j, sides;
    char buf[BUFSIZ];		/* Used only for small strings */
    unsigned char xbuffer[BUFSIZ];	/* Initial buffer for xb */
    agxbuf xb;
    node_t *n;
    edge_t *e;
    point pt;

    e_arrows = s_arrows = 0;
    setYInvert(g);
    agxbinit(&xb, BUFSIZ, xbuffer);
    safe_dcl(g, g->proto->n, "pos", "", agnodeattr);
    safe_dcl(g, g->proto->n, "rects", "", agnodeattr);
    N_width = safe_dcl(g, g->proto->n, "width", "", agnodeattr);
    N_height = safe_dcl(g, g->proto->n, "height", "", agnodeattr);
    safe_dcl(g, g->proto->e, "pos", "", agedgeattr);
    if (GD_has_labels(g) & EDGE_LABEL)
	safe_dcl(g, g->proto->e, "lp", "", agedgeattr);
    if (GD_has_labels(g) & HEAD_LABEL)
	safe_dcl(g, g->proto->e, "head_lp", "", agedgeattr);
    if (GD_has_labels(g) & TAIL_LABEL)
	safe_dcl(g, g->proto->e, "tail_lp", "", agedgeattr);
    if (GD_label(g)) {
	safe_dcl(g, g, "lp", "", agraphattr);
	if (GD_label(g)->text[0]) {
	    pt = GD_label(g)->p;
	    sprintf(buf, "%d,%d", pt.x, YDIR(pt.y));
	    agset(g, "lp", buf);
	}
    }
    safe_dcl(g, g, "bb", "", agraphattr);
    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
	sprintf(buf, "%d,%d", ND_coord_i(n).x, YDIR(ND_coord_i(n).y));
	agset(n, "pos", buf);
	sprintf(buf, "%.2f", PS2INCH(ND_ht_i(n)));
	agxset(n, N_height->index, buf);
	sprintf(buf, "%.2f", PS2INCH(ND_lw_i(n) + ND_rw_i(n)));
	agxset(n, N_width->index, buf);
	if (strcmp(ND_shape(n)->name, "record") == 0) {
	    set_record_rects(n, ND_shape_info(n), &xb);
	    agxbpop(&xb);	/* get rid of last space */
	    agset(n, "rects", agxbuse(&xb));
	} else {
	    polygon_t *poly;
	    int i;
	    if (N_vertices && isPolygon(n)) {
		poly = (polygon_t *) ND_shape_info(n);
		sides = poly->sides;
		if (sides < 3) {
		    char *p = agget(n, "samplepoints");
		    if (p)
			sides = atoi(p);
		    else
			sides = 8;
		    if (sides < 3)
			sides = 8;
		}
		for (i = 0; i < sides; i++) {
		    if (i > 0)
			agxbputc(&xb, ' ');
		    if (poly->sides >= 3)
			sprintf(buf, "%.3f %.3f",
				PS2INCH(poly->vertices[i].x),
				YFDIR(PS2INCH(poly->vertices[i].y)));
		    else
			sprintf(buf, "%.3f %.3f",
				ND_width(n) / 2.0 * cos(i /
							(double) sides *
							PI * 2.0),
				YFDIR(ND_height(n) / 2.0 *
				   sin(i / (double) sides * PI * 2.0)));
		    agxbput(&xb, buf);
		}
		agxset(n, N_vertices->index, agxbuse(&xb));
	    }
	}
	if (State >= GVSPLINES) {
	    for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
		if (ED_edge_type(e) == IGNORED)
		    continue;
		if (ED_spl(e) == NULL)
		    continue;	/* reported in postproc */
		for (i = 0; i < ED_spl(e)->size; i++) {
		    if (i > 0)
			agxbputc(&xb, ';');
		    if (ED_spl(e)->list[i].sflag) {
			s_arrows = 1;
			sprintf(buf, "s,%d,%d ",
				ED_spl(e)->list[i].sp.x,
				YDIR(ED_spl(e)->list[i].sp.y));
			agxbput(&xb, buf);
		    }
		    if (ED_spl(e)->list[i].eflag) {
			e_arrows = 1;
			sprintf(buf, "e,%d,%d ",
				ED_spl(e)->list[i].ep.x,
				YDIR(ED_spl(e)->list[i].ep.y));
			agxbput(&xb, buf);
		    }
		    for (j = 0; j < ED_spl(e)->list[i].size; j++) {
			if (j > 0)
			    agxbputc(&xb, ' ');
			pt = ED_spl(e)->list[i].list[j];
			sprintf(buf, "%d,%d", pt.x, YDIR(pt.y));
			agxbput(&xb, buf);
		    }
		}
		agset(e, "pos", agxbuse(&xb));
		if (ED_label(e)) {
		    pt = ED_label(e)->p;
		    sprintf(buf, "%d,%d", pt.x, YDIR(pt.y));
		    agset(e, "lp", buf);
		}
		if (ED_head_label(e)) {
		    pt = ED_head_label(e)->p;
		    sprintf(buf, "%d,%d", pt.x, YDIR(pt.y));
		    agset(e, "head_lp", buf);
		}
		if (ED_tail_label(e)) {
		    pt = ED_tail_label(e)->p;
		    sprintf(buf, "%d,%d", pt.x, YDIR(pt.y));
		    agset(e, "tail_lp", buf);
		}
	    }
	}
    }
    rec_attach_bb(g);
    agxbfree(&xb);

    if (HAS_CLUST_EDGE(g))
	undoClusterEdges(g);
    
    *sp = s_arrows;
    *ep = e_arrows;
}