rumai 2.0.2 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CREDITS +2 -0
- data/bin/rumai +20 -8
- data/doc/api/classes/IO.html +72 -0
- data/doc/api/classes/Integer.html +110 -0
- data/doc/api/classes/Object.html +60 -0
- data/doc/api/classes/Rumai.html +867 -0
- data/doc/api/classes/Rumai/Area.html +836 -0
- data/doc/api/classes/Rumai/Chain.html +197 -0
- data/doc/api/classes/Rumai/Client.html +865 -0
- data/doc/api/classes/Rumai/ClientContainer.html +191 -0
- data/doc/api/classes/Rumai/ExportInstanceMethods.html +69 -0
- data/doc/api/classes/Rumai/IXP.html +131 -0
- data/doc/api/classes/Rumai/IXP/Agent.html +836 -0
- data/doc/api/classes/Rumai/IXP/Agent/FidStream.html +456 -0
- data/doc/api/classes/Rumai/IXP/Agent/MODES.html +108 -0
- data/doc/api/classes/Rumai/IXP/Agent/RangedPool.html +241 -0
- data/doc/api/classes/Rumai/IXP/Error.html +67 -0
- data/doc/api/classes/Rumai/IXP/Fcall.html +323 -0
- data/doc/api/classes/Rumai/IXP/Qid.html +153 -0
- data/doc/api/classes/Rumai/IXP/Rattach.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rauth.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rclunk.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rcreate.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rerror.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rflush.html +67 -0
- data/doc/api/classes/Rumai/IXP/Ropen.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rread.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rremove.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rstat.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rversion.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rwalk.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rwrite.html +67 -0
- data/doc/api/classes/Rumai/IXP/Rwstat.html +67 -0
- data/doc/api/classes/Rumai/IXP/Stat.html +252 -0
- data/doc/api/classes/Rumai/IXP/Stream.html +131 -0
- data/doc/api/classes/Rumai/IXP/Struct.html +315 -0
- data/doc/api/classes/Rumai/IXP/Struct/Field.html +415 -0
- data/doc/api/classes/Rumai/IXP/Struct/Field/CounteeField.html +153 -0
- data/doc/api/classes/Rumai/IXP/Struct/Field/CounterField.html +104 -0
- data/doc/api/classes/Rumai/IXP/Tattach.html +68 -0
- data/doc/api/classes/Rumai/IXP/Tauth.html +67 -0
- data/doc/api/classes/Rumai/IXP/Tclunk.html +67 -0
- data/doc/api/classes/Rumai/IXP/Tcreate.html +68 -0
- data/doc/api/classes/Rumai/IXP/Terror.html +110 -0
- data/doc/api/classes/Rumai/IXP/Tflush.html +67 -0
- data/doc/api/classes/Rumai/IXP/Topen.html +165 -0
- data/doc/api/classes/Rumai/IXP/Tread.html +67 -0
- data/doc/api/classes/Rumai/IXP/Tremove.html +67 -0
- data/doc/api/classes/Rumai/IXP/Tstat.html +67 -0
- data/doc/api/classes/Rumai/IXP/Tversion.html +86 -0
- data/doc/api/classes/Rumai/IXP/Twalk.html +68 -0
- data/doc/api/classes/Rumai/IXP/Twrite.html +68 -0
- data/doc/api/classes/Rumai/IXP/Twstat.html +67 -0
- data/doc/api/classes/Rumai/Node.html +817 -0
- data/doc/api/classes/Rumai/View.html +818 -0
- data/doc/api/classes/Rumai/WidgetImpl.html +65 -0
- data/doc/api/classes/Rumai/WidgetNode.html +68 -0
- data/doc/api/classes/String.html +163 -0
- data/doc/api/classes/StringIO.html +72 -0
- data/doc/api/classes/Time.html +156 -0
- data/doc/api/created.rid +1 -0
- data/doc/api/css/main.css +263 -0
- data/doc/api/css/panel.css +383 -0
- data/doc/api/css/reset.css +53 -0
- data/doc/api/files/CREDITS.html +64 -0
- data/doc/api/files/LICENSE.html +76 -0
- data/doc/api/files/lib/rumai/fs_rb.html +75 -0
- data/doc/api/files/lib/rumai/ixp/message_rb.html +91 -0
- data/doc/api/files/lib/rumai/ixp/transport_rb.html +75 -0
- data/doc/api/files/lib/rumai/ixp_rb.html +69 -0
- data/doc/api/files/lib/rumai/wm_rb.html +77 -0
- data/doc/api/files/lib/rumai_rb.html +65 -0
- data/doc/api/i/arrows.png +0 -0
- data/doc/api/i/results_bg.png +0 -0
- data/doc/api/i/tree_bg.png +0 -0
- data/doc/api/index.html +14 -18
- data/doc/api/js/jquery-1.3.2.min.js +19 -0
- data/doc/api/js/jquery-effect.js +593 -0
- data/doc/api/js/main.js +22 -0
- data/doc/api/js/searchdoc.js +605 -0
- data/doc/api/panel/index.html +63 -0
- data/doc/api/panel/search_index.js +1 -0
- data/doc/api/panel/tree.js +1 -0
- data/doc/history.erb +41 -16
- data/doc/index.erb +14 -11
- data/doc/index.xhtml +519 -846
- data/doc/intro.erb +33 -32
- data/doc/setup.erb +14 -13
- data/doc/usage.erb +69 -35
- data/lib/rumai.rb +13 -5
- data/lib/rumai/fs.rb +71 -27
- data/lib/rumai/ixp.rb +4 -0
- data/lib/rumai/ixp/message.rb +178 -81
- data/lib/rumai/ixp/transport.rb +144 -91
- data/lib/rumai/wm.rb +717 -593
- data/rakefile +14 -0
- data/test/rumai/ixp/message.rb +42 -54
- metadata +110 -89
- data/Rakefile +0 -8
- data/doc/api/IO.html +0 -53
- data/doc/api/Integer.html +0 -102
- data/doc/api/Object.html +0 -23
- data/doc/api/Rumai.html +0 -1218
- data/doc/api/Rumai/Area.html +0 -1088
- data/doc/api/Rumai/Chain.html +0 -230
- data/doc/api/Rumai/Client.html +0 -1264
- data/doc/api/Rumai/ClientContainer.html +0 -227
- data/doc/api/Rumai/ExportInstMethods.html +0 -115
- data/doc/api/Rumai/IXP.html +0 -23
- data/doc/api/Rumai/IXP/Agent.html +0 -1222
- data/doc/api/Rumai/IXP/Agent/FidStream.html +0 -602
- data/doc/api/Rumai/IXP/Agent/RangedPool.html +0 -263
- data/doc/api/Rumai/IXP/Error.html +0 -32
- data/doc/api/Rumai/IXP/Fcall.html +0 -398
- data/doc/api/Rumai/IXP/Qid.html +0 -99
- data/doc/api/Rumai/IXP/Rattach.html +0 -71
- data/doc/api/Rumai/IXP/Rauth.html +0 -71
- data/doc/api/Rumai/IXP/Rclunk.html +0 -71
- data/doc/api/Rumai/IXP/Rcreate.html +0 -71
- data/doc/api/Rumai/IXP/Rerror.html +0 -71
- data/doc/api/Rumai/IXP/Rflush.html +0 -71
- data/doc/api/Rumai/IXP/Ropen.html +0 -71
- data/doc/api/Rumai/IXP/Rread.html +0 -71
- data/doc/api/Rumai/IXP/Rremove.html +0 -71
- data/doc/api/Rumai/IXP/Rstat.html +0 -71
- data/doc/api/Rumai/IXP/Rversion.html +0 -71
- data/doc/api/Rumai/IXP/Rwalk.html +0 -71
- data/doc/api/Rumai/IXP/Rwrite.html +0 -71
- data/doc/api/Rumai/IXP/Rwstat.html +0 -71
- data/doc/api/Rumai/IXP/Stat.html +0 -188
- data/doc/api/Rumai/IXP/Stream.html +0 -112
- data/doc/api/Rumai/IXP/Struct.html +0 -348
- data/doc/api/Rumai/IXP/Struct/ClassField.html +0 -177
- data/doc/api/Rumai/IXP/Struct/Field.html +0 -549
- data/doc/api/Rumai/IXP/Struct/Field/CounteeField.html +0 -175
- data/doc/api/Rumai/IXP/Struct/Field/CounterField.html +0 -95
- data/doc/api/Rumai/IXP/Struct/Integer8Field.html +0 -181
- data/doc/api/Rumai/IXP/Struct/StringField.html +0 -128
- data/doc/api/Rumai/IXP/Tattach.html +0 -71
- data/doc/api/Rumai/IXP/Tauth.html +0 -71
- data/doc/api/Rumai/IXP/Tclunk.html +0 -71
- data/doc/api/Rumai/IXP/Tcreate.html +0 -71
- data/doc/api/Rumai/IXP/Terror.html +0 -156
- data/doc/api/Rumai/IXP/Tflush.html +0 -71
- data/doc/api/Rumai/IXP/Topen.html +0 -113
- data/doc/api/Rumai/IXP/Tread.html +0 -71
- data/doc/api/Rumai/IXP/Tremove.html +0 -71
- data/doc/api/Rumai/IXP/Tstat.html +0 -71
- data/doc/api/Rumai/IXP/Tversion.html +0 -83
- data/doc/api/Rumai/IXP/Twalk.html +0 -71
- data/doc/api/Rumai/IXP/Twrite.html +0 -71
- data/doc/api/Rumai/IXP/Twstat.html +0 -71
- data/doc/api/Rumai/Node.html +0 -1139
- data/doc/api/Rumai/View.html +0 -1280
- data/doc/api/Rumai/WidgetImpl.html +0 -196
- data/doc/api/Rumai/WidgetNode.html +0 -184
- data/doc/api/String.html +0 -180
- data/doc/api/StringIO.html +0 -53
- data/doc/api/Time.html +0 -175
- data/doc/api/all-methods.html +0 -1436
- data/doc/api/all-namespaces.html +0 -140
- data/doc/api/app.js +0 -18
- data/doc/api/jquery.js +0 -11
- data/doc/api/readme.html +0 -38
- data/doc/api/style.css +0 -68
- data/doc/api/syntax_highlight.css +0 -21
- data/doc/theory.erb +0 -3
data/lib/rumai.rb
CHANGED
@@ -1,12 +1,20 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2008 Suraj N. Kurapati
|
3
|
+
# See the LICENSE file for details.
|
4
|
+
#++
|
5
|
+
|
1
6
|
require 'rubygems'
|
2
|
-
gem 'inochi', '~>
|
7
|
+
gem 'inochi', '~> 1'
|
3
8
|
require 'inochi'
|
4
9
|
|
5
10
|
Inochi.init :Rumai,
|
6
|
-
:version => '2.0
|
7
|
-
:release => '2009-
|
8
|
-
:website => 'http://snk.tuxfamily.org/lib/rumai',
|
9
|
-
:tagline => 'Ruby interface to the wmii window manager'
|
11
|
+
:version => '2.1.0',
|
12
|
+
:release => '2009-05-09',
|
13
|
+
:website => 'http://snk.tuxfamily.org/lib/rumai/',
|
14
|
+
:tagline => 'Ruby interface to the wmii window manager',
|
15
|
+
:develop => {
|
16
|
+
:dfect => nil, # for unit testing
|
17
|
+
}
|
10
18
|
|
11
19
|
require 'rumai/fs'
|
12
20
|
require 'rumai/wm'
|
data/lib/rumai/fs.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
1
|
# File system abstractions over the 9P2000 protocol.
|
2
|
+
#--
|
3
|
+
# Copyright 2006 Suraj N. Kurapati
|
4
|
+
# See the LICENSE file for details.
|
5
|
+
#++
|
2
6
|
|
3
7
|
require 'rumai/ixp'
|
4
8
|
require 'socket'
|
@@ -6,6 +10,7 @@ require 'socket'
|
|
6
10
|
module Rumai
|
7
11
|
# address of the IXP server socket on this machine
|
8
12
|
display = ENV['DISPLAY'] || ':0.0'
|
13
|
+
|
9
14
|
IXP_SOCK_ADDR = ENV['WMII_ADDRESS'].sub(/.*!/, '') rescue
|
10
15
|
"/tmp/ns.#{ENV['USER']}.#{display[/:\d+/]}/wmii"
|
11
16
|
|
@@ -13,33 +18,40 @@ module Rumai
|
|
13
18
|
# We use a single, global connection to wmii's IXP server.
|
14
19
|
IXP_AGENT = IXP::Agent.new UNIXSocket.new(IXP_SOCK_ADDR)
|
15
20
|
|
16
|
-
rescue
|
17
|
-
|
21
|
+
rescue => error
|
22
|
+
error.message << %{
|
18
23
|
Ensure that (1) the WMII_ADDRESS environment variable is set and that (2)
|
19
24
|
it correctly specifies the filesystem path of wmii's IXP socket file,
|
20
25
|
which is typically located at "/tmp/ns.$USER.:$DISPLAY/wmii".
|
21
26
|
}.gsub(/^ +/, '').gsub(/\A|\z/, "\n")
|
22
27
|
|
23
|
-
raise
|
28
|
+
raise error
|
24
29
|
end
|
25
30
|
|
31
|
+
##
|
26
32
|
# An entry in the IXP file system.
|
33
|
+
#
|
27
34
|
class Node
|
28
35
|
@@cache = Hash.new {|h,k| h[k] = Node.new(k) }
|
29
36
|
|
30
37
|
attr_reader :path
|
31
38
|
|
32
|
-
def initialize
|
33
|
-
@path =
|
39
|
+
def initialize path
|
40
|
+
@path = path.to_s.squeeze('/')
|
34
41
|
end
|
35
42
|
|
43
|
+
##
|
36
44
|
# Returns file statistics about this node.
|
45
|
+
#
|
37
46
|
# See Rumai::IXP::Client#stat for details.
|
47
|
+
#
|
38
48
|
def stat
|
39
49
|
IXP_AGENT.stat @path
|
40
50
|
end
|
41
51
|
|
52
|
+
##
|
42
53
|
# Tests if this node exists on the IXP server.
|
54
|
+
#
|
43
55
|
def exist?
|
44
56
|
begin
|
45
57
|
true if stat
|
@@ -48,91 +60,122 @@ module Rumai
|
|
48
60
|
end
|
49
61
|
end
|
50
62
|
|
63
|
+
##
|
51
64
|
# Tests if this node is a directory.
|
65
|
+
#
|
52
66
|
def directory?
|
53
67
|
exist? and stat.directory?
|
54
68
|
end
|
55
69
|
|
70
|
+
##
|
56
71
|
# Returns the names of all files in this directory.
|
72
|
+
#
|
57
73
|
def entries
|
58
74
|
IXP_AGENT.entries @path rescue []
|
59
75
|
end
|
60
76
|
|
77
|
+
##
|
61
78
|
# Opens this node for I/O access.
|
79
|
+
#
|
62
80
|
# See Rumai::IXP::Client#open for details.
|
63
|
-
|
64
|
-
|
81
|
+
#
|
82
|
+
def open mode = 'r', &block
|
83
|
+
IXP_AGENT.open @path, mode, &block
|
65
84
|
end
|
66
85
|
|
86
|
+
##
|
67
87
|
# Returns the entire content of this node.
|
88
|
+
#
|
68
89
|
# See Rumai::IXP::Client#read for details.
|
69
|
-
|
70
|
-
|
90
|
+
#
|
91
|
+
def read *args
|
92
|
+
IXP_AGENT.read @path, *args
|
71
93
|
end
|
72
94
|
|
95
|
+
##
|
73
96
|
# Invokes the given block for every line in the content of this node.
|
74
|
-
|
97
|
+
#
|
98
|
+
def each_line &block #:yields: line
|
75
99
|
open do |file|
|
76
100
|
until (chunk = file.read(true)).empty?
|
77
|
-
chunk.each_line(&
|
101
|
+
chunk.each_line(&block)
|
78
102
|
end
|
79
103
|
end
|
80
104
|
end
|
81
105
|
|
106
|
+
##
|
82
107
|
# Writes the given content to this node.
|
83
|
-
|
84
|
-
|
108
|
+
#
|
109
|
+
def write content
|
110
|
+
IXP_AGENT.write @path, content
|
85
111
|
end
|
86
112
|
|
113
|
+
##
|
87
114
|
# Creates a file corresponding to this node on the IXP server.
|
115
|
+
#
|
88
116
|
# See Rumai::IXP::Client#create for details.
|
89
|
-
|
90
|
-
|
117
|
+
#
|
118
|
+
def create *args
|
119
|
+
IXP_AGENT.create @path, *args
|
91
120
|
end
|
92
121
|
|
122
|
+
##
|
93
123
|
# Deletes the file corresponding to this node on the IXP server.
|
124
|
+
#
|
94
125
|
def remove
|
95
126
|
IXP_AGENT.remove @path
|
96
127
|
end
|
97
128
|
|
129
|
+
##
|
98
130
|
# Returns the given sub-path as a Node object.
|
99
|
-
|
100
|
-
|
131
|
+
#
|
132
|
+
def [] sub_path
|
133
|
+
@@cache[ File.join(@path, sub_path.to_s) ]
|
101
134
|
end
|
102
135
|
|
136
|
+
##
|
103
137
|
# Returns the parent node of this node.
|
138
|
+
#
|
104
139
|
def parent
|
105
140
|
@@cache[ File.dirname(@path) ]
|
106
141
|
end
|
107
142
|
|
143
|
+
##
|
108
144
|
# Returns all child nodes of this node.
|
145
|
+
#
|
109
146
|
def children
|
110
147
|
entries.map! {|c| self[c] }
|
111
148
|
end
|
112
149
|
|
113
150
|
include Enumerable
|
151
|
+
|
152
|
+
##
|
114
153
|
# Iterates through each child of this directory.
|
115
|
-
|
116
|
-
|
154
|
+
#
|
155
|
+
def each &block
|
156
|
+
children.each(&block)
|
117
157
|
end
|
118
158
|
|
159
|
+
##
|
119
160
|
# Deletes all child nodes.
|
161
|
+
#
|
120
162
|
def clear
|
121
163
|
children.each do |c|
|
122
164
|
c.remove
|
123
165
|
end
|
124
166
|
end
|
125
167
|
|
168
|
+
##
|
126
169
|
# Provides access to child nodes through method calls.
|
127
170
|
#
|
128
171
|
# :call-seq: node.child -> Node
|
129
172
|
#
|
130
|
-
def method_missing
|
131
|
-
child = self[
|
173
|
+
def method_missing meth, *args
|
174
|
+
child = self[meth]
|
132
175
|
|
133
176
|
# speed up future accesses
|
134
177
|
(class << self; self; end).instance_eval do
|
135
|
-
define_method
|
178
|
+
define_method meth do
|
136
179
|
child
|
137
180
|
end
|
138
181
|
end
|
@@ -141,6 +184,7 @@ module Rumai
|
|
141
184
|
end
|
142
185
|
end
|
143
186
|
|
187
|
+
##
|
144
188
|
# Makes instance methods accessible through class
|
145
189
|
# methods. This is done to emulate the File class:
|
146
190
|
#
|
@@ -149,10 +193,10 @@ module Rumai
|
|
149
193
|
#
|
150
194
|
# Both of the above expressions are equivalent.
|
151
195
|
#
|
152
|
-
module
|
153
|
-
def self.extended
|
154
|
-
|
155
|
-
(class <<
|
196
|
+
module ExportInstanceMethods
|
197
|
+
def self.extended target #:nodoc:
|
198
|
+
target.instance_methods(false).each do |meth|
|
199
|
+
(class << target; self; end).instance_eval do
|
156
200
|
define_method meth do |path, *args|
|
157
201
|
new(path).__send__(meth, *args)
|
158
202
|
end
|
@@ -165,5 +209,5 @@ module Rumai
|
|
165
209
|
# that the Externalize* module can do its magic. If we include()d
|
166
210
|
# the module instead before all methods in the class have been
|
167
211
|
# defined, then the magic would only apply to SOME of the methods!
|
168
|
-
Node.extend
|
212
|
+
Node.extend ExportInstanceMethods
|
169
213
|
end
|
data/lib/rumai/ixp.rb
CHANGED
data/lib/rumai/ixp/message.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
# Primitives for the 9P2000 protocol.
|
2
2
|
#
|
3
3
|
# See http://cm.bell-labs.com/sys/man/5/INDEX.html
|
4
|
+
#
|
4
5
|
# See http://swtch.com/plan9port/man/man9/
|
5
6
|
#
|
7
|
+
#--
|
8
|
+
# Copyright 2007 Suraj N. Kurapati
|
9
|
+
# See the LICENSE file for details.
|
10
|
+
#++
|
6
11
|
|
7
12
|
module Rumai
|
8
13
|
module IXP
|
@@ -19,49 +24,67 @@ module Rumai
|
|
19
24
|
const_set "BYTE#{bytes}_MASK", mask
|
20
25
|
end
|
21
26
|
|
27
|
+
##
|
22
28
|
# A 9P2000 byte stream.
|
29
|
+
#
|
23
30
|
module Stream
|
24
31
|
# uchar, ushort, uint32 (all of them little-endian)
|
25
32
|
PACKING_FLAGS = { 1 => 'C', 2 => 'v', 4 => 'V' }.freeze
|
26
33
|
|
34
|
+
##
|
27
35
|
# Unpacks the given number of bytes from this 9P2000 byte stream.
|
28
|
-
|
29
|
-
|
36
|
+
#
|
37
|
+
def read_9p num_bytes
|
38
|
+
read(num_bytes).unpack(PACKING_FLAGS[num_bytes])[0]
|
30
39
|
end
|
31
40
|
end
|
32
41
|
|
42
|
+
##
|
33
43
|
# A common container for exceptions concerning IXP.
|
44
|
+
#
|
34
45
|
class Error < StandardError
|
35
46
|
end
|
36
47
|
|
48
|
+
##
|
37
49
|
# A serializable 9P2000 data structure.
|
50
|
+
#
|
38
51
|
module Struct
|
39
52
|
attr_reader :fields
|
40
53
|
|
54
|
+
##
|
41
55
|
# Allows field values to be initialized via the constructor.
|
42
|
-
#
|
43
|
-
|
56
|
+
#
|
57
|
+
# [field_values]
|
58
|
+
# a mapping from field name to field value
|
59
|
+
#
|
60
|
+
def initialize field_values = {}
|
44
61
|
@fields = self.class.fields
|
45
|
-
@values =
|
62
|
+
@values = field_values
|
46
63
|
end
|
47
64
|
|
65
|
+
##
|
48
66
|
# Transforms this object into a string of 9P2000 bytes.
|
67
|
+
#
|
49
68
|
def to_9p
|
50
69
|
@fields.inject('') {|s,f| s << f.to_9p(@values) }
|
51
70
|
end
|
52
71
|
|
72
|
+
##
|
53
73
|
# Populates this object with information
|
54
74
|
# from the given 9P2000 byte stream.
|
55
|
-
|
75
|
+
#
|
76
|
+
def load_9p stream
|
56
77
|
@fields.each do |f|
|
57
|
-
f.load_9p
|
78
|
+
f.load_9p stream, @values
|
58
79
|
end
|
59
80
|
end
|
60
81
|
|
82
|
+
##
|
61
83
|
# Provides a convenient DSL (for defining fields)
|
62
84
|
# to all objects which *include* this module.
|
63
|
-
|
64
|
-
|
85
|
+
#
|
86
|
+
def self.included target
|
87
|
+
class << target
|
65
88
|
# Returns a list of fields which compose this Struct.
|
66
89
|
def fields
|
67
90
|
@fields ||=
|
@@ -72,11 +95,14 @@ module Rumai
|
|
72
95
|
end
|
73
96
|
end
|
74
97
|
|
98
|
+
##
|
75
99
|
# Defines a new field in this Struct.
|
76
|
-
#
|
77
|
-
|
78
|
-
|
79
|
-
|
100
|
+
#
|
101
|
+
# [args] arguments for Field.new()
|
102
|
+
#
|
103
|
+
def field name, format = nil, *args
|
104
|
+
c = Field.factory(format)
|
105
|
+
f = c.new(name.to_sym, format, *args)
|
80
106
|
fields << f # register field as being part of this structure
|
81
107
|
|
82
108
|
# provide accessor methods to field values
|
@@ -85,19 +111,21 @@ module Rumai
|
|
85
111
|
@values[#{f.name.inspect}]
|
86
112
|
end
|
87
113
|
|
88
|
-
def #{f.name}=
|
89
|
-
@values[#{f.name.inspect}] =
|
114
|
+
def #{f.name}= value
|
115
|
+
@values[#{f.name.inspect}] = value
|
90
116
|
end
|
91
117
|
}
|
92
118
|
|
93
119
|
return f
|
94
120
|
end
|
95
121
|
|
122
|
+
##
|
96
123
|
# Creates a new instance of this class from the
|
97
124
|
# given 9P2000 byte stream and returns the instance.
|
98
|
-
|
99
|
-
|
100
|
-
msg.
|
125
|
+
#
|
126
|
+
def from_9p stream, msg_class = self
|
127
|
+
msg = msg_class.new
|
128
|
+
msg.load_9p(stream)
|
101
129
|
msg
|
102
130
|
end
|
103
131
|
end
|
@@ -105,48 +133,65 @@ module Rumai
|
|
105
133
|
|
106
134
|
private
|
107
135
|
|
108
|
-
|
136
|
+
##
|
137
|
+
# A field inside a Struct.
|
138
|
+
#
|
139
|
+
# A field's value is considered to be either:
|
109
140
|
# * array of format when <code>counter && format.is_a? Class</code>
|
110
141
|
# * raw byte string when <code>counter && format.nil?</code>
|
142
|
+
#
|
111
143
|
class Field
|
112
144
|
attr_reader :name, :format, :counter, :countee
|
113
145
|
|
114
|
-
|
115
|
-
#
|
116
|
-
#
|
117
|
-
|
118
|
-
|
119
|
-
|
146
|
+
##
|
147
|
+
# [name]
|
148
|
+
# unique (among all fields in a struct) name for the field
|
149
|
+
#
|
150
|
+
# [format]
|
151
|
+
# number of bytes, a class, or nil
|
152
|
+
#
|
153
|
+
# [counter]
|
154
|
+
# field which counts the length of this field's value
|
155
|
+
#
|
156
|
+
def initialize name, format = nil, counter = nil
|
157
|
+
@name = name
|
158
|
+
@format = format
|
120
159
|
@countee = nil
|
121
|
-
self.counter =
|
160
|
+
self.counter = counter
|
122
161
|
end
|
123
162
|
|
163
|
+
##
|
124
164
|
# Sets the counter for this field (implying that the
|
125
165
|
# length of this field is counted by the given field).
|
126
|
-
|
127
|
-
|
166
|
+
#
|
167
|
+
def counter= field
|
168
|
+
if @counter = field
|
128
169
|
extend CounteeField
|
129
170
|
@counter.countee = self
|
130
171
|
end
|
131
172
|
end
|
132
173
|
|
174
|
+
##
|
133
175
|
# Sets the countee for this field (implying that
|
134
176
|
# this field counts the length of the given field).
|
135
|
-
|
136
|
-
|
177
|
+
#
|
178
|
+
def countee= field
|
179
|
+
if @countee = field
|
137
180
|
extend CounterField
|
138
181
|
end
|
139
182
|
end
|
140
183
|
|
184
|
+
##
|
141
185
|
# Returns a Field class that best represents the given format.
|
142
|
-
|
143
|
-
|
186
|
+
#
|
187
|
+
def self.factory format
|
188
|
+
if format == String
|
144
189
|
StringField
|
145
190
|
|
146
|
-
elsif
|
191
|
+
elsif format.is_a? Class
|
147
192
|
ClassField
|
148
193
|
|
149
|
-
elsif
|
194
|
+
elsif format == 8
|
150
195
|
Integer8Field
|
151
196
|
|
152
197
|
else
|
@@ -154,42 +199,54 @@ module Rumai
|
|
154
199
|
end
|
155
200
|
end
|
156
201
|
|
202
|
+
##
|
157
203
|
# Transforms this object into a string of 9P2000 bytes.
|
158
|
-
|
159
|
-
|
204
|
+
#
|
205
|
+
def to_9p field_values
|
206
|
+
value_to_9p field_values[@name]
|
160
207
|
end
|
161
208
|
|
209
|
+
##
|
162
210
|
# Populates this object with information
|
163
211
|
# taken from the given 9P2000 byte stream.
|
164
|
-
|
165
|
-
|
212
|
+
#
|
213
|
+
def load_9p stream, field_values
|
214
|
+
field_values[@name] = value_from_9p stream
|
166
215
|
end
|
167
216
|
|
168
217
|
private
|
169
218
|
|
219
|
+
##
|
170
220
|
# Converts the given value, according to the format
|
171
221
|
# of this field, into a string of 9P2000 bytes.
|
172
|
-
|
173
|
-
|
222
|
+
#
|
223
|
+
def value_to_9p value
|
224
|
+
value.to_i.to_9p @format.to_i
|
174
225
|
end
|
175
226
|
|
227
|
+
##
|
176
228
|
# Parses a value, according to the format of
|
177
229
|
# this field, from the given 9P2000 byte stream.
|
178
|
-
|
179
|
-
|
230
|
+
#
|
231
|
+
def value_from_9p stream
|
232
|
+
stream.read_9p @format.to_i
|
180
233
|
end
|
181
234
|
|
235
|
+
##
|
182
236
|
# Methods for a field that counts the length of another field.
|
237
|
+
#
|
183
238
|
module CounterField
|
184
|
-
def to_9p
|
185
|
-
value_to_9p
|
239
|
+
def to_9p field_values
|
240
|
+
value_to_9p field_values[@countee.name].length
|
186
241
|
end
|
187
242
|
end
|
188
243
|
|
244
|
+
##
|
189
245
|
# Methods for a field whose length is counted by another field.
|
246
|
+
#
|
190
247
|
module CounteeField
|
191
|
-
def to_9p
|
192
|
-
value =
|
248
|
+
def to_9p field_values
|
249
|
+
value = field_values[@name]
|
193
250
|
|
194
251
|
if @format
|
195
252
|
value.map {|v| value_to_9p v}.join
|
@@ -198,54 +255,66 @@ module Rumai
|
|
198
255
|
end
|
199
256
|
end
|
200
257
|
|
201
|
-
def load_9p
|
202
|
-
count =
|
258
|
+
def load_9p stream, field_values
|
259
|
+
count = field_values[@counter.name].to_i
|
203
260
|
|
204
|
-
|
261
|
+
field_values[@name] =
|
205
262
|
if @format
|
206
|
-
Array.new(count) { value_from_9p
|
263
|
+
Array.new(count) { value_from_9p stream }
|
207
264
|
else
|
208
|
-
|
265
|
+
stream.read(count) # raw byte sequence
|
209
266
|
end
|
210
267
|
end
|
211
268
|
end
|
212
269
|
end
|
213
270
|
|
271
|
+
#:stopdoc:
|
272
|
+
|
273
|
+
##
|
214
274
|
# A field whose value knows how to convert itself to and from 9p.
|
215
|
-
|
216
|
-
|
217
|
-
|
275
|
+
#
|
276
|
+
class ClassField < Field
|
277
|
+
def value_to_9p value
|
278
|
+
value.to_9p
|
218
279
|
end
|
219
280
|
|
220
|
-
def value_from_9p
|
221
|
-
@format.from_9p
|
281
|
+
def value_from_9p stream
|
282
|
+
@format.from_9p stream
|
222
283
|
end
|
223
284
|
end
|
224
285
|
|
286
|
+
##
|
225
287
|
# A field whose value is a string.
|
226
|
-
|
227
|
-
|
228
|
-
|
288
|
+
#
|
289
|
+
class StringField < ClassField
|
290
|
+
def value_to_9p value
|
291
|
+
value.to_s.to_9p
|
229
292
|
end
|
230
293
|
end
|
231
294
|
|
295
|
+
##
|
232
296
|
# A field whose value is a 8-byte integer.
|
233
|
-
|
234
|
-
|
235
|
-
|
297
|
+
#
|
298
|
+
class Integer8Field < Field
|
299
|
+
def value_to_9p value
|
300
|
+
v = value.to_i
|
236
301
|
(BYTE4_MASK & v).to_9p(4) << # lower bytes
|
237
302
|
(BYTE4_MASK & (v >> BYTE4_BITS)).to_9p(4) # higher bytes
|
238
303
|
end
|
239
304
|
|
240
|
-
def value_from_9p
|
241
|
-
|
305
|
+
def value_from_9p stream
|
306
|
+
stream.read_9p(4) | (stream.read_9p(4) << BYTE4_BITS)
|
242
307
|
end
|
243
308
|
end
|
309
|
+
|
310
|
+
#:startdoc:
|
244
311
|
end
|
245
312
|
|
313
|
+
##
|
246
314
|
# Holds information about a file being accessed on a 9P2000 server.
|
247
315
|
#
|
248
316
|
# See http://cm.bell-labs.com/magic/man2html/5/intro
|
317
|
+
#
|
249
318
|
class Qid
|
250
319
|
include Struct
|
251
320
|
|
@@ -265,9 +334,11 @@ module Rumai
|
|
265
334
|
QTFILE = 0x00 # type bits for plain file
|
266
335
|
end
|
267
336
|
|
337
|
+
##
|
268
338
|
# Holds information about a file on a 9P2000 server.
|
269
339
|
#
|
270
340
|
# See http://cm.bell-labs.com/magic/man2html/5/stat
|
341
|
+
#
|
271
342
|
class Stat
|
272
343
|
include Struct
|
273
344
|
|
@@ -301,16 +372,20 @@ module Rumai
|
|
301
372
|
DMWRITE = 0x2 # mode bit for write permission
|
302
373
|
DMEXEC = 0x1 # mode bit for execute permission
|
303
374
|
|
375
|
+
##
|
304
376
|
# Tests if this file is a directory.
|
377
|
+
#
|
305
378
|
def directory?
|
306
379
|
mode & DMDIR > 0
|
307
380
|
end
|
308
381
|
end
|
309
382
|
|
383
|
+
##
|
310
384
|
# Fcall is the basic unit of communication in the 9P2000 protocol.
|
311
385
|
# It is analogous to a "packet" in the Internetwork Protocol (IP).
|
312
386
|
#
|
313
387
|
# See http://cm.bell-labs.com/magic/man2html/2/fcall
|
388
|
+
#
|
314
389
|
class Fcall
|
315
390
|
include Struct
|
316
391
|
|
@@ -322,7 +397,9 @@ module Rumai
|
|
322
397
|
#
|
323
398
|
field :tag , 2
|
324
399
|
|
400
|
+
##
|
325
401
|
# Transforms this object into a string of 9P2000 bytes.
|
402
|
+
#
|
326
403
|
def to_9p
|
327
404
|
data = type.to_9p(1) << super
|
328
405
|
size = (data.length + 4).to_9p(4)
|
@@ -331,19 +408,22 @@ module Rumai
|
|
331
408
|
|
332
409
|
class << self
|
333
410
|
alias __from_9p__ from_9p
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
411
|
+
undef from_9p
|
412
|
+
|
413
|
+
##
|
414
|
+
# Creates a new instance of this class from the
|
415
|
+
# given 9P2000 byte stream and returns the instance.
|
416
|
+
#
|
417
|
+
def from_9p stream
|
418
|
+
size = stream.read_9p(4)
|
419
|
+
type = stream.read_9p(1)
|
420
|
+
|
421
|
+
unless fcall = TYPE_TO_CLASS[type]
|
422
|
+
raise Error, "illegal fcall type: #{type}"
|
423
|
+
end
|
341
424
|
|
342
|
-
|
343
|
-
raise Error, "illegal fcall type: #{type}"
|
425
|
+
__from_9p__ stream, fcall
|
344
426
|
end
|
345
|
-
|
346
|
-
__from_9p__ aStream, fcall
|
347
427
|
end
|
348
428
|
|
349
429
|
NOTAG = BYTE2_MASK # (ushort)
|
@@ -531,6 +611,9 @@ module Rumai
|
|
531
611
|
class Rwstat < Fcall
|
532
612
|
end
|
533
613
|
|
614
|
+
##
|
615
|
+
# A remote function call (fcall).
|
616
|
+
#
|
534
617
|
class Fcall
|
535
618
|
CLASS_TO_TYPE = {
|
536
619
|
Tversion => 100,
|
@@ -565,12 +648,16 @@ module Rumai
|
|
565
648
|
|
566
649
|
TYPE_TO_CLASS = CLASS_TO_TYPE.invert.freeze
|
567
650
|
|
651
|
+
##
|
568
652
|
# Returns the value of the 'type' field for this fcall.
|
653
|
+
#
|
569
654
|
def self.type
|
570
655
|
CLASS_TO_TYPE[self]
|
571
656
|
end
|
572
657
|
|
658
|
+
##
|
573
659
|
# Returns the value of the 'type' field for this fcall.
|
660
|
+
#
|
574
661
|
def type
|
575
662
|
self.class.type
|
576
663
|
end
|
@@ -579,36 +666,46 @@ module Rumai
|
|
579
666
|
end
|
580
667
|
|
581
668
|
class Integer
|
669
|
+
##
|
582
670
|
# Transforms this object into a string of 9P2000 bytes.
|
583
|
-
|
584
|
-
|
671
|
+
#
|
672
|
+
def to_9p num_bytes
|
673
|
+
[self].pack Rumai::IXP::Stream::PACKING_FLAGS[num_bytes]
|
585
674
|
end
|
586
675
|
end
|
587
676
|
|
588
677
|
# count[2] s[count]
|
589
678
|
class String
|
679
|
+
##
|
590
680
|
# Transforms this object into a string of 9P2000 bytes.
|
681
|
+
#
|
591
682
|
def to_9p
|
592
683
|
length.to_9p(2) << self[0, Rumai::IXP::BYTE2_MASK]
|
593
684
|
end
|
594
685
|
|
686
|
+
##
|
595
687
|
# Creates a new instance of this class from the
|
596
688
|
# given 9P2000 byte stream and returns the instance.
|
597
|
-
|
598
|
-
|
689
|
+
#
|
690
|
+
def self.from_9p stream
|
691
|
+
stream.read(stream.read_9p(2))
|
599
692
|
end
|
600
693
|
end
|
601
694
|
|
602
695
|
class Time
|
696
|
+
##
|
603
697
|
# Transforms this object into a string of 9P2000 bytes.
|
698
|
+
#
|
604
699
|
def to_9p
|
605
700
|
to_i.to_9p(4)
|
606
701
|
end
|
607
702
|
|
703
|
+
##
|
608
704
|
# Creates a new instance of this class from the
|
609
705
|
# given 9P2000 byte stream and returns the instance.
|
610
|
-
|
611
|
-
|
706
|
+
#
|
707
|
+
def self.from_9p stream
|
708
|
+
at stream.read_9p(4)
|
612
709
|
end
|
613
710
|
end
|
614
711
|
|