Tk Library Source Code

Artifact [3cf54a433c]
Login

Artifact 3cf54a433c5784c77291bdec1e7834fb5c6c8a9d:

Attachment "483125.diff" to ticket [483125ffff] added by andreas_kupries 2001-11-20 06:29:54.
? modules/fileinput
? modules/ftp/LOG
? modules/ftp/bar
? modules/ftp/foo
? modules/ftp/test_ftpchan.tcl
? modules/ftp/example
? modules/ftpd/examples
Index: ChangeLog
===================================================================
RCS file: /cvsroot/tcllib/tcllib/ChangeLog,v
retrieving revision 1.86
diff -u -r1.86 ChangeLog
--- ChangeLog	2001/11/19 21:02:19	1.86
+++ ChangeLog	2001/11/19 23:26:48
@@ -1,7 +1,9 @@
 2001-11-19  Andreas Kupries  <[email protected]>
 
+	* struct/graph: Applied patch #483125
+	
 	* smtpd: Example consolidation: Moved the smtpd example to
-	'examples' directory.
+	  'examples' directory.
 
 	* ftp: Implemented FR #481161.
 
Index: modules/struct/ChangeLog
===================================================================
RCS file: /cvsroot/tcllib/tcllib/modules/struct/ChangeLog,v
retrieving revision 1.16
diff -u -r1.16 ChangeLog
--- modules/struct/ChangeLog	2001/10/17 17:27:26	1.16
+++ modules/struct/ChangeLog	2001/11/19 23:26:49
@@ -1,3 +1,12 @@
+2001-11-19  Andreas Kupries  <[email protected]>
+
+	* graph.test:
+	* graph.n:
+	* graph.tcl: Applied patch #483125 provided by Frank Pilhofer
+	  <[email protected]>. The patch adds key/value information for the whole
+	  graph and extends the selection methods 'arcs' and 'nodes' to
+	  allow selection based on keys and their values.
+
 2001-10-16  Andreas Kupries  <[email protected]>
 
 	* pkgIndex.tcl:
Index: modules/struct/graph.n
===================================================================
RCS file: /cvsroot/tcllib/tcllib/modules/struct/graph.n,v
retrieving revision 1.5
diff -u -r1.5 graph.n
--- modules/struct/graph.n	2001/10/17 17:27:26	1.5
+++ modules/struct/graph.n	2001/11/19 23:26:49
@@ -94,37 +94,48 @@
 Remove a keyed value from the arc \fIarc\fR.  If no key is
 specified, the key \fBdata\fR is assumed.
 .TP
-\fIgraphName\fR \fBarcs\fR ?-in|-out|-adj|-inner|-embedding \fInodelist\fR?
-
+\fIgraphName\fR \fBarcs\fR ?-key \fIkey\fR? ?-value \fIvalue\fR? ?-in|-out|-adj|-inner|-embedding \fInodelist\fR?
 Return a list of arcs in the graph. If no restriction is specified a
-list containing all arcs is returned. If one of the five possible
-restrictions is specified only arcs satisfying that restriction are
-returned. All restrictions involve a list of nodes, specified after
-the key for the restriction itself.
-.IP
+list containing all arcs is returned. Restrictions can limit the list
+of returned arcs based on the nodes that are connected by the arc, on
+the keyed values associated with the arc, or both. The restrictions
+that involve connected nodes have a list of nodes as argument,
+specified after the name of the restriction itself.
+.RS
+.TP
 \fB-in\fR
 Return a list of all arcs whose target is one of the nodes in the
 \fInodelist\fR.
-.IP
+.TP
 \fB-out\fR
 Return a list of all arcs whose source is one of the nodes in the
 \fInodelist\fR.
-.IP
+.TP
 \fB-adj\fR
 Return a list of all arcs adjacent to at least one of the nodes in
 the \fInodelist\fR. This is the union of the nodes returned by
 \fB-in\fR and \fB-out\fR.
-.IP
+.TP
 \fB-inner\fR
 Return a list of all arcs adjacent to two of the nodes in the
 \fInodelist\fR. This is the set of arcs in the subgraph spawned by
 the specified nodes.
-.IP
+.TP
 \fB-embedding\fR
 Return a list of all arcs adjacent to exactly one of the nodes in the
 \fInodelist\fR. This is the set of arcs connecting the subgraph
 spawned by the specified nodes to the rest of the graph.
 .TP
