Skip to content

Instantly share code, notes, and snippets.

@steveroush
Created May 30, 2026 03:23
Show Gist options
  • Select an option

  • Save steveroush/a5d1e9332f4f0ef5a5ea9cc0442cbd15 to your computer and use it in GitHub Desktop.

Select an option

Save steveroush/a5d1e9332f4f0ef5a5ea9cc0442cbd15 to your computer and use it in GitHub Desktop.
gvEd.gvpr - a partial macro feature for Graphviz
/********************************************************************
gvEd.gvpr - edit Graphviz attributes
gvEd.gvpr provides a partial macro-like capability to Graphviz
- a pseudo attribute/macro can be defined and then referenced
in the value component of later attribute references
usage:
gvpr -cf gvEd.gvpr
gvpr -a "Pxx" -cf gvEd.gvpr myfile.gv # macro names must begin with xx
********************************************************************/
BEGIN{
graph_t Root;
int i, j;
string editedStr, attName1, attVal1, attName2, attVal2, objType;
string attsN[], attsE[], attsG[], attsThisOType[];
string lbltype[int], oType, aName, Prefix;
string help;
help=" USAGE:
gvpr -cf gvEd.gvpr # report & reformatted input
gvpr -a 'Pxx' -cf gvEd.gvpr myfile.gv # macronames must begin with xx
";
int legalName[];
legalName["Damping"] = 1;
legalName["K"] = 1;
legalName["TBbalance"] = 1;
legalName["URL"] = 1;
legalName["Attributes"] = 1;
legalName["area"] = 1;
legalName["arrowhead"] = 1;
legalName["arrowsize"] = 1;
legalName["arrowtail"] = 1;
legalName["_background"] = 1;
legalName["bb"] = 1;
legalName["beautify"] = 1;
legalName["bgcolor"] = 1;
legalName["center"] = 1;
legalName["charset"] = 1;
legalName["class"] = 1;
legalName["cluster"] = 1;
legalName["clusterrank"] = 1;
legalName["color"] = 1;
legalName["colorscheme"] = 1;
legalName["comment"] = 1;
legalName["compound"] = 1;
legalName["concentrate"] = 1;
legalName["constraint"] = 1;
legalName["decorate"] = 1;
legalName["defaultdist"] = 1;
legalName["dim"] = 1;
legalName["dimen"] = 1;
legalName["dir"] = 1;
legalName["diredgeconstraints"] = 1;
legalName["distortion"] = 1;
legalName["dpi"] = 1;
legalName["edgeURL"] = 1;
legalName["edgehref"] = 1;
legalName["edgetarget"] = 1;
legalName["edgetooltip"] = 1;
legalName["epsilon"] = 1;
legalName["esep"] = 1;
legalName["fillcolor"] = 1;
legalName["fixedsize"] = 1;
legalName["fontcolor"] = 1;
legalName["fontname"] = 1;
legalName["fontnames"] = 1;
legalName["fontpath"] = 1;
legalName["fontsize"] = 1;
legalName["forcelabels"] = 1;
legalName["gradientangle"] = 1;
legalName["group"] = 1;
legalName["headURL"] = 1;
legalName["head_lp"] = 1;
legalName["headclip"] = 1;
legalName["headhref"] = 1;
legalName["headlabel"] = 1;
legalName["headport"] = 1;
legalName["headtarget"] = 1;
legalName["headtooltip"] = 1;
legalName["height"] = 1;
legalName["href"] = 1;
legalName["id"] = 1;
legalName["image"] = 1;
legalName["imagepath"] = 1;
legalName["imagepos"] = 1;
legalName["imagescale"] = 1;
legalName["inputscale"] = 1;
legalName["label"] = 1;
legalName["labelURL"] = 1;
legalName["label_scheme"] = 1;
legalName["labelangle"] = 1;
legalName["labeldistance"] = 1;
legalName["labelfloat"] = 1;
legalName["labelfontcolor"] = 1;
legalName["labelfontname"] = 1;
legalName["labelfontsize"] = 1;
legalName["labelhref"] = 1;
legalName["labeljust"] = 1;
legalName["labelloc"] = 1;
legalName["labeltarget"] = 1;
legalName["labeltooltip"] = 1;
legalName["landscape"] = 1;
legalName["layer"] = 1;
legalName["layerlistsep"] = 1;
legalName["layers"] = 1;
legalName["layerselect"] = 1;
legalName["layersep"] = 1;
legalName["layout"] = 1;
legalName["len"] = 1;
legalName["levels"] = 1;
legalName["levelsgap"] = 1;
legalName["lhead"] = 1;
legalName["lheight"] = 1;
legalName["linelength"] = 1;
legalName["lp"] = 1;
legalName["ltail"] = 1;
legalName["lwidth"] = 1;
legalName["margin"] = 1;
legalName["maxiter"] = 1;
legalName["mclimit"] = 1;
legalName["mindist"] = 1;
legalName["minlen"] = 1;
legalName["mode"] = 1;
legalName["model"] = 1;
legalName["newrank"] = 1;
legalName["nodesep"] = 1;
legalName["nojustify"] = 1;
legalName["normalize"] = 1;
legalName["notranslate"] = 1;
legalName["nslimit"] = 1;
legalName["nslimit1"] = 1;
legalName["oneblock"] = 1;
legalName["ordering"] = 1;
legalName["orientation"] = 1;
legalName["outputorder"] = 1;
legalName["overlap"] = 1;
legalName["overlap_scaling"] = 1;
legalName["overlap_shrink"] = 1;
legalName["pack"] = 1;
legalName["packmode"] = 1;
legalName["pad"] = 1;
legalName["page"] = 1;
legalName["pagedir"] = 1;
legalName["pencolor"] = 1;
legalName["penwidth"] = 1;
legalName["peripheries"] = 1;
legalName["pin"] = 1;
legalName["pos"] = 1;
legalName["quadtree"] = 1;
legalName["quantum"] = 1;
legalName["rank"] = 1;
legalName["rankdir"] = 1;
legalName["ranksep"] = 1;
legalName["ratio"] = 1;
legalName["rects"] = 1;
legalName["regular"] = 1;
legalName["remincross"] = 1;
legalName["repulsiveforce"] = 1;
legalName["resolution"] = 1;
legalName["root"] = 1;
legalName["rotate"] = 1;
legalName["rotation"] = 1;
legalName["samehead"] = 1;
legalName["sametail"] = 1;
legalName["samplepoints"] = 1;
legalName["scale"] = 1;
legalName["searchsize"] = 1;
legalName["sep"] = 1;
legalName["shape"] = 1;
legalName["shapefile"] = 1;
legalName["showboxes"] = 1;
legalName["sides"] = 1;
legalName["size"] = 1;
legalName["skew"] = 1;
legalName["smoothing"] = 1;
legalName["sortv"] = 1;
legalName["splines"] = 1;
legalName["start"] = 1;
legalName["style"] = 1;
legalName["stylesheet"] = 1;
legalName["tailURL"] = 1;
legalName["tail_lp"] = 1;
legalName["tailclip"] = 1;
legalName["tailhref"] = 1;
legalName["taillabel"] = 1;
legalName["tailport"] = 1;
legalName["tailtarget"] = 1;
legalName["tailtooltip"] = 1;
legalName["target"] = 1;
legalName["tooltip"] = 1;
legalName["truecolor"] = 1;
legalName["vertices"] = 1;
legalName["viewport"] = 1;
legalName["voro_margin"] = 1;
legalName["weight"] = 1;
legalName["width"] = 1;
legalName["xdotversion"] = 1;
legalName["xlabel"] = 1;
legalName["xlp"] = 1;
legalName["z"] = 1;
lbltype[0]="label";
lbltype[1]="xlabel";
lbltype[2]="taillabel";
lbltype[3]="headlabel";
//////////////////////////////////////////////////////////////////////
void editObj(obj_t thisO){
int isHTML;
objType=kindOf(thisO);
print(" editObj thisO: ", thisO, " (", objType,")");
unset(attsThisOType);
// string attsN[], attsE[], attsG[], attsThisOType[];
if (objType=="N"){
for (attsN[i])
attsThisOType[i]=attsN[i];
}else if (objType=="E"){
for (attsE[i])
attsThisOType[i]=attsE[i];
}else{
for (attsG[i])
attsThisOType[i]=attsG[i];
}
for (attsThisOType[i]){
attName1=attsThisOType[i];
print(" checking attribute: ", attName1);
if (legalName[attName1]==1) {
print(" defined ATTR (skip) >", attName1, "<");
} else if (index(attName1,Prefix)!=0) {
print(" missing Prefix ATTR (skip) >", attName1, "< >",Prefix,"<");
} else { // possible macro
if (hasAttr(thisO, attName1)) { // does not help or hurt??
attVal1=aget(thisO, attName1);
print(" macro ATTR >", attName1, "< >", attVal1, "<");
if (attVal1!="xxxxxxxxxxx") { // if macro has a value != ""
for (attsThisOType[j]){
attName2=attsThisOType[j];
if (legalName[attName2]==1) {
if (hasAttr(thisO, attName2)) { // does not help or hurt??
attVal2=aget(thisO, attName2);
Root.WorkStr=aget(thisO, attName2);
attVal2=Root.WorkStr;
isHTML=ishtml(Root.WorkStr); // NOTE: ishtml(attVal2) fails !!??
print(" Root.WorkStr ishtml: ", isHTML, " ", Root.WorkStr);
print(" ATTR edit >", attName2,"< >", attName1,"< ++", attVal2, "++");
if (isHTML!=0)
print(" HTML ", attVal2);
else
print(" not HTML", attVal2);
//if (attVal1 != "" && index(attVal2, attName1)>=0) {
if (index(attVal2, attName1)>=0) {
print(" MATCH : ", attVal2, " ", attName1);
editedStr=gsub(attVal2, attName1, attVal1);
print(" EDITED >", editedStr,"<");
print(" html check:", attVal2);
if (isHTML) {
print(" treat as HTML");
Root.htmlWrk2=html(Root, editedStr);
aset(thisO, attName2, Root.htmlWrk2);
}else{
aset(thisO, attName2, editedStr);
}
}
}
}
}
}
}
}
}
}
//////////////////////////////////////////////////////////////////////
graph_t graphTraverse(graph_t thisGraph) {
graph_t aGraph;
editObj(thisGraph);
for (aGraph = fstsubg(thisGraph); aGraph; aGraph = nxtsubg(aGraph)) {
editObj(aGraph);
}
return thisGraph;
}
} // END OF BEGIN
BEG_G{
Root=$G;
print("/***********************************************************************");
print("gvEd.gvpr output:");
print("");
print(" debugging:");
/////////////////////////////////////////////////////////////////////////////////////////////////
oType="G";
i=0;
for (aName = fstAttr(Root, oType); aName != ""; aName = nxtAttr(Root, oType, aName))
attsG[i++]=aName;
oType="N";
i=0;
for (aName = fstAttr(Root, oType); aName != ""; aName = nxtAttr(Root, oType, aName))
attsN[i++]=aName;
oType="E";
i=0;
for (aName = fstAttr(Root, oType); aName != ""; aName = nxtAttr(Root, oType, aName))
attsE[i++]=aName;
/////////////////////////////////////////////////////////////////////////////////////////////////
i=0;
Prefix="";
while (i<ARGC) {
print(" ARG >", ARGV[i],"<");
if (ARGV[i]=="P") {
Prefix=ARGV[++i];
} else if (ARGV[i]=="P*") {
Prefix=substr(ARGV[i],1);
} else {
printf(2, help);
exit (1);
}
print(" Prefix >",Prefix,"<");
i++;
}
graphTraverse($G);
}
N{
editObj($);
}
E{
editObj($);
}
END_G{
print(" end of debugging output");
print("*******************************************************************/");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment