├── .gitattributes ├── .github └── workflows │ └── go.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── _examples ├── rw.go └── simple.go ├── alias.go ├── buf.gen.yaml ├── buf.work.yaml ├── cdt ├── cdt.go └── link.go ├── cgraph ├── attribute.go ├── cgraph.go ├── init.go └── link.go ├── cmd └── dot │ ├── dot.go │ ├── go.mod │ └── go.sum ├── compatible_test.go ├── go.mod ├── go.sum ├── graphviz.go ├── graphviz.version ├── graphviz_test.go ├── gvc ├── device_plugin.go ├── gvc.go ├── image_plugin.go ├── image_renderer.go ├── init.go ├── link.go ├── plugin.go └── render_plugin.go ├── internal ├── tools │ └── nori │ │ ├── Makefile │ │ ├── buf.gen.yaml │ │ ├── buf.work.yaml │ │ ├── cmd │ │ └── protoc-gen-nori │ │ │ └── main.go │ │ ├── generate_c.go │ │ ├── generate_go.go │ │ ├── generator.go │ │ ├── go.mod │ │ ├── go.sum │ │ ├── nori │ │ └── nori.pb.go │ │ ├── nori_test.go │ │ ├── proto │ │ └── nori │ │ │ └── nori.proto │ │ ├── protocompiler.go │ │ └── templates │ │ ├── bind.c.tmpl │ │ └── bind.go.tmpl └── wasm │ ├── bind.go │ ├── bind.proto │ ├── build │ ├── Dockerfile │ ├── Makefile │ ├── bind.c │ └── patch.c │ ├── ext.go │ └── graphviz.wasm ├── option.go └── testdata ├── .gitignore ├── directed ├── KW91.gv ├── Latin1.gv ├── NaN.gv ├── abstract.gv ├── alf.gv ├── arrows.gv ├── awilliams.gv ├── biological.gv ├── clust.gv ├── clust1.gv ├── clust2.gv ├── clust3.gv ├── clust4.gv ├── clust5.gv ├── crazy.gv ├── ctext.gv ├── dfa.gv ├── fig6.gv ├── fsm.gv ├── grammar.gv ├── hashtable.gv ├── honda-tokoro.gv ├── japanese.gv ├── jcctree.gv ├── jsort.gv ├── ldbxtried.gv ├── longflat.gv ├── mike.gv ├── nhg.gv ├── oldarrows.gv ├── pgram.gv ├── pm2way.gv ├── pmpipe.gv ├── polypoly.gv ├── proc3d.gv ├── psfonttest.gv ├── record2.gv ├── records.gv ├── rowe.gv ├── russian.gv ├── sdh.gv ├── shells.gv ├── states.gv ├── structs.gv ├── switch.gv ├── table.gv ├── train11.gv ├── trapeziumlr.gv ├── tree.gv ├── triedds.gv ├── try.gv ├── unix.gv ├── unix2.gv ├── viewfile.gv └── world.gv ├── imagehash.json ├── logo.png └── undirected ├── ER.gv ├── Heawood.gv ├── Petersen.gv ├── ngk10_4.gv └── process.gv /.gitattributes: -------------------------------------------------------------------------------- 1 | internal/** linguist-documentation 2 | -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | jobs: 8 | build: 9 | name: Test 10 | strategy: 11 | matrix: 12 | os: [ubuntu-latest, windows-latest, macos-latest] 13 | go-version: [ "1.22.0", "1.23" ] 14 | runs-on: ${{ matrix.os }} 15 | steps: 16 | - name: checkout 17 | uses: actions/checkout@v4 18 | - name: setup Go ${{ matrix.go-version }} 19 | uses: actions/setup-go@v4 20 | with: 21 | go-version: ${{ matrix.go-version }} 22 | - name: build dot command 23 | run: cd ./cmd/dot && go build -v . 24 | - name: test 25 | if: ${{ matrix.os != 'windows-latest' }} 26 | run: go test -race -v ./... 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.svg 3 | *.png 4 | *.jpg 5 | .DS_Store 6 | bin 7 | internal/wasm/build/graphviz 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Masaaki Goshima 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | export 2 | 3 | CONTAINER_NAME := graphviz-wasm 4 | IMAGE_NAME := graphviz-wasm 5 | GOBIN := $(PWD)/bin 6 | PATH := $(GOBIN):internal/tools/nori/bin:$(PATH) 7 | 8 | .PHONY: tools 9 | tools: nori 10 | go install github.com/bufbuild/buf/cmd/buf@v1.32.2 11 | 12 | fmt/buf: 13 | buf format --write 14 | 15 | generate/wasm: container/build 16 | $(eval CONTAINER_ID := $(shell docker create graphviz-wasm)) 17 | docker cp "$(CONTAINER_ID):/work/graphviz.wasm" ./internal/wasm/graphviz.wasm 18 | 19 | container/build: 20 | docker build ./internal/wasm/build -t $(IMAGE_NAME) --build-arg GRAPHVIZ_VERSION=$(shell cat graphviz.version) 21 | 22 | container/prune: 23 | docker container prune 24 | 25 | .PHONY: generate/buf 26 | generate/buf: 27 | $(GOBIN)/buf generate 28 | mv bind.c internal/wasm/build 29 | mv bind.go internal/wasm/ 30 | 31 | .PHONY: nori 32 | nori: 33 | make build -C ./internal/tools/nori 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-graphviz [![Go](https://github.com/goccy/go-graphviz/workflows/Go/badge.svg)](https://github.com/goccy/go-graphviz/actions) [![GoDoc](https://godoc.org/github.com/goccy/go-graphviz?status.svg)](https://pkg.go.dev/github.com/goccy/go-graphviz) 2 | 3 | Go bindings for Graphviz 4 | 5 | 6 | 7 | # Features 8 | 9 | Graphviz version is [here](./graphviz.version) 10 | 11 | - Pure Go Library 12 | - No need to install Graphviz library ( ~`brew install graphviz`~ or ~`apt-get install graphviz`~ ) 13 | - The Graphviz library has been converted to WebAssembly (WASM) and embedded it, so it works consistently across all environments 14 | - Supports encoding/decoding for DOT language 15 | - Supports custom renderer for custom format 16 | - Supports setting graph properties in a type-safe manner 17 | 18 | ## Supported Layout 19 | 20 | `circo` `dot` `fdp` `neato` `nop` `nop1` `nop2` `osage` `patchwork` `sfdp` `twopi` 21 | 22 | ## Supported Format 23 | 24 | `dot` `svg` `png` `jpg` 25 | 26 | The above are the formats supported by default. You can also add custom formats. 27 | 28 | # Installation 29 | 30 | ```bash 31 | $ go get github.com/goccy/go-graphviz 32 | ``` 33 | 34 | # Synopsis 35 | 36 | ## 1. Write DOT Graph in Go 37 | 38 | ```go 39 | package main 40 | 41 | import ( 42 | "bytes" 43 | "fmt" 44 | "log" 45 | 46 | "github.com/goccy/go-graphviz" 47 | ) 48 | 49 | func main() { 50 | ctx := context.Background() 51 | g, err := graphviz.New(ctx) 52 | if err != nil { panic(err )} 53 | 54 | graph, err := g.Graph() 55 | if err != nil { panic(err) } 56 | defer func() { 57 | if err := graph.Close(); err != nil { panic(err) } 58 | g.Close() 59 | }() 60 | n, err := graph.CreateNodeByName("n") 61 | if err != nil { panic(err) } 62 | 63 | m, err := graph.CreateNodeByName("m") 64 | if err != nil { panic(err) } 65 | 66 | e, err := graph.CreateEdgeByName("e", n, m) 67 | if err != nil { panic(err) } 68 | e.SetLabel("e") 69 | 70 | var buf bytes.Buffer 71 | if err := g.Render(ctx, graph, "dot", &buf); err != nil { 72 | log.Fatal(err) 73 | } 74 | fmt.Println(buf.String()) 75 | } 76 | ``` 77 | 78 | ## 2. Parse DOT Graph 79 | 80 | ```go 81 | path := "/path/to/dot.gv" 82 | b, err := os.ReadFile(path) 83 | if err != nil { panic(err) } 84 | graph, err := graphviz.ParseBytes(b) 85 | ``` 86 | 87 | ## 3. Render Graph 88 | 89 | ```go 90 | ctx := context.Background() 91 | g, err := graphviz.New(ctx) 92 | if err != nil { panic(err) } 93 | 94 | graph, err := g.Graph() 95 | if err != nil { panic(err) } 96 | 97 | // create your graph 98 | 99 | // 1. write encoded PNG data to buffer 100 | var buf bytes.Buffer 101 | if err := g.Render(ctx, graph, graphviz.PNG, &buf); err != nil { panic(err) } 102 | 103 | // 2. get as image.Image instance 104 | image, err := g.RenderImage(ctx, graph) 105 | if err != nil { panic(err) } 106 | 107 | // 3. write to file directly 108 | if err := g.RenderFilename(ctx, graph, graphviz.PNG, "/path/to/graph.png"); err != nil { panic(err) } 109 | ``` 110 | 111 | # Tool 112 | 113 | ## `dot` 114 | 115 | ### Installation 116 | 117 | ```bash 118 | $ go install github.com/goccy/go-graphviz/cmd/dot@latest 119 | ``` 120 | 121 | ### Usage 122 | 123 | ``` 124 | Usage: 125 | dot [OPTIONS] 126 | 127 | Application Options: 128 | -T= specify output format ( currently supported: dot svg png jpg ) (default: dot) 129 | -K= specify layout engine ( currently supported: circo dot fdp neato nop nop1 nop2 osage patchwork sfdp twopi ) 130 | -o= specify output file name 131 | 132 | Help Options: 133 | -h, --help Show this help message 134 | ``` 135 | 136 | # How it works 137 | 138 | 1. Generates bindings between Go and C from [Protocol Buffers file](./internal/wasm/bind.proto). 139 | 2. Builds graphviz.wasm on the [docker container](./internal/wasm/build/Dockerfile). 140 | 3. Uses Graphviz functionality from a sub-packages ( `cdt` `cgraph` `gvc` ) via the `internal/wasm` package. 141 | 4. `graphviz` package provides facade interface for all sub packages. 142 | 143 | # License 144 | 145 | MIT 146 | 147 | This library embeds and uses `graphviz.wasm`, which is generated based on the original source code of Graphviz. Therefore, the `graphviz.wasm` follows [the license adopted by Graphviz](https://graphviz.org/license) ( Eclipse Public License ). 148 | -------------------------------------------------------------------------------- /_examples/rw.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "log" 7 | 8 | "github.com/goccy/go-graphviz" 9 | ) 10 | 11 | func renderDOTGraph(ctx context.Context) ([]byte, error) { 12 | g, err := graphviz.New(ctx) 13 | if err != nil { 14 | return nil, err 15 | } 16 | graph, err := g.Graph() 17 | if err != nil { 18 | return nil, err 19 | } 20 | defer func() { 21 | if err := graph.Close(); err != nil { 22 | log.Fatal(err) 23 | } 24 | g.Close() 25 | }() 26 | n, err := graph.CreateNodeByName("n") 27 | if err != nil { 28 | return nil, err 29 | } 30 | m, err := graph.CreateNodeByName("m") 31 | if err != nil { 32 | return nil, err 33 | } 34 | e, err := graph.CreateEdgeByName("e", n, m) 35 | if err != nil { 36 | return nil, err 37 | } 38 | e.SetLabel("e") 39 | var buf bytes.Buffer 40 | if err := g.Render(ctx, graph, "dot", &buf); err != nil { 41 | return nil, err 42 | } 43 | return buf.Bytes(), nil 44 | } 45 | 46 | func _main(ctx context.Context) error { 47 | graphBytes, err := renderDOTGraph(ctx) 48 | if err != nil { 49 | return err 50 | } 51 | graph, err := graphviz.ParseBytes(graphBytes) 52 | if err != nil { 53 | return err 54 | } 55 | n, err := graph.NodeByName("n") 56 | if err != nil { 57 | return err 58 | } 59 | l, err := graph.CreateNodeByName("l") 60 | if err != nil { 61 | return err 62 | } 63 | e2, err := graph.CreateEdgeByName("e2", n, l) 64 | if err != nil { 65 | return err 66 | } 67 | e2.SetLabel("e2") 68 | g, err := graphviz.New(ctx) 69 | if err != nil { 70 | return err 71 | } 72 | defer func() { 73 | if err := graph.Close(); err != nil { 74 | log.Fatal(err) 75 | } 76 | g.Close() 77 | }() 78 | g.RenderFilename(ctx, graph, "png", "rw.png") 79 | return nil 80 | } 81 | 82 | func main() { 83 | if err := _main(context.Background()); err != nil { 84 | log.Fatalf("%+v", err) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /_examples/simple.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "fmt" 7 | "log" 8 | 9 | "github.com/goccy/go-graphviz" 10 | ) 11 | 12 | func _main(ctx context.Context) error { 13 | g, err := graphviz.New(ctx) 14 | if err != nil { 15 | return err 16 | } 17 | graph, err := g.Graph() 18 | if err != nil { 19 | return err 20 | } 21 | defer func() { 22 | if err := graph.Close(); err != nil { 23 | log.Fatal(err) 24 | } 25 | g.Close() 26 | }() 27 | n, err := graph.CreateNodeByName("n") 28 | if err != nil { 29 | return err 30 | } 31 | m, err := graph.CreateNodeByName("m") 32 | if err != nil { 33 | return err 34 | } 35 | e, err := graph.CreateEdgeByName("e", n, m) 36 | if err != nil { 37 | return err 38 | } 39 | e.SetLabel("e") 40 | var buf bytes.Buffer 41 | if err := g.Render(ctx, graph, "dot", &buf); err != nil { 42 | log.Fatalf("%+v", err) 43 | } 44 | fmt.Println(buf.String()) 45 | return nil 46 | } 47 | 48 | func main() { 49 | if err := _main(context.Background()); err != nil { 50 | log.Fatal(err) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /buf.gen.yaml: -------------------------------------------------------------------------------- 1 | version: v1 2 | managed: 3 | enabled: true 4 | plugins: 5 | - plugin: nori 6 | out: . 7 | -------------------------------------------------------------------------------- /buf.work.yaml: -------------------------------------------------------------------------------- 1 | version: v1 2 | directories: 3 | - ./internal/tools/nori/proto 4 | - internal/wasm 5 | -------------------------------------------------------------------------------- /cdt/cdt.go: -------------------------------------------------------------------------------- 1 | package cdt 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | 7 | "github.com/goccy/go-graphviz/internal/wasm" 8 | ) 9 | 10 | type Dict struct { 11 | wasm *wasm.Dict 12 | } 13 | 14 | func toDict(v *wasm.Dict) *Dict { 15 | if v == nil { 16 | return nil 17 | } 18 | return &Dict{wasm: v} 19 | } 20 | 21 | func (d *Dict) getWasm() *wasm.Dict { 22 | return d.wasm 23 | } 24 | 25 | type Hold struct { 26 | wasm *wasm.DictHold 27 | } 28 | 29 | func toHold(v *wasm.DictHold) *Hold { 30 | if v == nil { 31 | return nil 32 | } 33 | return &Hold{wasm: v} 34 | } 35 | 36 | func (h *Hold) getWasm() *wasm.DictHold { 37 | return h.wasm 38 | } 39 | 40 | type Link struct { 41 | wasm *wasm.DictLink 42 | } 43 | 44 | func toLink(v *wasm.DictLink) *Link { 45 | if v == nil { 46 | return nil 47 | } 48 | return &Link{wasm: v} 49 | } 50 | 51 | func (l *Link) getWasm() *wasm.DictLink { 52 | return l.wasm 53 | } 54 | 55 | type Method struct { 56 | wasm *wasm.DictMethod 57 | } 58 | 59 | func toMethod(v *wasm.DictMethod) *Method { 60 | if v == nil { 61 | return nil 62 | } 63 | return &Method{wasm: v} 64 | } 65 | 66 | func (m *Method) getWasm() *wasm.DictMethod { 67 | return m.wasm 68 | } 69 | 70 | type Data struct { 71 | wasm *wasm.DictData 72 | } 73 | 74 | func toData(v *wasm.DictData) *Data { 75 | if v == nil { 76 | return nil 77 | } 78 | return &Data{wasm: v} 79 | } 80 | 81 | func (d *Data) getWasm() *wasm.DictData { 82 | return d.wasm 83 | } 84 | 85 | type Disc struct { 86 | wasm *wasm.DictDisc 87 | } 88 | 89 | func toDisc(v *wasm.DictDisc) *Disc { 90 | if v == nil { 91 | return nil 92 | } 93 | return &Disc{wasm: v} 94 | } 95 | 96 | func (d *Disc) getWasm() *wasm.DictDisc { 97 | return d.wasm 98 | } 99 | 100 | type Stat struct { 101 | wasm *wasm.DictStat 102 | } 103 | 104 | func toStat(v *wasm.DictStat) *Stat { 105 | if v == nil { 106 | return nil 107 | } 108 | return &Stat{wasm: v} 109 | } 110 | 111 | func (s *Stat) getWasm() *wasm.DictStat { 112 | return s.wasm 113 | } 114 | 115 | type Search func(*Dict, any, int) any 116 | type Make func(*Dict, any, *Disc) any 117 | type Memory func(*Dict, any, uint, *Disc) any 118 | type Free func(*Dict, any, *Disc) 119 | type Compare func(*Dict, any, any, *Disc) int 120 | type Hash func(*Dict, any, *Disc) uint 121 | type Event func(*Dict, int, any, *Disc) int 122 | 123 | func StrHash(a1 any, a2 int) (uint, error) { 124 | return wasm.StrHash(context.Background(), a1, a2) 125 | } 126 | 127 | func Open(disc *Disc, mtd *Method) (*Dict, error) { 128 | res, err := wasm.NewDictWithDisc(context.Background(), disc.getWasm(), mtd.getWasm()) 129 | if err != nil { 130 | return nil, err 131 | } 132 | return toDict(res), nil 133 | } 134 | 135 | func (d *Dict) Close() error { 136 | res, err := d.wasm.Close(context.Background()) 137 | if err != nil { 138 | return err 139 | } 140 | return toError(res) 141 | } 142 | 143 | func (d *Dict) View(dict *Dict) (*Dict, error) { 144 | res, err := d.wasm.View(context.Background(), dict.getWasm()) 145 | if err != nil { 146 | return nil, err 147 | } 148 | return toDict(res), nil 149 | } 150 | 151 | func (d *Dict) Disc(disc *Disc) (*Disc, error) { 152 | res, err := d.wasm.Disc(context.Background(), disc.getWasm()) 153 | if err != nil { 154 | return nil, err 155 | } 156 | return toDisc(res), nil 157 | } 158 | 159 | func (d *Dict) Method(mtd *Method) (*Method, error) { 160 | res, err := d.wasm.Method(context.Background(), mtd.getWasm()) 161 | if err != nil { 162 | return nil, err 163 | } 164 | return toMethod(res), nil 165 | } 166 | 167 | func (d *Dict) Flatten() (*Link, error) { 168 | res, err := d.wasm.Flatten(context.Background()) 169 | if err != nil { 170 | return nil, err 171 | } 172 | return toLink(res), nil 173 | } 174 | 175 | func (d *Dict) Extract() (*Link, error) { 176 | res, err := d.wasm.Extract(context.Background()) 177 | if err != nil { 178 | return nil, err 179 | } 180 | return toLink(res), nil 181 | } 182 | 183 | func (d *Dict) Restore(link *Link) error { 184 | res, err := d.wasm.Restore(context.Background(), link.getWasm()) 185 | if err != nil { 186 | return err 187 | } 188 | return toError(res) 189 | } 190 | 191 | func (d *Dict) Walk(fn func(context.Context, *Dict, any, any) error, data any) error { 192 | // TODO 193 | res, err := d.wasm.Walk(context.Background(), wasm.CreateCallbackFunc(func(ctx context.Context, a1 any, a2 any) (int, error) { 194 | if err := fn(ctx, d, a1, a2); err != nil { 195 | return 0, err 196 | } 197 | return 0, nil 198 | }, wasm.WasmPtr(d.wasm)), data) 199 | if err != nil { 200 | return err 201 | } 202 | return toError(res) 203 | } 204 | 205 | func (d *Dict) Renew(a0 any) (any, error) { 206 | res, err := d.wasm.Renew(context.Background(), a0) 207 | if err != nil { 208 | return nil, err 209 | } 210 | return res, nil 211 | } 212 | 213 | func (d *Dict) Size() (int, error) { 214 | res, err := d.wasm.Size(context.Background()) 215 | if err != nil { 216 | return 0, err 217 | } 218 | return res, nil 219 | } 220 | 221 | func (d *Dict) Stat(a0 *Stat, a1 int) (int, error) { 222 | res, err := d.wasm.Stat(context.Background(), a0.getWasm(), a1) 223 | if err != nil { 224 | return 0, err 225 | } 226 | return res, nil 227 | } 228 | 229 | func (l *Link) Right() *Link { 230 | return toLink(l.wasm.GetRight()) 231 | } 232 | 233 | func (l *Link) SetRight(v *Link) { 234 | l.wasm.SetRight(v.getWasm()) 235 | } 236 | 237 | func (l *Link) Left() *Link { 238 | return toLink(l.wasm.GetLeft()) 239 | } 240 | 241 | func (l *Link) SetLeft(v *Link) { 242 | l.wasm.SetLeft(v.getWasm()) 243 | } 244 | 245 | func (l *Link) Hash() uint { 246 | return uint(l.wasm.GetHash()) 247 | } 248 | 249 | func (l *Link) SetHash(v uint) { 250 | l.wasm.SetHash(uint32(v)) 251 | } 252 | 253 | func toError(result int) error { 254 | if result == 0 { 255 | return nil 256 | } 257 | if e, _ := wasm.LastError(context.Background()); e != "" { 258 | return errors.New(e) 259 | } 260 | return nil 261 | } 262 | -------------------------------------------------------------------------------- /cdt/link.go: -------------------------------------------------------------------------------- 1 | package cdt 2 | 3 | import ( 4 | "github.com/goccy/go-graphviz/internal/wasm" 5 | ) 6 | 7 | func toLinkWasm(v *Link) *wasm.DictLink { 8 | if v == nil { 9 | return nil 10 | } 11 | return v.wasm 12 | } 13 | 14 | func toDictWasm(v *Dict) *wasm.Dict { 15 | if v == nil { 16 | return nil 17 | } 18 | return v.wasm 19 | } 20 | -------------------------------------------------------------------------------- /cgraph/init.go: -------------------------------------------------------------------------------- 1 | package cgraph 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/goccy/go-graphviz/internal/wasm" 7 | ) 8 | 9 | var ( 10 | Directed *Desc 11 | StrictDirected *Desc 12 | UnDirected *Desc 13 | StrictUnDirected *Desc 14 | ) 15 | 16 | func init() { 17 | if err := setGlobalVars(context.Background()); err != nil { 18 | panic(err) 19 | } 20 | } 21 | 22 | func setGlobalVars(ctx context.Context) error { 23 | // Set MAX to prevent outputting internally generated errors or warnings with agerr to the stderr. 24 | wasm.SetError(ctx, wasm.MAX) 25 | 26 | directed, err := wasm.NewGraphDescriptor(ctx) 27 | if err != nil { 28 | return err 29 | } 30 | directed.SetDirected(1) 31 | directed.SetMaingraph(1) 32 | 33 | strictDirected, err := wasm.NewGraphDescriptor(ctx) 34 | if err != nil { 35 | return err 36 | } 37 | strictDirected.SetDirected(1) 38 | strictDirected.SetStrict(1) 39 | strictDirected.SetMaingraph(1) 40 | 41 | undirected, err := wasm.NewGraphDescriptor(ctx) 42 | if err != nil { 43 | return err 44 | } 45 | undirected.SetMaingraph(1) 46 | 47 | strictUndirected, err := wasm.NewGraphDescriptor(ctx) 48 | if err != nil { 49 | return err 50 | } 51 | strictUndirected.SetStrict(1) 52 | strictUndirected.SetMaingraph(1) 53 | 54 | Directed = toDesc(directed) 55 | StrictDirected = toDesc(strictDirected) 56 | UnDirected = toDesc(undirected) 57 | StrictUnDirected = toDesc(strictUndirected) 58 | 59 | return nil 60 | } 61 | -------------------------------------------------------------------------------- /cgraph/link.go: -------------------------------------------------------------------------------- 1 | package cgraph 2 | 3 | import ( 4 | _ "unsafe" 5 | 6 | "github.com/goccy/go-graphviz/cdt" 7 | "github.com/goccy/go-graphviz/internal/wasm" 8 | ) 9 | 10 | //go:linkname toDict github.com/goccy/go-graphviz/cdt.toDict 11 | func toDict(*wasm.Dict) *cdt.Dict 12 | 13 | //go:linkname toDictWasm github.com/goccy/go-graphviz/cdt.toDictWasm 14 | func toDictWasm(*cdt.Dict) *wasm.Dict 15 | 16 | //go:linkname toDictLink github.com/goccy/go-graphviz/cdt.toLink 17 | func toDictLink(*wasm.DictLink) *cdt.Link 18 | 19 | //go:linkname toDictLinkWasm github.com/goccy/go-graphviz/cdt.toLinkWasm 20 | func toDictLinkWasm(*cdt.Link) *wasm.DictLink 21 | 22 | func toGraphWasm(v *Graph) *wasm.Graph { 23 | if v == nil { 24 | return nil 25 | } 26 | return v.wasm 27 | } 28 | -------------------------------------------------------------------------------- /cmd/dot/dot.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "io" 8 | "os" 9 | 10 | "github.com/goccy/go-graphviz" 11 | "github.com/jessevdk/go-flags" 12 | "golang.org/x/term" 13 | ) 14 | 15 | type Option struct { 16 | Format graphviz.Format `description:"specify output format ( currently supported: dot svg png jpg )" short:"T" default:"dot"` 17 | Layout graphviz.Layout `description:"specify layout engine ( currently supported: circo dot fdp neato nop nop1 nop2 osage patchwork sfdp twopi )" short:"K"` 18 | OutputFile string `description:"specify output file name" short:"o" required:"true"` 19 | } 20 | 21 | func readGraph(args []string) (*graphviz.Graph, error) { 22 | if len(args) == 0 { 23 | if term.IsTerminal(0) { 24 | return nil, errors.New("required dot file or stdin") 25 | } 26 | bytes, err := io.ReadAll(os.Stdin) 27 | if err != nil { 28 | return nil, err 29 | } 30 | return graphviz.ParseBytes(bytes) 31 | } 32 | dotFile := args[0] 33 | return graphviz.ParseFile(dotFile) 34 | } 35 | 36 | func _main(ctx context.Context, args []string, opt *Option) (e error) { 37 | graph, err := readGraph(args) 38 | if err != nil { 39 | return err 40 | } 41 | g, err := graphviz.New(ctx) 42 | if err != nil { 43 | return err 44 | } 45 | defer func() { 46 | if err := graph.Close(); err != nil { 47 | e = err 48 | } 49 | if err := g.Close(); err != nil { 50 | e = err 51 | } 52 | }() 53 | if opt.Layout != "" { 54 | g.SetLayout(opt.Layout) 55 | } 56 | return g.RenderFilename(ctx, graph, opt.Format, opt.OutputFile) 57 | } 58 | 59 | func main() { 60 | var opt Option 61 | parser := flags.NewParser(&opt, flags.Default) 62 | args, err := parser.Parse() 63 | if err != nil { 64 | return 65 | } 66 | if err := _main(context.Background(), args, &opt); err != nil { 67 | fmt.Println(err) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /cmd/dot/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/goccy/go-graphviz/cmd/dot 2 | 3 | go 1.22.0 4 | 5 | require ( 6 | github.com/goccy/go-graphviz v0.2.5 7 | github.com/jessevdk/go-flags v1.6.1 8 | golang.org/x/term v0.25.0 9 | ) 10 | 11 | require ( 12 | github.com/disintegration/imaging v1.6.2 // indirect 13 | github.com/flopp/go-findfont v0.1.0 // indirect 14 | github.com/fogleman/gg v1.3.0 // indirect 15 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect 16 | github.com/tetratelabs/wazero v1.8.1 // indirect 17 | golang.org/x/image v0.21.0 // indirect 18 | golang.org/x/sys v0.26.0 // indirect 19 | golang.org/x/text v0.19.0 // indirect 20 | ) 21 | -------------------------------------------------------------------------------- /cmd/dot/go.sum: -------------------------------------------------------------------------------- 1 | github.com/corona10/goimagehash v1.1.0 h1:teNMX/1e+Wn/AYSbLHX8mj+mF9r60R1kBeqE9MkoYwI= 2 | github.com/corona10/goimagehash v1.1.0/go.mod h1:VkvE0mLn84L4aF8vCb6mafVajEb6QYMHl2ZJLn0mOGI= 3 | github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= 4 | github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= 5 | github.com/flopp/go-findfont v0.1.0 h1:lPn0BymDUtJo+ZkV01VS3661HL6F4qFlkhcJN55u6mU= 6 | github.com/flopp/go-findfont v0.1.0/go.mod h1:wKKxRDjD024Rh7VMwoU90i6ikQRCr+JTHB5n4Ejkqvw= 7 | github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8= 8 | github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= 9 | github.com/goccy/go-graphviz v0.2.5 h1:Z3JNjmdN6q8n2/Jc1qpB+yaMH2ZcRAfq3J52Go+sm3g= 10 | github.com/goccy/go-graphviz v0.2.5/go.mod h1:hssjl/qbvUXGmloY81BwXt2nqoApKo7DFgDj5dLJGb8= 11 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= 12 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= 13 | github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4= 14 | github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc= 15 | github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= 16 | github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= 17 | github.com/tetratelabs/wazero v1.8.1 h1:NrcgVbWfkWvVc4UtT4LRLDf91PsOzDzefMdwhLfA550= 18 | github.com/tetratelabs/wazero v1.8.1/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs= 19 | golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 20 | golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s= 21 | golang.org/x/image v0.21.0/go.mod h1:vUbsLavqK/W303ZroQQVKQ+Af3Yl6Uz1Ppu5J/cLz78= 22 | golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= 23 | golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 24 | golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= 25 | golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= 26 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 27 | golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= 28 | golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 29 | -------------------------------------------------------------------------------- /compatible_test.go: -------------------------------------------------------------------------------- 1 | package graphviz_test 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/base64" 7 | "encoding/json" 8 | "fmt" 9 | "image" 10 | "os" 11 | "os/exec" 12 | "path/filepath" 13 | "testing" 14 | 15 | "github.com/corona10/goimagehash" 16 | "github.com/goccy/go-graphviz" 17 | ) 18 | 19 | var ( 20 | testPaths = []string{ 21 | filepath.Join("testdata", "directed"), 22 | filepath.Join("testdata", "undirected"), 23 | } 24 | imageHashJSON = filepath.Join("testdata", "imagehash.json") 25 | ) 26 | 27 | const ( 28 | imageThreshold = 40 29 | ) 30 | 31 | func generateTestData() error { 32 | pathToHashDump := map[string]string{} 33 | for _, path := range testPaths { 34 | if err := filepath.Walk(path, func(p string, info os.FileInfo, err error) error { 35 | if info.IsDir() { 36 | return nil 37 | } 38 | tmpfile, err := os.CreateTemp("", "graphviz") 39 | if err != nil { 40 | return err 41 | } 42 | defer os.Remove(tmpfile.Name()) 43 | if err := exec.Command("dot", "-Tpng", fmt.Sprintf("-o%s", tmpfile.Name()), p).Run(); err != nil { 44 | return err 45 | } 46 | img, _, err := image.Decode(tmpfile) 47 | if err != nil { 48 | return err 49 | } 50 | hash, err := goimagehash.DifferenceHash(img) 51 | if err != nil { 52 | return err 53 | } 54 | var b bytes.Buffer 55 | if err := hash.Dump(&b); err != nil { 56 | return err 57 | } 58 | pathToHashDump[p] = base64.StdEncoding.EncodeToString(b.Bytes()) 59 | return nil 60 | }); err != nil { 61 | return err 62 | } 63 | } 64 | content, err := json.Marshal(pathToHashDump) 65 | if err != nil { 66 | return err 67 | } 68 | if err := os.WriteFile(imageHashJSON, content, 0644); err != nil { 69 | return err 70 | } 71 | return nil 72 | } 73 | 74 | func TestGraphviz_Compatible(t *testing.T) { 75 | // generate testdata/imagehash.json 76 | //if err := generateTestData(); err != nil { 77 | // t.Fatal(err) 78 | //} 79 | var pathToHashDump map[string]string 80 | file, err := os.ReadFile(imageHashJSON) 81 | if err != nil { 82 | t.Fatal(err) 83 | } 84 | if err := json.Unmarshal(file, &pathToHashDump); err != nil { 85 | t.Fatal(err) 86 | } 87 | for _, path := range testPaths { 88 | filepath.Walk(path, func(path string, info os.FileInfo, err error) error { 89 | if info.IsDir() { 90 | return nil 91 | } 92 | t.Run(path, func(t *testing.T) { 93 | file, err := os.ReadFile(path) 94 | if err != nil { 95 | t.Fatal(err) 96 | } 97 | graph, err := graphviz.ParseBytes(file) 98 | if err != nil { 99 | t.Fatal(err) 100 | } 101 | defer graph.Close() 102 | ctx := context.Background() 103 | g, err := graphviz.New(ctx) 104 | if err != nil { 105 | t.Fatal(err) 106 | } 107 | defer g.Close() 108 | image, err := g.RenderImage(ctx, graph) 109 | if err != nil { 110 | t.Fatal(err) 111 | } 112 | hash, err := goimagehash.DifferenceHash(image) 113 | if err != nil { 114 | t.Fatal(err) 115 | } 116 | dump, err := base64.StdEncoding.DecodeString(pathToHashDump[path]) 117 | if err != nil { 118 | t.Fatal(err) 119 | } 120 | targetHash, err := goimagehash.LoadImageHash(bytes.NewBuffer(dump)) 121 | if err != nil { 122 | t.Fatal(err) 123 | } 124 | distance, err := hash.Distance(targetHash) 125 | if err != nil { 126 | t.Fatal(err) 127 | } 128 | if distance > imageThreshold { 129 | t.Fatalf("doesn't compatible image with dot. %s distance = %d", path, distance) 130 | } 131 | }) 132 | return nil 133 | }) 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/goccy/go-graphviz 2 | 3 | go 1.22.0 4 | 5 | require ( 6 | github.com/corona10/goimagehash v1.1.0 7 | github.com/disintegration/imaging v1.6.2 8 | github.com/flopp/go-findfont v0.1.0 9 | github.com/fogleman/gg v1.3.0 10 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 11 | github.com/tetratelabs/wazero v1.8.1 12 | golang.org/x/image v0.21.0 13 | ) 14 | 15 | require ( 16 | github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect 17 | golang.org/x/text v0.19.0 // indirect 18 | ) 19 | 20 | replace github.com/flopp/go-findfont => github.com/goccy/go-findfont v0.0.0-20250109093214-c2e12b298c75 21 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/corona10/goimagehash v1.1.0 h1:teNMX/1e+Wn/AYSbLHX8mj+mF9r60R1kBeqE9MkoYwI= 2 | github.com/corona10/goimagehash v1.1.0/go.mod h1:VkvE0mLn84L4aF8vCb6mafVajEb6QYMHl2ZJLn0mOGI= 3 | github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= 4 | github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= 5 | github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8= 6 | github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= 7 | github.com/goccy/go-findfont v0.0.0-20250109093214-c2e12b298c75 h1:XIuIPArJ/7VuKj7uygrjl7yBYP+sTa58ljJzOxU4qDc= 8 | github.com/goccy/go-findfont v0.0.0-20250109093214-c2e12b298c75/go.mod h1:bBfDkbCgtwEhoHfxProwm41bZX3SAcOHZbgbillrYQs= 9 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= 10 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= 11 | github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= 12 | github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= 13 | github.com/tetratelabs/wazero v1.8.1 h1:NrcgVbWfkWvVc4UtT4LRLDf91PsOzDzefMdwhLfA550= 14 | github.com/tetratelabs/wazero v1.8.1/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs= 15 | golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 16 | golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s= 17 | golang.org/x/image v0.21.0/go.mod h1:vUbsLavqK/W303ZroQQVKQ+Af3Yl6Uz1Ppu5J/cLz78= 18 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 19 | golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= 20 | golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 21 | -------------------------------------------------------------------------------- /graphviz.go: -------------------------------------------------------------------------------- 1 | package graphviz 2 | 3 | import ( 4 | "context" 5 | "image" 6 | "io" 7 | "io/fs" 8 | 9 | "github.com/goccy/go-graphviz/cgraph" 10 | "github.com/goccy/go-graphviz/gvc" 11 | "github.com/goccy/go-graphviz/internal/wasm" 12 | ) 13 | 14 | type Graphviz struct { 15 | ctx *gvc.Context 16 | name string 17 | dir *GraphDescriptor 18 | layout Layout 19 | } 20 | 21 | type Layout string 22 | 23 | const ( 24 | CIRCO Layout = "circo" 25 | DOT Layout = "dot" 26 | FDP Layout = "fdp" 27 | NEATO Layout = "neato" 28 | NOP Layout = "nop" 29 | NOP1 Layout = "nop1" 30 | NOP2 Layout = "nop2" 31 | OSAGE Layout = "osage" 32 | PATCHWORK Layout = "patchwork" 33 | SFDP Layout = "sfdp" 34 | TWOPI Layout = "twopi" 35 | ) 36 | 37 | type Format string 38 | 39 | const ( 40 | XDOT Format = "dot" 41 | SVG Format = "svg" 42 | PNG Format = "png" 43 | JPG Format = "jpg" 44 | ) 45 | 46 | func New(ctx context.Context) (*Graphviz, error) { 47 | c, err := gvc.New(ctx) 48 | if err != nil { 49 | return nil, err 50 | } 51 | return &Graphviz{ 52 | ctx: c, 53 | dir: Directed, 54 | layout: DOT, 55 | }, nil 56 | } 57 | 58 | func NewWithPlugins(ctx context.Context, plugins ...Plugin) (*Graphviz, error) { 59 | c, err := gvc.NewWithPlugins(ctx, plugins...) 60 | if err != nil { 61 | return nil, err 62 | } 63 | return &Graphviz{ 64 | ctx: c, 65 | dir: Directed, 66 | layout: DOT, 67 | }, nil 68 | } 69 | 70 | func (g *Graphviz) Close() error { 71 | return g.ctx.Close() 72 | } 73 | 74 | func (g *Graphviz) SetLayout(layout Layout) *Graphviz { 75 | g.layout = layout 76 | return g 77 | } 78 | 79 | func (g *Graphviz) Render(ctx context.Context, graph *Graph, format Format, w io.Writer) (e error) { 80 | defer func() { 81 | if err := g.ctx.FreeLayout(ctx, graph); err != nil { 82 | e = err 83 | } 84 | }() 85 | 86 | if err := g.ctx.Layout(ctx, graph, string(g.layout)); err != nil { 87 | return err 88 | } 89 | if err := g.ctx.RenderData(ctx, graph, string(format), w); err != nil { 90 | return err 91 | } 92 | return nil 93 | } 94 | 95 | func (g *Graphviz) RenderImage(ctx context.Context, graph *Graph) (img image.Image, e error) { 96 | defer func() { 97 | if err := g.ctx.FreeLayout(ctx, graph); err != nil { 98 | e = err 99 | } 100 | }() 101 | 102 | if err := g.ctx.Layout(ctx, graph, string(g.layout)); err != nil { 103 | return nil, err 104 | } 105 | image, err := g.ctx.RenderImage(ctx, graph, string(PNG)) 106 | if err != nil { 107 | return nil, err 108 | } 109 | return image, nil 110 | } 111 | 112 | func (g *Graphviz) RenderFilename(ctx context.Context, graph *Graph, format Format, path string) (e error) { 113 | defer func() { 114 | if err := g.ctx.FreeLayout(ctx, graph); err != nil { 115 | e = err 116 | } 117 | }() 118 | 119 | if err := g.ctx.Layout(ctx, graph, string(g.layout)); err != nil { 120 | return err 121 | } 122 | if err := g.ctx.RenderFilename(ctx, graph, string(format), path); err != nil { 123 | return err 124 | } 125 | return nil 126 | } 127 | 128 | func (g *Graphviz) Graph(option ...GraphOption) (*Graph, error) { 129 | for _, opt := range option { 130 | opt(g) 131 | } 132 | graph, err := cgraph.Open(g.name, g.dir, nil) 133 | if err != nil { 134 | return nil, err 135 | } 136 | return graph, nil 137 | } 138 | 139 | func SetFileSystem(fs fs.FS) { 140 | wasm.SetWasmFileSystem(fs) 141 | } 142 | -------------------------------------------------------------------------------- /graphviz.version: -------------------------------------------------------------------------------- 1 | 12.1.2 2 | -------------------------------------------------------------------------------- /graphviz_test.go: -------------------------------------------------------------------------------- 1 | package graphviz_test 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "embed" 7 | "io/fs" 8 | "os" 9 | "path/filepath" 10 | "testing" 11 | 12 | "github.com/goccy/go-graphviz" 13 | ) 14 | 15 | func TestGraphviz_Image(t *testing.T) { 16 | ctx := context.Background() 17 | g, err := graphviz.New(ctx) 18 | if err != nil { 19 | t.Fatal(err) 20 | } 21 | graph, err := g.Graph() 22 | if err != nil { 23 | t.Fatalf("%+v", err) 24 | } 25 | defer func() { 26 | graph.Close() 27 | g.Close() 28 | }() 29 | n, err := graph.CreateNodeByName("n") 30 | if err != nil { 31 | t.Fatalf("%+v", err) 32 | } 33 | m, err := graph.CreateNodeByName("m") 34 | if err != nil { 35 | t.Fatalf("%+v", err) 36 | } 37 | e, err := graph.CreateEdgeByName("e", n, m) 38 | if err != nil { 39 | t.Fatalf("%+v", err) 40 | } 41 | e.SetLabel("e") 42 | 43 | t.Run("png", func(t *testing.T) { 44 | t.Run("Render", func(t *testing.T) { 45 | var buf bytes.Buffer 46 | if err := g.Render(ctx, graph, graphviz.PNG, &buf); err != nil { 47 | t.Fatalf("failed to render: %+v", err) 48 | } 49 | if len(buf.Bytes()) == 0 { 50 | t.Fatal("failed to encode png") 51 | } 52 | }) 53 | t.Run("RenderImage", func(t *testing.T) { 54 | image, err := g.RenderImage(ctx, graph) 55 | if err != nil { 56 | t.Fatalf("%+v", err) 57 | } 58 | bounds := image.Bounds() 59 | if bounds.Max.X != 83 { 60 | t.Fatalf("expected bounds x is %d. but got %d", 83, bounds.Max.X) 61 | } 62 | if bounds.Max.Y != 177 { 63 | t.Fatalf("expected bounds y is %d. but got %d", 177, bounds.Max.Y) 64 | } 65 | }) 66 | }) 67 | t.Run("jpg", func(t *testing.T) { 68 | t.Run("Render", func(t *testing.T) { 69 | var buf bytes.Buffer 70 | if err := g.Render(ctx, graph, graphviz.JPG, &buf); err != nil { 71 | t.Fatalf("%+v", err) 72 | } 73 | if len(buf.Bytes()) == 0 { 74 | t.Fatal("failed to encode jpg") 75 | } 76 | }) 77 | t.Run("RenderImage", func(t *testing.T) { 78 | image, err := g.RenderImage(ctx, graph) 79 | if err != nil { 80 | t.Fatalf("%+v", err) 81 | } 82 | bounds := image.Bounds() 83 | if bounds.Max.X != 83 { 84 | t.Fatal("failed to get image") 85 | } 86 | if bounds.Max.Y != 177 { 87 | t.Fatal("failed to get image") 88 | } 89 | }) 90 | }) 91 | } 92 | 93 | func TestParseBytes(t *testing.T) { 94 | type test struct { 95 | input string 96 | expectedErr bool 97 | } 98 | 99 | tests := []test{ 100 | {input: "graph test1 { a -- b }"}, 101 | {input: "graph test2 { a -- b", expectedErr: true}, 102 | {input: "graph test3 { a -- b }"}, 103 | {input: "graph test4 { a -- }", expectedErr: true}, 104 | {input: "graph test5 { a -- c }"}, 105 | {input: "graph test6 { a - b }", expectedErr: true}, 106 | {input: "graph test7 { d -- e }"}, 107 | } 108 | 109 | for _, test := range tests { 110 | t.Run(test.input, func(t *testing.T) { 111 | _, err := graphviz.ParseBytes([]byte(test.input)) 112 | if test.expectedErr && err == nil { 113 | t.Fatal("expected parsing error") 114 | } else if !test.expectedErr && err != nil { 115 | t.Fatalf("failed to parse: %v", err) 116 | } 117 | }) 118 | } 119 | } 120 | 121 | func TestParseFile(t *testing.T) { 122 | type test struct { 123 | input string 124 | expectedErr bool 125 | } 126 | 127 | tests := []test{ 128 | {input: "graph test1 { a -- b }"}, 129 | {input: "graph test2 { a -- b", expectedErr: true}, 130 | {input: "graph test3 { a -- b }"}, 131 | {input: "graph test4 { a -- }", expectedErr: true}, 132 | {input: "graph test5 { a -- c }"}, 133 | {input: "graph test6 { a - b }", expectedErr: true}, 134 | {input: "graph test7 { d -- e }"}, 135 | } 136 | 137 | createTempFile := func(t *testing.T, content string) *os.File { 138 | file, err := os.CreateTemp("", "*") 139 | if err != nil { 140 | t.Fatalf("There was an error creating a temporary file. Error: %+v", err) 141 | return nil 142 | } 143 | _, err = file.WriteString(content) 144 | if err != nil { 145 | t.Fatalf("There was an error writing '%s' to a temporary file. Error: %+v", content, err) 146 | return nil 147 | } 148 | return file 149 | } 150 | 151 | for _, test := range tests { 152 | t.Run(test.input, func(t *testing.T) { 153 | tmpfile := createTempFile(t, test.input) 154 | defer os.Remove(tmpfile.Name()) 155 | 156 | _, err := graphviz.ParseFile(tmpfile.Name()) 157 | if test.expectedErr && err == nil { 158 | t.Fatal("expected parsing error") 159 | } else if !test.expectedErr && err != nil { 160 | t.Fatalf("failed to parse: %v", err) 161 | } 162 | }) 163 | } 164 | } 165 | 166 | //go:embed testdata/logo.png 167 | var logoFS embed.FS 168 | 169 | type imageFS struct{} 170 | 171 | func (fs *imageFS) Open(name string) (fs.File, error) { 172 | return logoFS.Open(filepath.Join("testdata", name)) 173 | } 174 | 175 | func TestImageRender(t *testing.T) { 176 | ctx := context.Background() 177 | graphviz.SetFileSystem(new(imageFS)) 178 | 179 | g, err := graphviz.New(ctx) 180 | if err != nil { 181 | t.Fatal(err) 182 | } 183 | graph, err := g.Graph() 184 | if err != nil { 185 | t.Fatalf("%+v", err) 186 | } 187 | defer func() { 188 | graph.Close() 189 | g.Close() 190 | }() 191 | n, err := graph.CreateNodeByName("n") 192 | if err != nil { 193 | t.Fatalf("%+v", err) 194 | } 195 | n.SetLabel("") 196 | 197 | // specify dummy image path. 198 | // Normally, a path to `testdata` would be required before `logo.png`, 199 | // but we confirm that the image can be loaded by appending the path to `testdata` within the `imageFS` specified by graphviz.SetFileSystem function. 200 | // This test is to verify that images can be loaded relative to the specified FileSystem. 201 | n.SetImage("logo.png") 202 | m, err := graph.CreateNodeByName("m") 203 | if err != nil { 204 | t.Fatalf("%+v", err) 205 | } 206 | if _, err := graph.CreateEdgeByName("e", n, m); err != nil { 207 | t.Fatalf("%+v", err) 208 | } 209 | var buf bytes.Buffer 210 | if err := g.Render(ctx, graph, "png", &buf); err != nil { 211 | t.Fatal(err) 212 | } 213 | if len(buf.Bytes()) == 0 { 214 | t.Fatal("failed to render image") 215 | } 216 | } 217 | 218 | func TestNodeDegree(t *testing.T) { 219 | type test struct { 220 | nodeName string 221 | expectedIndegree int 222 | expectedOutdegree int 223 | expectedTotalDegree int 224 | } 225 | 226 | type graphtest struct { 227 | input string 228 | tests []test 229 | } 230 | 231 | graphtests := []graphtest{ 232 | {input: "digraph test { a -> b }", tests: []test{ 233 | {nodeName: "a", expectedIndegree: 0, expectedOutdegree: 1, expectedTotalDegree: 1}, 234 | {nodeName: "b", expectedIndegree: 1, expectedOutdegree: 0, expectedTotalDegree: 1}, 235 | }}, 236 | {input: "digraph test { a -> b; a -> b; a -> a; c -> a }", tests: []test{ 237 | {nodeName: "a", expectedIndegree: 2, expectedOutdegree: 3, expectedTotalDegree: 5}, 238 | {nodeName: "b", expectedIndegree: 2, expectedOutdegree: 0, expectedTotalDegree: 2}, 239 | {nodeName: "c", expectedIndegree: 0, expectedOutdegree: 1, expectedTotalDegree: 1}, 240 | }}, 241 | {input: "graph test { a -- b; a -- b; a -- a; c -- a }", tests: []test{ 242 | {nodeName: "a", expectedIndegree: 2, expectedOutdegree: 3, expectedTotalDegree: 5}, 243 | {nodeName: "b", expectedIndegree: 2, expectedOutdegree: 0, expectedTotalDegree: 2}, 244 | {nodeName: "c", expectedIndegree: 0, expectedOutdegree: 1, expectedTotalDegree: 1}, 245 | }}, 246 | {input: "strict graph test { a -- b; b -- a; a -- a; c -- a }", tests: []test{ 247 | {nodeName: "a", expectedIndegree: 2, expectedOutdegree: 2, expectedTotalDegree: 4}, 248 | {nodeName: "b", expectedIndegree: 1, expectedOutdegree: 0, expectedTotalDegree: 1}, 249 | {nodeName: "c", expectedIndegree: 0, expectedOutdegree: 1, expectedTotalDegree: 1}, 250 | }}, 251 | } 252 | 253 | for _, graphtest := range graphtests { 254 | input := graphtest.input 255 | graph, err := graphviz.ParseBytes([]byte(input)) 256 | if err != nil { 257 | t.Fatalf("Input: %s. Error: %+v", input, err) 258 | } 259 | 260 | for _, test := range graphtest.tests { 261 | nodeName := test.nodeName 262 | node, err := graph.NodeByName(nodeName) 263 | if err != nil || node == nil { 264 | t.Fatalf("Unable to retrieve node '%s'. Input: %s. Error: %+v", nodeName, input, err) 265 | } 266 | 267 | indegree, err := graph.Indegree(node) 268 | if err != nil { 269 | t.Fatal(err) 270 | } 271 | if test.expectedIndegree != indegree { 272 | t.Errorf("Unexpected indegree for node '%s'. Input: %s. Expected: %d. Actual: %d.", nodeName, input, test.expectedIndegree, indegree) 273 | } 274 | outdegree, err := graph.Outdegree(node) 275 | if err != nil { 276 | t.Fatal(err) 277 | } 278 | if test.expectedOutdegree != outdegree { 279 | t.Errorf("Unexpected outdegree for node '%s'. Input: %s. Expected: %d. Actual: %d.", nodeName, input, test.expectedOutdegree, outdegree) 280 | } 281 | totalDegree, err := graph.TotalDegree(node) 282 | if err != nil { 283 | t.Fatal(err) 284 | } 285 | if test.expectedTotalDegree != totalDegree { 286 | t.Errorf("Unexpected total degree for node '%s'. Input: %s. Expected: %d. Actual: %d.", nodeName, input, test.expectedTotalDegree, totalDegree) 287 | } 288 | } 289 | } 290 | } 291 | 292 | func TestEdgeSourceAndTarget(t *testing.T) { 293 | ctx := context.Background() 294 | graph, err := graphviz.New(ctx) 295 | if err != nil { 296 | t.Fatalf("Error: %+v", err) 297 | } 298 | 299 | g, err := graph.Graph() 300 | if err != nil { 301 | t.Fatalf("Error: %+v", err) 302 | } 303 | 304 | nodeA, err := g.CreateNodeByName("a") 305 | if err != nil { 306 | t.Fatalf("Error: %+v", err) 307 | } 308 | 309 | nodeB, err := g.CreateNodeByName("b") 310 | if err != nil { 311 | t.Fatalf("Error: %+v", err) 312 | } 313 | 314 | edge, err := g.CreateEdgeByName("edge", nodeA, nodeB) 315 | if err != nil { 316 | t.Fatalf("Error: %+v", err) 317 | } 318 | 319 | head, err := edge.Head() 320 | if err != nil { 321 | t.Fatalf("Error: %+v", err) 322 | } 323 | if head == nil { 324 | t.Fatalf("Source is nil") 325 | } 326 | 327 | headName, err := head.Name() 328 | if err != nil { 329 | t.Fatalf("Error: %+v", err) 330 | } 331 | 332 | if headName != "b" { 333 | t.Fatalf("Expected source name to be 'b', got '%s'", headName) 334 | } 335 | 336 | target, err := edge.Tail() 337 | if err != nil { 338 | t.Fatalf("Error: %+v", err) 339 | } 340 | if target == nil { 341 | t.Fatalf("Target is nil") 342 | } 343 | 344 | tailName, err := target.Name() 345 | if err != nil { 346 | t.Fatalf("Error: %+v", err) 347 | } 348 | 349 | if tailName != "a" { 350 | t.Fatalf("Expected target name to be 'a', got '%s'", tailName) 351 | } 352 | } 353 | -------------------------------------------------------------------------------- /gvc/device_plugin.go: -------------------------------------------------------------------------------- 1 | package gvc 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/goccy/go-graphviz/internal/wasm" 7 | ) 8 | 9 | type DevicePlugin struct { 10 | plugin *wasm.PluginAPI 11 | } 12 | 13 | func (p *DevicePlugin) raw() *wasm.PluginAPI { 14 | return p.plugin 15 | } 16 | 17 | type DeviceFeature int64 18 | 19 | var ( 20 | DeviceDoesPages DeviceFeature = DeviceFeature(wasm.DEVICE_DOES_PAGES) 21 | DeviceDoesLayers DeviceFeature = DeviceFeature(wasm.DEVICE_DOES_LAYERS) 22 | DeviceEvents DeviceFeature = DeviceFeature(wasm.DEVICE_EVENTS) 23 | DeviceDoesTrueColor DeviceFeature = DeviceFeature(wasm.DEVICE_DOES_TRUECOLOR) 24 | DeviceBinaryFormat DeviceFeature = DeviceFeature(wasm.DEVICE_BINARY_FORMAT) 25 | DeviceCompressedFormat DeviceFeature = DeviceFeature(wasm.DEVICE_COMPRESSED_FORMAT) 26 | DeviceNoWriter DeviceFeature = DeviceFeature(wasm.DEVICE_NO_WRITER) 27 | ) 28 | 29 | type DevicePluginOption func(*deviceConfig) 30 | 31 | func WithDeviceQuality(quality int) DevicePluginOption { 32 | return func(cfg *deviceConfig) { 33 | cfg.Quality = int64(quality) 34 | } 35 | } 36 | 37 | func WithDeviceFeatures(features ...DeviceFeature) DevicePluginOption { 38 | return func(cfg *deviceConfig) { 39 | cfg.Features = features 40 | } 41 | } 42 | 43 | func WithDeviceDPI(x, y float64) DevicePluginOption { 44 | return func(cfg *deviceConfig) { 45 | cfg.DPI = deviceDPI{ 46 | X: x, 47 | Y: y, 48 | } 49 | } 50 | } 51 | 52 | func NewDevicePlugin(ctx context.Context, typ string, opts ...DevicePluginOption) (*DevicePlugin, error) { 53 | cfg := defaultDevicePluginConfig(typ) 54 | for _, opt := range opts { 55 | opt(cfg) 56 | } 57 | return newDevicePlugin(ctx, cfg) 58 | } 59 | 60 | func PNGDevicePlugin(ctx context.Context) (*DevicePlugin, error) { 61 | return newDevicePlugin(ctx, defaultDevicePluginConfig("png:png")) 62 | } 63 | 64 | func JPGDevicePlugin(ctx context.Context) (*DevicePlugin, error) { 65 | return newDevicePlugin(ctx, defaultDevicePluginConfig("jpg:jpg")) 66 | } 67 | 68 | type deviceDPI struct { 69 | X float64 70 | Y float64 71 | } 72 | 73 | type deviceConfig struct { 74 | Type string 75 | Quality int64 76 | Features []DeviceFeature 77 | DPI deviceDPI 78 | } 79 | 80 | func defaultDevicePluginConfig(typ string) *deviceConfig { 81 | return &deviceConfig{ 82 | Type: typ, 83 | Quality: 1, 84 | Features: []DeviceFeature{ 85 | DeviceBinaryFormat, 86 | DeviceDoesTrueColor, 87 | }, 88 | DPI: deviceDPI{ 89 | X: 96, 90 | Y: 96, 91 | }, 92 | } 93 | } 94 | 95 | func newDevicePlugin(ctx context.Context, cfg *deviceConfig) (*DevicePlugin, error) { 96 | plg, err := wasm.NewPluginAPI(ctx) 97 | if err != nil { 98 | return nil, err 99 | } 100 | if err := plg.SetApi(wasm.API_DEVICE); err != nil { 101 | return nil, err 102 | } 103 | types, err := wasm.NewPluginInstalled(ctx) 104 | if err != nil { 105 | return nil, err 106 | } 107 | if err := types.SetType(cfg.Type); err != nil { 108 | return nil, err 109 | } 110 | if err := types.SetQuality(cfg.Quality); err != nil { 111 | return nil, err 112 | } 113 | features, err := wasm.NewDeviceFeatures(ctx) 114 | if err != nil { 115 | return nil, err 116 | } 117 | var flags int64 118 | for _, feature := range cfg.Features { 119 | flags |= int64(feature) 120 | } 121 | features.SetFlags(flags) 122 | dpi, err := wasm.NewPointFloat(ctx) 123 | if err != nil { 124 | return nil, err 125 | } 126 | dpi.SetX(cfg.DPI.X) 127 | dpi.SetY(cfg.DPI.Y) 128 | features.SetDefaultDpi(dpi) 129 | if err := types.SetFeatures(features); err != nil { 130 | return nil, err 131 | } 132 | term, err := wasm.PluginInstalledZero(ctx) 133 | if err != nil { 134 | return nil, err 135 | } 136 | if err := plg.SetTypes([]*wasm.PluginInstalled{types, term}); err != nil { 137 | return nil, err 138 | } 139 | return &DevicePlugin{ 140 | plugin: plg, 141 | }, nil 142 | } 143 | -------------------------------------------------------------------------------- /gvc/gvc.go: -------------------------------------------------------------------------------- 1 | package gvc 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "errors" 7 | "fmt" 8 | "image" 9 | _ "image/jpeg" 10 | _ "image/png" 11 | "io" 12 | "os" 13 | 14 | "github.com/goccy/go-graphviz/cgraph" 15 | "github.com/goccy/go-graphviz/internal/wasm" 16 | ) 17 | 18 | type Context struct { 19 | gvc *wasm.Context 20 | } 21 | 22 | func New(ctx context.Context) (*Context, error) { 23 | plugins, err := DefaultPlugins(ctx) 24 | if err != nil { 25 | return nil, err 26 | } 27 | return NewWithPlugins(ctx, plugins...) 28 | } 29 | 30 | func NewWithPlugins(ctx context.Context, plugins ...Plugin) (*Context, error) { 31 | plgs, err := newPlugins(ctx, plugins...) 32 | if err != nil { 33 | return nil, err 34 | } 35 | gvc, err := wasm.GetContextWithPlugins(ctx, plgs, 1) 36 | if err != nil { 37 | return nil, err 38 | } 39 | if gvc == nil { 40 | return nil, fmt.Errorf("failed to create graphviz context") 41 | } 42 | return &Context{gvc: gvc}, nil 43 | } 44 | 45 | func (c *Context) Close() error { 46 | res, err := c.gvc.FreeContext(context.Background()) 47 | if err != nil { 48 | return err 49 | } 50 | return toError(res) 51 | } 52 | 53 | func (c *Context) Layout(ctx context.Context, g *cgraph.Graph, engine string) error { 54 | res, err := c.gvc.Layout(ctx, toGraphWasm(g), engine) 55 | if err != nil { 56 | return err 57 | } 58 | return toError(res) 59 | } 60 | 61 | func (c *Context) RenderData(ctx context.Context, g *cgraph.Graph, format string, w io.Writer) error { 62 | var ( 63 | s string 64 | renderedLen uint 65 | ) 66 | if _, err := c.gvc.RenderData(ctx, toGraphWasm(g), format, &s, &renderedLen); err != nil { 67 | return err 68 | } 69 | if _, err := w.Write([]byte(s)); err != nil { 70 | return err 71 | } 72 | return nil 73 | } 74 | 75 | func (c *Context) RenderImage(ctx context.Context, g *cgraph.Graph, format string) (image.Image, error) { 76 | var buf bytes.Buffer 77 | if err := c.RenderData(ctx, g, format, &buf); err != nil { 78 | return nil, err 79 | } 80 | img, _, err := image.Decode(&buf) 81 | if err != nil { 82 | return nil, err 83 | } 84 | return img, nil 85 | } 86 | 87 | func (c *Context) RenderFilename(ctx context.Context, g *cgraph.Graph, format, filename string) error { 88 | if _, err := os.Stat(filename); err != nil { 89 | // file does not exist. 90 | // Since gvc.RenderFilename fails if the file doesn't exist, we create it beforehand. 91 | if _, err := os.Create(filename); err != nil { 92 | return fmt.Errorf("failed to create file: %w", err) 93 | } 94 | } 95 | res, err := c.gvc.RenderFilename(ctx, toGraphWasm(g), format, filename) 96 | if err != nil { 97 | return err 98 | } 99 | return toError(res) 100 | } 101 | 102 | func (c *Context) FreeLayout(ctx context.Context, g *cgraph.Graph) error { 103 | res, err := c.gvc.FreeLayout(ctx, toGraphWasm(g)) 104 | if err != nil { 105 | return err 106 | } 107 | return toError(res) 108 | } 109 | 110 | func (c *Context) Clone(ctx context.Context) (*Context, error) { 111 | gvc, err := c.gvc.Clone(ctx) 112 | if err != nil { 113 | return nil, err 114 | } 115 | return &Context{gvc: gvc}, nil 116 | } 117 | 118 | func (c *Context) FreeClonedContext(ctx context.Context) error { 119 | return c.gvc.FreeClonedContext(ctx) 120 | } 121 | 122 | func newPlugins(ctx context.Context, plugins ...Plugin) ([]*wasm.SymList, error) { 123 | defaults, err := wasm.DefaultSymList(ctx) 124 | if err != nil { 125 | return nil, err 126 | } 127 | if len(plugins) == 0 { 128 | return defaults, nil 129 | } 130 | sym, err := wasm.NewSymList(ctx) 131 | if err != nil { 132 | return nil, err 133 | } 134 | if err := sym.SetName("gvplugin_go_LTX_library"); err != nil { 135 | return nil, err 136 | } 137 | lib, err := wasm.NewPluginLibrary(ctx) 138 | if err != nil { 139 | return nil, err 140 | } 141 | if err := lib.SetPackageName("go"); err != nil { 142 | return nil, err 143 | } 144 | var apis []*wasm.PluginAPI 145 | for _, plg := range plugins { 146 | apis = append(apis, plg.raw()) 147 | } 148 | term, err := wasm.PluginAPIZero(ctx) 149 | if err != nil { 150 | return nil, err 151 | } 152 | apis = append(apis, term) 153 | 154 | if err := lib.SetApis(apis); err != nil { 155 | return nil, err 156 | } 157 | if err := sym.SetAddress(lib); err != nil { 158 | return nil, err 159 | } 160 | symTerm, err := wasm.SymListZero(ctx) 161 | if err != nil { 162 | return nil, err 163 | } 164 | return append(append([]*wasm.SymList{sym}, defaults...), symTerm), nil 165 | } 166 | 167 | func toError(result int) error { 168 | if result == 0 { 169 | return nil 170 | } 171 | return lastError() 172 | } 173 | 174 | func lastError() error { 175 | if e, _ := wasm.LastError(context.Background()); e != "" { 176 | return errors.New(e) 177 | } 178 | return nil 179 | } 180 | -------------------------------------------------------------------------------- /gvc/image_plugin.go: -------------------------------------------------------------------------------- 1 | package gvc 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/goccy/go-graphviz/internal/wasm" 7 | ) 8 | 9 | type LoadImagePlugin struct { 10 | plugin *wasm.PluginAPI 11 | } 12 | 13 | func (p *LoadImagePlugin) raw() *wasm.PluginAPI { 14 | return p.plugin 15 | } 16 | 17 | type loadImageConfig struct { 18 | Type string 19 | Engine LoadImageEngine 20 | } 21 | 22 | type LoadImageEngine interface { 23 | LoadImage(ctx context.Context, job *Job, shape *UserShape, bf *BoxFloat, filled bool) error 24 | } 25 | 26 | type DefaultLoadImageEngine struct { 27 | } 28 | 29 | func NewLoadImagePlugin(ctx context.Context, typ string, engine LoadImageEngine) (*LoadImagePlugin, error) { 30 | cfg := defaultLoadImagePluginConfig(typ, engine) 31 | return newLoadImagePlugin(ctx, cfg) 32 | } 33 | 34 | func PNGLoadImagePlugin(ctx context.Context, engine LoadImageEngine) (*LoadImagePlugin, error) { 35 | return NewLoadImagePlugin(ctx, "png:png", engine) 36 | } 37 | 38 | func defaultLoadImagePluginConfig(typ string, engine LoadImageEngine) *loadImageConfig { 39 | return &loadImageConfig{ 40 | Type: typ, 41 | Engine: engine, 42 | } 43 | } 44 | 45 | func newLoadImagePlugin(ctx context.Context, cfg *loadImageConfig) (*LoadImagePlugin, error) { 46 | plg, err := wasm.NewPluginAPI(ctx) 47 | if err != nil { 48 | return nil, err 49 | } 50 | if err := plg.SetApi(wasm.API_LOADIMAGE); err != nil { 51 | return nil, err 52 | } 53 | types, err := wasm.NewPluginInstalled(ctx) 54 | if err != nil { 55 | return nil, err 56 | } 57 | if err := types.SetType(cfg.Type); err != nil { 58 | return nil, err 59 | } 60 | if err := types.SetQuality(1); err != nil { 61 | return nil, err 62 | } 63 | engine, err := newLoadImageEngine(ctx, cfg.Engine) 64 | if err != nil { 65 | return nil, err 66 | } 67 | if err := types.SetEngine(engine); err != nil { 68 | return nil, err 69 | } 70 | term, err := wasm.PluginInstalledZero(ctx) 71 | if err != nil { 72 | return nil, err 73 | } 74 | if err := plg.SetTypes([]*wasm.PluginInstalled{types, term}); err != nil { 75 | return nil, err 76 | } 77 | return &LoadImagePlugin{ 78 | plugin: plg, 79 | }, nil 80 | } 81 | 82 | func newLoadImageEngine(ctx context.Context, engine LoadImageEngine) (*wasm.LoadImageEngine, error) { 83 | e, err := wasm.NewLoadImageEngine(ctx) 84 | if err != nil { 85 | return nil, err 86 | } 87 | ptr := wasm.WasmPtr(e) 88 | if err := e.SetLoadImage(ctx, wasm.CreateCallbackFunc(func(ctx context.Context, job *wasm.Job, shape *wasm.UserShape, bf *wasm.BoxFloat, filled bool) error { 89 | return engine.LoadImage(ctx, toJob(job), toUserShape(shape), toBoxFloat(bf), filled) 90 | }, ptr)); err != nil { 91 | return nil, err 92 | } 93 | return e, nil 94 | } 95 | -------------------------------------------------------------------------------- /gvc/init.go: -------------------------------------------------------------------------------- 1 | package gvc 2 | 3 | import ( 4 | "github.com/goccy/go-graphviz/internal/wasm" 5 | ) 6 | 7 | func init() { 8 | getRenderEnginePtr := func(job *wasm.Job) uint64 { 9 | return job.GetGvc().GetApi()[wasm.API_RENDER].GetTypeptr().GetEngine().(uint64) 10 | } 11 | getLoadImageEnginePtr := func(job *wasm.Job) uint64 { 12 | return job.GetGvc().GetApi()[wasm.API_LOADIMAGE].GetTypeptr().GetEngine().(uint64) 13 | } 14 | 15 | wasm.Register_RenderEngine_BeginJob(func(job *wasm.Job) (uint64, error) { return getRenderEnginePtr(job), nil }) 16 | wasm.Register_RenderEngine_EndJob(func(job *wasm.Job) (uint64, error) { return getRenderEnginePtr(job), nil }) 17 | wasm.Register_RenderEngine_BeginGraph(func(job *wasm.Job) (uint64, error) { return getRenderEnginePtr(job), nil }) 18 | wasm.Register_RenderEngine_EndGraph(func(job *wasm.Job) (uint64, error) { return getRenderEnginePtr(job), nil }) 19 | wasm.Register_RenderEngine_BeginLayer(func(job *wasm.Job, _ string, _ int, _ int) (uint64, error) { return getRenderEnginePtr(job), nil }) 20 | wasm.Register_RenderEngine_EndLayer(func(job *wasm.Job) (uint64, error) { return getRenderEnginePtr(job), nil }) 21 | wasm.Register_RenderEngine_BeginPage(func(job *wasm.Job) (uint64, error) { return getRenderEnginePtr(job), nil }) 22 | wasm.Register_RenderEngine_EndPage(func(job *wasm.Job) (uint64, error) { return getRenderEnginePtr(job), nil }) 23 | wasm.Register_RenderEngine_BeginCluster(func(job *wasm.Job) (uint64, error) { return getRenderEnginePtr(job), nil }) 24 | wasm.Register_RenderEngine_EndCluster(func(job *wasm.Job) (uint64, error) { return getRenderEnginePtr(job), nil }) 25 | wasm.Register_RenderEngine_BeginNodes(func(job *wasm.Job) (uint64, error) { return getRenderEnginePtr(job), nil }) 26 | wasm.Register_RenderEngine_EndNodes(func(job *wasm.Job) (uint64, error) { return getRenderEnginePtr(job), nil }) 27 | wasm.Register_RenderEngine_BeginEdges(func(job *wasm.Job) (uint64, error) { return getRenderEnginePtr(job), nil }) 28 | wasm.Register_RenderEngine_EndEdges(func(job *wasm.Job) (uint64, error) { return getRenderEnginePtr(job), nil }) 29 | wasm.Register_RenderEngine_BeginNode(func(job *wasm.Job) (uint64, error) { return getRenderEnginePtr(job), nil }) 30 | wasm.Register_RenderEngine_EndNode(func(job *wasm.Job) (uint64, error) { return getRenderEnginePtr(job), nil }) 31 | wasm.Register_RenderEngine_BeginEdge(func(job *wasm.Job) (uint64, error) { return getRenderEnginePtr(job), nil }) 32 | wasm.Register_RenderEngine_EndEdge(func(job *wasm.Job) (uint64, error) { return getRenderEnginePtr(job), nil }) 33 | wasm.Register_RenderEngine_BeginAnchor(func(job *wasm.Job, _ string, _ string, _ string, _ string) (uint64, error) { 34 | return getRenderEnginePtr(job), nil 35 | }) 36 | wasm.Register_RenderEngine_EndAnchor(func(job *wasm.Job) (uint64, error) { return getRenderEnginePtr(job), nil }) 37 | wasm.Register_RenderEngine_BeginLabel(func(job *wasm.Job, _ wasm.LabelType) (uint64, error) { return getRenderEnginePtr(job), nil }) 38 | wasm.Register_RenderEngine_EndLabel(func(job *wasm.Job) (uint64, error) { return getRenderEnginePtr(job), nil }) 39 | wasm.Register_RenderEngine_Textspan(func(job *wasm.Job, _ *wasm.PointFloat, _ *wasm.Textspan) (uint64, error) { 40 | return getRenderEnginePtr(job), nil 41 | }) 42 | wasm.Register_RenderEngine_ResolveColor(func(job *wasm.Job, _ *wasm.Color) (uint64, error) { return getRenderEnginePtr(job), nil }) 43 | wasm.Register_RenderEngine_Ellipse(func(job *wasm.Job, _ []*wasm.PointFloat, _ int) (uint64, error) { return getRenderEnginePtr(job), nil }) 44 | wasm.Register_RenderEngine_Polygon(func(job *wasm.Job, _ []*wasm.PointFloat, _ uint32, _ int) (uint64, error) { 45 | return getRenderEnginePtr(job), nil 46 | }) 47 | wasm.Register_RenderEngine_Beziercurve(func(job *wasm.Job, _ []*wasm.PointFloat, _ uint32, _ int) (uint64, error) { 48 | return getRenderEnginePtr(job), nil 49 | }) 50 | wasm.Register_RenderEngine_Polyline(func(job *wasm.Job, _ []*wasm.PointFloat, _ uint32) (uint64, error) { 51 | return getRenderEnginePtr(job), nil 52 | }) 53 | wasm.Register_RenderEngine_Comment(func(job *wasm.Job, _ string) (uint64, error) { return getRenderEnginePtr(job), nil }) 54 | wasm.Register_RenderEngine_LibraryShape(func(job *wasm.Job, _ string, _ []*wasm.PointFloat, _ uint32, _ int) (uint64, error) { 55 | return getRenderEnginePtr(job), nil 56 | }) 57 | 58 | wasm.Register_LoadImageEngine_LoadImage(func(job *wasm.Job, shape *wasm.UserShape, bf *wasm.BoxFloat, filled bool) (uint64, error) { 59 | return getLoadImageEnginePtr(job), nil 60 | }) 61 | } 62 | -------------------------------------------------------------------------------- /gvc/link.go: -------------------------------------------------------------------------------- 1 | package gvc 2 | 3 | import ( 4 | _ "unsafe" 5 | 6 | "github.com/goccy/go-graphviz/cdt" 7 | "github.com/goccy/go-graphviz/cgraph" 8 | "github.com/goccy/go-graphviz/internal/wasm" 9 | ) 10 | 11 | //go:linkname toGraph github.com/goccy/go-graphviz/cgraph.toGraph 12 | func toGraph(*wasm.Graph) *cgraph.Graph 13 | 14 | //go:linkname toGraphWasm github.com/goccy/go-graphviz/cgraph.toGraphWasm 15 | func toGraphWasm(*cgraph.Graph) *wasm.Graph 16 | 17 | //go:linkname toNode github.com/goccy/go-graphviz/cgraph.toNode 18 | func toNode(*wasm.Node) *cgraph.Node 19 | 20 | //go:linkname toEdge github.com/goccy/go-graphviz/cgraph.toEdge 21 | func toEdge(*wasm.Edge) *cgraph.Edge 22 | 23 | //go:linkname toDictLink github.com/goccy/go-graphviz/cdt.toLink 24 | func toDictLink(*wasm.DictLink) *cdt.Link 25 | 26 | //go:linkname toDictLinkWasm github.com/goccy/go-graphviz/cdt.toLinkWasm 27 | func toDictLinkWasm(*cdt.Link) *wasm.DictLink 28 | -------------------------------------------------------------------------------- /gvc/plugin.go: -------------------------------------------------------------------------------- 1 | package gvc 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/goccy/go-graphviz/internal/wasm" 7 | ) 8 | 9 | type Plugin interface { 10 | raw() *wasm.PluginAPI 11 | } 12 | 13 | func DefaultPlugins(ctx context.Context) ([]Plugin, error) { 14 | pngRenderPlugin, err := PNGRenderPlugin(ctx) 15 | if err != nil { 16 | return nil, err 17 | } 18 | pngDevicePlugin, err := PNGDevicePlugin(ctx) 19 | if err != nil { 20 | return nil, err 21 | } 22 | jpgRenderPlugin, err := JPGRenderPlugin(ctx) 23 | if err != nil { 24 | return nil, err 25 | } 26 | jpgDevicePlugin, err := JPGDevicePlugin(ctx) 27 | if err != nil { 28 | return nil, err 29 | } 30 | pngLoadImagePlugin, err := PNGLoadImagePlugin(ctx, pngRenderPlugin.RenderEngine()) 31 | if err != nil { 32 | return nil, err 33 | } 34 | return []Plugin{ 35 | pngRenderPlugin, 36 | pngDevicePlugin, 37 | jpgRenderPlugin, 38 | jpgDevicePlugin, 39 | pngLoadImagePlugin, 40 | }, nil 41 | } 42 | -------------------------------------------------------------------------------- /internal/tools/nori/Makefile: -------------------------------------------------------------------------------- 1 | export 2 | 3 | GOBIN := $(PWD)/bin 4 | PATH := $(GOBIN):$(PATH) 5 | LDFLAGS := -w -s 6 | 7 | .PHONY: tools 8 | tools: 9 | go install github.com/bufbuild/buf/cmd/buf@v1.32.2 10 | 11 | .PHONY: fmt 12 | fmt: tidy fmt/buf 13 | 14 | .PHONY: tidy 15 | tidy: 16 | go mod tidy 17 | 18 | fmt/buf: 19 | $(GOBIN)/buf format --write 20 | 21 | .PHONY: generate 22 | generate: build generate/buf 23 | 24 | generate/buf: 25 | buf generate 26 | 27 | .PHONY: build 28 | build: build/protoc-gen-nori 29 | 30 | build/protoc-gen-nori: 31 | go build -ldflags "$(LDFLAGS)" -o $(GOBIN)/protoc-gen-nori ./cmd/protoc-gen-nori 32 | -------------------------------------------------------------------------------- /internal/tools/nori/buf.gen.yaml: -------------------------------------------------------------------------------- 1 | version: v1 2 | plugins: 3 | - plugin: go 4 | out: . 5 | opt: module=github.com/goccy/nori 6 | -------------------------------------------------------------------------------- /internal/tools/nori/buf.work.yaml: -------------------------------------------------------------------------------- 1 | version: v1 2 | directories: 3 | - proto 4 | -------------------------------------------------------------------------------- /internal/tools/nori/cmd/protoc-gen-nori/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "io" 6 | "log" 7 | "os" 8 | 9 | "google.golang.org/protobuf/proto" 10 | "google.golang.org/protobuf/types/pluginpb" 11 | 12 | "github.com/goccy/nori" 13 | ) 14 | 15 | func main() { 16 | if err := _main(); err != nil { 17 | log.Fatal(err) 18 | } 19 | } 20 | 21 | func _main() error { 22 | req, err := parseRequest(os.Stdin) 23 | if err != nil { 24 | return err 25 | } 26 | resp, err := nori.Generate(context.Background(), req) 27 | if err != nil { 28 | return err 29 | } 30 | if resp == nil { 31 | return nil 32 | } 33 | if err := outputResponse(resp); err != nil { 34 | return err 35 | } 36 | return nil 37 | } 38 | 39 | func parseRequest(r io.Reader) (*pluginpb.CodeGeneratorRequest, error) { 40 | buf, err := io.ReadAll(r) 41 | if err != nil { 42 | return nil, err 43 | } 44 | 45 | var req pluginpb.CodeGeneratorRequest 46 | if err := proto.Unmarshal(buf, &req); err != nil { 47 | return nil, err 48 | } 49 | return &req, nil 50 | } 51 | 52 | func outputResponse(resp *pluginpb.CodeGeneratorResponse) error { 53 | buf, err := proto.Marshal(resp) 54 | if err != nil { 55 | return err 56 | } 57 | if _, err = os.Stdout.Write(buf); err != nil { 58 | return err 59 | } 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /internal/tools/nori/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/goccy/nori 2 | 3 | go 1.22.0 4 | 5 | require ( 6 | github.com/bufbuild/protocompile v0.14.0 7 | google.golang.org/protobuf v1.34.2 8 | ) 9 | 10 | require golang.org/x/sync v0.8.0 // indirect 11 | -------------------------------------------------------------------------------- /internal/tools/nori/go.sum: -------------------------------------------------------------------------------- 1 | github.com/bufbuild/protocompile v0.14.0 h1:z3DW4IvXE5G/uTOnSQn+qwQQxvhckkTWLS/0No/o7KU= 2 | github.com/bufbuild/protocompile v0.14.0/go.mod h1:N6J1NYzkspJo3ZwyL4Xjvli86XOj1xq4qAasUFxGups= 3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 6 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 7 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 8 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 9 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= 10 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 11 | golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= 12 | golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 13 | google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= 14 | google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= 15 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 16 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 17 | -------------------------------------------------------------------------------- /internal/tools/nori/nori_test.go: -------------------------------------------------------------------------------- 1 | package nori_test 2 | 3 | import ( 4 | "context" 5 | "path/filepath" 6 | "testing" 7 | 8 | "google.golang.org/protobuf/types/pluginpb" 9 | 10 | "github.com/goccy/nori" 11 | ) 12 | 13 | func TestNori(t *testing.T) { 14 | bindProto := filepath.Join("internal", "wasm", "bind.proto") 15 | ctx := context.Background() 16 | files, err := nori.ProtoCompile(ctx, bindProto, filepath.Join(".."), filepath.Join("proto")) 17 | if err != nil { 18 | t.Fatal(err) 19 | } 20 | if _, err := nori.Generate(ctx, &pluginpb.CodeGeneratorRequest{ 21 | ProtoFile: files, 22 | }); err != nil { 23 | t.Fatal(err) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /internal/tools/nori/proto/nori/nori.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package nori; 4 | 5 | import "google/protobuf/descriptor.proto"; 6 | 7 | option go_package = "github.com/goccy/nori/nori;nori"; 8 | 9 | extend google.protobuf.FileOptions { 10 | FileRule file = 5000; 11 | } 12 | 13 | extend google.protobuf.ServiceOptions { 14 | ServiceRule service = 5000; 15 | } 16 | 17 | extend google.protobuf.MethodOptions { 18 | MethodRule method = 5000; 19 | } 20 | 21 | extend google.protobuf.MessageOptions { 22 | MessageRule message = 5000; 23 | } 24 | 25 | extend google.protobuf.FieldOptions { 26 | FieldRule field = 5000; 27 | } 28 | 29 | extend google.protobuf.EnumOptions { 30 | EnumRule enum = 5000; 31 | } 32 | 33 | extend google.protobuf.EnumValueOptions { 34 | EnumValueRule enum_value = 5000; 35 | } 36 | 37 | extend google.protobuf.OneofOptions { 38 | OneofRule oneof = 5000; 39 | } 40 | 41 | message FileRule { 42 | repeated Export export = 1; 43 | } 44 | 45 | message Export { 46 | repeated string header = 1; 47 | repeated FunctionDef func = 2; 48 | repeated MethodDef method = 3; 49 | } 50 | 51 | message FunctionDef { 52 | string name = 1; 53 | string alias = 2; 54 | repeated Type args = 3; 55 | Type return = 4; 56 | } 57 | 58 | message MethodDef { 59 | string recv = 1; 60 | string name = 2; 61 | string alias = 3; 62 | repeated Type args = 4; 63 | Type return = 5; 64 | } 65 | 66 | enum TypeKind { 67 | UNKNOWN = 0; // unknown type. 68 | STRUCT = 1; // structure type. 69 | INT = 2; // int type. 70 | UINT = 3; // unsigned int type. 71 | VOIDPTR = 4; // void* type. 72 | CHARPTR = 5; // char* type. 73 | STRING = 6; // std::string type. 74 | BOOL = 7; // bool type. 75 | UINT64 = 8; // uint64 type. 76 | INT64 = 9; // int64 type. 77 | ENUM = 10; // enum type. 78 | FUNCPTR = 11; // function pointer type. 79 | DOUBLE = 12; // double type. 80 | INT32 = 13; 81 | UINT32 = 14; 82 | FLOAT = 15; 83 | CHAR = 16; 84 | } 85 | 86 | message Type { 87 | TypeKind kind = 1; // type kind. 88 | string ref = 2; // reference name for type. 89 | uint64 pointer = 3; // pointer number. 90 | bool const = 4; // const value. 91 | bool addr = 5; // & operatored value. 92 | bool array = 6; // array type value. 93 | optional uint64 array_num = 7; // array size. 94 | optional uint64 array_num_arg = 8; // the argument number to decide array num. 95 | optional uint64 string_length_arg = 9; // the argument number to decide string length. 96 | 97 | // It is used as an argument for funcptr. 98 | // To uniquely determine a function between Go and C, some of the arguments need to be flagged. 99 | // It is used to specify those arguments. 100 | // When using funcptr, you must specify funcbaseptr for one of the arguments. 101 | bool funcbaseptr = 10; 102 | } 103 | 104 | message EnumRule { 105 | string alias = 1; 106 | } 107 | 108 | message EnumValueRule { 109 | string alias = 1; 110 | } 111 | 112 | message OneofRule {} 113 | 114 | message ServiceRule { 115 | } 116 | 117 | message MethodRule { 118 | } 119 | 120 | message MessageRule { 121 | string alias = 1; 122 | FunctionDef funcptr = 2; 123 | bool anonymous = 3; 124 | string parent = 4; 125 | optional bool constructor = 5; 126 | } 127 | 128 | message FieldRule { 129 | string alias = 1; 130 | Type type = 2; 131 | } 132 | 133 | message Any {} 134 | 135 | message List {} -------------------------------------------------------------------------------- /internal/tools/nori/protocompiler.go: -------------------------------------------------------------------------------- 1 | package nori 2 | 3 | import ( 4 | "context" 5 | "io" 6 | "os" 7 | 8 | "github.com/bufbuild/protocompile" 9 | "github.com/bufbuild/protocompile/linker" 10 | "github.com/bufbuild/protocompile/protoutil" 11 | "github.com/bufbuild/protocompile/reporter" 12 | "google.golang.org/protobuf/reflect/protoreflect" 13 | "google.golang.org/protobuf/types/descriptorpb" 14 | 15 | _ "embed" 16 | ) 17 | 18 | type errorReporter struct { 19 | errs []reporter.ErrorWithPos 20 | } 21 | 22 | func (r *errorReporter) Error(err reporter.ErrorWithPos) error { 23 | r.errs = append(r.errs, err) 24 | return nil 25 | } 26 | 27 | func (r *errorReporter) Warning(_ reporter.ErrorWithPos) { 28 | } 29 | 30 | func ProtoCompile(ctx context.Context, file string, importPaths ...string) ([]*descriptorpb.FileDescriptorProto, error) { 31 | var r errorReporter 32 | 33 | compiler := protocompile.Compiler{ 34 | Resolver: protocompile.WithStandardImports(&protocompile.SourceResolver{ 35 | ImportPaths: importPaths, 36 | Accessor: func(p string) (io.ReadCloser, error) { 37 | return os.Open(p) 38 | }, 39 | }), 40 | SourceInfoMode: protocompile.SourceInfoStandard, 41 | Reporter: &r, 42 | } 43 | files := []string{file} 44 | linkedFiles, err := compiler.Compile(ctx, files...) 45 | if err != nil { 46 | return nil, err 47 | } 48 | protoFiles := getProtoFiles(linkedFiles) 49 | return protoFiles, nil 50 | } 51 | 52 | func getProtoFiles(linkedFiles []linker.File) []*descriptorpb.FileDescriptorProto { 53 | var ( 54 | protos []*descriptorpb.FileDescriptorProto 55 | protoUniqueMap = make(map[string]struct{}) 56 | ) 57 | for _, linkedFile := range linkedFiles { 58 | for _, proto := range getFileDescriptors(linkedFile) { 59 | if _, exists := protoUniqueMap[proto.GetName()]; exists { 60 | continue 61 | } 62 | protos = append(protos, proto) 63 | protoUniqueMap[proto.GetName()] = struct{}{} 64 | } 65 | } 66 | return protos 67 | } 68 | 69 | func getFileDescriptors(file protoreflect.FileDescriptor) []*descriptorpb.FileDescriptorProto { 70 | var protoFiles []*descriptorpb.FileDescriptorProto 71 | fileImports := file.Imports() 72 | for i := 0; i < fileImports.Len(); i++ { 73 | protoFiles = append(protoFiles, getFileDescriptors(fileImports.Get(i))...) 74 | } 75 | protoFiles = append(protoFiles, protoutil.ProtoFromFileDescriptor(file)) 76 | return protoFiles 77 | } 78 | -------------------------------------------------------------------------------- /internal/tools/nori/templates/bind.c.tmpl: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-nori. DO NOT EDIT! 2 | 3 | #include 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif /* __cplusplus */ 8 | 9 | // this is imported by host function in Go. 10 | void *wasm_bridge_get_go_funcptr(void *funcbaseptr); 11 | 12 | {{ range .Headers }} 13 | #include "{{ . }}" 14 | {{- end }} 15 | 16 | typedef struct { char *p; int n; } GoString; 17 | typedef struct { int len; void *data; } GoSlice; 18 | typedef struct { void *t; void *v; } GoInterface; 19 | 20 | static GoString *newStringWithLength(char *src, int length) { 21 | GoString *ret = (GoString *)malloc(sizeof(GoString)); 22 | ret->p = src; 23 | ret->n = length; 24 | return ret; 25 | } 26 | 27 | static GoString *newString(char *src) { 28 | return newStringWithLength(src, strlen(src)); 29 | } 30 | 31 | static GoString *newFloatString(double src) { 32 | char *s = (char *)malloc(32); 33 | memset(s, 0, 32); 34 | snprintf(s, 32, "%lf", src); 35 | return newStringWithLength(s, strlen(s)); 36 | } 37 | 38 | static void to_string_ptr(void *arg) { 39 | char **strptr = (char **)arg; 40 | *(void **)arg = newString(*strptr); 41 | } 42 | 43 | static void to_string_ptr_with_length(void *arg, int length) { 44 | char **strptr = (char **)arg; 45 | *(void **)arg = newStringWithLength(*strptr, length); 46 | } 47 | 48 | {{- range .ExportCallbackFunctions }} 49 | {{- $name := .Name }} 50 | {{ .Return }} wasm_bridge_{{ $name }}({{- range .Args -}}{{ .Value.GoType }} arg{{- .Index -}}{{- if not .IsLastArg -}}, {{ end -}}{{- end -}}); 51 | 52 | {{ .Return }} {{ $name }}({{- range .Args -}}{{- .Value.CType }} _arg{{- .Index -}}{{- if not .IsLastArg -}}, {{ end -}}{{- end -}}) { 53 | {{- range .Args }} 54 | {{- template "toGoValue" .Value }} 55 | {{- end }} 56 | return wasm_bridge_{{ $name }}( 57 | {{- range .Args }} 58 | arg{{- .Index }}{{- if not .IsLastArg -}},{{- end -}} 59 | {{- end }} 60 | ); 61 | } 62 | {{ end }} 63 | 64 | {{- range .ExportEnums }} 65 | {{ range .Values }} 66 | int wasm_bridge_get_{{ .Name }}() { 67 | return {{ .Name }}; 68 | } 69 | {{ end }} 70 | {{- end }} 71 | 72 | {{ range .ExportMessages }} 73 | {{- if .HasConstructor }} 74 | void *wasm_bridge_new_{{ .Name }}() { 75 | void *ret = malloc(sizeof({{ .Type }})); 76 | memset(ret, 0, sizeof({{ .Type }})); 77 | return ret; 78 | } 79 | {{ end }} 80 | {{- range .Fields }} 81 | {{- if .Value.IsFunction }} 82 | void wasm_bridge_set_{{ .Name }}({{ .ReceiverType }} *recv) { 83 | {{ .Value.Src }} = {{ .Value.FuncName }}; 84 | } 85 | {{- else }} 86 | void wasm_bridge_get_{{ .Name }}({{ .ReceiverType }} *recv, {{ .Value.GoType }}* ret) { 87 | {{- template "toGoValue" .Value }} 88 | *ret = {{ .Value.Dst }}; 89 | } 90 | 91 | void wasm_bridge_set_{{ .Name }}({{ .ReceiverType }} *recv, {{ .Value.WasmType }} v) { 92 | {{- template "toCValue" (map "Value" .Value "Dst" .Value.Src "Src" "v" ) }} 93 | } 94 | {{- end }} 95 | {{ end }} 96 | {{- end }} 97 | 98 | {{ range .ExportFunctions }} 99 | void wasm_bridge_{{ .Name }}({{- range .Args -}}{{- .Value.WasmType }} _arg{{- .Index -}}{{- if not .IsLastArg -}}, {{ end -}}{{- end -}}) { 100 | {{- range .FuncArgs }} 101 | {{- if not .Value.IsFunction }} 102 | {{ .Value.CType }} {{ .Dst }}; 103 | {{- template "toCValue" (map "Value" .Value "Dst" .Dst "Src" .Src ) }} 104 | {{- end }} 105 | {{- end }} 106 | 107 | {{- if .Return }} 108 | {{ .Return.Value.CType }} ret = {{ .Function }}( 109 | {{- range .FuncArgs }} 110 | {{- if .Value.IsFunction }} 111 | {{ .Value.FuncName }}{{- if not .IsLastArg -}},{{ end -}} 112 | {{- else }} 113 | arg{{ .Index }}{{- if not .IsLastArg -}},{{ end -}} 114 | {{- end }} 115 | {{- end }} 116 | ); 117 | {{- $funcArgs := .FuncArgs }} 118 | {{- range $funcArgs }} 119 | {{- if .Value.IsPtrValue }} 120 | {{- if .Value.IsStringKind }} 121 | {{- if .Value.ArgStringLength }} 122 | 123 | {{- $index := .Value.ArgStringLength }} 124 | {{- $arg := index $funcArgs $index }} 125 | {{- if $arg.Value.IsPtrValue }} 126 | to_string_ptr_with_length(_arg{{ .Index }}, *(int *)_arg{{ $index }}); 127 | {{- else }} 128 | to_string_ptr_with_length(_arg{{ .Index }}, _arg{{ $index }}); 129 | {{- end }} 130 | {{- else }} 131 | to_string_ptr(_arg{{ .Index }}); 132 | {{- end }} 133 | 134 | {{- end }} 135 | {{- end }} 136 | {{- end }} 137 | {{- template "toGoValue" .Return.Value }} 138 | *_arg{{ .Return.Index }} = {{ .Return.Value.Dst }}; 139 | {{- else }} 140 | {{ .Function }}( 141 | {{- range .FuncArgs }} 142 | {{- if .Value.IsFunction }} 143 | {{ .Value.FuncName }}{{- if not .IsLastArg -}},{{- end -}} 144 | {{- else }} 145 | arg{{ .Index }}{{- if not .IsLastArg -}},{{ end -}} 146 | {{- end }} 147 | {{- end }} 148 | ); 149 | {{- end }} 150 | } 151 | {{ end }} 152 | 153 | #ifdef __cplusplus 154 | } 155 | #endif /* __cplusplus */ 156 | 157 | 158 | {{- define "toCValue" -}} 159 | {{- if .Value.IsSlice }} 160 | {{- if not .Value.FixedArrayNum }} 161 | {{ .Dst }} = ({{ .Value.CType }})malloc(sizeof({{ .Value.Elem.CType }}) * {{ .Src }}->len); 162 | {{- end }} 163 | for (int i = 0; i < {{ .Src }}->len; i++) { 164 | void *elem = ((void **){{ .Src }}->data)[i * 2]; 165 | {{- if .Value.IsPtrValue }} 166 | {{ .Dst }}[i] = ({{ .Value.Elem.CType }})elem; 167 | {{- else }} 168 | memcpy(&{{ .Dst }}[i], elem, sizeof({{ .Value.Elem.CType }})); 169 | {{- end }} 170 | } 171 | {{- else }} 172 | {{ .Dst }} = {{ .Value.Converter }}{{ .Src }}; 173 | {{- end }} 174 | {{- end -}} 175 | 176 | {{- define "toGoValue" -}} 177 | {{- if .IsSlice }} 178 | {{- template "toSlice" . }} 179 | {{- else if .IsString }} 180 | GoString *{{ .Dst }} = newString({{ .Src }}); 181 | {{- else if and .IsPtrValue .IsStringKind }} 182 | to_string_ptr({{ .Src }}); 183 | {{- else if .IsFloat }} 184 | GoString *{{ .Dst }} = newFloatString({{ .Src }}); 185 | {{- else if .IsStruct }} 186 | void *{{ .Dst }} = malloc(sizeof({{ .Src }})); 187 | memcpy({{ .Dst }}, &{{ .Src }}, sizeof({{ .Src }})); 188 | {{- else }} 189 | {{ .CType }} {{ .Dst }} = {{ .Converter }}{{ .Src }}; 190 | {{- end }} 191 | {{- end -}} 192 | 193 | {{- define "toSlice" -}} 194 | GoSlice *{{ .Dst }} = (GoSlice *)malloc(sizeof(GoSlice)); 195 | {{- if .FixedArrayNum }} 196 | int {{ .Dst }}_length = {{ .FixedArrayNum }}; 197 | {{- else if .ArrayNumArgIndex }} 198 | int {{ .Dst }}_length = _arg{{ .ArrayNumArgIndex }}; 199 | {{- else if or .IsStringKind .Type.Pointer }} 200 | int {{ .Dst }}_length = 0; 201 | for (int i = 0; {{ .Src }}[i] != NULL; i++) { 202 | {{ .Dst }}_length++; 203 | } 204 | {{- else }} 205 | int {{ .Dst }}_length = 0; 206 | {{- end }} 207 | {{ .Dst }}->len = {{ .Dst }}_length; 208 | void **{{ .Dst }}_data = (void **)malloc(8 * {{ .Dst }}_length); 209 | {{ .Dst }}->data = {{ .Dst }}_data; 210 | for (int i = 0; i < {{ .Dst }}_length; i++) { 211 | {{- template "toGoValue" .Elem }} 212 | *{{ .Dst }}_data = (void *){{ .IntPtr }}v; 213 | {{ .Dst }}_data += 2; // move data header address by 2 word (8 bytes). 214 | } 215 | 216 | {{- end -}} 217 | -------------------------------------------------------------------------------- /internal/wasm/build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/webassembly/wasi-sdk:wasi-sdk-24 2 | 3 | ARG GRAPHVIZ_VERSION 4 | 5 | ENV PATH=/opt/wasi-sdk/bin:$PATH 6 | ENV USE_CCACHE=1 7 | ENV CCACHE_DIR=/ccache 8 | 9 | RUN \ 10 | --mount=type=cache,target=/var/lib/apt,sharing=locked \ 11 | --mount=type=cache,target=/var/cache/apt,sharing=locked \ 12 | apt-get update && apt install -y pkg-config libexpat1-dev wget ccache 13 | 14 | RUN wget https://github.com/WebAssembly/binaryen/releases/download/version_119/binaryen-version_119-x86_64-linux.tar.gz 15 | RUN tar -zxvf binaryen-version_119-x86_64-linux.tar.gz 16 | 17 | RUN wget https://github.com/libexpat/libexpat/releases/download/R_2_6_3/expat-2.6.3.tar.gz 18 | RUN tar -zxvf expat-2.6.3.tar.gz && mv expat-2.6.3 expat 19 | 20 | RUN wget https://gitlab.com/api/v4/projects/4207231/packages/generic/graphviz-releases/$GRAPHVIZ_VERSION/graphviz-$GRAPHVIZ_VERSION.tar.gz 21 | RUN tar -zxvf graphviz-$GRAPHVIZ_VERSION.tar.gz && mv graphviz-$GRAPHVIZ_VERSION graphviz 22 | 23 | RUN cd graphviz && ./configure --host=amd64 --enable-ltdl=no --with-ipsepcola=no 24 | RUN cd expat && ./configure --host amd64 25 | 26 | RUN rm /graphviz/lib/rbtree/test_red_black_tree.c # remove the file includes main function. 27 | 28 | WORKDIR /work 29 | 30 | ENV PATH=/binaryen-version_119/bin:$PATH 31 | 32 | RUN \ 33 | --mount=type=cache,target=/ccache,sharing=locked \ 34 | --mount=type=bind,source=Makefile,target=Makefile \ 35 | --mount=type=bind,source=patch.c,target=patch.c \ 36 | --mount=type=bind,source=bind.c,target=bind.c \ 37 | make build 38 | 39 | RUN wasm-opt -g --strip --strip-producers -c -Os graphviz.wasm -o graphviz.wasm 40 | -------------------------------------------------------------------------------- /internal/wasm/build/Makefile: -------------------------------------------------------------------------------- 1 | CC := clang 2 | 3 | GRAPHVIZ_ROOT := /graphviz 4 | EXPAT_ROOT := /expat 5 | 6 | TARGET := graphviz.wasm 7 | 8 | build: 9 | ccache $(CC) \ 10 | -g0 -Os \ 11 | --sysroot=/opt/wasi-sdk/share/wasi-sysroot \ 12 | --target=wasm32-wasi \ 13 | -Wextra \ 14 | -Wno-format-security \ 15 | -Wno-bitwise-instead-of-logical \ 16 | -Wno-implicit-function-declaration \ 17 | -Wno-incompatible-pointer-types-discards-qualifiers \ 18 | -Wno-sign-compare \ 19 | -Wno-missing-field-initializers \ 20 | -Wno-undef \ 21 | -Wno-uninitialized \ 22 | -Wno-unused \ 23 | -Wno-unused-parameter \ 24 | -Wno-write-strings \ 25 | -Wno-char-subscripts \ 26 | -Wno-writable-strings \ 27 | -Wl,--export-all \ 28 | -Wl,--no-entry \ 29 | -Wl,--error-limit=0 \ 30 | -Wl,--import-undefined \ 31 | -funsigned-char \ 32 | -D_WASI_EMULATED_SIGNAL \ 33 | -D_WASI_EMULATED_MMAN \ 34 | -D_WASI_EMULATED_PROCESS_CLOCKS \ 35 | -lwasi-emulated-mman \ 36 | -lwasi-emulated-getpid \ 37 | -lwasi-emulated-signal \ 38 | -lwasi-emulated-process-clocks \ 39 | -I$(GRAPHVIZ_ROOT) \ 40 | -I$(GRAPHVIZ_ROOT)/lib/ \ 41 | -I$(GRAPHVIZ_ROOT)/lib/ast \ 42 | -I$(GRAPHVIZ_ROOT)/lib/cdt \ 43 | -I$(GRAPHVIZ_ROOT)/lib/cgraph \ 44 | -I$(GRAPHVIZ_ROOT)/lib/circogen \ 45 | -I$(GRAPHVIZ_ROOT)/lib/common \ 46 | -I$(GRAPHVIZ_ROOT)/lib/dotgen \ 47 | -I$(GRAPHVIZ_ROOT)/lib/edgepaint \ 48 | -I$(GRAPHVIZ_ROOT)/lib/expr \ 49 | -I$(GRAPHVIZ_ROOT)/lib/fdpgen \ 50 | -I$(GRAPHVIZ_ROOT)/lib/gvc \ 51 | -I$(GRAPHVIZ_ROOT)/lib/label \ 52 | -I$(GRAPHVIZ_ROOT)/lib/mingle \ 53 | -I$(GRAPHVIZ_ROOT)/lib/neatogen \ 54 | -I$(GRAPHVIZ_ROOT)/lib/ortho \ 55 | -I$(GRAPHVIZ_ROOT)/lib/osage \ 56 | -I$(GRAPHVIZ_ROOT)/lib/pack \ 57 | -I$(GRAPHVIZ_ROOT)/lib/patchwork \ 58 | -I$(GRAPHVIZ_ROOT)/lib/pathplan \ 59 | -I$(GRAPHVIZ_ROOT)/lib/rbtree \ 60 | -I$(GRAPHVIZ_ROOT)/lib/sfdpgen \ 61 | -I$(GRAPHVIZ_ROOT)/lib/sfio \ 62 | -I$(GRAPHVIZ_ROOT)/lib/sparse \ 63 | -I$(GRAPHVIZ_ROOT)/lib/topfish \ 64 | -I$(GRAPHVIZ_ROOT)/libtwopigen \ 65 | -I$(GRAPHVIZ_ROOT)/lib/util \ 66 | -I$(GRAPHVIZ_ROOT)/lib/vmalloc \ 67 | -I$(GRAPHVIZ_ROOT)/lib/vpsc \ 68 | -I$(GRAPHVIZ_ROOT)/lib/xdot \ 69 | -I$(EXPAT_ROOT) \ 70 | -I$(EXPAT_ROOT)/lib \ 71 | $(GRAPHVIZ_ROOT)/lib/ast/*.c \ 72 | $(GRAPHVIZ_ROOT)/lib/cdt/*.c \ 73 | $(GRAPHVIZ_ROOT)/lib/cgraph/*.c \ 74 | $(GRAPHVIZ_ROOT)/lib/circogen/*.c \ 75 | $(GRAPHVIZ_ROOT)/lib/common/*.c \ 76 | $(GRAPHVIZ_ROOT)/lib/dotgen/*.c \ 77 | $(GRAPHVIZ_ROOT)/lib/edgepaint/*.c \ 78 | $(GRAPHVIZ_ROOT)/lib/expr/*.c \ 79 | $(GRAPHVIZ_ROOT)/lib/fdpgen/*.c \ 80 | $(GRAPHVIZ_ROOT)/lib/gvc/*.c \ 81 | $(GRAPHVIZ_ROOT)/lib/label/*.c \ 82 | $(GRAPHVIZ_ROOT)/lib/ortho/*.c \ 83 | $(GRAPHVIZ_ROOT)/lib/osage/*.c \ 84 | $(GRAPHVIZ_ROOT)/lib/pack/*.c \ 85 | $(GRAPHVIZ_ROOT)/lib/patchwork/*.c \ 86 | $(GRAPHVIZ_ROOT)/lib/pathplan/*.c \ 87 | $(GRAPHVIZ_ROOT)/lib/rbtree/*.c \ 88 | $(GRAPHVIZ_ROOT)/lib/sfdpgen/*.c \ 89 | $(GRAPHVIZ_ROOT)/lib/sfio/*.c \ 90 | $(GRAPHVIZ_ROOT)/lib/sfio/Sfio_f/_sfslen.c \ 91 | $(GRAPHVIZ_ROOT)/lib/sparse/*.c \ 92 | $(GRAPHVIZ_ROOT)/lib/util/*.c \ 93 | $(GRAPHVIZ_ROOT)/lib/vmalloc/*.c \ 94 | $(GRAPHVIZ_ROOT)/lib/xdot/*.c \ 95 | $(GRAPHVIZ_ROOT)/lib/neatogen/adjust.c \ 96 | $(GRAPHVIZ_ROOT)/lib/neatogen/circuit.c \ 97 | $(GRAPHVIZ_ROOT)/lib/neatogen/edges.c \ 98 | $(GRAPHVIZ_ROOT)/lib/neatogen/geometry.c \ 99 | $(GRAPHVIZ_ROOT)/lib/neatogen/heap.c \ 100 | $(GRAPHVIZ_ROOT)/lib/neatogen/hedges.c \ 101 | $(GRAPHVIZ_ROOT)/lib/neatogen/info.c \ 102 | $(GRAPHVIZ_ROOT)/lib/neatogen/neatoinit.c \ 103 | $(GRAPHVIZ_ROOT)/lib/neatogen/legal.c \ 104 | $(GRAPHVIZ_ROOT)/lib/neatogen/lu.c \ 105 | $(GRAPHVIZ_ROOT)/lib/neatogen/matinv.c \ 106 | $(GRAPHVIZ_ROOT)/lib/neatogen/memory.c \ 107 | $(GRAPHVIZ_ROOT)/lib/neatogen/poly.c \ 108 | $(GRAPHVIZ_ROOT)/lib/neatogen/site.c \ 109 | $(GRAPHVIZ_ROOT)/lib/neatogen/solve.c \ 110 | $(GRAPHVIZ_ROOT)/lib/neatogen/neatosplines.c \ 111 | $(GRAPHVIZ_ROOT)/lib/neatogen/stuff.c \ 112 | $(GRAPHVIZ_ROOT)/lib/neatogen/voronoi.c \ 113 | $(GRAPHVIZ_ROOT)/lib/neatogen/stress.c \ 114 | $(GRAPHVIZ_ROOT)/lib/neatogen/kkutils.c \ 115 | $(GRAPHVIZ_ROOT)/lib/neatogen/matrix_ops.c \ 116 | $(GRAPHVIZ_ROOT)/lib/neatogen/embed_graph.c \ 117 | $(GRAPHVIZ_ROOT)/lib/neatogen/dijkstra.c \ 118 | $(GRAPHVIZ_ROOT)/lib/neatogen/conjgrad.c \ 119 | $(GRAPHVIZ_ROOT)/lib/neatogen/pca.c \ 120 | $(GRAPHVIZ_ROOT)/lib/neatogen/closest.c \ 121 | $(GRAPHVIZ_ROOT)/lib/neatogen/bfs.c \ 122 | $(GRAPHVIZ_ROOT)/lib/neatogen/constraint.c \ 123 | $(GRAPHVIZ_ROOT)/lib/neatogen/quad_prog_solve.c \ 124 | $(GRAPHVIZ_ROOT)/lib/neatogen/smart_ini_x.c \ 125 | $(GRAPHVIZ_ROOT)/lib/neatogen/constrained_majorization.c \ 126 | $(GRAPHVIZ_ROOT)/lib/neatogen/opt_arrangement.c \ 127 | $(GRAPHVIZ_ROOT)/lib/neatogen/overlap.c \ 128 | $(GRAPHVIZ_ROOT)/lib/neatogen/call_tri.c \ 129 | $(GRAPHVIZ_ROOT)/lib/neatogen/compute_hierarchy.c \ 130 | $(GRAPHVIZ_ROOT)/lib/neatogen/delaunay.c \ 131 | $(GRAPHVIZ_ROOT)/lib/neatogen/multispline.c \ 132 | $(GRAPHVIZ_ROOT)/lib/neatogen/sgd.c \ 133 | $(GRAPHVIZ_ROOT)/lib/neatogen/randomkit.c \ 134 | $(GRAPHVIZ_ROOT)/lib/twopigen/*.c \ 135 | $(GRAPHVIZ_ROOT)/plugin/dot_layout/*.c \ 136 | $(GRAPHVIZ_ROOT)/plugin/neato_layout/*.c \ 137 | $(GRAPHVIZ_ROOT)/plugin/core/*.c \ 138 | $(EXPAT_ROOT)/lib/*.c \ 139 | patch.c \ 140 | bind.c \ 141 | -o $(TARGET) 142 | -------------------------------------------------------------------------------- /internal/wasm/build/patch.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "gvplugin.h" 4 | #include "gvplugin_render.h" 5 | 6 | static const char *tmpfilename = "tmpfile"; 7 | 8 | FILE *tmpfile(void) 9 | { 10 | return fopen(tmpfilename, "w+"); 11 | } 12 | 13 | extern gvplugin_library_t gvplugin_dot_layout_LTX_library; 14 | extern gvplugin_library_t gvplugin_neato_layout_LTX_library; 15 | extern gvplugin_library_t gvplugin_core_LTX_library; 16 | 17 | lt_symlist_t lt_preloaded_symbols[] = { 18 | { "gvplugin_dot_layout_LTX_library", (void *)(&gvplugin_dot_layout_LTX_library) }, 19 | { "gvplugin_neato_layout_LTX_library", (void*)(&gvplugin_neato_layout_LTX_library) }, 20 | { "gvplugin_core_LTX_library", (void*)(&gvplugin_core_LTX_library) }, 21 | }; 22 | 23 | static gvplugin_api_t api_zero = {(api_t)0, 0}; 24 | static gvplugin_installed_t installed_zero = {0, NULL, 0, NULL, NULL}; 25 | static lt_symlist_t symlist_zero = {NULL, NULL}; 26 | 27 | typedef struct { int len; void *data; } GoSlice; 28 | 29 | void wasm_bridge_PluginAPI_zero(void **ret) { 30 | *ret = &api_zero; 31 | } 32 | 33 | void wasm_bridge_PluginInstalled_zero(void **ret) { 34 | *ret = &installed_zero; 35 | } 36 | 37 | void wasm_bridge_SymList_zero(void **ret) { 38 | *ret = &symlist_zero; 39 | } 40 | 41 | void wasm_bridge_SymList_default(GoSlice **ret) { 42 | GoSlice *v = (GoSlice *)malloc(sizeof(GoSlice)); 43 | size_t len = sizeof(lt_preloaded_symbols) / sizeof(lt_preloaded_symbols[0]); 44 | v->len = len; 45 | void **data = malloc(8 * len); 46 | v->data = data; 47 | for (int i = 0; i < len; i++) { 48 | lt_symlist_t *elem = (lt_symlist_t *)malloc(sizeof(lt_symlist_t)); 49 | memcpy(elem, <_preloaded_symbols[i], sizeof(lt_symlist_t)); 50 | *data = elem; 51 | data += 2; 52 | } 53 | *ret = v; 54 | } 55 | 56 | int main() { return 0; } 57 | -------------------------------------------------------------------------------- /internal/wasm/ext.go: -------------------------------------------------------------------------------- 1 | package wasm 2 | 3 | import ( 4 | "context" 5 | "io/fs" 6 | "sync" 7 | ) 8 | 9 | func DefaultSymList(ctx context.Context) ([]*SymList, error) { 10 | p, err := mod.NewPtr(ctx) 11 | if err != nil { 12 | return nil, err 13 | } 14 | if _, err := mod.ExportedFunction("wasm_bridge_SymList_default").Call(ctx, p); err != nil { 15 | return nil, err 16 | } 17 | ptr, err := mod.readU32(p) 18 | if err != nil { 19 | return nil, err 20 | } 21 | slice, err := mod.toSlice(ctx, ptr) 22 | if err != nil { 23 | return nil, err 24 | } 25 | return newSymListSlice(slice), nil 26 | } 27 | 28 | func PluginAPIZero(ctx context.Context) (*PluginAPI, error) { 29 | p, err := mod.NewPtr(ctx) 30 | if err != nil { 31 | return nil, err 32 | } 33 | if _, err := mod.ExportedFunction("wasm_bridge_PluginAPI_zero").Call(ctx, p); err != nil { 34 | return nil, err 35 | } 36 | ptr, err := mod.readU32(p) 37 | if err != nil { 38 | return nil, err 39 | } 40 | return newPluginAPI(ptr), nil 41 | } 42 | 43 | func PluginInstalledZero(ctx context.Context) (*PluginInstalled, error) { 44 | p, err := mod.NewPtr(ctx) 45 | if err != nil { 46 | return nil, err 47 | } 48 | if _, err := mod.ExportedFunction("wasm_bridge_PluginInstalled_zero").Call(ctx, p); err != nil { 49 | return nil, err 50 | } 51 | ptr, err := mod.readU32(p) 52 | if err != nil { 53 | return nil, err 54 | } 55 | return newPluginInstalled(ptr), nil 56 | } 57 | 58 | func SymListZero(ctx context.Context) (*SymList, error) { 59 | p, err := mod.NewPtr(ctx) 60 | if err != nil { 61 | return nil, err 62 | } 63 | if _, err := mod.ExportedFunction("wasm_bridge_SymList_zero").Call(ctx, p); err != nil { 64 | return nil, err 65 | } 66 | ptr, err := mod.readU32(p) 67 | if err != nil { 68 | return nil, err 69 | } 70 | return newSymList(ptr), nil 71 | } 72 | 73 | var ( 74 | fsMu sync.Mutex 75 | ) 76 | 77 | func SetWasmFileSystem(fs fs.FS) { 78 | fsMu.Lock() 79 | mod.fs.subFS = fs 80 | fsMu.Unlock() 81 | } 82 | 83 | func FileSystem() fs.FS { 84 | fsMu.Lock() 85 | defer fsMu.Unlock() 86 | return mod.fs 87 | } 88 | -------------------------------------------------------------------------------- /internal/wasm/graphviz.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goccy/go-graphviz/4ceff9e58e1a67056b302f85d0b793404e7280ee/internal/wasm/graphviz.wasm -------------------------------------------------------------------------------- /option.go: -------------------------------------------------------------------------------- 1 | package graphviz 2 | 3 | type GraphOption func(g *Graphviz) 4 | 5 | func WithName(name string) GraphOption { 6 | return func(g *Graphviz) { 7 | g.name = name 8 | } 9 | } 10 | 11 | func WithDirectedType(desc *GraphDescriptor) GraphOption { 12 | return func(g *Graphviz) { 13 | g.dir = desc 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /testdata/.gitignore: -------------------------------------------------------------------------------- 1 | !*.svg 2 | !*.png 3 | !*.jpg 4 | -------------------------------------------------------------------------------- /testdata/directed/KW91.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | style=bold; 3 | subgraph cluster_outer { 4 | Act_1 -> Act_21; 5 | Act_1 -> Act_23; 6 | Act_25 -> Act_3; 7 | subgraph cluster_inner { 8 | label = " Act_2"; 9 | {Act_21 -> Act_22 [minlen=2]; rank=same;} 10 | Act_22 -> Act_23; 11 | Act_22 -> Act_24; 12 | {Act_23 -> Act_24 [minlen=2]; rank=same;} 13 | Act_23 -> Act_25; 14 | Act_24 -> Act_25; 15 | } 16 | } 17 | Ext_1 -> Act_1; 18 | Act_3 -> Ext_2; 19 | Ext_3 -> Act_24; 20 | } 21 | -------------------------------------------------------------------------------- /testdata/directed/Latin1.gv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goccy/go-graphviz/4ceff9e58e1a67056b302f85d0b793404e7280ee/testdata/directed/Latin1.gv -------------------------------------------------------------------------------- /testdata/directed/NaN.gv: -------------------------------------------------------------------------------- 1 | digraph xyz { 2 | orientation=landscape; 3 | ratio=compress; 4 | size="16,10"; 5 | AbstractMemory -> Memory; 6 | AliasedMemory -> AliasedMemory; 7 | AliasedMemory -> Memory; 8 | Architecture -> ROOT; 9 | Assembly -> ROOT; 10 | AtomProperties -> NRAtom; 11 | AtomWr -> Wr; 12 | Break -> Break; 13 | Break -> Target; 14 | Breakpoint -> Breakpoint; 15 | Breakpoint -> Event; 16 | Breakpoint -> ROOT; 17 | CDB -> Target; 18 | CDB -> Thread; 19 | CommonFrame -> Target; 20 | ControlOps -> InterpF; 21 | Displayed -> Displayed; 22 | Displayed -> InterpTypes; 23 | ETimer -> RTHeapRep; 24 | Event -> Event; 25 | Event -> ROOT; 26 | Event -> Target; 27 | EventHandler -> ROOT; 28 | EventHandler -> StandardEvents; 29 | Expression -> ROOT; 30 | ExpressionServer -> Expression; 31 | FollowBreakpoint -> Breakpoint; 32 | Formatter -> ROOT; 33 | Formatter -> Thread; 34 | Frame -> Frame; 35 | Frame -> Memory; 36 | Frame -> Target; 37 | FrameClass -> Frame; 38 | IntIntTbl -> IntIntTbl; 39 | IntIntTbl -> ROOT; 40 | Interp -> InterpF; 41 | Interp -> ROOT; 42 | InterpF -> Interp; 43 | InterpF -> InterpF; 44 | InterpF -> ROOT; 45 | InterpScan -> TokenStream; 46 | InterpTypes -> InterpTypes; 47 | InterpTypes -> ROOT; 48 | List -> Thread; 49 | LoadState -> LoadState; 50 | LoadState -> LoadStateRep; 51 | LoadState -> ROOT; 52 | LoadStateRep -> LoadState; 53 | LocationRep -> Memory; 54 | MC68Frame -> CommonFrame; 55 | MC68GCommonFrame -> EventHandler; 56 | MUTEX -> ROOT; 57 | Memory -> Displayed; 58 | Memory -> InterpTypes; 59 | MipsFrame -> CommonFrame; 60 | MipsFrame -> InterpTypes; 61 | MipsGCommonFrame -> EventHandler; 62 | NRAtom -> AtomProperties; 63 | NRAtom -> ROOT; 64 | NopBreakpoint -> Breakpoint; 65 | PSFormatter -> InterpTypes; 66 | PSInterp -> InterpTypes; 67 | PSLoadState -> InterpTypes; 68 | PSMemory -> InterpTypes; 69 | ProtectedWire -> ProtectedWire; 70 | ProtectedWire -> Wire; 71 | RTHeap -> RTHeapRep; 72 | RTHeapRep -> ROOT; 73 | Rd -> RdClass; 74 | RdClass -> MUTEX; 75 | RegisterMemory -> Memory; 76 | Scope -> ROOT; 77 | Scope -> Scope; 78 | Scope -> Target; 79 | SourceLoc -> Target; 80 | SourceMap -> ROOT; 81 | SparcFrame -> CommonFrame; 82 | SparcGCommonFrame -> EventHandler; 83 | StandardEvents -> StandardEvents; 84 | StandardEvents -> Target; 85 | StreamWire -> Wire; 86 | Symbol -> Displayed; 87 | Symbol -> Symbol; 88 | TThread -> ROOT; 89 | TThread -> Target; 90 | Target -> Displayed; 91 | Target -> Event; 92 | Target -> FrameClass; 93 | Target -> ROOT; 94 | Target -> TThread; 95 | Target -> Target; 96 | Target -> TargetF; 97 | Target -> Thread; 98 | TargetF -> Target; 99 | TargetState -> Assembly; 100 | TextRd -> Rd; 101 | TextWr -> Wr; 102 | Thread -> ROOT; 103 | Thread -> Thread; 104 | TokenStream -> ROOT; 105 | TokenStream -> TokenStream; 106 | Trap -> ROOT; 107 | TrapMemory -> Memory; 108 | UFileRd -> Rd; 109 | UFileRd -> UFileRd; 110 | UFileWr -> UFileWr; 111 | UFileWr -> Wr; 112 | UnixHandler -> Event; 113 | UnixHandler -> UnixHandler; 114 | UserBreak -> Break; 115 | UserBreak -> Breakpoint; 116 | UserBreak -> Event; 117 | UserBreak -> Trap; 118 | UserBreak -> UserBreak; 119 | VaxFrame -> CommonFrame; 120 | VaxGCommonFrame -> EventHandler; 121 | Wire -> ROOT; 122 | Wire -> TrapMemory; 123 | Wire -> Wire; 124 | Wr -> WrClass; 125 | WrClass -> MUTEX; 126 | } 127 | -------------------------------------------------------------------------------- /testdata/directed/abstract.gv: -------------------------------------------------------------------------------- 1 | digraph abstract { 2 | size="6,6"; 3 | S24 -> 27; 4 | S24 -> 25; 5 | S1 -> 10; 6 | S1 -> 2; 7 | S35 -> 36; 8 | S35 -> 43; 9 | S30 -> 31; 10 | S30 -> 33; 11 | 9 -> 42; 12 | 9 -> T1; 13 | 25 -> T1; 14 | 25 -> 26; 15 | 27 -> T24; 16 | 2 -> 3; 17 | 2 -> 16; 18 | 2 -> 17; 19 | 2 -> T1; 20 | 2 -> 18; 21 | 10 -> 11; 22 | 10 -> 14; 23 | 10 -> T1; 24 | 10 -> 13; 25 | 10 -> 12; 26 | 31 -> T1; 27 | 31 -> 32; 28 | 33 -> T30; 29 | 33 -> 34; 30 | 42 -> 4; 31 | 26 -> 4; 32 | 3 -> 4; 33 | 16 -> 15; 34 | 17 -> 19; 35 | 18 -> 29; 36 | 11 -> 4; 37 | 14 -> 15; 38 | 37 -> 39; 39 | 37 -> 41; 40 | 37 -> 38; 41 | 37 -> 40; 42 | 13 -> 19; 43 | 12 -> 29; 44 | 43 -> 38; 45 | 43 -> 40; 46 | 36 -> 19; 47 | 32 -> 23; 48 | 34 -> 29; 49 | 39 -> 15; 50 | 41 -> 29; 51 | 38 -> 4; 52 | 40 -> 19; 53 | 4 -> 5; 54 | 19 -> 21; 55 | 19 -> 20; 56 | 19 -> 28; 57 | 5 -> 6; 58 | 5 -> T35; 59 | 5 -> 23; 60 | 21 -> 22; 61 | 20 -> 15; 62 | 28 -> 29; 63 | 6 -> 7; 64 | 15 -> T1; 65 | 22 -> 23; 66 | 22 -> T35; 67 | 29 -> T30; 68 | 7 -> T8; 69 | 23 -> T24; 70 | 23 -> T1; 71 | } 72 | -------------------------------------------------------------------------------- /testdata/directed/alf.gv: -------------------------------------------------------------------------------- 1 | digraph Alf { 2 | size = "6,9"; 3 | node [ shape = record ]; 4 | Decl [ label = "\n\nDecl|{name|access|decl_flags|extern_c_linkage}"]; 5 | Nontype_decl [ label = "Nontype_decl|{type}"]; 6 | Defined_decl [ label = "Defined_decl|{linkage}"]; 7 | Data_decl [ label = "Data_decl|{storage_class}"]; 8 | Function_decl [ label = "Function_decl|{formals|defaults}"]; 9 | Data [ label = "Data|{initializer}"]; 10 | Function [ label = "Function|{body}"]; 11 | Constructor [ label = "Constructor|{member_initializers}"]; 12 | Aggregate -> Type_decl ; 13 | Class -> Aggregate; 14 | Union -> Aggregate; 15 | Data -> Data_decl; 16 | Data -> Defn; 17 | Data_decl -> Defined_decl; 18 | Data_member -> Nontype_decl ; 19 | Defined_decl -> Nontype_decl; 20 | Defn -> Defined_decl; 21 | Enum -> Type_decl ; 22 | Enumerator -> Nontype_decl ; 23 | Function -> Defn; 24 | Function -> Function_decl; 25 | Constructor -> Function; 26 | Destructor -> Function; 27 | Function_decl -> Defined_decl; 28 | Nontype_decl -> Decl ; 29 | Template_type_arg -> Type_decl ; 30 | Type_decl -> Decl ; 31 | Typedef -> Type_decl ; 32 | } 33 | -------------------------------------------------------------------------------- /testdata/directed/arrows.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | graph [rankdir=LR nodesep=0] 3 | node [shape=point label=""] 4 | edge [fontsize=10] 5 | _box -> box [arrowhead=box label=box] 6 | box -> boxbox [arrowhead=boxbox label=boxbox] 7 | _box -> lbox [arrowhead=lbox label=lbox] 8 | lbox -> lboxlbox [arrowhead=lboxlbox label=lboxlbox] 9 | _box -> rbox [arrowhead=rbox label=rbox] 10 | rbox -> rboxrbox [arrowhead=rboxrbox label=rboxrbox] 11 | _box -> olbox [arrowhead=olbox label=olbox] 12 | olbox -> olboxolbox [arrowhead=olboxolbox label=olboxolbox] 13 | _box -> orbox [arrowhead=orbox label=orbox] 14 | orbox -> orboxorbox [arrowhead=orboxorbox label=orboxorbox] 15 | _box -> obox [arrowhead=obox label=obox] 16 | obox -> oboxobox [arrowhead=oboxobox label=oboxobox] 17 | _crow -> crow [arrowhead=crow label=crow] 18 | crow -> crowcrow [arrowhead=crowcrow label=crowcrow] 19 | _crow -> lcrow [arrowhead=lcrow label=lcrow] 20 | lcrow -> lcrowlcrow [arrowhead=lcrowlcrow label=lcrowlcrow] 21 | _crow -> rcrow [arrowhead=rcrow label=rcrow] 22 | rcrow -> rcrowrcrow [arrowhead=rcrowrcrow label=rcrowrcrow] 23 | _diamond -> diamond [arrowhead=diamond label=diamond] 24 | diamond -> diamonddiamond [arrowhead=diamonddiamond label=diamonddiamond] 25 | _diamond -> ldiamond [arrowhead=ldiamond label=ldiamond] 26 | ldiamond -> ldiamondldiamond [arrowhead=ldiamondldiamond label=ldiamondldiamond] 27 | _diamond -> rdiamond [arrowhead=rdiamond label=rdiamond] 28 | rdiamond -> rdiamondrdiamond [arrowhead=rdiamondrdiamond label=rdiamondrdiamond] 29 | _diamond -> oldiamond [arrowhead=oldiamond label=oldiamond] 30 | oldiamond -> oldiamondoldiamond [arrowhead=oldiamondoldiamond label=oldiamondoldiamond] 31 | _diamond -> ordiamond [arrowhead=ordiamond label=ordiamond] 32 | ordiamond -> ordiamondordiamond [arrowhead=ordiamondordiamond label=ordiamondordiamond] 33 | _diamond -> odiamond [arrowhead=odiamond label=odiamond] 34 | odiamond -> odiamondodiamond [arrowhead=odiamondodiamond label=odiamondodiamond] 35 | _dot -> dot [arrowhead=dot label=dot] 36 | dot -> dotdot [arrowhead=dotdot label=dotdot] 37 | _dot -> odot [arrowhead=odot label=odot] 38 | odot -> odotodot [arrowhead=odotodot label=odotodot] 39 | _inv -> inv [arrowhead=inv label=inv] 40 | inv -> invinv [arrowhead=invinv label=invinv] 41 | _inv -> linv [arrowhead=linv label=linv] 42 | linv -> linvlinv [arrowhead=linvlinv label=linvlinv] 43 | _inv -> rinv [arrowhead=rinv label=rinv] 44 | rinv -> rinvrinv [arrowhead=rinvrinv label=rinvrinv] 45 | _inv -> olinv [arrowhead=olinv label=olinv] 46 | olinv -> olinvolinv [arrowhead=olinvolinv label=olinvolinv] 47 | _inv -> orinv [arrowhead=orinv label=orinv] 48 | orinv -> orinvorinv [arrowhead=orinvorinv label=orinvorinv] 49 | _inv -> oinv [arrowhead=oinv label=oinv] 50 | oinv -> oinvoinv [arrowhead=oinvoinv label=oinvoinv] 51 | _none -> none [arrowhead=none label=none] 52 | none -> nonenone [arrowhead=nonenone label=nonenone] 53 | _normal -> normal [arrowhead=normal label=normal] 54 | normal -> normalnormal [arrowhead=normalnormal label=normalnormal] 55 | _normal -> lnormal [arrowhead=lnormal label=lnormal] 56 | lnormal -> lnormallnormal [arrowhead=lnormallnormal label=lnormallnormal] 57 | _normal -> rnormal [arrowhead=rnormal label=rnormal] 58 | rnormal -> rnormalrnormal [arrowhead=rnormalrnormal label=rnormalrnormal] 59 | _normal -> olnormal [arrowhead=olnormal label=olnormal] 60 | olnormal -> olnormalolnormal [arrowhead=olnormalolnormal label=olnormalolnormal] 61 | _normal -> ornormal [arrowhead=ornormal label=ornormal] 62 | ornormal -> ornormalornormal [arrowhead=ornormalornormal label=ornormalornormal] 63 | _normal -> onormal [arrowhead=onormal label=onormal] 64 | onormal -> onormalonormal [arrowhead=onormalonormal label=onormalonormal] 65 | _tee -> tee [arrowhead=tee label=tee] 66 | tee -> teetee [arrowhead=teetee label=teetee] 67 | _tee -> ltee [arrowhead=ltee label=ltee] 68 | ltee -> lteeltee [arrowhead=lteeltee label=lteeltee] 69 | _tee -> rtee [arrowhead=rtee label=rtee] 70 | rtee -> rteertee [arrowhead=rteertee label=rteertee] 71 | _vee -> vee [arrowhead=vee label=vee] 72 | vee -> veevee [arrowhead=veevee label=veevee] 73 | _vee -> lvee [arrowhead=lvee label=lvee] 74 | lvee -> lveelvee [arrowhead=lveelvee label=lveelvee] 75 | _vee -> rvee [arrowhead=rvee label=rvee] 76 | rvee -> rveervee [arrowhead=rveervee label=rveervee] 77 | _curve -> curve [arrowhead=curve label=curve] 78 | curve -> curvecurve [arrowhead=curvecurve label=curvecurve] 79 | _curve -> lcurve [arrowhead=lcurve label=lcurve] 80 | lcurve -> lcurvelcurve [arrowhead=lcurvelcurve label=lcurvelcurve] 81 | _curve -> rcurve [arrowhead=rcurve label=rcurve] 82 | rcurve -> rcurvercurve [arrowhead=rcurvercurve label=rcurvercurve] 83 | _icurve -> icurve [arrowhead=icurve label=icurve] 84 | icurve -> icurveicurve [arrowhead=icurveicurve label=icurveicurve] 85 | _icurve -> licurve [arrowhead=licurve label=licurve] 86 | licurve -> licurvelicurve [arrowhead=licurvelicurve label=licurvelicurve] 87 | _icurve -> ricurve [arrowhead=ricurve label=ricurve] 88 | ricurve -> ricurvericurve [arrowhead=ricurvericurve label=ricurvericurve] 89 | } 90 | -------------------------------------------------------------------------------- /testdata/directed/awilliams.gv: -------------------------------------------------------------------------------- 1 | digraph pvn { 2 | ordering=out; 3 | 4 | node_1 -> node_2; 5 | node_1 [label="ID: 1\ntype: 48\nnbr out: 0\nnbr chi: 11"]; 6 | node_2 [label="ID: 2\ntype: 8\nnbr out: 0\nnbr chi: 0"]; 7 | node_1 -> node_3; 8 | node_3 [label="ID: 3\ntype: 1\nnbr out: 0\nnbr chi: 0"]; 9 | node_1 -> node_4; 10 | node_4 [label="ID: 4\ntype: 6\nnbr out: 0\nnbr chi: 0"]; 11 | node_1 -> node_5; 12 | node_5 [label="ID: 5\ntype: 14\nnbr out: 0\nnbr chi: 0"]; 13 | node_1 -> node_6; 14 | node_6 [label="ID: 6\ntype: 14\nnbr out: 0\nnbr chi: 0"]; 15 | node_1 -> node_7; 16 | node_7 [label="ID: 7\ntype: 49\nnbr out: 0\nnbr chi: 0"]; 17 | node_7 -> node_8; 18 | node_8 [label="ID: 8\ntype: 45\nnbr out: 2\nnbr chi: 0"]; 19 | node_8 -> node_9; 20 | node_9 [label="ID: 9\ntype: 48\nnbr out: 0\nnbr chi: 4"]; 21 | node_9 -> node_10; 22 | node_10 [label="ID: 10\ntype: 8\nnbr out: 0\nnbr chi: 0"]; 23 | node_9 -> node_11; 24 | node_11 [label="ID: 11\ntype: 1\nnbr out: 0\nnbr chi: 0"]; 25 | node_9 -> node_12; 26 | node_12 [label="ID: 12\ntype: 5\nnbr out: 0\nnbr chi: 0"]; 27 | node_9 -> node_13; 28 | node_13 [label="ID: 13\ntype: 16\nnbr out: 0\nnbr chi: 0"]; 29 | node_8 -> node_14; 30 | node_14 [label="ID: 14\ntype: 39\nnbr out: 1\nnbr chi: 0"]; 31 | node_14 -> node_15; 32 | node_15 [label="ID: 15\ntype: 55\nnbr out: 0\nnbr chi: 0"]; 33 | node_15 -> node_16; 34 | node_16 [label="ID: 16\ntype: 48\nnbr out: 0\nnbr chi: 3"]; 35 | node_16 -> node_17; 36 | node_17 [label="ID: 17\ntype: 1\nnbr out: 0\nnbr chi: 0"]; 37 | node_16 -> node_18; 38 | node_18 [label="ID: 18\ntype: 6\nnbr out: 0\nnbr chi: 0"]; 39 | node_16 -> node_19; 40 | node_19 [label="ID: 19\ntype: 45\nnbr out: 1\nnbr chi: 0"]; 41 | node_19 -> node_20; 42 | node_20 [label="ID: 20\ntype: 48\nnbr out: 0\nnbr chi: 5"]; 43 | node_20 -> node_21; 44 | node_21 [label="ID: 21\ntype: 38\nnbr out: 0\nnbr chi: 0"]; 45 | node_20 -> node_22; 46 | node_22 [label="ID: 22\ntype: 8\nnbr out: 0\nnbr chi: 0"]; 47 | node_20 -> node_23; 48 | node_23 [label="ID: 23\ntype: 1\nnbr out: 0\nnbr chi: 0"]; 49 | node_20 -> node_24; 50 | node_24 [label="ID: 24\ntype: 5\nnbr out: 0\nnbr chi: 0"]; 51 | node_20 -> node_25; 52 | node_25 [label="ID: 25\ntype: 16\nnbr out: 0\nnbr chi: 0"]; 53 | node_19 -> node_26; 54 | node_26 [label="ID: 26\ntype: 41\nnbr out: 12\nnbr chi: 0"]; 55 | node_26 -> node_27; 56 | node_27 [label="ID: 27\ntype: 48\nnbr out: 0\nnbr chi: 5"]; 57 | node_27 -> node_28; 58 | node_28 [label="ID: 28\ntype: 38\nnbr out: 0\nnbr chi: 0"]; 59 | node_27 -> node_29; 60 | node_29 [label="ID: 29\ntype: 8\nnbr out: 0\nnbr chi: 0"]; 61 | node_27 -> node_30; 62 | node_30 [label="ID: 30\ntype: 1\nnbr out: 0\nnbr chi: 0"]; 63 | node_27 -> node_31; 64 | node_31 [label="ID: 31\ntype: 5\nnbr out: 0\nnbr chi: 0"]; 65 | node_27 -> node_32; 66 | node_32 [label="ID: 32\ntype: 16\nnbr out: 0\nnbr chi: 0"]; 67 | node_26 -> node_27; 68 | node_26 -> node_27; 69 | node_26 -> node_27; 70 | node_26 -> node_27; 71 | node_26 -> node_27; 72 | node_26 -> node_27; 73 | node_26 -> node_27; 74 | node_26 -> node_27; 75 | node_26 -> node_27; 76 | node_26 -> node_27; 77 | node_26 -> node_27; 78 | node_26 -> node_33; 79 | node_33 [label="ID: 33\ntype: 48\nnbr out: 0\nnbr chi: 5"]; 80 | node_33 -> node_34; 81 | node_34 [label="ID: 34\ntype: 38\nnbr out: 0\nnbr chi: 0"]; 82 | node_33 -> node_35; 83 | node_35 [label="ID: 35\ntype: 14\nnbr out: 0\nnbr chi: 0"]; 84 | node_33 -> node_36; 85 | node_36 [label="ID: 36\ntype: 14\nnbr out: 0\nnbr chi: 0"]; 86 | node_33 -> node_37; 87 | node_37 [label="ID: 37\ntype: 20\nnbr out: 0\nnbr chi: 0"]; 88 | node_33 -> node_38; 89 | node_38 [label="ID: 38\ntype: 16\nnbr out: 0\nnbr chi: 0"]; 90 | node_15 -> node_39; 91 | node_39 [label="ID: 39\ntype: 45\nnbr out: 1\nnbr chi: 0"]; 92 | node_39 -> node_40; 93 | node_40 [label="ID: 40\ntype: 16\nnbr out: 0\nnbr chi: 0"]; 94 | node_39 -> node_41; 95 | node_41 [label="ID: 41\ntype: 48\nnbr out: 0\nnbr chi: 3"]; 96 | node_41 -> node_42; 97 | node_42 [label="ID: 42\ntype: 14\nnbr out: 0\nnbr chi: 0"]; 98 | node_41 -> node_43; 99 | node_43 [label="ID: 43\ntype: 1\nnbr out: 0\nnbr chi: 0"]; 100 | node_41 -> node_44; 101 | node_44 [label="ID: 44\ntype: 6\nnbr out: 0\nnbr chi: 0"]; 102 | node_15 -> node_45; 103 | node_45 [label="ID: 45\ntype: 48\nnbr out: 0\nnbr chi: 4"]; 104 | node_45 -> node_46; 105 | node_46 [label="ID: 46\ntype: 14\nnbr out: 0\nnbr chi: 0"]; 106 | node_45 -> node_47; 107 | node_47 [label="ID: 47\ntype: 45\nnbr out: 1\nnbr chi: 0"]; 108 | node_47 -> node_48; 109 | node_48 [label="ID: 48\ntype: 14\nnbr out: 0\nnbr chi: 0"]; 110 | node_47 -> node_49; 111 | node_49 [label="ID: 49\ntype: 14\nnbr out: 0\nnbr chi: 0"]; 112 | node_45 -> node_50; 113 | node_50 [label="ID: 50\ntype: 14\nnbr out: 0\nnbr chi: 0"]; 114 | node_45 -> node_51; 115 | node_51 [label="ID: 51\ntype: 45\nnbr out: 1\nnbr chi: 0"]; 116 | node_51 -> node_52; 117 | node_52 [label="ID: 52\ntype: 45\nnbr out: 1\nnbr chi: 0"]; 118 | node_52 -> node_53; 119 | node_53 [label="ID: 53\ntype: 54\nnbr out: 0\nnbr chi: 0"]; 120 | node_52 -> node_54; 121 | node_54 [label="ID: 54\ntype: 16\nnbr out: 0\nnbr chi: 0"]; 122 | node_51 -> node_55; 123 | node_55 [label="ID: 55\ntype: 48\nnbr out: 0\nnbr chi: 3"]; 124 | node_55 -> node_56; 125 | node_56 [label="ID: 56\ntype: 14\nnbr out: 0\nnbr chi: 0"]; 126 | node_55 -> node_57; 127 | node_57 [label="ID: 57\ntype: 1\nnbr out: 0\nnbr chi: 0"]; 128 | node_55 -> node_58; 129 | node_58 [label="ID: 58\ntype: 6\nnbr out: 0\nnbr chi: 0"]; 130 | node_15 -> node_59; 131 | node_59 [label="ID: 59\ntype: 48\nnbr out: 0\nnbr chi: 5"]; 132 | node_59 -> node_60; 133 | node_60 [label="ID: 60\ntype: 38\nnbr out: 0\nnbr chi: 0"]; 134 | node_59 -> node_61; 135 | node_61 [label="ID: 61\ntype: 8\nnbr out: 0\nnbr chi: 0"]; 136 | node_59 -> node_62; 137 | node_62 [label="ID: 62\ntype: 1\nnbr out: 0\nnbr chi: 0"]; 138 | node_59 -> node_63; 139 | node_63 [label="ID: 63\ntype: 5\nnbr out: 0\nnbr chi: 0"]; 140 | node_59 -> node_64; 141 | node_64 [label="ID: 64\ntype: 16\nnbr out: 0\nnbr chi: 0"]; 142 | node_15 -> node_65; 143 | node_65 [label="ID: 65\ntype: 48\nnbr out: 0\nnbr chi: 5"]; 144 | node_65 -> node_66; 145 | node_66 [label="ID: 66\ntype: 38\nnbr out: 0\nnbr chi: 0"]; 146 | node_65 -> node_67; 147 | node_67 [label="ID: 67\ntype: 14\nnbr out: 0\nnbr chi: 0"]; 148 | node_65 -> node_68; 149 | node_68 [label="ID: 68\ntype: 14\nnbr out: 0\nnbr chi: 0"]; 150 | node_65 -> node_69; 151 | node_69 [label="ID: 69\ntype: 20\nnbr out: 0\nnbr chi: 0"]; 152 | node_65 -> node_70; 153 | node_70 [label="ID: 70\ntype: 16\nnbr out: 0\nnbr chi: 0"]; 154 | node_14 -> node_71; 155 | node_71 [label="ID: 71\ntype: 45\nnbr out: 1\nnbr chi: 0"]; 156 | node_71 -> node_72; 157 | node_72 [label="ID: 72\ntype: 16\nnbr out: 0\nnbr chi: 0"]; 158 | node_71 -> node_73; 159 | node_73 [label="ID: 73\ntype: 48\nnbr out: 0\nnbr chi: 3"]; 160 | node_73 -> node_74; 161 | node_74 [label="ID: 74\ntype: 14\nnbr out: 0\nnbr chi: 0"]; 162 | node_73 -> node_75; 163 | node_75 [label="ID: 75\ntype: 1\nnbr out: 0\nnbr chi: 0"]; 164 | node_73 -> node_76; 165 | node_76 [label="ID: 76\ntype: 6\nnbr out: 0\nnbr chi: 0"]; 166 | node_8 -> node_77; 167 | node_77 [label="ID: 77\ntype: 45\nnbr out: 1\nnbr chi: 0"]; 168 | node_77 -> node_78; 169 | node_78 [label="ID: 78\ntype: 16\nnbr out: 0\nnbr chi: 0"]; 170 | node_77 -> node_79; 171 | node_79 [label="ID: 79\ntype: 48\nnbr out: 0\nnbr chi: 3"]; 172 | node_79 -> node_80; 173 | node_80 [label="ID: 80\ntype: 14\nnbr out: 0\nnbr chi: 0"]; 174 | node_79 -> node_81; 175 | node_81 [label="ID: 81\ntype: 1\nnbr out: 0\nnbr chi: 0"]; 176 | node_79 -> node_82; 177 | node_82 [label="ID: 82\ntype: 6\nnbr out: 0\nnbr chi: 0"]; 178 | node_1 -> node_83; 179 | node_83 [label="ID: 83\ntype: 38\nnbr out: 0\nnbr chi: 0"]; 180 | node_1 -> node_84; 181 | node_84 [label="ID: 84\ntype: 8\nnbr out: 0\nnbr chi: 0"]; 182 | node_1 -> node_85; 183 | node_85 [label="ID: 85\ntype: 1\nnbr out: 0\nnbr chi: 0"]; 184 | node_1 -> node_86; 185 | node_86 [label="ID: 86\ntype: 5\nnbr out: 0\nnbr chi: 0"]; 186 | node_1 -> node_87; 187 | node_87 [label="ID: 87\ntype: 16\nnbr out: 0\nnbr chi: 0"]; 188 | } 189 | -------------------------------------------------------------------------------- /testdata/directed/biological.gv: -------------------------------------------------------------------------------- 1 | digraph g { 2 | rankdir=LR; 3 | 4 | node [shape=rpromoter colorscheme=rdbu5 color=1 style=filled fontcolor=3]; Hef1a; TRE; UAS; Hef1aLacOid; 5 | Hef1aLacOid [label="Hef1a-LacOid"]; 6 | node [shape=rarrow colorscheme=rdbu5 color=5 style=filled fontcolor=3]; Gal4VP16; LacI; rtTA3; DeltamCherry; 7 | Gal4VP16 [label="Gal4-VP16"]; 8 | product [shape=oval style=filled colorscheme=rdbu5 color=2 label=""]; 9 | repression [shape=oval label="LacI repression" fontcolor=black style=dotted]; 10 | node [shape=oval style=filled colorscheme=rdbu5 color=4 fontcolor=5]; 11 | combination [label="rtTA3 + Doxycycline"]; 12 | LacIprotein [label="LacI"]; 13 | rtTA3protein [label="rtTA3"]; 14 | Gal4VP16protein [label="Gal4-VP16"]; 15 | 16 | 17 | subgraph cluster_0 { 18 | colorscheme=rdbu5; 19 | color=3; 20 | node [colorscheme=rdbu5 fontcolor=3]; 21 | Hef1a -> Gal4VP16 [arrowhead=none]; 22 | Gal4VP16 -> UAS [arrowhead=none]; 23 | UAS -> LacI [arrowhead=none]; 24 | LacI -> Hef1aLacOid [arrowhead=none]; 25 | Hef1aLacOid -> rtTA3 [arrowhead=none]; 26 | rtTA3 -> TRE [arrowhead=none]; 27 | TRE -> DeltamCherry [arrowhead=none] 28 | } 29 | 30 | Gal4VP16 -> Gal4VP16protein; 31 | Gal4VP16protein -> UAS; 32 | LacI -> LacIprotein; 33 | LacIprotein -> repression; 34 | repression -> Hef1aLacOid [arrowhead=tee]; 35 | IPTG -> repression [arrowhead=tee]; 36 | rtTA3 -> rtTA3protein; 37 | rtTA3protein -> combination; 38 | combination -> TRE; 39 | Doxycycline -> combination; 40 | DeltamCherry -> product; 41 | 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /testdata/directed/clust.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | subgraph cluster_0 { 3 | label = "hello world"; 4 | a -> b; 5 | a -> c; 6 | color = hotpink; 7 | } 8 | 9 | subgraph cluster_1 { 10 | label = "MSDOT"; 11 | style= "dashed"; 12 | color=purple; 13 | x -> y; 14 | x -> z; 15 | y -> z; 16 | y -> q; 17 | } 18 | 19 | top -> a; 20 | top -> y; 21 | y -> b; 22 | } 23 | -------------------------------------------------------------------------------- /testdata/directed/clust1.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | subgraph cluster_c0 {a0 -> a1 -> a2 -> a3;} 3 | subgraph cluster_c1 {b0 -> b1 -> b2 -> b3;} 4 | x -> a0; 5 | x -> b0; 6 | a1 -> a3; 7 | a3 -> a0; 8 | } 9 | -------------------------------------------------------------------------------- /testdata/directed/clust2.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | subgraph cluster_c0 {a0 -> a1 -> a2 -> a3;} 3 | subgraph cluster_c1 {b0 -> b1 -> b2 -> b3;} 4 | x -> a0; 5 | x -> b0; 6 | a1 -> b3; 7 | b3 -> a1; 8 | } 9 | -------------------------------------------------------------------------------- /testdata/directed/clust3.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | subgraph cluster_c0 {a0 -> a1 -> a2 -> a3;} 3 | subgraph cluster_c1 {b0 -> b1 -> b2 -> b3;} 4 | x -> a0; 5 | x -> b0; 6 | a1 -> b3; 7 | b1 -> a3; 8 | } 9 | -------------------------------------------------------------------------------- /testdata/directed/clust4.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | 3 | subgraph cluster_0 { 4 | style=filled; 5 | color=lightgrey; 6 | node [style=filled,color=white]; 7 | a0 -> a1 -> a2 -> a3; 8 | label = "process #1"; 9 | } 10 | 11 | subgraph cluster_1 { 12 | node [style=filled]; 13 | b0 -> b1 -> b2 -> b3; 14 | label = "process #2"; 15 | color=blue 16 | } 17 | start -> a0; 18 | start -> b0; 19 | a1 -> b3; 20 | b2 -> a3; 21 | a3 -> a0; 22 | a3 -> end; 23 | b3 -> end; 24 | 25 | start [shape=Mdiamond]; 26 | end [shape=Msquare]; 27 | } 28 | -------------------------------------------------------------------------------- /testdata/directed/clust5.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | size="6,6"; 3 | a -> b -> c; 4 | 5 | subgraph cluster0 { 6 | x0 -> y0; 7 | x0 -> z0; 8 | } 9 | 10 | subgraph cluster1 { 11 | x1 -> y1; 12 | x1 -> z1; 13 | } 14 | 15 | subgraph cluster2 { 16 | x2 -> y2; 17 | x2 -> z2; 18 | } 19 | 20 | a -> x0; 21 | b -> x1; 22 | b -> x2; 23 | a -> z2; 24 | c -> z1; 25 | } 26 | -------------------------------------------------------------------------------- /testdata/directed/crazy.gv: -------------------------------------------------------------------------------- 1 | digraph "unix" { 2 | graph [ fontname = "Helvetica-Oblique", 3 | fontsize = 36, 4 | label = "\n\n\n\nObject Oriented Graphs\nStephen North, 3/19/93", 5 | size = "6,6" ]; 6 | node [ shape = polygon, 7 | sides = 4, 8 | distortion = "0.0", 9 | orientation = "0.0", 10 | skew = "0.0", 11 | color = white, 12 | style = filled, 13 | fontname = "Helvetica-Outline" ]; 14 | "5th Edition" [sides=9, distortion="0.936354", orientation=28, skew="-0.126818", color=salmon2]; 15 | "6th Edition" [sides=5, distortion="0.238792", orientation=11, skew="0.995935", color=deepskyblue]; 16 | "PWB 1.0" [sides=8, distortion="0.019636", orientation=79, skew="-0.440424", color=goldenrod2]; 17 | LSX [sides=9, distortion="-0.698271", orientation=22, skew="-0.195492", color=burlywood2]; 18 | "1 BSD" [sides=7, distortion="0.265084", orientation=26, skew="0.403659", color=gold1]; 19 | "Mini Unix" [distortion="0.039386", orientation=2, skew="-0.461120", color=greenyellow]; 20 | Wollongong [sides=5, distortion="0.228564", orientation=63, skew="-0.062846", color=darkseagreen]; 21 | Interdata [distortion="0.624013", orientation=56, skew="0.101396", color=dodgerblue1]; 22 | "Unix/TS 3.0" [sides=8, distortion="0.731383", orientation=43, skew="-0.824612", color=thistle2]; 23 | "PWB 2.0" [sides=6, distortion="0.592100", orientation=34, skew="-0.719269", color=darkolivegreen3]; 24 | "7th Edition" [sides=10, distortion="0.298417", orientation=65, skew="0.310367", color=chocolate]; 25 | "8th Edition" [distortion="-0.997093", orientation=50, skew="-0.061117", color=turquoise3]; 26 | "32V" [sides=7, distortion="0.878516", orientation=19, skew="0.592905", color=steelblue3]; 27 | V7M [sides=10, distortion="-0.960249", orientation=32, skew="0.460424", color=navy]; 28 | "Ultrix-11" [sides=10, distortion="-0.633186", orientation=10, skew="0.333125", color=darkseagreen4]; 29 | Xenix [sides=8, distortion="-0.337997", orientation=52, skew="-0.760726", color=coral]; 30 | "UniPlus+" [sides=7, distortion="0.788483", orientation=39, skew="-0.526284", color=darkolivegreen3]; 31 | "9th Edition" [sides=7, distortion="0.138690", orientation=55, skew="0.554049", color=coral3]; 32 | "2 BSD" [sides=7, distortion="-0.010661", orientation=84, skew="0.179249", color=blanchedalmond]; 33 | "2.8 BSD" [distortion="-0.239422", orientation=44, skew="0.053841", color=lightskyblue1]; 34 | "2.9 BSD" [distortion="-0.843381", orientation=70, skew="-0.601395", color=aquamarine2]; 35 | "3 BSD" [sides=10, distortion="0.251820", orientation=18, skew="-0.530618", color=lemonchiffon]; 36 | "4 BSD" [sides=5, distortion="-0.772300", orientation=24, skew="-0.028475", color=darkorange1]; 37 | "4.1 BSD" [distortion="-0.226170", orientation=38, skew="0.504053", color=lightyellow1]; 38 | "4.2 BSD" [sides=10, distortion="-0.807349", orientation=50, skew="-0.908842", color=darkorchid4]; 39 | "4.3 BSD" [sides=10, distortion="-0.030619", orientation=76, skew="0.985021", color=lemonchiffon2]; 40 | "Ultrix-32" [distortion="-0.644209", orientation=21, skew="0.307836", color=goldenrod3]; 41 | "PWB 1.2" [sides=7, distortion="0.640971", orientation=84, skew="-0.768455", color=cyan]; 42 | "USG 1.0" [distortion="0.758942", orientation=42, skew="0.039886", color=blue]; 43 | "CB Unix 1" [sides=9, distortion="-0.348692", orientation=42, skew="0.767058", color=firebrick]; 44 | "USG 2.0" [distortion="0.748625", orientation=74, skew="-0.647656", color=chartreuse4]; 45 | "CB Unix 2" [sides=10, distortion="0.851818", orientation=32, skew="-0.020120", color=greenyellow]; 46 | "CB Unix 3" [sides=10, distortion="0.992237", orientation=29, skew="0.256102", color=bisque4]; 47 | "Unix/TS++" [sides=6, distortion="0.545461", orientation=16, skew="0.313589", color=mistyrose2]; 48 | "PDP-11 Sys V" [sides=9, distortion="-0.267769", orientation=40, skew="0.271226", color=cadetblue1]; 49 | "USG 3.0" [distortion="-0.848455", orientation=44, skew="0.267152", color=bisque2]; 50 | "Unix/TS 1.0" [distortion="0.305594", orientation=75, skew="0.070516", color=orangered]; 51 | "TS 4.0" [sides=10, distortion="-0.641701", orientation=50, skew="-0.952502", color=crimson]; 52 | "System V.0" [sides=9, distortion="0.021556", orientation=26, skew="-0.729938", color=darkorange1]; 53 | "System V.2" [sides=6, distortion="0.985153", orientation=33, skew="-0.399752", color=darkolivegreen4]; 54 | "System V.3" [sides=7, distortion="-0.687574", orientation=58, skew="-0.180116", color=lightsteelblue1]; 55 | "5th Edition" -> "6th Edition"; 56 | "5th Edition" -> "PWB 1.0"; 57 | "6th Edition" -> LSX; 58 | "6th Edition" -> "1 BSD"; 59 | "6th Edition" -> "Mini Unix"; 60 | "6th Edition" -> Wollongong; 61 | "6th Edition" -> Interdata; 62 | Interdata -> "Unix/TS 3.0"; 63 | Interdata -> "PWB 2.0"; 64 | Interdata -> "7th Edition"; 65 | "7th Edition" -> "8th Edition"; 66 | "7th Edition" -> "32V"; 67 | "7th Edition" -> V7M; 68 | "7th Edition" -> "Ultrix-11"; 69 | "7th Edition" -> Xenix; 70 | "7th Edition" -> "UniPlus+"; 71 | V7M -> "Ultrix-11"; 72 | "8th Edition" -> "9th Edition"; 73 | "1 BSD" -> "2 BSD"; 74 | "2 BSD" -> "2.8 BSD"; 75 | "2.8 BSD" -> "Ultrix-11"; 76 | "2.8 BSD" -> "2.9 BSD"; 77 | "32V" -> "3 BSD"; 78 | "3 BSD" -> "4 BSD"; 79 | "4 BSD" -> "4.1 BSD"; 80 | "4.1 BSD" -> "4.2 BSD"; 81 | "4.1 BSD" -> "2.8 BSD"; 82 | "4.1 BSD" -> "8th Edition"; 83 | "4.2 BSD" -> "4.3 BSD"; 84 | "4.2 BSD" -> "Ultrix-32"; 85 | "PWB 1.0" -> "PWB 1.2"; 86 | "PWB 1.0" -> "USG 1.0"; 87 | "PWB 1.2" -> "PWB 2.0"; 88 | "USG 1.0" -> "CB Unix 1"; 89 | "USG 1.0" -> "USG 2.0"; 90 | "CB Unix 1" -> "CB Unix 2"; 91 | "CB Unix 2" -> "CB Unix 3"; 92 | "CB Unix 3" -> "Unix/TS++"; 93 | "CB Unix 3" -> "PDP-11 Sys V"; 94 | "USG 2.0" -> "USG 3.0"; 95 | "USG 3.0" -> "Unix/TS 3.0"; 96 | "PWB 2.0" -> "Unix/TS 3.0"; 97 | "Unix/TS 1.0" -> "Unix/TS 3.0"; 98 | "Unix/TS 3.0" -> "TS 4.0"; 99 | "Unix/TS++" -> "TS 4.0"; 100 | "CB Unix 3" -> "TS 4.0"; 101 | "TS 4.0" -> "System V.0"; 102 | "System V.0" -> "System V.2"; 103 | "System V.2" -> "System V.3"; 104 | } 105 | -------------------------------------------------------------------------------- /testdata/directed/ctext.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | xyz [label = "hello\nworld",color="slateblue",fontsize=24,fontname="Palatino-Italic",style=filled,fontcolor="hotpink"]; 3 | node [style=filled]; 4 | red [color=red]; 5 | green [color=green]; 6 | blue [color=blue,fontcolor=black]; 7 | cyan [color=cyan]; 8 | magenta [color=magenta]; 9 | yellow [color=yellow]; 10 | orange [color=orange]; 11 | red -> green; 12 | red -> blue; 13 | blue -> cyan; 14 | blue -> magenta; 15 | green -> yellow; 16 | green -> orange; 17 | } 18 | -------------------------------------------------------------------------------- /testdata/directed/dfa.gv: -------------------------------------------------------------------------------- 1 | digraph g { 2 | "start" [ label = "MWGC-" ]; 3 | "n1" [ label = "WC-MG" ]; 4 | "n2" [ label = "MWC-G" ]; 5 | "n3" [ label = "C-MWG" ]; 6 | "n4" [ label = "W-MGC" ]; 7 | "n5" [ label = "MGC-W" ]; 8 | "n6" [ label = "MWG-C" ]; 9 | "n7" [ label = "G-MWC" ]; 10 | "n8" [ label = "MG-WC" ]; 11 | "n9" [ label = "-MWGC" ]; 12 | "start" -> "n1" [ label = "g" ]; 13 | "n1" -> "start" [ label = "g" ]; 14 | subgraph l { rank = same; "n3" "n4" } 15 | subgraph r { rank = same; "n5" "n6" } 16 | "n1" -> "n2" [ label = "m" ]; 17 | "n2" -> "n1" [ label = "m" ]; 18 | "n2" -> "n3" [ label = "w" ]; 19 | "n3" -> "n2" [ label = "w" ]; 20 | "n2" -> "n4" [ label = "c" ]; 21 | "n4" -> "n2" [ label = "c" ]; 22 | "n3" -> "n5" [ label = "g" ]; 23 | "n5" -> "n3" [ label = "g" ]; 24 | "n4" -> "n6" [ label = "g" ]; 25 | "n6" -> "n4" [ label = "g" ]; 26 | "n5" -> "n7" [ label = "c" ]; 27 | "n7" -> "n5" [ label = "c" ]; 28 | "n6" -> "n7" [ label = "w" ]; 29 | "n7" -> "n6" [ label = "w" ]; 30 | "n7" -> "n8" [ label = "m" ]; 31 | "n8" -> "n7" [ label = "m" ]; 32 | "n8" -> "n9" [ label = "g" ]; 33 | "n9" -> "n8" [ label = "g" ]; 34 | } 35 | -------------------------------------------------------------------------------- /testdata/directed/fig6.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | size = "8,8"; 3 | {rank=min S8 S24 S1 S35 S30} 4 | {rank=max T8 T24 T1 T35 T30} 5 | S8 -> 9; 6 | S24 -> 27; 7 | S24 -> 25; 8 | S1 -> 10; 9 | S1 -> 2; 10 | S35 -> 36; 11 | S35 -> 43; 12 | S30 -> 31; 13 | S30 -> 33; 14 | 9 -> 42; 15 | 9 -> T1; 16 | 25 -> T1; 17 | 25 -> 26; 18 | 27 -> T24; 19 | 2 -> 3; 20 | 2 -> 16; 21 | 2 -> 17; 22 | 2 -> T1; 23 | 2 -> 18; 24 | 10 -> 11; 25 | 10 -> 14; 26 | 10 -> T1; 27 | 10 -> 13; 28 | 10 -> 12; 29 | 31 -> T1; 30 | 31 -> 32; 31 | 33 -> T30; 32 | 33 -> 34; 33 | 42 -> 4; 34 | 26 -> 4; 35 | 3 -> 4; 36 | 16 -> 15; 37 | 17 -> 19; 38 | 18 -> 29; 39 | 11 -> 4; 40 | 14 -> 15; 41 | 37 -> 39; 42 | 37 -> 41; 43 | 37 -> 38; 44 | 37 -> 40; 45 | 13 -> 19; 46 | 12 -> 29; 47 | 43 -> 38; 48 | 43 -> 40; 49 | 36 -> 19; 50 | 32 -> 23; 51 | 34 -> 29; 52 | 39 -> 15; 53 | 41 -> 29; 54 | 38 -> 4; 55 | 40 -> 19; 56 | 4 -> 5; 57 | 19 -> 21; 58 | 19 -> 20; 59 | 19 -> 28; 60 | 5 -> 6; 61 | 5 -> T35; 62 | 5 -> 23; 63 | 21 -> 22; 64 | 20 -> 15; 65 | 28 -> 29; 66 | 6 -> 7; 67 | 15 -> T1; 68 | 22 -> 23; 69 | 22 -> T35; 70 | 29 -> T30; 71 | 7 -> T8; 72 | 23 -> T24; 73 | 23 -> T1; 74 | } 75 | -------------------------------------------------------------------------------- /testdata/directed/fsm.gv: -------------------------------------------------------------------------------- 1 | digraph finite_state_machine { 2 | 3 | node [shape = doublecircle]; LR_0 LR_3 LR_4 LR_8; 4 | node [shape = circle]; 5 | rankdir=LR; 6 | LR_0 -> LR_2 [ label = "SS(B)" ]; 7 | LR_0 -> LR_1 [ label = "SS(S)" ]; 8 | LR_1 -> LR_3 [ label = "S($end)" ]; 9 | LR_2 -> LR_6 [ label = "SS(b)" ]; 10 | LR_2 -> LR_5 [ label = "SS(a)" ]; 11 | LR_2 -> LR_4 [ label = "S(A)" ]; 12 | LR_5 -> LR_7 [ label = "S(b)" ]; 13 | LR_5 -> LR_5 [ label = "S(a)" ]; 14 | LR_6 -> LR_6 [ label = "S(b)" ]; 15 | LR_6 -> LR_5 [ label = "S(a)" ]; 16 | LR_7 -> LR_8 [ label = "S(b)" ]; 17 | LR_7 -> LR_5 [ label = "S(a)" ]; 18 | LR_8 -> LR_6 [ label = "S(b)" ]; 19 | LR_8 -> LR_5 [ label = "S(a)" ]; 20 | } 21 | -------------------------------------------------------------------------------- /testdata/directed/grammar.gv: -------------------------------------------------------------------------------- 1 | digraph L0 { 2 | size = "8,8"; 3 | ordering=out; 4 | node [shape = box]; 5 | 6 | n0 [label="E"]; 7 | n1 [label="T"]; 8 | n2 [label="F"]; 9 | n3 [label="IDENT : a "]; 10 | n4 [label="+"]; 11 | n5 [label="T"]; 12 | n6 [label="F"]; 13 | n7 [label="("]; 14 | n8 [label="E"]; 15 | n9 [label="T"]; 16 | n10 [label="F"]; 17 | n11 [label="IDENT : b "]; 18 | n12 [label="*"]; 19 | n13 [label="F"]; 20 | n14 [label="IDENT : c "]; 21 | n15 [label=")"]; 22 | n16 [label="*"]; 23 | n17 [label="F"]; 24 | n18 [label="("]; 25 | n19 [label="E"]; 26 | n20 [label="T"]; 27 | n21 [label="F"]; 28 | n22 [label="IDENT : d "]; 29 | n23 [label="*"]; 30 | n24 [label="F"]; 31 | n25 [label="IDENT : e "]; 32 | n26 [label="+"]; 33 | n27 [label="T"]; 34 | n28 [label="F"]; 35 | n29 [label="("]; 36 | n30 [label="E"]; 37 | n31 [label="T"]; 38 | n32 [label="F"]; 39 | n33 [label="IDENT : a "]; 40 | n34 [label="*"]; 41 | n35 [label="F"]; 42 | n36 [label="IDENT : b "]; 43 | n37 [label=")"]; 44 | n38 [label=")"]; 45 | n39 [label="+"]; 46 | n40 [label="T"]; 47 | n41 [label="F"]; 48 | n42 [label="IDENT : q "]; 49 | n0 -> { n1 n4 n5 n39 n40 }; 50 | n1 -> n2 ; 51 | n2 -> n3 ; 52 | n5 -> { n6 n16 n17 }; 53 | n6 -> { n7 n8 n15 }; 54 | n8 -> n9 ; 55 | n9 -> { n10 n12 n13 }; 56 | n10 -> n11 ; 57 | n13 -> n14 ; 58 | n17 -> { n18 n19 n38 }; 59 | n19 -> { n20 n26 n27 }; 60 | n20 -> { n21 n23 n24 }; 61 | n21 -> n22 ; 62 | n24 -> n25 ; 63 | n27 -> n28 ; 64 | n28 -> { n29 n30 n37 }; 65 | n30 -> n31 ; 66 | n31 -> { n32 n34 n35 }; 67 | n32 -> n33 ; 68 | n35 -> n36 ; 69 | n40 -> n41 ; 70 | n41 -> n42 ; 71 | } 72 | -------------------------------------------------------------------------------- /testdata/directed/hashtable.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | nodesep=.05; 3 | rankdir=LR; 4 | node [shape=record,width=.1,height=.1]; 5 | 6 | node0 [label = " | | | | | | | ",height=2.0]; 7 | node [width = 1.5]; 8 | node1 [label = "{ n14 | 719 |

}"]; 9 | node2 [label = "{ a1 | 805 |

}"]; 10 | node3 [label = "{ i9 | 718 |

}"]; 11 | node4 [label = "{ e5 | 989 |

}"]; 12 | node5 [label = "{ t20 | 959 |

}"] ; 13 | node6 [label = "{ o15 | 794 |

}"] ; 14 | node7 [label = "{ s19 | 659 |

}"] ; 15 | 16 | node0:f0 -> node1:n; 17 | node0:f1 -> node2:n; 18 | node0:f2 -> node3:n; 19 | node0:f5 -> node4:n; 20 | node0:f6 -> node5:n; 21 | node2:p -> node6:n; 22 | node4:p -> node7:n; 23 | } 24 | -------------------------------------------------------------------------------- /testdata/directed/honda-tokoro.gv: -------------------------------------------------------------------------------- 1 | digraph "Honda-Tokoro" { 2 | rankdir="LR" ranksep="0.2" edge[labelfontsize="8" fontsize="8" labeldistance="0.8" arrowsize="0.9" labelangle="-30" dir="none"] nodesep="0.2" node[width="0" height="0" fontsize="10"] 3 | 4 | /*Net net00*/ 5 | 6 | n000 [label="z"] 7 | n001->n000 [headlabel=":s:" arrowhead="invdot"] 8 | n001 [label="m"] 9 | n002->n001 [samehead="m002" headlabel=":r:" samearrowhead="1" arrowhead="invdot" arrowtail="inv"] 10 | n002 [label="p1"] 11 | n003->n002 [headlabel=":s:" arrowhead="dot"] 12 | n003 [label="b"] 13 | n004->n003 14 | n004 [label="x1"] 15 | n022->n004 [weight="0" headlabel=":s/r:" fontsize="8" arrowhead="invdot"] 16 | n003->n002 [samehead="m000" fontsize="8" samearrowhead="1" arrowtail="inv"] 17 | n005->n002 [samehead="m000" headlabel=":u:" fontsize="8" samearrowhead="1" arrowhead="dot" arrowtail="inv"] 18 | n005->n001 [samehead="m002" samearrowhead="1"] 19 | n005 [label="b"] 20 | n006->n005 [arrowtail="inv"] 21 | n006 [label="p2"] 22 | n007->n006 [headlabel=":s:" arrowhead="dot"] 23 | n007 [label="b"] 24 | n008->n007 25 | n008 [label="x2"] 26 | n022->n008 [weight="0" headlabel=":s/r:" fontsize="8" arrowhead="invdot"] 27 | n007->n006 [samehead="m001" headlabel=":u:" fontsize="8" samearrowhead="1" arrowhead="dot" arrowtail="inv"] 28 | n009->n006 [samehead="m001" samearrowhead="1" arrowtail="inv"] 29 | n009 [label="b2"] 30 | n022->n009 [fontsize="8"] 31 | n022->n009 [fontsize="8"] 32 | n010->n006 [samehead="m001" samearrowhead="1" arrowtail="inv"] 33 | n010 [label="b2"] 34 | n022->n010 [fontsize="8"] 35 | n022->n010 [fontsize="8"] 36 | n011->n000 [headlabel=":r:" arrowhead="invdot" arrowtail="inv"] 37 | n011 [label="n"] 38 | n012->n011 [samehead="m005" headlabel=":s:" samearrowhead="1" arrowhead="dot"] 39 | n012 [label="b"] 40 | n013->n012 41 | n013 [label="c1"] 42 | n014->n013 [headlabel=":r:" arrowhead="invdot"] 43 | n014 [label="b"] 44 | n015->n014 [arrowtail="inv"] 45 | n015 [label="y1"] 46 | n023->n015 [weight="0" headlabel=":s/r:" fontsize="8" arrowhead="dot"] 47 | n016->n015 [samehead="m003" headlabel=":u:" fontsize="8" samearrowhead="1" arrowhead="dot" arrowtail="inv"] 48 | n018->n015 [samehead="m003" fontsize="8" samearrowhead="1" arrowtail="inv"] 49 | n014->n011 [samehead="m006" headlabel=":u:" fontsize="8" samearrowhead="1" arrowhead="dot" arrowtail="inv"] 50 | n012->n011 [samehead="m006" fontsize="8" samearrowhead="1" arrowtail="inv"] 51 | n016->n011 [samehead="m005" samearrowhead="1"] 52 | n016 [label="b"] 53 | n017->n016 54 | n017 [label="c2"] 55 | n018->n017 [headlabel=":r:" arrowhead="invdot"] 56 | n018 [label="b"] 57 | n019->n018 [arrowtail="inv"] 58 | n019 [label="y2"] 59 | n023->n019 [weight="0" headlabel=":s/r:" fontsize="8" arrowhead="dot"] 60 | n020->n019 [samehead="m004" headlabel=":u:" samearrowhead="1" arrowhead="dot" arrowtail="inv"] 61 | n020 [label="b2"] 62 | n023->n020 [fontsize="8"] 63 | n023->n020 [fontsize="8"] 64 | n021->n019 [samehead="m004" samearrowhead="1" arrowtail="inv"] 65 | n021 [label="b2"] 66 | n023->n021 [fontsize="8"] 67 | n023->n021 [fontsize="8"] 68 | n022 [width="0.5" label="[P]" shape="box" style="dashed" height="0.35"] 69 | n023 [width="0.5" label="[Q]" shape="box" style="dashed" height="0.35"] 70 | {/*L=x1*/rank=same n004 n015} 71 | {/*L=p1*/rank=same n002 n013} 72 | {/*L=b*/rank=same n009 n010 n020 n021} 73 | {/*L=x2*/rank=same n008 n019} 74 | {/*L=p2*/rank=same n006 n017} 75 | {/*L=m*/rank=same n001 n011} 76 | } 77 | -------------------------------------------------------------------------------- /testdata/directed/japanese.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | graph [label="下駄配列の派生図"] 3 | 4 | getas [label = "下駄配列"]; 5 | new_getas [label = "新下駄配列"]; 6 | getas_in_fine_weather [label = "日和下駄配列"]; 7 | black_lacquered_getas [label = "黒塗り下駄配列"]; 8 | black_lacquered_getas_made_of_paulownia [label = "黒塗り桐下駄配列"]; 9 | lacquered_getas [label = "塗り下駄配列"]; 10 | new_JIS_getas [label = "新JIS下駄配列"]; 11 | 12 | getas -> { 13 | getas_in_fine_weather 14 | lacquered_getas 15 | new_JIS_getas new_getas 16 | lacquered_getas 17 | }; 18 | 19 | lacquered_getas -> black_lacquered_getas; 20 | black_lacquered_getas -> black_lacquered_getas_made_of_paulownia; 21 | black_lacquered_getas_made_of_paulownia -> black_lacquered_getas; 22 | 23 | black_lacquered_getas -> getas_in_fine_weather [style = dotted]; 24 | } 25 | -------------------------------------------------------------------------------- /testdata/directed/jcctree.gv: -------------------------------------------------------------------------------- 1 | digraph "tree" { 2 | // The problem disappeared when I removed the "ELEM3 -> ID5;" line! 3 | //size="4,5"; 4 | ordering=out; 5 | node [shape=plaintext]; 6 | SPEC -> DEF2; 7 | SPEC -> DEF1; 8 | DEF1 -> ID1; 9 | DEF1 -> SET1; 10 | DEF1 -> SC1; 11 | DEF2 -> ID2; 12 | DEF2 -> SET2; 13 | DEF2 -> SC2; 14 | SET1 -> OPEN1; 15 | SET1 -> ELEM1; 16 | SET1 -> SC3; 17 | SET1 -> ELEM2; 18 | SET1 -> CLOSE1; 19 | ELEM1 -> ID3; 20 | SET2 -> OPEN2; 21 | SET2 -> ELEM3; 22 | SET2 -> CLOSE2; 23 | ELEM2 -> ID4; 24 | ELEM3 -> ID5; 25 | DEF1 [label=DEF]; 26 | DEF2 [label=DEF]; 27 | SET1 [label=SET]; 28 | SC1 [label=";"]; 29 | SC3 [label=";"]; 30 | SET2 [label=SET]; 31 | SC2 [label=";"]; 32 | OPEN1 [label="{"]; 33 | OPEN2 [label="{"]; 34 | CLOSE1 [label="}"]; 35 | CLOSE2 [label="}"]; 36 | ELEM1 [label=ELEMENT]; 37 | ELEM2 [label=ELEMENT]; 38 | ELEM3 [label=ELEMENT]; 39 | ID1 [label=cities]; 40 | ID2 [label=insects]; 41 | ID3 [label=andover]; 42 | ID4 [label=boston]; 43 | ID5 [label=fly]; 44 | } 45 | -------------------------------------------------------------------------------- /testdata/directed/jsort.gv: -------------------------------------------------------------------------------- 1 | digraph prof { 2 | size="6,4"; ratio = fill; 3 | node [style=filled]; 4 | start -> main [color="0.002 0.999 0.999"]; 5 | start -> on_exit [color="0.649 0.701 0.701"]; 6 | main -> sort [color="0.348 0.839 0.839"]; 7 | main -> merge [color="0.515 0.762 0.762"]; 8 | main -> term [color="0.647 0.702 0.702"]; 9 | main -> signal [color="0.650 0.700 0.700"]; 10 | main -> sbrk [color="0.650 0.700 0.700"]; 11 | main -> unlink [color="0.650 0.700 0.700"]; 12 | main -> newfile [color="0.650 0.700 0.700"]; 13 | main -> fclose [color="0.650 0.700 0.700"]; 14 | main -> close [color="0.650 0.700 0.700"]; 15 | main -> brk [color="0.650 0.700 0.700"]; 16 | main -> setbuf [color="0.650 0.700 0.700"]; 17 | main -> copyproto [color="0.650 0.700 0.700"]; 18 | main -> initree [color="0.650 0.700 0.700"]; 19 | main -> safeoutfil [color="0.650 0.700 0.700"]; 20 | main -> getpid [color="0.650 0.700 0.700"]; 21 | main -> sprintf [color="0.650 0.700 0.700"]; 22 | main -> creat [color="0.650 0.700 0.700"]; 23 | main -> rem [color="0.650 0.700 0.700"]; 24 | main -> oldfile [color="0.650 0.700 0.700"]; 25 | sort -> msort [color="0.619 0.714 0.714"]; 26 | sort -> filbuf [color="0.650 0.700 0.700"]; 27 | sort -> newfile [color="0.650 0.700 0.700"]; 28 | sort -> fclose [color="0.650 0.700 0.700"]; 29 | sort -> setbuf [color="0.650 0.700 0.700"]; 30 | sort -> setfil [color="0.650 0.700 0.700"]; 31 | msort -> qsort [color="0.650 0.700 0.700"]; 32 | msort -> insert [color="0.650 0.700 0.700"]; 33 | msort -> wline [color="0.650 0.700 0.700"]; 34 | msort -> div [color="0.650 0.700 0.700"]; 35 | msort -> cmpsave [color="0.650 0.700 0.700"]; 36 | merge -> insert [color="0.650 0.700 0.700"]; 37 | merge -> rline [color="0.650 0.700 0.700"]; 38 | merge -> wline [color="0.650 0.700 0.700"]; 39 | merge -> unlink [color="0.650 0.700 0.700"]; 40 | merge -> fopen [color="0.650 0.700 0.700"]; 41 | merge -> fclose [color="0.650 0.700 0.700"]; 42 | merge -> setfil [color="0.650 0.700 0.700"]; 43 | merge -> mul [color="0.650 0.700 0.700"]; 44 | merge -> setbuf [color="0.650 0.700 0.700"]; 45 | merge -> cmpsave [color="0.650 0.700 0.700"]; 46 | insert -> cmpa [color="0.650 0.700 0.700"]; 47 | wline -> flsbuf [color="0.649 0.700 0.700"]; 48 | qsort -> cmpa [color="0.650 0.700 0.700"]; 49 | rline -> filbuf [color="0.649 0.700 0.700"]; 50 | xflsbuf -> write [color="0.650 0.700 0.700"]; 51 | flsbuf -> xflsbuf [color="0.649 0.700 0.700"]; 52 | filbuf -> read [color="0.650 0.700 0.700"]; 53 | term -> unlink [color="0.650 0.700 0.700"]; 54 | term -> signal [color="0.650 0.700 0.700"]; 55 | term -> setfil [color="0.650 0.700 0.700"]; 56 | term -> exit [color="0.650 0.700 0.700"]; 57 | endopen -> open [color="0.650 0.700 0.700"]; 58 | fopen -> endopen [color="0.639 0.705 0.705"]; 59 | fopen -> findiop [color="0.650 0.700 0.700"]; 60 | newfile -> fopen [color="0.634 0.707 0.707"]; 61 | newfile -> setfil [color="0.650 0.700 0.700"]; 62 | fclose -> fflush [color="0.642 0.704 0.704"]; 63 | fclose -> close [color="0.650 0.700 0.700"]; 64 | fflush -> xflsbuf [color="0.635 0.707 0.707"]; 65 | malloc -> morecore [color="0.325 0.850 0.850"]; 66 | malloc -> demote [color="0.650 0.700 0.700"]; 67 | morecore -> sbrk [color="0.650 0.700 0.700"]; 68 | morecore -> getfreehdr [color="0.650 0.700 0.700"]; 69 | morecore -> free [color="0.650 0.700 0.700"]; 70 | morecore -> getpagesize [color="0.650 0.700 0.700"]; 71 | morecore -> putfreehdr [color="0.650 0.700 0.700"]; 72 | morecore -> udiv [color="0.650 0.700 0.700"]; 73 | morecore -> umul [color="0.650 0.700 0.700"]; 74 | on_exit -> malloc [color="0.325 0.850 0.850"]; 75 | signal -> sigvec [color="0.650 0.700 0.700"]; 76 | moncontrol -> profil [color="0.650 0.700 0.700"]; 77 | getfreehdr -> sbrk [color="0.650 0.700 0.700"]; 78 | free -> insert [color="0.650 0.700 0.700"]; 79 | insert -> getfreehdr [color="0.650 0.700 0.700"]; 80 | setfil -> div [color="0.650 0.700 0.700"]; 81 | setfil -> rem [color="0.650 0.700 0.700"]; 82 | sigvec -> sigblock [color="0.650 0.700 0.700"]; 83 | sigvec -> sigsetmask [color="0.650 0.700 0.700"]; 84 | doprnt -> urem [color="0.650 0.700 0.700"]; 85 | doprnt -> udiv [color="0.650 0.700 0.700"]; 86 | doprnt -> strlen [color="0.650 0.700 0.700"]; 87 | doprnt -> localeconv [color="0.650 0.700 0.700"]; 88 | sprintf -> doprnt [color="0.650 0.700 0.700"]; 89 | cmpa [color="0.000 1.000 1.000"]; 90 | wline [color="0.201 0.753 1.000"]; 91 | insert [color="0.305 0.625 1.000"]; 92 | rline [color="0.355 0.563 1.000"]; 93 | sort [color="0.408 0.498 1.000"]; 94 | qsort [color="0.449 0.447 1.000"]; 95 | write [color="0.499 0.386 1.000"]; 96 | read [color="0.578 0.289 1.000"]; 97 | msort [color="0.590 0.273 1.000"]; 98 | merge [color="0.603 0.258 1.000"]; 99 | unlink [color="0.628 0.227 1.000"]; 100 | filbuf [color="0.641 0.212 1.000"]; 101 | open [color="0.641 0.212 1.000"]; 102 | sbrk [color="0.647 0.204 1.000"]; 103 | signal [color="0.647 0.204 1.000"]; 104 | moncontrol [color="0.647 0.204 1.000"]; 105 | xflsbuf [color="0.650 0.200 1.000"]; 106 | flsbuf [color="0.650 0.200 1.000"]; 107 | div [color="0.650 0.200 1.000"]; 108 | cmpsave [color="0.650 0.200 1.000"]; 109 | rem [color="0.650 0.200 1.000"]; 110 | setfil [color="0.650 0.200 1.000"]; 111 | close [color="0.650 0.200 1.000"]; 112 | fclose [color="0.650 0.200 1.000"]; 113 | fflush [color="0.650 0.200 1.000"]; 114 | setbuf [color="0.650 0.200 1.000"]; 115 | endopen [color="0.650 0.200 1.000"]; 116 | findiop [color="0.650 0.200 1.000"]; 117 | fopen [color="0.650 0.200 1.000"]; 118 | mul [color="0.650 0.200 1.000"]; 119 | newfile [color="0.650 0.200 1.000"]; 120 | sigblock [color="0.650 0.200 1.000"]; 121 | sigsetmask [color="0.650 0.200 1.000"]; 122 | sigvec [color="0.650 0.200 1.000"]; 123 | udiv [color="0.650 0.200 1.000"]; 124 | urem [color="0.650 0.200 1.000"]; 125 | brk [color="0.650 0.200 1.000"]; 126 | getfreehdr [color="0.650 0.200 1.000"]; 127 | strlen [color="0.650 0.200 1.000"]; 128 | umul [color="0.650 0.200 1.000"]; 129 | doprnt [color="0.650 0.200 1.000"]; 130 | copyproto [color="0.650 0.200 1.000"]; 131 | creat [color="0.650 0.200 1.000"]; 132 | demote [color="0.650 0.200 1.000"]; 133 | exit [color="0.650 0.200 1.000"]; 134 | free [color="0.650 0.200 1.000"]; 135 | getpagesize [color="0.650 0.200 1.000"]; 136 | getpid [color="0.650 0.200 1.000"]; 137 | initree [color="0.650 0.200 1.000"]; 138 | insert [color="0.650 0.200 1.000"]; 139 | localeconv [color="0.650 0.200 1.000"]; 140 | main [color="0.650 0.200 1.000"]; 141 | malloc [color="0.650 0.200 1.000"]; 142 | morecore [color="0.650 0.200 1.000"]; 143 | oldfile [color="0.650 0.200 1.000"]; 144 | on_exit [color="0.650 0.200 1.000"]; 145 | profil [color="0.650 0.200 1.000"]; 146 | putfreehdr [color="0.650 0.200 1.000"]; 147 | safeoutfil [color="0.650 0.200 1.000"]; 148 | sprintf [color="0.650 0.200 1.000"]; 149 | term [color="0.650 0.200 1.000"]; 150 | } 151 | -------------------------------------------------------------------------------- /testdata/directed/ldbxtried.gv: -------------------------------------------------------------------------------- 1 | digraph g { 2 | graph [ 3 | fontsize = "14" 4 | fontname = "Times-Roman" 5 | fontcolor = "black" 6 | color = "black" 7 | ]; 8 | node [ 9 | fontsize = "14" 10 | fontname = "Times-Roman" 11 | fontcolor = "black" 12 | shape = "box" 13 | color = "black" 14 | width = "0.5" 15 | style = "filled" 16 | ]; 17 | edge [ 18 | fontsize = "14" 19 | fontname = "Times-Roman" 20 | fontcolor = "black" 21 | color = "black" 22 | ]; 23 | "n0" [ 24 | label = "18519\n?" 25 | color = "lightblue" 26 | ]; 27 | "n1" [ 28 | label = "4836" 29 | shape = "ellipse" 30 | color = "maroon1" 31 | ]; 32 | "n2" [ 33 | label = "ttyqa" 34 | shape = "ellipse" 35 | color = "maroon1" 36 | ]; 37 | "n448" [ 38 | label = "21079\nlefty" 39 | color = "lightblue" 40 | ]; 41 | "n449" [ 42 | label = "tried.lefty" 43 | shape = "ellipse" 44 | color = "maroon1" 45 | ]; 46 | "n454" [ 47 | fontsize = "7" 48 | label = "bunting\n6000" 49 | shape = "doublecircle" 50 | color = "green" 51 | ]; 52 | "n460" [ 53 | label = "" 54 | shape = "doublecircle" 55 | color = "yellow" 56 | ]; 57 | "n461" [ 58 | label = "" 59 | shape = "doublecircle" 60 | color = "yellow" 61 | ]; 62 | "n462" [ 63 | label = "21084\ntried" 64 | color = "lightblue" 65 | ]; 66 | "n464" [ 67 | label = "21086\nldbx" 68 | color = "lightblue" 69 | ]; 70 | "n466" [ 71 | label = "ldbx" 72 | shape = "ellipse" 73 | color = "maroon1" 74 | ]; 75 | "n468" [ 76 | label = "21087\nlefty" 77 | color = "lightblue" 78 | ]; 79 | "n469" [ 80 | label = "sh21086.1" 81 | shape = "ellipse" 82 | color = "maroon1" 83 | ]; 84 | "n474" [ 85 | fontsize = "7" 86 | label = "bunting\n6000" 87 | shape = "doublecircle" 88 | color = "green" 89 | ]; 90 | "n479" [ 91 | label = "ldbx.lefty" 92 | shape = "ellipse" 93 | color = "maroon1" 94 | ]; 95 | "n482" [ 96 | label = "" 97 | shape = "doublecircle" 98 | color = "yellow" 99 | ]; 100 | "n483" [ 101 | label = "" 102 | shape = "doublecircle" 103 | color = "yellow" 104 | ]; 105 | "n484" [ 106 | label = "21088\ndot" 107 | color = "lightblue" 108 | ]; 109 | "n486" [ 110 | label = "" 111 | shape = "doublecircle" 112 | color = "yellow" 113 | ]; 114 | "n487" [ 115 | label = "" 116 | shape = "doublecircle" 117 | color = "yellow" 118 | ]; 119 | "n488" [ 120 | label = "21089\nxterm" 121 | color = "lightblue" 122 | ]; 123 | "n496" [ 124 | fontsize = "7" 125 | label = "bunting\n6000" 126 | shape = "doublecircle" 127 | color = "green" 128 | ]; 129 | "n500" [ 130 | label = "ptyq2" 131 | shape = "ellipse" 132 | color = "maroon1" 133 | ]; 134 | "n503" [ 135 | label = "21090\nldbxmp" 136 | color = "lightblue" 137 | ]; 138 | "n505" [ 139 | label = "ttyq2" 140 | shape = "ellipse" 141 | color = "maroon1" 142 | ]; 143 | "n512" [ 144 | label = "ptyq5" 145 | shape = "ellipse" 146 | color = "maroon1" 147 | ]; 148 | "n513" [ 149 | label = "ttyq5" 150 | shape = "ellipse" 151 | color = "maroon1" 152 | ]; 153 | "n514" [ 154 | label = "21091\ndbx" 155 | color = "lightblue" 156 | ]; 157 | "n518" [ 158 | label = "tty" 159 | shape = "ellipse" 160 | color = "maroon1" 161 | ]; 162 | "n526" [ 163 | label = "delaunay.c" 164 | shape = "ellipse" 165 | color = "maroon1" 166 | ]; 167 | subgraph "cluster0" { 168 | graph [ 169 | fontsize = "14" 170 | fontname = "Times-Roman" 171 | fontcolor = "black" 172 | label = "toucan" 173 | color = "black" 174 | ]; 175 | node [ 176 | fontsize = "14" 177 | fontname = "Times-Roman" 178 | fontcolor = "black" 179 | shape = "box" 180 | color = "black" 181 | width = "0.5" 182 | style = "filled" 183 | ]; 184 | edge [ 185 | fontsize = "14" 186 | fontname = "Times-Roman" 187 | fontcolor = "black" 188 | color = "black" 189 | ]; 190 | "n0" 191 | "n468" 192 | "n486" 193 | "n460" 194 | "n487" 195 | "n514" 196 | "n461" 197 | "n488" 198 | "n462" 199 | "n464" 200 | "n482" 201 | "n483" 202 | "n448" 203 | "n484" 204 | "n503" 205 | } 206 | "n0" -> "n1" [ 207 | dir = "both" 208 | ]; 209 | "n0" -> "n2" [ 210 | dir = "both" 211 | ]; 212 | "n0" -> "n2" [ 213 | dir = "both" 214 | ]; 215 | "n0" -> "n2" [ 216 | dir = "both" 217 | ]; 218 | "n0" -> "n448" [ 219 | style = "dotted" 220 | ]; 221 | "n448" -> "n2" [ 222 | dir = "both" 223 | ]; 224 | "n448" -> "n2" [ 225 | dir = "both" 226 | ]; 227 | "n448" -> "n2" [ 228 | dir = "both" 229 | ]; 230 | "n448" -> "n449" [ 231 | dir = "back" 232 | ]; 233 | "n448" -> "n454" [ 234 | dir = "both" 235 | ]; 236 | "n448" -> "n460" [ 237 | dir = "back" 238 | ]; 239 | "n448" -> "n461" [ 240 | dir = "forward" 241 | ]; 242 | "n448" -> "n462" [ 243 | style = "dotted" 244 | ]; 245 | "n462" -> "n2" [ 246 | dir = "both" 247 | ]; 248 | "n462" -> "n2" [ 249 | dir = "both" 250 | ]; 251 | "n462" -> "n2" [ 252 | dir = "both" 253 | ]; 254 | "n462" -> "n449" [ 255 | dir = "back" 256 | ]; 257 | "n462" -> "n460" [ 258 | dir = "forward" 259 | ]; 260 | "n462" -> "n461" [ 261 | dir = "back" 262 | ]; 263 | "n462" -> "n460" [ 264 | dir = "forward" 265 | ]; 266 | "n462" -> "n461" [ 267 | dir = "back" 268 | ]; 269 | "n0" -> "n464" [ 270 | style = "dotted" 271 | ]; 272 | "n464" -> "n2" [ 273 | dir = "both" 274 | ]; 275 | "n464" -> "n2" [ 276 | dir = "both" 277 | ]; 278 | "n464" -> "n2" [ 279 | dir = "both" 280 | ]; 281 | "n464" -> "n466" [ 282 | dir = "back" 283 | ]; 284 | "n464" -> "n468" [ 285 | style = "dotted" 286 | ]; 287 | "n468" -> "n2" [ 288 | dir = "both" 289 | ]; 290 | "n468" -> "n2" [ 291 | dir = "both" 292 | ]; 293 | "n468" -> "n469" [ 294 | dir = "back" 295 | ]; 296 | "n468" -> "n474" [ 297 | dir = "both" 298 | ]; 299 | "n468" -> "n479" [ 300 | dir = "back" 301 | ]; 302 | "n468" -> "n482" [ 303 | dir = "back" 304 | ]; 305 | "n468" -> "n483" [ 306 | dir = "forward" 307 | ]; 308 | "n468" -> "n484" [ 309 | style = "dotted" 310 | ]; 311 | "n484" -> "n2" [ 312 | dir = "both" 313 | ]; 314 | "n484" -> "n483" [ 315 | dir = "back" 316 | ]; 317 | "n484" -> "n479" [ 318 | dir = "back" 319 | ]; 320 | "n484" -> "n482" [ 321 | dir = "forward" 322 | ]; 323 | "n468" -> "n486" [ 324 | dir = "back" 325 | ]; 326 | "n468" -> "n487" [ 327 | dir = "forward" 328 | ]; 329 | "n468" -> "n488" [ 330 | style = "dotted" 331 | ]; 332 | "n488" -> "n486" [ 333 | dir = "forward" 334 | ]; 335 | "n488" -> "n2" [ 336 | dir = "both" 337 | ]; 338 | "n488" -> "n487" [ 339 | dir = "back" 340 | ]; 341 | "n488" -> "n469" [ 342 | dir = "back" 343 | ]; 344 | "n488" -> "n2" [ 345 | dir = "both" 346 | ]; 347 | "n488" -> "n479" [ 348 | dir = "back" 349 | ]; 350 | "n488" -> "n496" [ 351 | dir = "both" 352 | ]; 353 | "n488" -> "n500" [ 354 | dir = "both" 355 | ]; 356 | "n488" -> "n503" [ 357 | style = "dotted" 358 | ]; 359 | "n503" -> "n479" [ 360 | dir = "back" 361 | ]; 362 | "n503" -> "n486" [ 363 | dir = "forward" 364 | ]; 365 | "n503" -> "n487" [ 366 | dir = "back" 367 | ]; 368 | "n503" -> "n505" [ 369 | dir = "both" 370 | ]; 371 | "n503" -> "n505" [ 372 | dir = "both" 373 | ]; 374 | "n503" -> "n505" [ 375 | dir = "forward" 376 | ]; 377 | "n503" -> "n512" [ 378 | dir = "both" 379 | ]; 380 | "n503" -> "n514" [ 381 | style = "dotted" 382 | ]; 383 | "n514" -> "n487" [ 384 | dir = "back" 385 | ]; 386 | "n514" -> "n486" [ 387 | dir = "forward" 388 | ]; 389 | "n514" -> "n479" [ 390 | dir = "back" 391 | ]; 392 | "n514" -> "n505" [ 393 | dir = "forward" 394 | ]; 395 | "n503" -> "n486" [ 396 | dir = "forward" 397 | ]; 398 | "n514" -> "n518" [ 399 | dir = "back" 400 | ]; 401 | "n514" -> "n513" [ 402 | dir = "both" 403 | ]; 404 | "n514" -> "n513" [ 405 | dir = "both" 406 | ]; 407 | "n514" -> "n518" [ 408 | dir = "back" 409 | ]; 410 | "n514" -> "n526" [ 411 | dir = "back" 412 | ]; 413 | "n503" -> "n487" [ 414 | dir = "back" 415 | ]; 416 | } 417 | -------------------------------------------------------------------------------- /testdata/directed/longflat.gv: -------------------------------------------------------------------------------- 1 | digraph if 2 | { 3 | rankdir=LR; 4 | {rank=same;b;c;} 5 | a->b; 6 | c->b[label="long long long"]; 7 | } 8 | -------------------------------------------------------------------------------- /testdata/directed/mike.gv: -------------------------------------------------------------------------------- 1 | digraph mike{ 2 | size = "8,8"; 3 | a -> A; 4 | a -> m; 5 | a -> E; 6 | t -> O; 7 | r -> V; 8 | r -> Q; 9 | p -> B; 10 | m -> R; 11 | l -> C; 12 | c -> C; 13 | W -> X; 14 | W -> D; 15 | V -> W; 16 | T -> U; 17 | Q -> T; 18 | Q -> H; 19 | Q -> A; 20 | O -> K; 21 | L -> U; 22 | K -> L; 23 | K -> J; 24 | K -> E; 25 | J -> I; 26 | R -> B; 27 | P -> F; 28 | H -> R; 29 | H -> P; 30 | U -> H; 31 | G -> U; 32 | E -> G; 33 | C -> Z; 34 | C -> D; 35 | S -> D; 36 | B -> N; 37 | B -> D; 38 | B -> S; 39 | M -> B; 40 | A -> M; 41 | N -> Y; 42 | } 43 | -------------------------------------------------------------------------------- /testdata/directed/nhg.gv: -------------------------------------------------------------------------------- 1 | digraph automata_0 { 2 | size ="8.5, 11"; 3 | node [shape = circle]; 4 | 0 [ style = filled, color=lightgrey ]; 5 | 2 [ shape = doublecircle ]; 6 | 0 -> 2 [ label = "a " ]; 7 | 0 -> 1 [ label = "other " ]; 8 | 1 -> 2 [ label = "a " ]; 9 | 1 -> 1 [ label = "other " ]; 10 | 2 -> 2 [ label = "a " ]; 11 | 2 -> 1 [ label = "other " ]; 12 | "Machine: a" [ shape = plaintext ]; 13 | } 14 | -------------------------------------------------------------------------------- /testdata/directed/oldarrows.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | // leave some space for the head/taillabels 3 | graph [ranksep=1.5 splines=true overlap=false] 4 | 5 | // to avoid confusion, remember this: 6 | // it's spelt tail/head, but it's read start/end 7 | 8 | // put head/tail labels farther from the node 9 | edge [labeldistance=3] 10 | 11 | // not interested in node labels 12 | node [shape=circle width=0.5 label=""] 13 | 14 | { 15 | edge [dir=back samehead=ahead samearrowhead=1] 16 | a->Z [arrowtail=none taillabel=none] 17 | b->Z [arrowtail=normal taillabel=normal] 18 | c->Z [arrowtail=inv taillabel=inv] 19 | d->Z [arrowtail=dot taillabel=dot] 20 | e->Z [arrowtail=odot taillabel=odot] 21 | f->Z [arrowtail=invdot taillabel=invdot] 22 | g->Z [arrowtail=invodot taillabel=invodot] 23 | h->Z [arrowtail=open taillabel=open] 24 | i->Z [arrowtail=halfopen taillabel=halfopen arrowhead=inv headlabel=samehead] 25 | j->Z [arrowtail=empty taillabel=empty] 26 | k->Z [arrowtail=invempty taillabel=invempty] 27 | l->Z [arrowtail=diamond taillabel=diamond] 28 | m->Z [arrowtail=odiamond taillabel=odiamond] 29 | n->Z [arrowtail=box taillabel=box] 30 | o->Z [arrowtail=obox taillabel=obox] 31 | p->Z [arrowtail=tee taillabel=tee] 32 | q->Z [arrowtail=crow taillabel=crow] 33 | } 34 | { 35 | edge [sametail=atail samearrowtail=1] 36 | Z->A [arrowhead=none headlabel=none] 37 | Z->B [arrowhead=normal headlabel=normal] 38 | Z->C [arrowhead=inv headlabel=inv] 39 | Z->D [arrowhead=dot headlabel=dot] 40 | Z->E [arrowhead=odot headlabel=odot] 41 | Z->F [arrowhead=invdot headlabel=invdot] 42 | Z->G [arrowhead=invodot headlabel=invodot] 43 | Z->H [arrowhead=open headlabel=open] 44 | Z->I [arrowhead=halfopen headlabel=halfopen arrowtail=inv taillabel=sametail] 45 | Z->J [arrowhead=empty headlabel=empty] 46 | Z->K [arrowhead=invempty headlabel=invempty] 47 | Z->L [arrowhead=diamond headlabel=diamond] 48 | Z->M [arrowhead=odiamond headlabel=odiamond] 49 | Z->N [arrowhead=box headlabel=box] 50 | Z->O [arrowhead=obox headlabel=obox] 51 | Z->P [arrowhead=tee headlabel=tee] 52 | Z->Q [arrowhead=crow headlabel=crow] 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /testdata/directed/pgram.gv: -------------------------------------------------------------------------------- 1 | digraph test { 2 | 3 | size="7,9.5"; 4 | page="8,10.5"; 5 | ratio=fill; 6 | rankdir=LR; 7 | 8 | { rank=same; 9 | node [shape=house]; 10 | A;C;E;G;I;K;M;O;Q;S;U;W;Y; 11 | node [shape=invhouse]; 12 | B;D;F;H;J;L;N;P;R;T;V;X;Z; 13 | } 14 | 15 | { rank=same; 16 | node [shape=parallelogram]; 17 | "Parallelogram" [label="This is a test\nof a multiline\nlabel in an\nparallelogram with approx\nsquare aspect"]; 18 | "a ----- long thin parallelogram"; 19 | "xx" [label="m"]; 20 | "yy" [label="a\nb\nc\nd\ne\nf"]; 21 | node [shape=octagon]; 22 | "Octagon" [label="This is a test\nof a multiline\nlabel in an\noctagon with approx\nsquare aspect"]; 23 | node [shape=parallelogram]; 24 | "Parallelogram" [label="This is a test\nof a multiline\nlabel in an\nparallelogram with approx\nsquare aspect"]; 25 | "a ----- long thin parallelogram"; 26 | "zz" [label="m"]; 27 | "qq" [label="a\nb\nc\nd\ne\nf"]; 28 | ordering=out; 29 | } 30 | 31 | Parallelogram -> A; 32 | Parallelogram -> B; 33 | Parallelogram -> C; 34 | Parallelogram -> D; 35 | Parallelogram -> E; 36 | Parallelogram -> F; 37 | Parallelogram -> G; 38 | Parallelogram -> H; 39 | Parallelogram -> I; 40 | Parallelogram -> J; 41 | Parallelogram -> K; 42 | Parallelogram -> L; 43 | Parallelogram -> M; 44 | Parallelogram -> N; 45 | Parallelogram -> O; 46 | Parallelogram -> P; 47 | Parallelogram -> Q; 48 | Parallelogram -> R; 49 | Parallelogram -> S; 50 | Parallelogram -> T; 51 | Parallelogram -> U; 52 | Parallelogram -> V; 53 | Parallelogram -> W; 54 | Parallelogram -> X; 55 | Parallelogram -> Y; 56 | Parallelogram -> Z; 57 | 58 | { rank=same; 59 | node [shape=triangle]; 60 | a;c;e;g;i;k;m;o;q;s;u;w;y; 61 | node [shape=tripleoctagon]; 62 | b;d;f;h;j;l;n;p;r;t;v;x;z; 63 | } 64 | 65 | a -> Parallelogram -> Octagon; 66 | b -> Parallelogram -> Octagon; 67 | c -> Parallelogram -> Octagon; 68 | d -> Parallelogram -> Octagon; 69 | e -> Parallelogram -> Octagon; 70 | f -> Parallelogram -> Octagon; 71 | g -> Parallelogram -> Octagon; 72 | h -> Parallelogram -> Octagon; 73 | i -> Parallelogram -> Octagon; 74 | j -> Parallelogram -> Octagon; 75 | k -> Parallelogram -> Octagon; 76 | l -> Parallelogram -> Octagon; 77 | m -> Parallelogram -> Octagon; 78 | n -> Parallelogram -> Octagon; 79 | o -> Parallelogram -> Octagon; 80 | p -> Parallelogram -> Octagon; 81 | q -> Parallelogram -> Octagon; 82 | r -> Parallelogram -> Octagon; 83 | s -> Parallelogram -> Octagon; 84 | t -> Parallelogram -> Octagon; 85 | u -> Parallelogram -> Octagon; 86 | v -> Parallelogram -> Octagon; 87 | w -> Parallelogram -> Octagon; 88 | x -> Parallelogram -> Octagon; 89 | y -> Parallelogram -> Octagon; 90 | z -> Parallelogram -> Octagon; 91 | } 92 | -------------------------------------------------------------------------------- /testdata/directed/pm2way.gv: -------------------------------------------------------------------------------- 1 | digraph g { 2 | graph [ 3 | ]; 4 | node [ 5 | fontsize = "14" 6 | fontname = "Times-Roman" 7 | fontcolor = "black" 8 | shape = "box" 9 | color = "black" 10 | width = "0.5" 11 | ]; 12 | edge [ 13 | fontsize = "14" 14 | fontname = "Times-Roman" 15 | fontcolor = "black" 16 | color = "black" 17 | ]; 18 | "22690" [ 19 | label = "22690\n?" 20 | pname = "?" 21 | kind = "proc" 22 | ]; 23 | "22692" [ 24 | label = "22692\ndotty" 25 | pname = "dotty" 26 | kind = "proc" 27 | ]; 28 | "116842+2595" [ 29 | label = "116842+2595\n/home/ek/work/sun4/bin/dotty" 30 | fname = "/home/ek/work/sun4/bin/dotty" 31 | shape = "ellipse" 32 | kind = "file" 33 | ]; 34 | "22693" [ 35 | label = "22693\nlefty" 36 | pname = "lefty" 37 | kind = "proc" 38 | ]; 39 | "182440-1" [ 40 | label = "182440-1\n182441-1\npipe" 41 | fontsize = "7" 42 | fname = "pipe" 43 | shape = "doublecircle" 44 | subkind = "pipe" 45 | kind = "file" 46 | ]; 47 | "182442-1" [ 48 | label = "182442-1\n182443-1\npipe" 49 | fontsize = "7" 50 | fname = "pipe" 51 | shape = "doublecircle" 52 | subkind = "pipe" 53 | kind = "file" 54 | ]; 55 | "22694" [ 56 | label = "22694\ndot" 57 | pname = "dot" 58 | kind = "proc" 59 | ]; 60 | "4761+2595" [ 61 | label = "4761+2595\n/home/ek/pm2.dot" 62 | fname = "/home/ek/pm2.dot" 63 | shape = "ellipse" 64 | kind = "file" 65 | ]; 66 | "22690" -> "22692" [ 67 | fontsize = "14" 68 | fontname = "Times-Roman" 69 | fontcolor = "black" 70 | color = "black" 71 | ]; 72 | "22692" -> "116842+2595" [ 73 | fontsize = "14" 74 | fontname = "Times-Roman" 75 | fontcolor = "black" 76 | dir = "back" 77 | color = "black" 78 | ]; 79 | "22692" -> "22693" [ 80 | fontsize = "14" 81 | fontname = "Times-Roman" 82 | fontcolor = "black" 83 | color = "black" 84 | ]; 85 | "22693" -> "182440-1" [ 86 | fontsize = "14" 87 | fontname = "Times-Roman" 88 | fontcolor = "black" 89 | dir = "back" 90 | color = "black" 91 | ]; 92 | "22693" -> "182442-1" [ 93 | fontsize = "14" 94 | fontname = "Times-Roman" 95 | fontcolor = "black" 96 | dir = "forward" 97 | color = "black" 98 | ]; 99 | "22693" -> "22694" [ 100 | fontsize = "14" 101 | fontname = "Times-Roman" 102 | fontcolor = "black" 103 | color = "black" 104 | ]; 105 | "22694" -> "182440-1" [ 106 | fontsize = "14" 107 | fontname = "Times-Roman" 108 | fontcolor = "black" 109 | dir = "forward" 110 | color = "black" 111 | ]; 112 | "22694" -> "182442-1" [ 113 | fontsize = "14" 114 | fontname = "Times-Roman" 115 | fontcolor = "black" 116 | dir = "back" 117 | color = "black" 118 | ]; 119 | "22693" -> "4761+2595" [ 120 | fontsize = "14" 121 | fontname = "Times-Roman" 122 | fontcolor = "black" 123 | dir = "back" 124 | color = "black" 125 | ]; 126 | } 127 | -------------------------------------------------------------------------------- /testdata/directed/pmpipe.gv: -------------------------------------------------------------------------------- 1 | digraph g { 2 | graph [ 3 | ]; 4 | node [ 5 | fontsize = "14" 6 | fontname = "Times-Roman" 7 | fontcolor = "black" 8 | shape = "box" 9 | color = "black" 10 | width = "0.5" 11 | ]; 12 | edge [ 13 | fontsize = "14" 14 | fontname = "Times-Roman" 15 | fontcolor = "black" 16 | color = "black" 17 | ]; 18 | "23296" [ 19 | label = "23296\n?" 20 | pname = "?" 21 | kind = "proc" 22 | ]; 23 | "182948-1" [ 24 | label = "182948-1\n182949-1\npipe" 25 | fontsize = "7" 26 | fname = "pipe" 27 | shape = "doublecircle" 28 | subkind = "pipe" 29 | kind = "file" 30 | ]; 31 | "23310" [ 32 | label = "23310\ncat" 33 | pname = "cat" 34 | kind = "proc" 35 | ]; 36 | "182950-1" [ 37 | label = "182950-1\n182951-1\npipe" 38 | fontsize = "7" 39 | fname = "pipe" 40 | shape = "doublecircle" 41 | subkind = "pipe" 42 | kind = "file" 43 | ]; 44 | "23311" [ 45 | label = "23311\ncat" 46 | pname = "cat" 47 | kind = "proc" 48 | ]; 49 | "182952-1" [ 50 | label = "182952-1\n182953-1\npipe" 51 | fontsize = "7" 52 | fname = "pipe" 53 | shape = "doublecircle" 54 | subkind = "pipe" 55 | kind = "file" 56 | ]; 57 | "23312" [ 58 | label = "23312\ncat" 59 | pname = "cat" 60 | kind = "proc" 61 | ]; 62 | "182954-1" [ 63 | label = "182954-1\n182955-1\npipe" 64 | fontsize = "7" 65 | fname = "pipe" 66 | shape = "doublecircle" 67 | subkind = "pipe" 68 | kind = "file" 69 | ]; 70 | "23313" [ 71 | label = "23313\ncat" 72 | pname = "cat" 73 | kind = "proc" 74 | ]; 75 | "79893+2568" [ 76 | label = "79893+2568\n/usr/share/lib/termcap" 77 | fname = "/usr/share/lib/termcap" 78 | shape = "ellipse" 79 | kind = "file" 80 | ]; 81 | "85+2560" [ 82 | label = "85+2560\n?" 83 | fname = "?" 84 | shape = "ellipse" 85 | kind = "file" 86 | ]; 87 | "23314" [ 88 | label = "23314\ncat" 89 | pname = "cat" 90 | kind = "proc" 91 | ]; 92 | "4151865284+0" [ 93 | label = "4151865284+0\n/tmp/termcap" 94 | fname = "/tmp/termcap" 95 | shape = "ellipse" 96 | kind = "file" 97 | ]; 98 | "23296" -> "23310" [ 99 | fontsize = "14" 100 | fontname = "Times-Roman" 101 | fontcolor = "black" 102 | color = "black" 103 | ]; 104 | "23296" -> "23311" [ 105 | fontsize = "14" 106 | fontname = "Times-Roman" 107 | fontcolor = "black" 108 | color = "black" 109 | ]; 110 | "23311" -> "182948-1" [ 111 | fontsize = "14" 112 | fontname = "Times-Roman" 113 | fontcolor = "black" 114 | dir = "back" 115 | color = "black" 116 | ]; 117 | "23310" -> "182948-1" [ 118 | fontsize = "14" 119 | fontname = "Times-Roman" 120 | fontcolor = "black" 121 | dir = "forward" 122 | color = "black" 123 | ]; 124 | "23296" -> "23312" [ 125 | fontsize = "14" 126 | fontname = "Times-Roman" 127 | fontcolor = "black" 128 | color = "black" 129 | ]; 130 | "23312" -> "182952-1" [ 131 | fontsize = "14" 132 | fontname = "Times-Roman" 133 | fontcolor = "black" 134 | dir = "forward" 135 | color = "black" 136 | ]; 137 | "23312" -> "182950-1" [ 138 | fontsize = "14" 139 | fontname = "Times-Roman" 140 | fontcolor = "black" 141 | dir = "back" 142 | color = "black" 143 | ]; 144 | "23296" -> "23313" [ 145 | fontsize = "14" 146 | fontname = "Times-Roman" 147 | fontcolor = "black" 148 | color = "black" 149 | ]; 150 | "23313" -> "182954-1" [ 151 | fontsize = "14" 152 | fontname = "Times-Roman" 153 | fontcolor = "black" 154 | dir = "forward" 155 | color = "black" 156 | ]; 157 | "23311" -> "182950-1" [ 158 | fontsize = "14" 159 | fontname = "Times-Roman" 160 | fontcolor = "black" 161 | dir = "forward" 162 | color = "black" 163 | ]; 164 | "23310" -> "79893+2568" [ 165 | fontsize = "14" 166 | fontname = "Times-Roman" 167 | fontcolor = "black" 168 | dir = "back" 169 | color = "black" 170 | ]; 171 | "23296" -> "85+2560" [ 172 | fontsize = "14" 173 | fontname = "Times-Roman" 174 | fontcolor = "black" 175 | dir = "both" 176 | color = "black" 177 | ]; 178 | "23296" -> "23314" [ 179 | fontsize = "14" 180 | fontname = "Times-Roman" 181 | fontcolor = "black" 182 | color = "black" 183 | ]; 184 | "23314" -> "85+2560" [ 185 | fontsize = "14" 186 | fontname = "Times-Roman" 187 | fontcolor = "black" 188 | dir = "both" 189 | color = "black" 190 | ]; 191 | "23314" -> "182954-1" [ 192 | fontsize = "14" 193 | fontname = "Times-Roman" 194 | fontcolor = "black" 195 | dir = "back" 196 | color = "black" 197 | ]; 198 | "23296" -> "85+2560" [ 199 | fontsize = "14" 200 | fontname = "Times-Roman" 201 | fontcolor = "black" 202 | dir = "both" 203 | color = "black" 204 | ]; 205 | "23314" -> "4151865284+0" [ 206 | fontsize = "14" 207 | fontname = "Times-Roman" 208 | fontcolor = "black" 209 | dir = "forward" 210 | color = "black" 211 | ]; 212 | "23313" -> "182952-1" [ 213 | fontsize = "14" 214 | fontname = "Times-Roman" 215 | fontcolor = "black" 216 | dir = "back" 217 | color = "black" 218 | ]; 219 | } 220 | -------------------------------------------------------------------------------- /testdata/directed/polypoly.gv: -------------------------------------------------------------------------------- 1 | digraph polypoly { 2 | 3 | size="7,9.5"; 4 | page="8.5,11"; 5 | ratio=fill; 6 | node [shape=polygon]; 7 | 8 | { rank=same; 9 | node [sides=0]; 10 | node [peripheries=1]; 11 | 0000 [label="M"]; 12 | 0001 [label="MMMMMMMMMM"]; 13 | 0002 [label="M\nM\nM\nM\nM\nM"]; 14 | 0003 [label="MMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM"]; 15 | node [peripheries=2]; 16 | 0010 [label="M"]; 17 | 0011 [label="MMMMMMMMMM"]; 18 | 0012 [label="M\nM\nM\nM\nM\nM"]; 19 | 0013 [label="MMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM"]; 20 | node [distortion=-.3]; 21 | 0110 [label="M"]; 22 | 0111 [label="MMMMMMMMMM"]; 23 | 0112 [label="M\nM\nM\nM\nM\nM"]; 24 | 0113 [label="MMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM"]; 25 | } 26 | { rank=same; 27 | node [sides=3]; 28 | node [peripheries=1]; 29 | node [orientation=0]; 30 | 3000 [label="M"]; 31 | 3001 [label="MMMMMMMMMM"]; 32 | 3002 [label="M\nM\nM\nM\nM\nM"]; 33 | 3003 [label="MMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM"]; 34 | node [peripheries=2]; 35 | node [orientation=60]; 36 | 3110 [label="M"]; 37 | 3111 [label="MMMMMMMMMM"]; 38 | 3112 [label="M\nM\nM\nM\nM\nM"]; 39 | 3113 [label="MMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM"]; 40 | } 41 | 3000->0000; 42 | { rank=same; 43 | node [sides=4]; 44 | node [peripheries=1]; 45 | node [orientation=0]; 46 | 4000 [label="M"]; 47 | 4001 [label="MMMMMMMMMM"]; 48 | 4002 [label="M\nM\nM\nM\nM\nM"]; 49 | 4003 [label="MMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM"]; 50 | node [peripheries=2]; 51 | node [orientation=45]; 52 | 4110 [label="M"]; 53 | 4111 [label="MMMMMMMMMM"]; 54 | 4112 [label="M\nM\nM\nM\nM\nM"]; 55 | 4113 [label="MMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM"]; 56 | } 57 | 4000->3000; 58 | { rank=same; 59 | node [sides=5]; 60 | node [peripheries=1]; 61 | node [orientation=0]; 62 | 5000 [label="M"]; 63 | 5001 [label="MMMMMMMMMM"]; 64 | 5002 [label="M\nM\nM\nM\nM\nM"]; 65 | 5003 [label="MMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM"]; 66 | node [peripheries=2]; 67 | node [orientation=36]; 68 | 5110 [label="M"]; 69 | 5111 [label="MMMMMMMMMM"]; 70 | 5112 [label="M\nM\nM\nM\nM\nM"]; 71 | 5113 [label="MMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM"]; 72 | } 73 | 5000->4000; 74 | { rank=same; 75 | node [sides=6]; 76 | node [peripheries=1]; 77 | node [orientation=0]; 78 | 6000 [label="M"]; 79 | 6001 [label="MMMMMMMMMM"]; 80 | 6002 [label="M\nM\nM\nM\nM\nM"]; 81 | 6003 [label="MMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM"]; 82 | node [peripheries=2]; 83 | node [orientation=30]; 84 | 6110 [label="M"]; 85 | 6111 [label="MMMMMMMMMM"]; 86 | 6112 [label="M\nM\nM\nM\nM\nM"]; 87 | 6113 [label="MMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM"]; 88 | } 89 | 6000->5000; 90 | { rank=same; 91 | node [sides=7]; 92 | node [peripheries=1]; 93 | node [orientation=0]; 94 | 7000 [label="M"]; 95 | 7001 [label="MMMMMMMMMM"]; 96 | 7002 [label="M\nM\nM\nM\nM\nM"]; 97 | 7003 [label="MMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM"]; 98 | node [peripheries=2]; 99 | node [orientation=25.7]; 100 | 7110 [label="M"]; 101 | 7111 [label="MMMMMMMMMM"]; 102 | 7112 [label="M\nM\nM\nM\nM\nM"]; 103 | 7113 [label="MMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM"]; 104 | } 105 | 7000->6000; 106 | { rank=same; 107 | node [sides=8]; 108 | node [peripheries=1]; 109 | node [orientation=0]; 110 | 8000 [label="M"]; 111 | 8001 [label="MMMMMMMMMM"]; 112 | 8002 [label="M\nM\nM\nM\nM\nM"]; 113 | 8003 [label="MMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM"]; 114 | node [peripheries=2]; 115 | node [orientation=22.5]; 116 | 8110 [label="M"]; 117 | 8111 [label="MMMMMMMMMM"]; 118 | 8112 [label="M\nM\nM\nM\nM\nM"]; 119 | 8113 [label="MMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM\nMMMMMMMMMM"]; 120 | } 121 | 8000->7000; 122 | { rank=same; 123 | node [sides=4]; 124 | node [peripheries=1]; 125 | node [regular=1]; 126 | node [distortion=.5]; 127 | node [orientation=0]; 128 | 9000 [label="M"]; 129 | node [orientation=45.]; 130 | 9001 [label="M"]; 131 | node [orientation=90.]; 132 | 9002 [label="M"]; 133 | node [orientation=135.]; 134 | 9003 [label="M"]; 135 | node [orientation=180.]; 136 | 9004 [label="M"]; 137 | node [orientation=225.]; 138 | 9005 [label="M"]; 139 | node [orientation=270.]; 140 | 9006 [label="M"]; 141 | node [orientation=315.]; 142 | 9007 [label="M"]; 143 | node [peripheries=2]; 144 | node [orientation=0]; 145 | 9010 [label="M"]; 146 | node [orientation=45.]; 147 | 9011 [label="M"]; 148 | node [orientation=90.]; 149 | 9012 [label="M"]; 150 | node [orientation=135.]; 151 | 9013 [label="M"]; 152 | node [orientation=180.]; 153 | 9014 [label="M"]; 154 | node [orientation=225.]; 155 | 9015 [label="M"]; 156 | node [orientation=270.]; 157 | 9016 [label="M"]; 158 | node [orientation=315.]; 159 | 9017 [label="M"]; 160 | } 161 | 9000->8000; 162 | } 163 | -------------------------------------------------------------------------------- /testdata/directed/proc3d.gv: -------------------------------------------------------------------------------- 1 | digraph g { 2 | graph [ 3 | fontname=Courier, 4 | fontsize=24, 5 | ranksep = 1.0, 6 | size="10,7.5", 7 | orientation=land, 8 | style="setlinewidth(8)" 9 | page = "8.5,11", 10 | center=true 11 | ]; 12 | node [ 13 | shape = "box" 14 | width = "0.5" 15 | ]; 16 | edge [ 17 | ]; 18 | subgraph cluster_0 { 19 | label="gryphon" 20 | "22342" 21 | "22343" 22 | "22346" 23 | "22347" 24 | "22351" 25 | "22344" 26 | "22345" 27 | "22348" 28 | "22350" 29 | "22357" 30 | } 31 | subgraph cluster_1 { 32 | label=toucan 33 | "22349" 34 | "22352" 35 | "22356" 36 | "22361" 37 | "22369" 38 | "22353" 39 | "22355" 40 | "22360" 41 | "22365" 42 | "22374" 43 | } 44 | subgraph cluster_2 { 45 | label=parker 46 | "22354" 47 | "22359" 48 | "22375" 49 | } 50 | subgraph cluster_3 { 51 | label=condor 52 | "22358" 53 | "22362" 54 | "22367" 55 | "22373" 56 | "22378" 57 | } 58 | subgraph cluster_4 { 59 | label=kite 60 | "22363" 61 | "22366" 62 | "22371" 63 | "22376" 64 | "22380" 65 | } 66 | subgraph cluster_5 { 67 | label=coot 68 | "22368" 69 | "22372" 70 | "22377" 71 | "22379" 72 | "22381" 73 | } 74 | "22316" [ 75 | label = "22316\nksh" 76 | pname = "ksh" 77 | kind = "proc" 78 | ]; 79 | "22324" [ 80 | label = "22324\nnmake" 81 | pname = "nmake" 82 | kind = "proc" 83 | ]; 84 | "22337" [ 85 | label = "22337\nksh" 86 | pname = "ksh" 87 | kind = "proc" 88 | ]; 89 | "22342" [ 90 | label = "22342\nksh" 91 | pname = "ksh" 92 | kind = "proc" 93 | ]; 94 | "22343" [ 95 | label = "22343\ngcc" 96 | pname = "gcc" 97 | kind = "proc" 98 | ]; 99 | "22344" [ 100 | label = "22344\nksh" 101 | pname = "ksh" 102 | kind = "proc" 103 | ]; 104 | "22345" [ 105 | label = "22345\ngcc" 106 | pname = "gcc" 107 | kind = "proc" 108 | ]; 109 | "22346" [ 110 | label = "22346\ncpp" 111 | pname = "cpp" 112 | kind = "proc" 113 | ]; 114 | "22347" [ 115 | label = "22347\ncc1" 116 | pname = "cc1" 117 | kind = "proc" 118 | ]; 119 | "22348" [ 120 | label = "22348\ncpp" 121 | pname = "cpp" 122 | kind = "proc" 123 | ]; 124 | "93736-32246" [ 125 | label = "93736-32246\n/home/ek/work/src/lefty/lefty.c" 126 | fname = "/home/ek/work/src/lefty/lefty.c" 127 | shape = "ellipse" 128 | kind = "file" 129 | ]; 130 | "22349" [ 131 | label = "22349\nksh" 132 | pname = "ksh" 133 | kind = "proc" 134 | ]; 135 | "22350" [ 136 | label = "22350\ncc1" 137 | pname = "cc1" 138 | kind = "proc" 139 | ]; 140 | "93627-32246" [ 141 | label = "93627-32246\n/home/ek/work/src/lefty/gfxview.c" 142 | fname = "/home/ek/work/src/lefty/gfxview.c" 143 | shape = "ellipse" 144 | kind = "file" 145 | ]; 146 | "22351" [ 147 | label = "22351\nas" 148 | pname = "as" 149 | kind = "proc" 150 | ]; 151 | "22352" [ 152 | label = "22352\ngcc" 153 | pname = "gcc" 154 | kind = "proc" 155 | ]; 156 | "22353" [ 157 | label = "22353\nksh" 158 | pname = "ksh" 159 | kind = "proc" 160 | ]; 161 | "22354" [ 162 | label = "22354\nksh" 163 | pname = "ksh" 164 | kind = "proc" 165 | ]; 166 | "22355" [ 167 | label = "22355\ngcc" 168 | pname = "gcc" 169 | kind = "proc" 170 | ]; 171 | "22356" [ 172 | label = "22356\ncpp" 173 | pname = "cpp" 174 | kind = "proc" 175 | ]; 176 | "22357" [ 177 | label = "22357\nas" 178 | pname = "as" 179 | kind = "proc" 180 | ]; 181 | "22358" [ 182 | label = "22358\nksh" 183 | pname = "ksh" 184 | kind = "proc" 185 | ]; 186 | "22359" [ 187 | label = "22359\ngcc" 188 | pname = "gcc" 189 | kind = "proc" 190 | ]; 191 | "22360" [ 192 | label = "22360\ncpp" 193 | pname = "cpp" 194 | kind = "proc" 195 | ]; 196 | "22361" [ 197 | label = "22361\ncc1" 198 | pname = "cc1" 199 | kind = "proc" 200 | ]; 201 | "93645-32246" [ 202 | label = "93645-32246\n/home/ek/work/src/lefty/txtview.c" 203 | fname = "/home/ek/work/src/lefty/txtview.c" 204 | shape = "ellipse" 205 | kind = "file" 206 | ]; 207 | "22362" [ 208 | label = "22362\ngcc" 209 | pname = "gcc" 210 | kind = "proc" 211 | ]; 212 | "22363" [ 213 | label = "22363\nksh" 214 | pname = "ksh" 215 | kind = "proc" 216 | ]; 217 | "22365" [ 218 | label = "22365\ncc1" 219 | pname = "cc1" 220 | kind = "proc" 221 | ]; 222 | "22366" [ 223 | label = "22366\ngcc" 224 | pname = "gcc" 225 | kind = "proc" 226 | ]; 227 | "93638-32246" [ 228 | label = "93638-32246\n/home/ek/work/src/lefty/internal.c" 229 | fname = "/home/ek/work/src/lefty/internal.c" 230 | shape = "ellipse" 231 | kind = "file" 232 | ]; 233 | "22367" [ 234 | label = "22367\ncpp" 235 | pname = "cpp" 236 | kind = "proc" 237 | ]; 238 | "22368" [ 239 | label = "22368\nksh" 240 | pname = "ksh" 241 | kind = "proc" 242 | ]; 243 | "22369" [ 244 | label = "22369\nas" 245 | pname = "as" 246 | kind = "proc" 247 | ]; 248 | "93642-32246" [ 249 | label = "93642-32246\n/home/ek/work/src/lefty/lex.c" 250 | fname = "/home/ek/work/src/lefty/lex.c" 251 | shape = "ellipse" 252 | kind = "file" 253 | ]; 254 | "22371" [ 255 | label = "22371\ncpp" 256 | pname = "cpp" 257 | kind = "proc" 258 | ]; 259 | "22372" [ 260 | label = "22372\ngcc" 261 | pname = "gcc" 262 | kind = "proc" 263 | ]; 264 | "22373" [ 265 | label = "22373\ncc1" 266 | pname = "cc1" 267 | kind = "proc" 268 | ]; 269 | "88860-32246" [ 270 | label = "88860-32246\n/home/ek/dev/src/lefty/stringify.c" 271 | fname = "/home/ek/dev/src/lefty/stringify.c" 272 | shape = "ellipse" 273 | kind = "file" 274 | ]; 275 | "22374" [ 276 | label = "22374\nas" 277 | pname = "as" 278 | kind = "proc" 279 | ]; 280 | "22375" [ 281 | label = "22375\nas" 282 | pname = "as" 283 | kind = "proc" 284 | ]; 285 | "22376" [ 286 | label = "22376\ncc1" 287 | pname = "cc1" 288 | kind = "proc" 289 | ]; 290 | "93626-32246" [ 291 | label = "93626-32246\n/home/ek/work/src/lefty/exec.c" 292 | fname = "/home/ek/work/src/lefty/exec.c" 293 | shape = "ellipse" 294 | kind = "file" 295 | ]; 296 | "22377" [ 297 | label = "22377\ncpp" 298 | pname = "cpp" 299 | kind = "proc" 300 | ]; 301 | "22378" [ 302 | label = "22378\nas" 303 | pname = "as" 304 | kind = "proc" 305 | ]; 306 | "22379" [ 307 | label = "22379\ncc1" 308 | pname = "cc1" 309 | kind = "proc" 310 | ]; 311 | "93643-32246" [ 312 | label = "93643-32246\n/home/ek/work/src/lefty/parse.c" 313 | fname = "/home/ek/work/src/lefty/parse.c" 314 | shape = "ellipse" 315 | kind = "file" 316 | ]; 317 | "22380" [ 318 | label = "22380\nas" 319 | pname = "as" 320 | kind = "proc" 321 | ]; 322 | "22381" [ 323 | label = "22381\nas" 324 | pname = "as" 325 | kind = "proc" 326 | ]; 327 | "37592-32246" [ 328 | label = "37592-32246\n/home/ek/dev/src/lefty/exec.h" 329 | fname = "/home/ek/dev/src/lefty/exec.h" 330 | shape = "ellipse" 331 | kind = "file" 332 | ]; 333 | "135504-32246" [ 334 | label = "135504-32246\n/home/ek/work/sun4/lefty/display.o" 335 | fname = "/home/ek/work/sun4/lefty/display.o" 336 | shape = "ellipse" 337 | kind = "file" 338 | ]; 339 | "22316" -> "22324" [ 340 | ]; 341 | "22324" -> "22337" [ 342 | ]; 343 | "22337" -> "22342" [ 344 | ]; 345 | "22342" -> "22343" [ 346 | ]; 347 | "22337" -> "22344" [ 348 | ]; 349 | "22344" -> "22345" [ 350 | ]; 351 | "22343" -> "22346" [ 352 | ]; 353 | "22343" -> "22347" [ 354 | ]; 355 | "22345" -> "22348" [ 356 | ]; 357 | "22346" -> "93736-32246" [ 358 | ]; 359 | "22337" -> "22349" [ 360 | ]; 361 | "22345" -> "22350" [ 362 | ]; 363 | "22348" -> "93627-32246" [ 364 | ]; 365 | "22343" -> "22351" [ 366 | ]; 367 | "22349" -> "22352" [ 368 | ]; 369 | "22337" -> "22353" [ 370 | ]; 371 | "22337" -> "22354" [ 372 | ]; 373 | "22353" -> "22355" [ 374 | ]; 375 | "22352" -> "22356" [ 376 | ]; 377 | "22345" -> "22357" [ 378 | ]; 379 | "22337" -> "22358" [ 380 | ]; 381 | "22354" -> "22359" [ 382 | ]; 383 | "22355" -> "22360" [ 384 | ]; 385 | "22352" -> "22361" [ 386 | ]; 387 | "22356" -> "93645-32246" [ 388 | ]; 389 | "22358" -> "22362" [ 390 | ]; 391 | "22337" -> "22363" [ 392 | ]; 393 | "22355" -> "22365" [ 394 | ]; 395 | "22363" -> "22366" [ 396 | ]; 397 | "22360" -> "93638-32246" [ 398 | ]; 399 | "22362" -> "22367" [ 400 | ]; 401 | "22337" -> "22368" [ 402 | ]; 403 | "22352" -> "22369" [ 404 | ]; 405 | "22324" -> "93642-32246" [ 406 | ]; 407 | "22366" -> "22371" [ 408 | ]; 409 | "22368" -> "22372" [ 410 | ]; 411 | "22362" -> "22373" [ 412 | ]; 413 | "22367" -> "88860-32246" [ 414 | ]; 415 | "22355" -> "22374" [ 416 | ]; 417 | "22359" -> "22375" [ 418 | ]; 419 | "22366" -> "22376" [ 420 | ]; 421 | "22371" -> "93626-32246" [ 422 | ]; 423 | "22372" -> "22377" [ 424 | ]; 425 | "22362" -> "22378" [ 426 | ]; 427 | "22372" -> "22379" [ 428 | ]; 429 | "22377" -> "93643-32246" [ 430 | ]; 431 | "22366" -> "22380" [ 432 | ]; 433 | "22372" -> "22381" [ 434 | ]; 435 | "22371" -> "37592-32246" [ 436 | ]; 437 | "22375" -> "135504-32246" [ 438 | ]; 439 | 440 | /* hack to increase node separation */ 441 | { rank = same; "22337" -> "93642-32246" [style=invis,minlen=10]; } 442 | 443 | } 444 | -------------------------------------------------------------------------------- /testdata/directed/psfonttest.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | rankdir=LR 3 | nodesep=0 4 | node [shape=none margin=0] 5 | edge [color=white] 6 | "AvantGarde-Book" [fontname="AvantGarde-Book"] 7 | "AvantGarde-Demi" [fontname="AvantGarde-Demi"] 8 | "AvantGarde-BookOblique" [fontname="AvantGarde-BookOblique"] 9 | "AvantGarde-DemiOblique" [fontname="AvantGarde-DemiOblique"] 10 | 11 | "AvantGarde-Book" -> "AvantGarde-Demi" -> "AvantGarde-BookOblique" -> "AvantGarde-DemiOblique" 12 | 13 | "Bookman-Light" [fontname="Bookman-Light"] 14 | "Bookman-Demi" [fontname="Bookman-Demi"] 15 | "Bookman-LightItalic" [fontname="Bookman-LightItalic"] 16 | "Bookman-DemiItalic" [fontname="Bookman-DemiItalic"] 17 | 18 | "Bookman-Light" -> "Bookman-Demi" -> "Bookman-LightItalic" -> "Bookman-DemiItalic" 19 | 20 | "Courier" [fontname="Courier"] 21 | "Courier-Bold" [fontname="Courier-Bold"] 22 | "Courier-Oblique" [fontname="Courier-Oblique"] 23 | "Courier-BoldOblique" [fontname="Courier-BoldOblique"] 24 | 25 | "Courier" -> "Courier-Bold" -> "Courier-Oblique" -> "Courier-BoldOblique" 26 | 27 | "Helvetica" [fontname="Helvetica"] 28 | "Helvetica-Bold" [fontname="Helvetica-Bold"] 29 | "Helvetica-Oblique" [fontname="Helvetica-Oblique"] 30 | "Helvetica-BoldOblique" [fontname="Helvetica-BoldOblique"] 31 | 32 | "Helvetica-Narrow" [fontname="Helvetica-Narrow"] 33 | "Helvetica-Narrow-Bold" [fontname="Helvetica-Narrow-Bold"] 34 | "Helvetica-Narrow-Oblique" [fontname="Helvetica-Narrow-Oblique"] 35 | "Helvetica-Narrow-BoldOblique" [fontname="Helvetica-Narrow-BoldOblique"] 36 | 37 | "Helvetica" -> "Helvetica-Bold" -> "Helvetica-Oblique" -> "Helvetica-BoldOblique" 38 | 39 | "Helvetica-Narrow" -> "Helvetica-Narrow-Bold" -> "Helvetica-Narrow-Oblique" -> "Helvetica-Narrow-BoldOblique" 40 | 41 | "NewCenturySchlbk-Roman" [fontname="NewCenturySchlbk-Roman"] 42 | "NewCenturySchlbk-Bold" [fontname="NewCenturySchlbk-Bold"] 43 | "NewCenturySchlbk-Italic" [fontname="NewCenturySchlbk-Italic"] 44 | "NewCenturySchlbk-BoldItalic" [fontname="NewCenturySchlbk-BoldItalic"] 45 | 46 | "NewCenturySchlbk-Roman" -> "NewCenturySchlbk-Bold" -> "NewCenturySchlbk-Italic" -> "NewCenturySchlbk-BoldItalic" 47 | 48 | "Palatino-Roman" [fontname="Palatino-Roman"] 49 | "Palatino-Bold" [fontname="Palatino-Bold"] 50 | "Palatino-Italic" [fontname="Palatino-Italic"] 51 | "Palatino-BoldItalic" [fontname="Palatino-BoldItalic"] 52 | 53 | "Palatino-Roman" -> "Palatino-Bold" -> "Palatino-Italic" -> "Palatino-BoldItalic" 54 | 55 | "Times-Roman" [fontname="Times-Roman"] 56 | "Times-Bold" [fontname="Times-Bold"] 57 | "Times-Italic" [fontname="Times-Italic"] 58 | "Times-BoldItalic" [fontname="Times-BoldItalic"] 59 | 60 | "Times-Roman" -> "Times-Bold" -> "Times-Italic" -> "Times-BoldItalic" 61 | 62 | "ZapfChancery-MediumItalic" [fontname="ZapfChancery-MediumItalic"] 63 | "ZapfDingbats" [fontname="ZapfDingbats"] 64 | "Symbol" [fontname="Symbol"] 65 | 66 | "Symbol" -> "ZapfDingbats" -> "ZapfChancery-MediumItalic" 67 | } 68 | -------------------------------------------------------------------------------- /testdata/directed/record2.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | node [shape=record]; 3 | a [label = " foo | x | bar"]; 4 | b [label = "a | { foo | x | bar } | b"]; 5 | a:f0 -> b:f1 6 | } 7 | -------------------------------------------------------------------------------- /testdata/directed/records.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | rankdir=LR; 3 | node [shape=record]; 4 | a [ label =" Graphs can\lbe fun\l| mid| right\r"]; 5 | b [ label =" | b | " ]; 6 | c [ label =" | c | " ]; 7 | x [ label =" | x | " ]; 8 | y [ label =" | y | " ]; 9 | z [ label =" | z | " ]; 10 | a:bala -> b:left; 11 | a:f1 -> d; 12 | a:f2 -> y:"p1"; 13 | c:"p1" -> d; 14 | b:mid -> x:"p1"; 15 | c:"p2" -> y:"p2"; 16 | b:left -> z:"p2"; 17 | } 18 | -------------------------------------------------------------------------------- /testdata/directed/rowe.gv: -------------------------------------------------------------------------------- 1 | digraph rowe { 2 | node [shape = box]; 3 | size = "6,6"; 4 | 1 -> 2; 5 | 1 -> 10; 6 | 10 -> 14; 7 | 10 -> 12; 8 | 10 -> 13; 9 | 10 -> 11; 10 | 2 -> 18; 11 | 2 -> 17; 12 | 2 -> 16; 13 | 2 -> 3; 14 | 11 -> 4; 15 | 16 -> 4; 16 | 3 -> 4; 17 | 4 -> 5; 18 | 13 -> 19; 19 | 17 -> 19; 20 | 5 -> 23; 21 | 5 -> 35; 22 | 5 -> 6; 23 | 37 -> 39; 24 | 37 -> 41; 25 | 37 -> 40; 26 | 37 -> 38; 27 | 19 -> 20; 28 | 19 -> 28; 29 | 19 -> 21; 30 | 12 -> 29; 31 | 18 -> 29; 32 | 41 -> 29; 33 | 28 -> 29; 34 | 29 -> 30; 35 | 30 -> 31; 36 | 30 -> 33; 37 | 31 -> 32; 38 | 21 -> 22; 39 | 32 -> 23; 40 | 22 -> 23; 41 | 6 -> 7; 42 | 23 -> 24; 43 | 7 -> 8; 44 | 24 -> 25; 45 | 24 -> 27; 46 | 35 -> 43; 47 | 35 -> 36; 48 | 8 -> 9; 49 | 14 -> 15; 50 | 39 -> 15; 51 | 20 -> 15; 52 | 33 -> 34; 53 | 43 -> 40; 54 | 43 -> 38; 55 | 25 -> 26; 56 | 9 -> 42; 57 | 10 -> 1; 58 | 15 -> 1; 59 | 23 -> 1; 60 | 31 -> 1; 61 | 2 -> 1; 62 | 25 -> 1; 63 | 9 -> 1; 64 | 38 -> 4; 65 | 26 -> 4; 66 | 42 -> 4; 67 | 40 -> 19; 68 | 36 -> 19; 69 | 34 -> 29; 70 | 33 -> 30; 71 | 27 -> 24; 72 | } 73 | -------------------------------------------------------------------------------- /testdata/directed/russian.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | Контрагенты -> БанковскиеСчета; 3 | Организации -> БанковскиеСчета; 4 | ВопросыДляАнкетирования -> ВариантыОтветовОпросов; 5 | Контрагенты -> ДоговорыВзаиморасчетов; 6 | Номенклатура -> ЕдиницыИзмерения; 7 | НоменклатурныеГруппы -> ЕдиницыИзмерения; 8 | СвойстваОбектов -> ЗначенияСвойствОбектов; 9 | } -------------------------------------------------------------------------------- /testdata/directed/sdh.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | graph [bgcolor=black]; /* set background */ 3 | edge [color=white]; 4 | graph[page="8.5,11",size="7.5,7",ratio=fill,center=1]; 5 | node[style=filled,label=""]; 6 | subgraph ds3CTP { 7 | rank = same; 8 | node[shape=box,color=green]; 9 | ds3CTP_1_1; 10 | ds3CTP_1_2; 11 | ds3CTP_5_1; 12 | ds3CTP_5_2; 13 | } 14 | subgraph t3TTP { 15 | rank = same; 16 | node[shape=invtriangle,color=red]; 17 | t3TTP_1_1; 18 | t3TTP_5_2; 19 | } 20 | subgraph vc3TTP { 21 | rank = same; 22 | node[shape=invtriangle,color=red]; 23 | vc3TTP_1_2; 24 | vc3TTP_5_1; 25 | } 26 | subgraph fabric { 27 | rank = same; 28 | node[shape=hexagon,color=blue]; 29 | fabric_1_2; 30 | fabric_4_1; 31 | fabric_5_1; 32 | } 33 | subgraph xp { 34 | rank = same; 35 | node[shape=diamond,color=blue]; 36 | xp_1_2; 37 | xp_4_1; 38 | xp_5_1; 39 | } 40 | subgraph au3CTP { 41 | rank = same; 42 | node[shape=box,color=green]; 43 | au3CTP_1_2; 44 | au3CTP_4_1; 45 | au3CTP_4_2; 46 | au3CTP_5_1; 47 | } 48 | subgraph aug { 49 | rank = same; 50 | node[shape=invtrapezium,color=pink]; 51 | aug_1_2; 52 | aug_4_1; 53 | aug_4_2; 54 | aug_5_1; 55 | } 56 | subgraph protectionTTP { 57 | rank = same; 58 | node[shape=invtriangle,color=red]; 59 | prTTP_1_2; 60 | prTTP_4_1; 61 | prTTP_4_2; 62 | prTTP_5_1; 63 | } 64 | subgraph protectionGroup { 65 | rank = same; 66 | node[shape=hexagon,color=blue]; 67 | pg_1_2; 68 | pg_4_1; 69 | pg_4_2; 70 | pg_5_1; 71 | } 72 | subgraph protectionUnit { 73 | rank = same; 74 | node[shape=diamond,color=blue]; 75 | pu_1_2; 76 | pu_4_1; 77 | pu_4_2; 78 | pu_5_1; 79 | } 80 | subgraph protectionCTP { 81 | node[shape=box,color=green]; 82 | prCTP_1_2; 83 | prCTP_4_1; 84 | prCTP_4_2; 85 | prCTP_5_1; 86 | } 87 | subgraph msTTP { 88 | rank = same; 89 | node[shape=invtriangle,color=red]; 90 | msTTP_1_2; 91 | msTTP_4_1; 92 | msTTP_4_2; 93 | msTTP_5_1; 94 | } 95 | subgraph msCTP { 96 | rank = same; 97 | node[shape=box,color=green]; 98 | msCTP_1_2; 99 | msCTP_3_1; 100 | msCTP_3_2; 101 | msCTP_4_1; 102 | msCTP_4_2; 103 | msCTP_5_1; 104 | } 105 | subgraph rsTTP { 106 | rank = same; 107 | node[shape=invtriangle,color=red]; 108 | rsTTP_1_2; 109 | rsTTP_3_1; 110 | rsTTP_3_2; 111 | rsTTP_4_1; 112 | rsTTP_4_2; 113 | rsTTP_5_1; 114 | } 115 | subgraph rsCTP { 116 | rank = same; 117 | node[shape=box,color=green]; 118 | rsCTP_1_2; 119 | rsCTP_2_1; 120 | rsCTP_2_2; 121 | rsCTP_3_1; 122 | rsCTP_3_2; 123 | rsCTP_4_1; 124 | rsCTP_4_2; 125 | rsCTP_5_1; 126 | } 127 | subgraph spiTTP { 128 | rank = same; 129 | node[shape=invtriangle,color=red]; 130 | spiTTP_1_2; 131 | spiTTP_2_1; 132 | spiTTP_2_2; 133 | spiTTP_3_1; 134 | spiTTP_3_2; 135 | spiTTP_4_1; 136 | spiTTP_4_2; 137 | spiTTP_5_1; 138 | } 139 | subgraph me { 140 | rank = same; 141 | node[shape=box,peripheries=2]; 142 | me_1; 143 | me_2; 144 | me_3; 145 | me_4; 146 | me_5; 147 | } 148 | subgraph client_server { 149 | edge[style=dotted,dir=none,weight=100]; 150 | ds3CTP_1_1->t3TTP_1_1; 151 | ds3CTP_1_2->vc3TTP_1_2; 152 | au3CTP_1_2->aug_1_2->prTTP_1_2; 153 | prCTP_1_2->msTTP_1_2; 154 | msCTP_1_2->rsTTP_1_2; 155 | rsCTP_1_2->spiTTP_1_2; 156 | rsCTP_2_1->spiTTP_2_1; 157 | rsCTP_2_2->spiTTP_2_2; 158 | msCTP_3_1->rsTTP_3_1; 159 | rsCTP_3_1->spiTTP_3_1; 160 | msCTP_3_2->rsTTP_3_2; 161 | rsCTP_3_2->spiTTP_3_2; 162 | au3CTP_4_1->aug_4_1->prTTP_4_1; 163 | prCTP_4_1->msTTP_4_1; 164 | msCTP_4_1->rsTTP_4_1; 165 | rsCTP_4_1->spiTTP_4_1; 166 | au3CTP_4_2->aug_4_2->prTTP_4_2; 167 | prCTP_4_2->msTTP_4_2; 168 | msCTP_4_2->rsTTP_4_2; 169 | rsCTP_4_2->spiTTP_4_2; 170 | ds3CTP_5_1->vc3TTP_5_1; 171 | au3CTP_5_1->aug_5_1->prTTP_5_1; 172 | prCTP_5_1->msTTP_5_1; 173 | msCTP_5_1->rsTTP_5_1; 174 | rsCTP_5_1->spiTTP_5_1; 175 | ds3CTP_5_2->t3TTP_5_2; 176 | } 177 | subgraph trail { 178 | edge[style=dashed,dir=none]; 179 | vc3TTP_1_2->vc3TTP_5_1; 180 | prTTP_1_2->prTTP_4_1; 181 | prTTP_4_2->prTTP_5_1; 182 | msTTP_1_2->msTTP_4_1; 183 | msTTP_4_2->msTTP_5_1; 184 | rsTTP_1_2->rsTTP_3_1; 185 | rsTTP_3_2->rsTTP_4_1; 186 | rsTTP_4_2->rsTTP_5_1; 187 | spiTTP_1_2->spiTTP_2_1; 188 | spiTTP_2_2->spiTTP_3_1; 189 | spiTTP_3_2->spiTTP_4_1; 190 | spiTTP_4_2->spiTTP_5_1; 191 | } 192 | subgraph contain { 193 | pu_1_2->pg_1_2; 194 | pu_4_1->pg_4_1; 195 | pu_4_2->pg_4_2; 196 | pu_5_1->pg_5_1; 197 | xp_1_2->fabric_1_2; 198 | xp_4_1->fabric_4_1; 199 | xp_5_1->fabric_5_1; 200 | fabric_1_2->me_1; 201 | fabric_4_1->me_4; 202 | fabric_5_1->me_5; 203 | pg_1_2->me_1; 204 | pg_4_1->me_4; 205 | pg_4_2->me_4; 206 | pg_5_1->me_5; 207 | t3TTP_1_1->me_1; 208 | t3TTP_5_2->me_5; 209 | vc3TTP_1_2->me_1; 210 | vc3TTP_5_1->me_5; 211 | prTTP_1_2->me_1; 212 | prTTP_4_1->me_4; 213 | prTTP_4_2->me_4; 214 | prTTP_5_1->me_5; 215 | msTTP_1_2->me_1; 216 | msTTP_4_1->me_4; 217 | msTTP_4_2->me_4; 218 | msTTP_5_1->me_5; 219 | rsTTP_1_2->me_1; 220 | rsTTP_3_1->me_3; 221 | rsTTP_3_2->me_3; 222 | rsTTP_4_1->me_4; 223 | rsTTP_4_2->me_4; 224 | rsTTP_5_1->me_5; 225 | spiTTP_1_2->me_1; 226 | spiTTP_2_1->me_2; 227 | spiTTP_2_2->me_2; 228 | spiTTP_3_1->me_3; 229 | spiTTP_3_2->me_3; 230 | spiTTP_4_1->me_4; 231 | spiTTP_4_2->me_4; 232 | spiTTP_5_1->me_5; 233 | } 234 | subgraph connectedBy { 235 | vc3TTP_1_2->fabric_1_2; 236 | au3CTP_1_2->fabric_1_2; 237 | au3CTP_4_1->fabric_4_1; 238 | au3CTP_4_2->fabric_4_1; 239 | vc3TTP_5_1->fabric_5_1; 240 | au3CTP_5_1->fabric_5_1; 241 | prTTP_1_2->pg_1_2; 242 | prTTP_4_1->pg_4_1; 243 | prTTP_4_2->pg_4_2; 244 | prTTP_5_1->pg_5_1; 245 | prCTP_1_2->pg_1_2; 246 | prCTP_4_1->pg_4_1; 247 | prCTP_4_2->pg_4_2; 248 | prCTP_5_1->pg_5_1; 249 | } 250 | subgraph crossConnection { 251 | edge[style=dotted,dir=none]; 252 | vc3TTP_1_2->xp_1_2->au3CTP_1_2; 253 | prTTP_1_2->pu_1_2->prCTP_1_2; 254 | prTTP_4_1->pu_4_1->prCTP_4_1; 255 | au3CTP_4_1->xp_4_1->au3CTP_4_2; 256 | prTTP_4_2->pu_4_2->prCTP_4_2; 257 | prTTP_5_1->pu_5_1->prCTP_5_1; 258 | vc3TTP_5_1->xp_5_1->au3CTP_5_1; 259 | } 260 | subgraph bindingConnection { 261 | edge[style=bold,dir=none,weight=100]; 262 | ds3CTP_1_1->ds3CTP_1_2; 263 | vc3TTP_1_2->au3CTP_1_2; 264 | prTTP_1_2->prCTP_1_2; 265 | msTTP_1_2->msCTP_1_2; 266 | rsTTP_1_2->rsCTP_1_2; 267 | rsCTP_2_1->rsCTP_2_2; 268 | rsTTP_3_1->rsCTP_3_1; 269 | msCTP_3_1->msCTP_3_2; 270 | rsTTP_3_2->rsCTP_3_2; 271 | prTTP_4_1->prCTP_4_1; 272 | msTTP_4_1->msCTP_4_1; 273 | rsTTP_4_1->rsCTP_4_1; 274 | au3CTP_4_1->au3CTP_4_2; 275 | prTTP_4_2->prCTP_4_2; 276 | msTTP_4_2->msCTP_4_2; 277 | rsTTP_4_2->rsCTP_4_2; 278 | prTTP_5_1->prCTP_5_1; 279 | msTTP_5_1->msCTP_5_1; 280 | rsTTP_5_1->rsCTP_5_1; 281 | ds3CTP_5_1->ds3CTP_5_2; 282 | vc3TTP_5_1->au3CTP_5_1; 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /testdata/directed/shells.gv: -------------------------------------------------------------------------------- 1 | digraph shells { 2 | size="7,8"; 3 | node [fontsize=24, shape = plaintext]; 4 | 5 | 1972 -> 1976; 6 | 1976 -> 1978; 7 | 1978 -> 1980; 8 | 1980 -> 1982; 9 | 1982 -> 1984; 10 | 1984 -> 1986; 11 | 1986 -> 1988; 12 | 1988 -> 1990; 13 | 1990 -> future; 14 | 15 | node [fontsize=20, shape = box]; 16 | { rank=same; 1976 Mashey Bourne; } 17 | { rank=same; 1978 Formshell csh; } 18 | { rank=same; 1980 esh vsh; } 19 | { rank=same; 1982 ksh "System-V"; } 20 | { rank=same; 1984 v9sh tcsh; } 21 | { rank=same; 1986 "ksh-i"; } 22 | { rank=same; 1988 KornShell Perl rc; } 23 | { rank=same; 1990 tcl Bash; } 24 | { rank=same; "future" POSIX "ksh-POSIX"; } 25 | 26 | Thompson -> Mashey; 27 | Thompson -> Bourne; 28 | Thompson -> csh; 29 | csh -> tcsh; 30 | Bourne -> ksh; 31 | Bourne -> esh; 32 | Bourne -> vsh; 33 | Bourne -> "System-V"; 34 | Bourne -> v9sh; 35 | v9sh -> rc; 36 | Bourne -> Bash; 37 | "ksh-i" -> Bash; 38 | KornShell -> Bash; 39 | esh -> ksh; 40 | vsh -> ksh; 41 | Formshell -> ksh; 42 | csh -> ksh; 43 | KornShell -> POSIX; 44 | "System-V" -> POSIX; 45 | ksh -> "ksh-i"; 46 | "ksh-i" -> KornShell; 47 | KornShell -> "ksh-POSIX"; 48 | Bourne -> Formshell; 49 | 50 | edge [style=invis]; 51 | 1984 -> v9sh -> tcsh ; 52 | 1988 -> rc -> KornShell; 53 | Formshell -> csh; 54 | KornShell -> Perl; 55 | } 56 | -------------------------------------------------------------------------------- /testdata/directed/states.gv: -------------------------------------------------------------------------------- 1 | /* 2 | The command line is 3 | 4 | dot -Tps -Grankdir=LR states.gv > states.ps 5 | 6 | and the file is: 7 | */ 8 | digraph states { 9 | size="3,2"; 10 | rankdir=LR; 11 | node [shape=ellipse]; 12 | empty [label = "Empty"]; 13 | stolen [label = "Stolen"]; 14 | waiting [label = "Waiting"]; 15 | full [label = "Full"]; 16 | empty -> full [label = "return"] 17 | empty -> stolen [label = "dispatch", wt=28] 18 | stolen -> full [label = "return"]; 19 | stolen -> waiting [label = "touch"]; 20 | waiting -> full [label = "return"]; 21 | } 22 | -------------------------------------------------------------------------------- /testdata/directed/structs.gv: -------------------------------------------------------------------------------- 1 | digraph structs { 2 | node [shape=record]; 3 | struct1 [shape=record,label=" left| middle| right"]; 4 | struct2 [shape=record,label=" one| two"]; 5 | struct3 [shape=record,label="hello\nworld |{ b |{c| d|e}| f}| g | h"]; 6 | struct1:f1 -> struct2:f0; 7 | struct1:f2 -> struct3:here; 8 | } 9 | -------------------------------------------------------------------------------- /testdata/directed/switch.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | graph [center=true rankdir=LR bgcolor="#808080"] 3 | edge [dir=none] 4 | node [width=0.3 height=0.3 label=""] 5 | { node [shape=circle style=invis] 6 | 1 2 3 4 5 6 7 8 10 20 30 40 50 60 70 80 7 | } 8 | { node [shape=circle] 9 | a b c d e f g h i j k l m n o p q r s t u v w x 10 | } 11 | { node [shape=diamond] 12 | A B C D E F G H I J K L M N O P Q R S T U V W X 13 | } 14 | 1 -> a -> {A B} [color="#0000ff"] 15 | 2 -> b -> {B A} [color="#ff0000"] 16 | 3 -> c -> {C D} [color="#ffff00"] 17 | 4 -> d -> {D C} [color="#00ff00"] 18 | 5 -> e -> {E F} [color="#000000"] 19 | 6 -> f -> {F E} [color="#00ffff"] 20 | 7 -> g -> {G H} [color="#ffffff"] 21 | 8 -> h -> {H G} [color="#ff00ff"] 22 | { edge [color="#ff0000:#0000ff"] 23 | A -> i -> {I K} 24 | B -> j -> {J L} 25 | } 26 | { edge [color="#00ff00:#ffff00"] 27 | C -> k -> {K I} 28 | D -> l -> {L J} 29 | } 30 | { edge [color="#00ffff:#000000"] 31 | E -> m -> {M O} 32 | F -> n -> {N P} 33 | } 34 | { edge [color="#ff00ff:#ffffff"] 35 | G -> o -> {O M} 36 | H -> p -> {P N} 37 | } 38 | { edge [color="#00ff00:#ffff00:#ff0000:#0000ff"] 39 | I -> q -> {Q U} 40 | J -> r -> {R V} 41 | K -> s -> {S W} 42 | L -> t -> {T X} 43 | } 44 | { edge [color="#ff00ff:#ffffff:#00ffff:#000000"] 45 | M -> u -> {U Q} 46 | N -> v -> {V R} 47 | O -> w -> {W S} 48 | P -> x -> {X T} 49 | } 50 | { edge [color="#ff00ff:#ffffff:#00ffff:#000000:#00ff00:#ffff00:#ff0000:#0000ff"] 51 | Q -> 10 52 | R -> 20 53 | S -> 30 54 | T -> 40 55 | U -> 50 56 | V -> 60 57 | W -> 70 58 | X -> 80 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /testdata/directed/table.gv: -------------------------------------------------------------------------------- 1 | digraph structs { 2 | node [shape=plaintext]; 3 | 4 | struct1 [label=< 5 | 6 | 7 | 8 | 9 | 10 |
abc
>]; 11 | 12 | struct2 [label=< 13 | 14 | 15 | 16 | 17 | 26 | 27 | 28 | 29 | 30 |
elefanteltwo
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
buca
c
f
patratos
4
31 | >]; 32 | 33 | struct3 [label=< 34 | 35 | 36 | 47 | 48 | 49 | 50 | 51 | 52 | 53 |
Hello 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
b
adinoy
rhino
climbUp
low
>]; 54 | 55 | struct1 -> struct3; 56 | struct1 -> struct2; 57 | } 58 | -------------------------------------------------------------------------------- /testdata/directed/train11.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | size="6,6"; 3 | node [shape=circle,fontsize=8]; 4 | rankdir=LR; 5 | st9 -> st9 [label="11/1"]; 6 | st9 -> st10 [label="10/1"]; 7 | st8 -> st8 [label="10/1"]; 8 | st8 -> st0 [label="00/-"]; 9 | st7 -> st8 [label="10/1"]; 10 | st7 -> st7 [label="00/1"]; 11 | st6 -> st6 [label="01/1"]; 12 | st6 -> st0 [label="00/-"]; 13 | st5 -> st6 [label="01/1"]; 14 | st5 -> st5 [label="11/1"]; 15 | st4 -> st4 [label="01/1"]; 16 | st4 -> st0 [label="00/-"]; 17 | st3 -> st4 [label="01/1"]; 18 | st3 -> st3 [label="00/1"]; 19 | st2 -> st9 [label="11/1"]; 20 | st2 -> st7 [label="00/1"]; 21 | st2 -> st2 [label="01/1"]; 22 | st10 -> st10 [label="10/1"]; 23 | st10 -> st0 [label="00/-"]; 24 | st1 -> st5 [label="11/1"]; 25 | st1 -> st3 [label="00/1"]; 26 | st1 -> st1 [label="10/1"]; 27 | st0 -> st2 [label="01/-"]; 28 | st0 -> st1 [label="10/-"]; 29 | st0 -> st0 [label="00/0"]; 30 | } 31 | -------------------------------------------------------------------------------- /testdata/directed/trapeziumlr.gv: -------------------------------------------------------------------------------- 1 | digraph test { 2 | 3 | size="7,9.5"; 4 | page="8,10.5"; 5 | ratio=fill; 6 | rankdir=LR; 7 | 8 | { rank=same; 9 | node [shape=house]; 10 | A;C;E;G;I;K;M;O;Q;S;U;W;Y; 11 | node [shape=invhouse]; 12 | B;D;F;H;J;L;N;P;R;T;V;X;Z; 13 | } 14 | 15 | { rank=same; 16 | node [shape=trapezium]; 17 | "Trapezium"; 18 | ordering=out; 19 | } 20 | 21 | Trapezium -> A; 22 | Trapezium -> B; 23 | Trapezium -> C; 24 | Trapezium -> D; 25 | Trapezium -> E; 26 | Trapezium -> F; 27 | Trapezium -> G; 28 | Trapezium -> H; 29 | Trapezium -> I; 30 | Trapezium -> J; 31 | Trapezium -> K; 32 | Trapezium -> L; 33 | Trapezium -> M; 34 | Trapezium -> N; 35 | Trapezium -> O; 36 | Trapezium -> P; 37 | Trapezium -> Q; 38 | Trapezium -> R; 39 | Trapezium -> S; 40 | Trapezium -> T; 41 | Trapezium -> U; 42 | Trapezium -> V; 43 | Trapezium -> W; 44 | Trapezium -> X; 45 | Trapezium -> Y; 46 | Trapezium -> Z; 47 | 48 | { rank=same; 49 | node [shape=parallelogram]; 50 | a;b;c;d;e;f;g;h;i;j;k;l;m;n;o;p;q;r;s;t;u;v;w;x;y;z; 51 | } 52 | 53 | a -> Trapezium; 54 | b -> Trapezium; 55 | c -> Trapezium; 56 | d -> Trapezium; 57 | e -> Trapezium; 58 | f -> Trapezium; 59 | g -> Trapezium; 60 | h -> Trapezium; 61 | i -> Trapezium; 62 | j -> Trapezium; 63 | k -> Trapezium; 64 | l -> Trapezium; 65 | m -> Trapezium; 66 | n -> Trapezium; 67 | o -> Trapezium; 68 | p -> Trapezium; 69 | q -> Trapezium; 70 | r -> Trapezium; 71 | s -> Trapezium; 72 | t -> Trapezium; 73 | u -> Trapezium; 74 | v -> Trapezium; 75 | w -> Trapezium; 76 | x -> Trapezium; 77 | y -> Trapezium; 78 | z -> Trapezium; 79 | } 80 | -------------------------------------------------------------------------------- /testdata/directed/tree.gv: -------------------------------------------------------------------------------- 1 | digraph g { 2 | node [shape = record,height=.1]; 3 | node0[label = " | G| "]; 4 | node1[label = " | E| "]; 5 | node2[label = " | B| "]; 6 | node3[label = " | F| "]; 7 | node4[label = " | R| "]; 8 | node5[label = " | H| "]; 9 | node6[label = " | Y| "]; 10 | node7[label = " | A| "]; 11 | node8[label = " | C| "]; 12 | "node0":f2 -> "node4":f1; 13 | "node0":f0 -> "node1":f1; 14 | "node1":f0 -> "node2":f1; 15 | "node1":f2 -> "node3":f1; 16 | "node2":f2 -> "node8":f1; 17 | "node2":f0 -> "node7":f1; 18 | "node4":f2 -> "node6":f1; 19 | "node4":f0 -> "node5":f1; 20 | } 21 | -------------------------------------------------------------------------------- /testdata/directed/triedds.gv: -------------------------------------------------------------------------------- 1 | digraph g { 2 | graph [ 3 | rankdir = "LR" 4 | ]; 5 | node [ 6 | fontsize = "16" 7 | shape = "ellipse" 8 | ]; 9 | edge [ 10 | ]; 11 | "node0" [ 12 | label = " 0x10ba8| " 13 | shape = "record" 14 | ]; 15 | "node1" [ 16 | label = " 0xf7fc4380| | |-1" 17 | shape = "record" 18 | ]; 19 | "node2" [ 20 | label = " 0xf7fc44b8| | |2" 21 | shape = "record" 22 | ]; 23 | "node3" [ 24 | label = " 3.43322790286038071e-06|44.79998779296875|0" 25 | shape = "record" 26 | ]; 27 | "node4" [ 28 | label = " 0xf7fc4380| | |2" 29 | shape = "record" 30 | ]; 31 | "node5" [ 32 | label = " (nil)| | |-1" 33 | shape = "record" 34 | ]; 35 | "node6" [ 36 | label = " 0xf7fc4380| | |1" 37 | shape = "record" 38 | ]; 39 | "node7" [ 40 | label = " 0xf7fc4380| | |2" 41 | shape = "record" 42 | ]; 43 | "node8" [ 44 | label = " (nil)| | |-1" 45 | shape = "record" 46 | ]; 47 | "node9" [ 48 | label = " (nil)| | |-1" 49 | shape = "record" 50 | ]; 51 | "node10" [ 52 | label = " (nil)| | |-1" 53 | shape = "record" 54 | ]; 55 | "node11" [ 56 | label = " (nil)| | |-1" 57 | shape = "record" 58 | ]; 59 | "node12" [ 60 | label = " 0xf7fc43e0| | |1" 61 | shape = "record" 62 | ]; 63 | "node0":f0 -> "node1":f0 [ 64 | id = 0 65 | ]; 66 | "node0":f1 -> "node2":f0 [ 67 | id = 1 68 | ]; 69 | "node1":f0 -> "node3":f0 [ 70 | id = 2 71 | ]; 72 | "node1":f1 -> "node4":f0 [ 73 | id = 3 74 | ]; 75 | "node1":f2 -> "node5":f0 [ 76 | id = 4 77 | ]; 78 | "node4":f0 -> "node3":f0 [ 79 | id = 5 80 | ]; 81 | "node4":f1 -> "node6":f0 [ 82 | id = 6 83 | ]; 84 | "node4":f2 -> "node10":f0 [ 85 | id = 7 86 | ]; 87 | "node6":f0 -> "node3":f0 [ 88 | id = 8 89 | ]; 90 | "node6":f1 -> "node7":f0 [ 91 | id = 9 92 | ]; 93 | "node6":f2 -> "node9":f0 [ 94 | id = 10 95 | ]; 96 | "node7":f0 -> "node3":f0 [ 97 | id = 11 98 | ]; 99 | "node7":f1 -> "node1":f0 [ 100 | id = 12 101 | ]; 102 | "node7":f2 -> "node8":f0 [ 103 | id = 13 104 | ]; 105 | "node10":f1 -> "node11":f0 [ 106 | id = 14 107 | ]; 108 | "node10":f2 -> "node12":f0 [ 109 | id = 15 110 | ]; 111 | "node11":f2 -> "node1":f0 [ 112 | id = 16 113 | ]; 114 | } 115 | -------------------------------------------------------------------------------- /testdata/directed/try.gv: -------------------------------------------------------------------------------- 1 | digraph G { 2 | subgraph cluster_small { 3 | a -> b; 4 | label=small; 5 | } 6 | 7 | subgraph cluster_big { 8 | p -> q -> r -> s -> t; 9 | label=big; 10 | t -> p; 11 | } 12 | 13 | t -> a; 14 | b -> q; 15 | } 16 | -------------------------------------------------------------------------------- /testdata/directed/unix.gv: -------------------------------------------------------------------------------- 1 | /* courtesy Ian Darwin and Geoff Collyer, Softquad Inc. */ 2 | digraph unix { 3 | size="6,6"; 4 | "5th Edition" -> "6th Edition"; 5 | "5th Edition" -> "PWB 1.0"; 6 | "6th Edition" -> "LSX"; 7 | "6th Edition" -> "1 BSD"; 8 | "6th Edition" -> "Mini Unix"; 9 | "6th Edition" -> "Wollongong"; 10 | "6th Edition" -> "Interdata"; 11 | "Interdata" -> "Unix/TS 3.0"; 12 | "Interdata" -> "PWB 2.0"; 13 | "Interdata" -> "7th Edition"; 14 | "7th Edition" -> "8th Edition"; 15 | "7th Edition" -> "32V"; 16 | "7th Edition" -> "V7M"; 17 | "7th Edition" -> "Ultrix-11"; 18 | "7th Edition" -> "Xenix"; 19 | "7th Edition" -> "UniPlus+"; 20 | "V7M" -> "Ultrix-11"; 21 | "8th Edition" -> "9th Edition"; 22 | "1 BSD" -> "2 BSD"; 23 | "2 BSD" -> "2.8 BSD"; 24 | "2.8 BSD" -> "Ultrix-11"; 25 | "2.8 BSD" -> "2.9 BSD"; 26 | "32V" -> "3 BSD"; 27 | "3 BSD" -> "4 BSD"; 28 | "4 BSD" -> "4.1 BSD"; 29 | "4.1 BSD" -> "4.2 BSD"; 30 | "4.1 BSD" -> "2.8 BSD"; 31 | "4.1 BSD" -> "8th Edition"; 32 | "4.2 BSD" -> "4.3 BSD"; 33 | "4.2 BSD" -> "Ultrix-32"; 34 | "PWB 1.0" -> "PWB 1.2"; 35 | "PWB 1.0" -> "USG 1.0"; 36 | "PWB 1.2" -> "PWB 2.0"; 37 | "USG 1.0" -> "CB Unix 1"; 38 | "USG 1.0" -> "USG 2.0"; 39 | "CB Unix 1" -> "CB Unix 2"; 40 | "CB Unix 2" -> "CB Unix 3"; 41 | "CB Unix 3" -> "Unix/TS++"; 42 | "CB Unix 3" -> "PDP-11 Sys V"; 43 | "USG 2.0" -> "USG 3.0"; 44 | "USG 3.0" -> "Unix/TS 3.0"; 45 | "PWB 2.0" -> "Unix/TS 3.0"; 46 | "Unix/TS 1.0" -> "Unix/TS 3.0"; 47 | "Unix/TS 3.0" -> "TS 4.0"; 48 | "Unix/TS++" -> "TS 4.0"; 49 | "CB Unix 3" -> "TS 4.0"; 50 | "TS 4.0" -> "System V.0"; 51 | "System V.0" -> "System V.2"; 52 | "System V.2" -> "System V.3"; 53 | } 54 | -------------------------------------------------------------------------------- /testdata/directed/unix2.gv: -------------------------------------------------------------------------------- 1 | /* Courtesy of Ian Darwin 2 | * and Geoff Collyer 3 | * Mildly updated by Ian Darwin in 2000. 4 | */ 5 | digraph unix { 6 | size="6,6"; 7 | node [color=lightblue2, style=filled]; 8 | "5th Edition" -> "6th Edition"; 9 | "5th Edition" -> "PWB 1.0"; 10 | "6th Edition" -> "LSX"; 11 | "6th Edition" -> "1 BSD"; 12 | "6th Edition" -> "Mini Unix"; 13 | "6th Edition" -> "Wollongong"; 14 | "6th Edition" -> "Interdata"; 15 | "Interdata" -> "Unix/TS 3.0"; 16 | "Interdata" -> "PWB 2.0"; 17 | "Interdata" -> "7th Edition"; 18 | "7th Edition" -> "8th Edition"; 19 | "7th Edition" -> "32V"; 20 | "7th Edition" -> "V7M"; 21 | "7th Edition" -> "Ultrix-11"; 22 | "7th Edition" -> "Xenix"; 23 | "7th Edition" -> "UniPlus+"; 24 | "V7M" -> "Ultrix-11"; 25 | "8th Edition" -> "9th Edition"; 26 | "9th Edition" -> "10th Edition"; 27 | "1 BSD" -> "2 BSD"; 28 | "2 BSD" -> "2.8 BSD"; 29 | "2.8 BSD" -> "Ultrix-11"; 30 | "2.8 BSD" -> "2.9 BSD"; 31 | "32V" -> "3 BSD"; 32 | "3 BSD" -> "4 BSD"; 33 | "4 BSD" -> "4.1 BSD"; 34 | "4.1 BSD" -> "4.2 BSD"; 35 | "4.1 BSD" -> "2.8 BSD"; 36 | "4.1 BSD" -> "8th Edition"; 37 | "4.2 BSD" -> "4.3 BSD"; 38 | "4.2 BSD" -> "Ultrix-32"; 39 | "4.3 BSD" -> "4.4 BSD"; 40 | "4.4 BSD" -> "FreeBSD"; 41 | "4.4 BSD" -> "NetBSD"; 42 | "4.4 BSD" -> "OpenBSD"; 43 | "PWB 1.0" -> "PWB 1.2"; 44 | "PWB 1.0" -> "USG 1.0"; 45 | "PWB 1.2" -> "PWB 2.0"; 46 | "USG 1.0" -> "CB Unix 1"; 47 | "USG 1.0" -> "USG 2.0"; 48 | "CB Unix 1" -> "CB Unix 2"; 49 | "CB Unix 2" -> "CB Unix 3"; 50 | "CB Unix 3" -> "Unix/TS++"; 51 | "CB Unix 3" -> "PDP-11 Sys V"; 52 | "USG 2.0" -> "USG 3.0"; 53 | "USG 3.0" -> "Unix/TS 3.0"; 54 | "PWB 2.0" -> "Unix/TS 3.0"; 55 | "Unix/TS 1.0" -> "Unix/TS 3.0"; 56 | "Unix/TS 3.0" -> "TS 4.0"; 57 | "Unix/TS++" -> "TS 4.0"; 58 | "CB Unix 3" -> "TS 4.0"; 59 | "TS 4.0" -> "System V.0"; 60 | "System V.0" -> "System V.2"; 61 | "System V.2" -> "System V.3"; 62 | "System V.3" -> "System V.4"; 63 | } 64 | -------------------------------------------------------------------------------- /testdata/directed/viewfile.gv: -------------------------------------------------------------------------------- 1 | digraph Viewfile { 2 | node [ style = filled ]; 3 | atoi [color=green]; 4 | chkmalloc [color=green]; 5 | close [color=green]; 6 | error [color=blue]; 7 | exit [color=blue]; 8 | fclose [color=green]; 9 | fgets [color=red]; 10 | fopen [color=green]; 11 | fprintf [color=blue]; 12 | free [color=blue]; 13 | free_list [color=blue]; 14 | fstat [color=green]; 15 | getopt [color=green]; 16 | init_list [color=green]; 17 | insert_list [color=green]; 18 | main [color=green]; 19 | makeargs [color=blue]; 20 | makepairs [color=green]; 21 | malloc [color=green]; 22 | open [color=green]; 23 | printf [color=red]; 24 | read [color=green]; 25 | rewind [color=green]; 26 | viewline [color=green]; 27 | viewlines [color=green]; 28 | walk_list [color=green]; 29 | write [color=green]; 30 | fclose -> close [color=green]; 31 | fgets -> fstat [color=green]; 32 | fgets -> read [color=green]; 33 | fopen -> open [color=green]; 34 | printf -> write [color=green]; 35 | main -> fgets [color=blue]; 36 | main -> getopt [color=green]; 37 | main -> makeargs [color=blue]; 38 | main -> makepairs [color=green]; 39 | main -> chkmalloc [color=green]; 40 | main -> error [color=blue]; 41 | main -> viewlines [color=green]; 42 | makeargs -> chkmalloc [color=blue]; 43 | makepairs -> atoi [color=green]; 44 | makepairs -> init_list [color=green]; 45 | makepairs -> insert_list [color=green]; 46 | makepairs -> chkmalloc [color=green]; 47 | free_list -> free [color=blue]; 48 | init_list -> chkmalloc [color=green]; 49 | insert_list -> chkmalloc [color=green]; 50 | walk_list -> error [color=blue]; 51 | walk_list -> viewline [color=green]; 52 | chkmalloc -> malloc [color=green]; 53 | chkmalloc -> error [color=blue]; 54 | error -> exit [color=blue]; 55 | error -> fprintf [color=blue]; 56 | error -> error [color=blue]; 57 | viewline -> fgets [color=red]; 58 | viewline -> printf [color=red]; 59 | viewline -> rewind [color=green]; 60 | viewlines -> fclose [color=green]; 61 | viewlines -> fopen [color=green]; 62 | viewlines -> walk_list [color=green]; 63 | viewlines -> viewline [color=blue]; 64 | } 65 | -------------------------------------------------------------------------------- /testdata/directed/world.gv: -------------------------------------------------------------------------------- 1 | digraph world { 2 | size="7,7"; 3 | {rank=same; S8 S24 S1 S35 S30;} 4 | {rank=same; T8 T24 T1 T35 T30;} 5 | {rank=same; 43 37 36 10 2;} 6 | {rank=same; 25 9 38 40 13 17 12 18;} 7 | {rank=same; 26 42 11 3 33 19 39 14 16;} 8 | {rank=same; 4 31 34 21 41 28 20;} 9 | {rank=same; 27 5 22 32 29 15;} 10 | {rank=same; 6 23;} 11 | {rank=same; 7;} 12 | 13 | S8 -> 9; 14 | S24 -> 25; 15 | S24 -> 27; 16 | S1 -> 2; 17 | S1 -> 10; 18 | S35 -> 43; 19 | S35 -> 36; 20 | S30 -> 31; 21 | S30 -> 33; 22 | 9 -> 42; 23 | 9 -> T1; 24 | 25 -> T1; 25 | 25 -> 26; 26 | 27 -> T24; 27 | 2 -> {3 ; 16 ; 17 ; T1 ; 18} 28 | 10 -> { 11 ; 14 ; T1 ; 13; 12;} 29 | 31 -> T1; 30 | 31 -> 32; 31 | 33 -> T30; 32 | 33 -> 34; 33 | 42 -> 4; 34 | 26 -> 4; 35 | 3 -> 4; 36 | 16 -> 15; 37 | 17 -> 19; 38 | 18 -> 29; 39 | 11 -> 4; 40 | 14 -> 15; 41 | 37 -> {39 ; 41 ; 38 ; 40;} 42 | 13 -> 19; 43 | 12 -> 29; 44 | 43 -> 38; 45 | 43 -> 40; 46 | 36 -> 19; 47 | 32 -> 23; 48 | 34 -> 29; 49 | 39 -> 15; 50 | 41 -> 29; 51 | 38 -> 4; 52 | 40 -> 19; 53 | 4 -> 5; 54 | 19 -> {21 ; 20 ; 28;} 55 | 5 -> {6 ; T35 ; 23;} 56 | 21 -> 22; 57 | 20 -> 15; 58 | 28 -> 29; 59 | 6 -> 7; 60 | 15 -> T1; 61 | 22 -> T35; 62 | 22 -> 23; 63 | 29 -> T30; 64 | 7 -> T8; 65 | 23 -> T24; 66 | 23 -> T1; 67 | } 68 | -------------------------------------------------------------------------------- /testdata/imagehash.json: -------------------------------------------------------------------------------- 1 | {"testdata/directed/KW91.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgHJiooLCYmBwEGAA==","testdata/directed/Latin1.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgOccAPK9BxDgEGAA==","testdata/directed/NaN.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgBARFlIZiYGQEGAA==","testdata/directed/abstract.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgSFksZSUlNDAEGAA==","testdata/directed/alf.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfg4GBY2GwsHBgEGAA==","testdata/directed/arrows.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfhSUlJSUnFSUgEGAA==","testdata/directed/awilliams.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgCAgIMCBhcXAEGAA==","testdata/directed/biological.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfjY2dkxKSkSEgEGAA==","testdata/directed/clust.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfg6JicXFldVVQEGAA==","testdata/directed/clust1.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgGipaUpDSWlAEGAA==","testdata/directed/clust2.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgeHqOqqqoqAwEGAA==","testdata/directed/clust3.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgOMnBwMmAyMgEGAA==","testdata/directed/clust4.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgOU3NRcXNTDgEGAA==","testdata/directed/clust5.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgGBycnU1ELAwEGAA==","testdata/directed/crazy.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgPITHRGxtDDgEGAA==","testdata/directed/ctext.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfh8bGx2FhZVFQEGAA==","testdata/directed/dfa.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgPDw8zMw4ODgEGAA==","testdata/directed/fig6.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfhKGxcdG5m5bgEGAA==","testdata/directed/fsm.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgYGBoeBMNbGQEGAA==","testdata/directed/grammar.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgaGiQmJpQAAgEGAA==","testdata/directed/hashtable.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgcERmcmVEdnAEGAA==","testdata/directed/honda-tokoro.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgnM9RCSVt5QAEGAA==","testdata/directed/japanese.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgcDkhMBiYmDgEGAA==","testdata/directed/jcctree.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgYLCZmZmxkZAEGAA==","testdata/directed/jsort.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgDCw1RMzclUQEGAA==","testdata/directed/ldbxtried.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgeFhsvDycfjgEGAA==","testdata/directed/longflat.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgDBAEBYTHEMQEGAA==","testdata/directed/mike.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgBITVGZ2YuPAEGAA==","testdata/directed/nhg.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgTEzhuLngfBwEGAA==","testdata/directed/oldarrows.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfhSHg4ODg4GUAEGAA==","testdata/directed/pgram.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfjMbCkai+jg4AEGAA==","testdata/directed/pm2way.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgYGB4mDg0GBgEGAA==","testdata/directed/pmpipe.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgGBgIaDgRSRgEGAA==","testdata/directed/polypoly.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfguLCwubkwQCwEGAA==","testdata/directed/proc3d.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgICRkZCRkZCQEGAA==","testdata/directed/psfonttest.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfiWlJSUlJSUhAEGAA==","testdata/directed/record2.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgqCB4mmiq6HgEGAA==","testdata/directed/records.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAADv+AAfkJW2l8Hg4eAQYA","testdata/directed/rowe.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgGkzRnxaa0MQEGAA==","testdata/directed/russian.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfhTU1NS0lISEgEGAA==","testdata/directed/sdh.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfiLm5qYtKTESgEGAA==","testdata/directed/shells.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfjPjZPnpK2PzQEGAA==","testdata/directed/states.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgDBwUZESne4AEGAA==","testdata/directed/structs.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgcLCxMxkZKAAEGAA==","testdata/directed/switch.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfg5JRtRa2dLdQEGAA==","testdata/directed/table.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgMDAcn5+fHxgEGAA==","testdata/directed/train11.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAADv+AAfkBAwcIHmSHAQYA","testdata/directed/trapeziumlr.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfjgcTMPDzNxwAEGAA==","testdata/directed/tree.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgGBhISMHI4uAEGAA==","testdata/directed/triedds.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfg4JGQuBhYWFgEGAA==","testdata/directed/try.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfiNqUtNjA8tKwEGAA==","testdata/directed/unix.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgPGzEV0dtbAwEGAA==","testdata/directed/unix2.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgPCzHR0xtLCwEGAA==","testdata/directed/viewfile.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgc9vZzx8nJGAEGAA==","testdata/directed/world.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgyNRUdhZU1JwEGAA==","testdata/undirected/ER.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgCAwIGFAYUFgEGAA==","testdata/undirected/Heawood.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfgIiJRSVlYWFgEGAA==","testdata/undirected/Petersen.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfhObSsqKs7GQQEGAA==","testdata/undirected/ngk10_4.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfiBKi0qIzlYAQEGAA==","testdata/undirected/process.gv":"IH8DAQEBRAH/gAABAgEESGFzaAEGAAEES2luZAEEAAAAD/+AAfg9Z0tCAwMDAwEGAA=="} -------------------------------------------------------------------------------- /testdata/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goccy/go-graphviz/4ceff9e58e1a67056b302f85d0b793404e7280ee/testdata/logo.png -------------------------------------------------------------------------------- /testdata/undirected/ER.gv: -------------------------------------------------------------------------------- 1 | graph ER { 2 | node [shape=box]; course; institute; student; 3 | node [shape=ellipse]; {node [label="name"] name0; name1; name2;} 4 | code; grade; number; 5 | node [shape=diamond,style=filled,color=lightgrey]; "C-I"; "S-C"; "S-I"; 6 | 7 | name0 -- course; 8 | code -- course; 9 | course -- "C-I" [label="n",len=1.00]; 10 | "C-I" -- institute [label="1",len=1.00]; 11 | institute -- name1; 12 | institute -- "S-I" [label="1",len=1.00]; 13 | "S-I" -- student [label="n",len=1.00]; 14 | student -- grade; 15 | student -- name2; 16 | student -- number; 17 | student -- "S-C" [label="m",len=1.00]; 18 | "S-C" -- course [label="n",len=1.00]; 19 | 20 | label = "\n\nEntity Relation Diagram\ndrawn by NEATO"; 21 | fontsize=20; 22 | } 23 | -------------------------------------------------------------------------------- /testdata/undirected/Heawood.gv: -------------------------------------------------------------------------------- 1 | /* 2 | * The transitive 6-net, also known as Heawood's graph, 3 | * can be used to test the "stability points" of the layout 4 | * algorithm. 5 | 6 | * The "ideal" layout occurs when len="2.5". The layout 7 | * loses the regularity when smaller values are used. 8 | */ 9 | graph "Heawood" { 10 | node [ 11 | fontname = "Arial" 12 | label = "\N" 13 | shape = "circle" 14 | width = "0.50000" 15 | height = "0.500000" 16 | color = "black" 17 | ] 18 | edge [ 19 | color = "black" 20 | ] 21 | /* The outer wheel */ 22 | "0" -- "1" -- "2" -- "3" -- "4" -- "5" -- "6" -- "7" -- "8" -- "9" -- "10" -- "11" -- "12" -- "13" -- "0"; 23 | /* The internal edges. The len = makes them internal */ 24 | "0" -- "5" [len = 2.5]; 25 | "2" -- "7" [len = 2.5]; 26 | "4" -- "9" [len = 2.5]; 27 | "6" -- "11" [len = 2.5]; 28 | "8" -- "13" [len = 2.5]; 29 | "10" -- "1" [len = 2.5]; 30 | "12" -- "3" [len = 2.5]; 31 | } 32 | -------------------------------------------------------------------------------- /testdata/undirected/Petersen.gv: -------------------------------------------------------------------------------- 1 | /* 2 | * The transitive 5-net, also known as Petersen's graph, 3 | * can be used to test the "stability points" of the layout 4 | * algorithm. 5 | * 6 | * The "ideal" layout is achieved for certain random seed 7 | * values when len=1.5. For len=2.5 or above, the layout 8 | * is stable. Sometimes, the graph is rendered "inside-out". 9 | */ 10 | graph "Petersen" { 11 | node [ 12 | fontname = "Arial" 13 | label = "\N" 14 | shape = "circle" 15 | width = "0.400000" 16 | height = "0.400000" 17 | color = "black" 18 | ] 19 | edge [ 20 | color = "black" 21 | ] 22 | /* Outer wheel. The len= is what makes it outer */ 23 | "0" -- "1" -- "2" -- "3" -- "4" -- "0" [ 24 | color = "blue" 25 | len = 2.6 26 | ] 27 | "0" -- "5" [ 28 | color = "red" 29 | weight = "5" 30 | ] 31 | "1" -- "6" [ 32 | color = "red" 33 | weight = "5" 34 | ] 35 | "2" -- "7" [ 36 | color = "red" 37 | weight = "5" 38 | ] 39 | "3" -- "8" [ 40 | color = "red" 41 | weight = "5" 42 | ] 43 | "4" -- "9" [ 44 | color = "red" 45 | weight = "5" 46 | ] 47 | "5" -- "7" -- "9" -- "6" -- "8" -- "5"; 48 | } 49 | -------------------------------------------------------------------------------- /testdata/undirected/ngk10_4.gv: -------------------------------------------------------------------------------- 1 | graph G { 2 | graph [splines=true overlap=false] 3 | 1 -- 30 [f=1]; 4 | 1 -- 40 [f=14]; 5 | 8 -- 46 [f=1]; 6 | 8 -- 16 [f=18]; 7 | 10 -- 25 [f=1]; 8 | 10 -- 19 [f=5]; 9 | 10 -- 33 [f=1]; 10 | 12 -- 8 [f=1]; 11 | 12 -- 36 [f=5]; 12 | 12 -- 17 [f=16]; 13 | 13 -- 38 [f=1]; 14 | 13 -- 24 [f=19]; 15 | 24 -- 49 [f=1]; 16 | 24 -- 13 [f=1]; 17 | 24 -- 47 [f=12]; 18 | 24 -- 12 [f=19]; 19 | 25 -- 27 [f=1]; 20 | 25 -- 12 [f=1]; 21 | 27 -- 12 [f=1]; 22 | 27 -- 14 [f=8]; 23 | 29 -- 10 [f=1]; 24 | 29 -- 8 [f=17]; 25 | 30 -- 24 [f=1]; 26 | 30 -- 44 [f=15]; 27 | 38 -- 29 [f=1]; 28 | 38 -- 35 [f=15]; 29 | 2 -- 42 [f=2]; 30 | 2 -- 35 [f=3]; 31 | 2 -- 11 [f=19]; 32 | 14 -- 18 [f=2]; 33 | 14 -- 24 [f=15]; 34 | 14 -- 38 [f=18]; 35 | 18 -- 49 [f=2]; 36 | 18 -- 47 [f=20]; 37 | 26 -- 41 [f=2]; 38 | 26 -- 42 [f=15]; 39 | 31 -- 39 [f=2]; 40 | 31 -- 47 [f=17]; 41 | 31 -- 25 [f=14]; 42 | 37 -- 26 [f=2]; 43 | 37 -- 16 [f=14]; 44 | 39 -- 50 [f=2]; 45 | 39 -- 14 [f=2]; 46 | 39 -- 18 [f=17]; 47 | 39 -- 47 [f=10]; 48 | 41 -- 31 [f=2]; 49 | 41 -- 8 [f=16]; 50 | 42 -- 44 [f=2]; 51 | 42 -- 29 [f=12]; 52 | 44 -- 37 [f=2]; 53 | 44 -- 32 [f=15]; 54 | 3 -- 20 [f=2]; 55 | 3 -- 28 [f=19]; 56 | 6 -- 45 [f=2]; 57 | 6 -- 28 [f=10]; 58 | 9 -- 6 [f=2]; 59 | 9 -- 16 [f=1]; 60 | 15 -- 16 [f=2]; 61 | 15 -- 48 [f=2]; 62 | 16 -- 50 [f=2]; 63 | 16 -- 32 [f=14]; 64 | 16 -- 39 [f=8]; 65 | 20 -- 33 [f=2]; 66 | 33 -- 9 [f=2]; 67 | 33 -- 46 [f=3]; 68 | 33 -- 48 [f=17]; 69 | 45 -- 15 [f=2]; 70 | 4 -- 17 [f=4]; 71 | 4 -- 15 [f=6]; 72 | 4 -- 12 [f=16]; 73 | 17 -- 21 [f=4]; 74 | 19 -- 35 [f=4]; 75 | 19 -- 15 [f=9]; 76 | 19 -- 43 [f=4]; 77 | 21 -- 19 [f=4]; 78 | 21 -- 50 [f=4]; 79 | 23 -- 36 [f=4]; 80 | 34 -- 23 [f=4]; 81 | 34 -- 24 [f=11]; 82 | 35 -- 34 [f=4]; 83 | 35 -- 16 [f=6]; 84 | 35 -- 18 [f=16]; 85 | 36 -- 46 [f=4]; 86 | 5 -- 7 [f=1]; 87 | 5 -- 36 [f=6]; 88 | 7 -- 32 [f=1]; 89 | 7 -- 11 [f=2]; 90 | 7 -- 14 [f=17]; 91 | 11 -- 40 [f=1]; 92 | 11 -- 50 [f=1]; 93 | 22 -- 46 [f=1]; 94 | 28 -- 43 [f=1]; 95 | 28 -- 8 [f=18]; 96 | 32 -- 28 [f=1]; 97 | 32 -- 39 [f=13]; 98 | 32 -- 42 [f=15]; 99 | 40 -- 22 [f=1]; 100 | 40 -- 47 [f=1]; 101 | 43 -- 11 [f=1]; 102 | 43 -- 17 [f=19]; 103 | } 104 | -------------------------------------------------------------------------------- /testdata/undirected/process.gv: -------------------------------------------------------------------------------- 1 | graph G { 2 | run -- intr; 3 | intr -- runbl; 4 | runbl -- run; 5 | run -- kernel; 6 | kernel -- zombie; 7 | kernel -- sleep; 8 | kernel -- runmem; 9 | sleep -- swap; 10 | swap -- runswap; 11 | runswap -- new; 12 | runswap -- runmem; 13 | new -- runmem; 14 | sleep -- runmem; 15 | } 16 | --------------------------------------------------------------------------------