+\fB-key\fR \fIkey\fR
+Limit the list of arcs that are returned to those arcs that have an
+associated key \fIkey\fR.
+.TP
+\fB-value\fR \fIvalue\fR
+This restriction can only be used in combination with \fB-key\fR. It
+limits the list of arcs that are returned to those arcs whose
+associated key \fIkey\fR has the value \fIvalue\fR.
+.RE
+.TP
 \fIgraphName\fR \fBnode degree\fR ?-in|-out? \fInode\fR
 Return the number of arcs adjacent to the specified \fInode\fR. If
 one of the restrictions \fB-in\fR or \fB-out\fR is given only the
@@ -163,20 +174,37 @@
 Remove a keyed value from the node \fInode\fR.  If no key is
 specified, the key \fBdata\fR is assumed.
 .TP
-\fIgraphName\fR \fBnodes\fR ?-in|-out|-adj|-inner|-embedding \fInodelist\fR?
-Return a list of nodes in the graph. If no restriction is specified a
-list containing all nodes is returned. If one of the five possible
-restrictions is specified only nodes satisfying that restriction are
-returned. All restrictions involve a list of nodes, specified after
-the key for the restriction itself.
-
+\fIgraphName\fR \fBnodes\fR ?-key \fIkey\fR? ?-value \fIvalue\fR? ?-in|-out|-adj|-inner|-embedding \fInodelist\fR?
+Return a list of nodes in the graph. Restrictions can limit the list
+of returned nodes based on neighboring nodes, or based on the keyed
+values associated with the node. The restrictions that involve
+neighboring nodes have a list of nodes as argument, specified after
+the name of the restriction itself.
+.sp
 The possible restrictions are the same as for method \fBarcs\fR. The
 set of nodes to return is computed as the union of all source and
 target nodes for all the arcs satisfying the restriction as defined
 for \fBarcs\fR.
 .TP
+\fIgraphName\fR \fBget\fR ?\fI-key key\fR?
+Return the value associated with the key \fIkey\fR for the graph. If
+no key is specified, the key \fBdata\fR is assumed.
+.TP
+\fIgraphName\fR \fBset\fR ?\fI-key key\fR? ?\fIvalue\fR?
+Set or get one of the keyed values associated with a graph. If no key
+is specified, the key \fBdata\fR is assumed. Each graph has the value
+"" assigned to the key \fBdata\fR automatically. A graph may have any
+number of keyed values associated with it. If \fIvalue\fR is not
+specified, this command returns the current value assigned to the key;
+if \fIvalue\fR is specified, this command assigns that value to the
+key.
+.TP
 \fIgraphName\fR \fBswap\fR \fInode1\fR \fInode2\fR
 Swap the position of \fInode1\fR and \fInode2\fR in the graph.
+.TP
+\fIgraphName\fR \fBunset\fR ?\fI-key key\fR?
+Remove a keyed value from the graph. If no key is specified, the key
+\fBdata\fR is assumed.
 .TP
 \fIgraphName\fR \fBwalk\fR \fInode\fR ?\fI-order order\fR? ?\fI-type type\fR? ?\fI-dir direction\fR? \fI-command cmd\fR
 
Index: modules/struct/graph.tcl
===================================================================
RCS file: /cvsroot/tcllib/tcllib/modules/struct/graph.tcl,v
retrieving revision 1.3
diff -u -r1.3 graph.tcl
--- modules/struct/graph.tcl	2001/06/22 15:29:18	1.3
+++ modules/struct/graph.tcl	2001/11/19 23:26:49
@@ -38,9 +38,12 @@
 	    "arc"		\
 	    "arcs"		\
 	    "destroy"		\
+	    "get"		\
 	    "node"		\
 	    "nodes"		\
+	    "set"		\
 	    "swap"		\
+	    "unset"             \
 	    "walk"		\
 	    ]
 
@@ -96,6 +99,10 @@
     # Set up the namespace
     namespace eval ::struct::graph::graph$name {
 
+	# Set up the map for values associated with the graph itself
+	variable graphData
+	array set graphData {data ""}
+
 	# Set up the map from nodes to the arcs coming to them
 	variable  inArcs
 	array set inArcs {}
@@ -447,53 +454,59 @@
 #	arcs	list of arcs
 
 proc ::struct::graph::_arcs {name args} {
-
-    if {[llength $args] == 0} {
-	# No restriction, deliver all.
 
-	upvar ::struct::graph::graph${name}::arcNodes arcNodes
-	return [array names arcNodes]
-    }
+    # Discriminate between conditions and nodes
 
-    # Get mode and node list
-
-    set cond [lindex $args 0]
-    set args [lrange $args 1 end]
+    set haveCond 0
+    set haveKey 0
+    set haveValue 0
+    set cond "none"
+    set condNodes [list]
 
-    # Validate that the cond is good.
-    switch -glob -- $cond {
-	"-in" {
-	    set cond "in"
-	}
-	"-out" {
-	    set cond "out"
-	}
-	"-adj" {
-	    set cond "adj"
-	}
-	"-inner" {
-	    set cond "inner"
-	}
-	"-embedding" {
-	    set cond "embedding"
-	}
-	default {
-	    error "invalid restriction \"$cond\": should be -in, -out,\
-		    -adj, -inner or -embedding"
+    for {set i 0} {$i < [llength $args]} {incr i} {
+	set arg [lindex $args $i]
+	switch -glob -- $arg {
+	    -in -
+	    -out -
+	    -adj -
+	    -inner -
+	    -embedding {
+		set haveCond 1
+		set cond [string range $arg 1 end]
+	    }
+	    -key {
+		incr i
+		set key [lindex $args $i]
+		set haveKey 1
+	    }
+	    -value {
+		incr i
+		set value [lindex $args $i]
+		set haveValue 1
+	    }
+	    -* {
+		error "invalid restriction \"$arg\": should be -in, -out,\
+			-adj, -inner, -embedding, -key or -value"
+	    }
+	    default {
+		lappend condNodes $arg
+	    }
 	}
     }
 
     # Validate that there are nodes to use in the restriction.
     # otherwise what's the point?
-    if {[llength $args] == 0} {
-	set usage "$name arcs ?-in|-out|-adj|-inner|-embedding node node...?"
-	error "no nodes specified: should be \"$usage\""
-    }
+    if {$haveCond} {
+	if {[llength $condNodes] == 0} {
+	    set usage "$name arcs ?-key key? ?-value value? ?-in|-out|-adj|-inner|-embedding node node...?"
+	    error "no nodes specified: should be \"$usage\""
+	}
 
-    # Make sure that the specified nodes exist!
-    foreach node $args {
-	if { ![__node_exists $name $node] } {
-	    error "node \"$node\" does not exist in graph \"$name\""
+	# Make sure that the specified nodes exist!
+	foreach node $condNodes {
+	    if { ![__node_exists $name $node] } {
+		error "node \"$node\" does not exist in graph \"$name\""
+	    }
 	}
     }
 
@@ -510,7 +523,7 @@
 	    # Result is all arcs going to at least one node
 	    # in the list of arguments.
 
-	    foreach node $args {
+	    foreach node $condNodes {
 		foreach e $inArcs($node) {
 		    if {[info exists coll($e)]} {continue}
 		    lappend arcs    $e
@@ -522,7 +535,7 @@
 	    # Result is all arcs coming from at least one node
 	    # in the list of arguments.
 
-	    foreach node $args {
+	    foreach node $condNodes {
 		foreach e $outArcs($node) {
 		    if {[info exists coll($e)]} {continue}
 		    lappend arcs    $e
@@ -534,7 +547,7 @@
 	    # Result is all arcs coming from or going to at
 	    # least one node in the list of arguments.
 
-	    foreach node $args {
+	    foreach node $condNodes {
 		foreach e $inArcs($node) {
 		    if {[info exists coll($e)]} {continue}
 		    lappend arcs    $e
@@ -551,11 +564,11 @@
 	    # Result is all arcs running between nodes in the list.
 
 	    array set group {}
-	    foreach node $args {
+	    foreach node $condNodes {
 		set group($node) .
 	    }
 
-	    foreach node $args {
+	    foreach node $condNodes {
 		foreach e $inArcs($node) {
 		    set n [lindex $arcNodes($e) 0]
 		    if {![info exists group($n)]} {continue}
@@ -574,15 +587,15 @@
 	}
 	embedding {
 	    # Result is all arcs from -adj minus the arcs from -inner.
-	    # IOW all arcs goint from a node in the list to a node
+	    # IOW all arcs going from a node in the list to a node
 	    # which is *not* in the list
 
 	    array set group {}
-	    foreach node $args {
+	    foreach node $condNodes {
 		set group($node) .
 	    }
 
-	    foreach node $args {
+	    foreach node $condNodes {
 		foreach e $inArcs($node) {
 		    set n [lindex $arcNodes($e) 0]
 		    if {[info exists group($n)]} {continue}
@@ -599,10 +612,37 @@
 		}
 	    }
 	}
+	none {
+	    set arcs [array names arcNodes]
+	}
 	default {error "Can't happen, panic"}
     }
 
-    return $arcs
+    #
+    # We have a list of arcs that match the relation to the nodes.
+    # Now filter according to -key and -value.
+    #
+
+    set filteredArcs [list]
+
+    if {$haveKey} {
+	foreach arc $arcs {
+	    catch {
+		set aval [__arc_get $name $arc -key $key]
+		if {$haveValue} {
+		    if {$aval == $value} {
+			lappend filteredArcs $arc
+		    }
+		} else {
+		    lappend filteredArcs $arc
+		}
+	    }
+	}
+    } else {
+	set filteredArcs $arcs
+    }
+
+    return $filteredArcs
 }
 
 # ::struct::graph::_destroy --
@@ -656,6 +696,28 @@
     return "node${nextUnusedNode}"
 }
 
+# ::struct::graph::_get --
+#
+#	Get a keyed value from the graph itself
+#
+# Arguments:
+#	name	name of the graph.
+#	flag	-key; anything else is an error
+#	key	key to lookup; defaults to data
+#
+# Results:
+#	value	value associated with the key given.
+
+proc ::struct::graph::_get {name {flag -key} {key data}} {
+    upvar ::struct::graph::graph${name}::graphData data
+
+    if { ![info exists data($key)] } {
+	error "invalid key \"$key\" for graph"
+    }
+
+    return $data($key)
+}
+
 # ::struct::graph::_node --
 #
 #	Dispatches the invocation of node methods to the proper handler
@@ -1021,53 +1083,59 @@
 #	nodes	list of nodes
 
 proc ::struct::graph::_nodes {name args} {
-
-    if {[llength $args] == 0} {
-	# No restriction, deliver all.
-
-	upvar ::struct::graph::graph${name}::inArcs inArcs
-	return [array names inArcs]
-    }
 
-    # Get mode and node list
+    # Discriminate between conditions and nodes
 
-    set cond [lindex $args 0]
-    set args [lrange $args 1 end]
+    set haveCond 0
+    set haveKey 0
+    set haveValue 0
+    set cond "none"
+    set condNodes [list]
 
-    # Validate that the cond is good.
-    switch -glob -- $cond {
-	"-in" {
-	    set cond "in"
-	}
-	"-out" {
-	    set cond "out"
-	}
-	"-adj" {
-	    set cond "adj"
-	}
-	"-inner" {
-	    set cond "inner"
-	}
-	"-embedding" {
-	    set cond "embedding"
-	}
-	default {
-	    error "invalid restriction \"$cond\": should be -in, -out,\
-		    -adj, -inner or -embedding"
+    for {set i 0} {$i < [llength $args]} {incr i} {
+	set arg [lindex $args $i]
+	switch -glob -- $arg {
+	    -in -
+	    -out -
+	    -adj -
+	    -inner -
+	    -embedding {
+		set haveCond 1
+		set cond [string range $arg 1 end]
+	    }
+	    -key {
+		incr i
+		set key [lindex $args $i]
+		set haveKey 1
+	    }
+	    -value {
+		incr i
+		set value [lindex $args $i]
+		set haveValue 1
+	    }
+	    -* {
+		error "invalid restriction \"$arg\": should be -in, -out,\
+			-adj, -inner, -embedding, -key or -value"
+	    }
+	    default {
+		lappend condNodes $arg
+	    }
 	}
     }
 
     # Validate that there are nodes to use in the restriction.
     # otherwise what's the point?
-    if {[llength $args] == 0} {
-	set usage "$name nodes ?-in|-out|-adj|-inner|-embedding node node...?"
-	error "no nodes specified: should be \"$usage\""
-    }
+    if {$haveCond} {
+	if {[llength $condNodes] == 0} {
+	    set usage "$name nodes ?-key key? ?-value value? ?-in|-out|-adj|-inner|-embedding node node...?"
+	    error "no nodes specified: should be \"$usage\""
+	}
 
-    # Make sure that the specified nodes exist!
-    foreach node $args {
-	if { ![__node_exists $name $node] } {
-	    error "node \"$node\" does not exist in graph \"$name\""
+	# Make sure that the specified nodes exist!
+	foreach node $condNodes {
+	    if { ![__node_exists $name $node] } {
+		error "node \"$node\" does not exist in graph \"$name\""
+	    }
 	}
     }
 
@@ -1084,7 +1152,7 @@
 	    # Result is all nodes with at least one arc going to
 	    # at least one node in the list of arguments.
 
-	    foreach node $args {
+	    foreach node $condNodes {
 		foreach e $inArcs($node) {
 		    set n [lindex $arcNodes($e) 0]
 		    if {[info exists coll($n)]} {continue}
@@ -1097,7 +1165,7 @@
 	    # Result is all nodes with at least one arc coming from
 	    # at least one node in the list of arguments.
 
-	    foreach node $args {
+	    foreach node $condNodes {
 		foreach e $outArcs($node) {
 		    set n [lindex $arcNodes($e) 1]
 		    if {[info exists coll($n)]} {continue}
@@ -1110,7 +1178,7 @@
 	    # Result is all nodes with at least one arc coming from
 	    # or going to at least one node in the list of arguments.
 
-	    foreach node $args {
+	    foreach node $condNodes {
 		foreach e $inArcs($node) {
 		    set n [lindex $arcNodes($e) 0]
 		    if {[info exists coll($n)]} {continue}
@@ -1131,11 +1199,11 @@
 	    # arguments.
 
 	    array set group {}
-	    foreach node $args {
+	    foreach node $condNodes {
 		set group($node) .
 	    }
 
-	    foreach node $args {
+	    foreach node $condNodes {
 		foreach e $inArcs($node) {
 		    set n [lindex $arcNodes($e) 0]
 		    if {![info exists group($n)]} {continue}
@@ -1158,11 +1226,11 @@
 	    # but not in the list itself!
 
 	    array set group {}
-	    foreach node $args {
+	    foreach node $condNodes {
 		set group($node) .
 	    }
 
-	    foreach node $args {
+	    foreach node $condNodes {
 		foreach e $inArcs($node) {
 		    set n [lindex $arcNodes($e) 0]
 		    if {[info exists group($n)]} {continue}
@@ -1179,12 +1247,87 @@
 		}
 	    }
 	}
+	none {
+	    set nodes [array names inArcs]
+	}
 	default {error "Can't happen, panic"}
     }
+
+    #
+    # We have a list of nodes that match the relation to the nodes.
+    # Now filter according to -key and -value.
+    #
+
+    set filteredNodes [list]
+
+    if {$haveKey} {
+	foreach node $nodes {
+	    catch {
+		set nval [__node_get $name $node -key $key]
+		if {$haveValue} {
+		    if {$nval == $value} {
+			lappend filteredNodes $node
+		    }
+		} else {
+		    lappend filteredNodes $node
+		}
+	    }
+	}
+    } else {
+	set filteredNodes $nodes
+    }
 
-    return $nodes
+    return $filteredNodes
 }
 
+# ::struct::graph::_set --
+#
+#	Set or get a keyed value from the graph itself
+#
+# Arguments:
+#	name	name of the graph.
+#	flag	-key; anything else is an error
+#	args	?-key key? ?value?
+#
+# Results:
+#	value	value associated with the key given.
+
+proc ::struct::graph::_set {name args} {
+    upvar ::struct::graph::graph${name}::graphData data
+
+    if { [llength $args] > 3 } {
+	error "wrong # args: should be \"$name set ?-key key?\
+		?value?\""
+    }
+
+    set key "data"
+    set haveValue 0
+    if { [llength $args] > 1 } {
+	foreach {flag key} $args break
+	if { ![string match "${flag}*" "-key"] } {
+	    error "invalid option \"$flag\": should be key"
+	}
+	if { [llength $args] == 3 } {
+	    set haveValue 1
+	    set value [lindex $args end]
+	}
+    } elseif { [llength $args] == 1 } {
+	set haveValue 1
+	set value [lindex $args end]
+    }
+
+    if { $haveValue } {
+	# Setting a value
+	return [set data($key) $value]
+    } else {
+	# Getting a value
+	if { ![info exists data($key)] } {
+	    error "invalid key \"$key\" for graph"
+	}
+	return $data($key)
+    }
+}
+
 # ::struct::graph::_swap --
 #
 #	Swap two nodes in a graph.
@@ -1249,6 +1392,33 @@
     array set node1Vals [array get node2Vals]
     unset node2Vals
     array set node2Vals $value1
+
+    return
+}
+
+# ::struct::graph::_unset --
+#
+#	Remove a keyed value from the graph itself
+#
+# Arguments:
+#	name	name of the graph.
+#	flag	-key; anything else is an error
+#	args	additional args: ?-key key?
+#
+# Results:
+#	None.
+
+proc ::struct::graph::_unset {name {flag -key} {key data}} {
+    upvar ::struct::graph::graph${name}::graphData data
+    
+    if { ![string match "${flag}*" "-key"] } {
+	error "invalid option \"$flag\": should be \"$name unset\
+		?-key key?\""
+    }
+
+    if { [info exists data($key)] } {
+	unset data($key)
+    }
 
     return
 }
Index: modules/struct/graph.test
===================================================================
RCS file: /cvsroot/tcllib/tcllib/modules/struct/graph.test,v
retrieving revision 1.3
diff -u -r1.3 graph.test
--- modules/struct/graph.test	2000/06/16 20:15:32	1.3
+++ modules/struct/graph.test	2001/11/19 23:26:49
@@ -39,7 +39,7 @@
     catch {mygraph foo} msg
     mygraph destroy
     set msg
-} "bad option \"foo\": must be arc, arcs, destroy, node, nodes, swap, or walk"
+} "bad option \"foo\": must be arc, arcs, destroy, get, node, nodes, set, swap, unset, or walk"
 
 test graph-0.4 {graph errors} {
     catch {graph set} msg
@@ -380,14 +380,14 @@
     catch {mygraph arcs -foo} msg
     mygraph destroy
     set msg
-} {invalid restriction "-foo": should be -in, -out, -adj, -inner or -embedding}
+} {invalid restriction "-foo": should be -in, -out, -adj, -inner, -embedding, -key or -value}
 
 test graph-10.3 {arcs} {
     graph mygraph
     catch {mygraph arcs -in} msg
     mygraph destroy
     set msg
-} {no nodes specified: should be "mygraph arcs ?-in|-out|-adj|-inner|-embedding node node...?"}
+} {no nodes specified: should be "mygraph arcs ?-key key? ?-value value? ?-in|-out|-adj|-inner|-embedding node node...?"}
 
 test graph-10.4 {arcs} {
     graph mygraph
@@ -445,6 +445,32 @@
 	{arcA arcB arcC}	\
 	]
 
+test graph-10.6 {arcs} {
+    graph mygraph
+    mygraph node insert n0
+    mygraph node insert n1
+    mygraph arc insert n0 n1 a1
+    mygraph arc insert n0 n1 a2
+    mygraph arc set a1 -key foobar 1
+    mygraph arc set a2 -key blubber 2
+    catch {mygraph arcs -key foobar} msg
+    mygraph destroy
+    set msg
+} {a1}
+
+test graph-10.7 {arcs} {
+    graph mygraph
+    mygraph node insert n0
+    mygraph node insert n1
+    mygraph arc insert n0 n1 a1
+    mygraph arc insert n0 n1 a2
+    mygraph arc set a1 -key foobar 1
+    mygraph arc set a2 -key foobar 2
+    catch {mygraph arcs -key foobar -value 1} msg
+    mygraph destroy
+    set msg
+} {a1}
+
 # ---------------------------------------------------
 
 test graph-11.1 {node degree} {
@@ -801,14 +827,14 @@
     catch {mygraph nodes -foo} msg
     mygraph destroy
     set msg
-} {invalid restriction "-foo": should be -in, -out, -adj, -inner or -embedding}
+} {invalid restriction "-foo": should be -in, -out, -adj, -inner, -embedding, -key or -value}
 
 test graph-19.3 {nodes} {
     graph mygraph
     catch {mygraph nodes -in} msg
     mygraph destroy
     set msg
-} {no nodes specified: should be "mygraph nodes ?-in|-out|-adj|-inner|-embedding node node...?"}
+} {no nodes specified: should be "mygraph nodes ?-key key? ?-value value? ?-in|-out|-adj|-inner|-embedding node node...?"}
 
 test graph-19.4 {nodes} {
     graph mygraph
@@ -865,6 +891,28 @@
 	{} \
 	{node1 node2 node3} \
 	]
+
+test graph-19.6 {arcs} {
+    graph mygraph
+    mygraph node insert n0
+    mygraph node insert n1
+    mygraph node set n0 -key foobar 1
+    mygraph node set n1 -key blubber 2
+    catch {mygraph nodes -key foobar} msg
+    mygraph destroy
+    set msg
+} {n0}
+
+test graph-19.7 {arcs} {
+    graph mygraph
+    mygraph node insert n0
+    mygraph node insert n1
+    mygraph node set n0 -key foobar 1
+    mygraph node set n1 -key foobar 2
+    catch {mygraph nodes -key foobar -value 1} msg
+    mygraph destroy
+    set msg
+} {n0}
 
 
 # ---------------------------------------------------