src: update tools to the new toolcontext helpers on option processing
[nit.git] / src / nitdbg_client.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2013 Lucas Bajolet <lucas.bajolet@gmail.com>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Client for the nit debugger nitdbg-server
18 #
19 # Can send commands to the debugger
20 module nitdbg_client
21
22 import socket
23 import toolcontext
24
25 redef class ToolContext
26
27 var opt_host_address: OptionString = new OptionString("Sets the host to debug from, use IPV4 only (Defaults to 127.0.0.1)", "--host")
28 var opt_debug_port: OptionInt = new OptionInt("Sets the debug port (Defaults to 22125) - Must be contained between 0 and 65535", 22125, "--port")
29
30 redef init
31 do
32 super
33 self.option_context.add_option(self.opt_host_address)
34 self.option_context.add_option(self.opt_debug_port)
35 end
36
37 end
38
39 redef class String
40
41 # Checks if the actual string is a valid IPv4 address
42 # That is, if the pattern is int.int.int.int where each int must be between 0 and 255
43 fun is_valid_ipv4_address: Bool
44 do
45 var components = self.split_with(".")
46 if components.length != 4 then return false
47 for i in components do
48 if not i.is_numeric or not (i.to_i <= 255 and i.to_i >= 0) then return false
49 end
50 return true
51 end
52
53 end
54
55 # Persistant connection to the debugger
56 # Default port = 22125
57 #
58 class DebugClient
59
60 var debugger_connection: Socket
61
62 init (host: String, port: Int)
63 do
64 self.debugger_connection = new Socket.stream_with_host(host, port)
65 print "[HOST ADDRESS] : "+debugger_connection.address
66 print "[HOST] : "+debugger_connection.host.as(not null)
67 print "[PORT] : "+debugger_connection.port.to_s
68 end
69
70 init with_port (host: String, port: Int)
71 do
72 debugger_connection = new Socket.stream_with_host(host, port)
73 end
74
75 fun send_command(command: String)
76 do
77 debugger_connection.write(command+"\n")
78 end
79
80 fun connected: Bool
81 do
82 return self.debugger_connection.connected
83 end
84
85 fun ready: Bool
86 do
87 return debugger_connection.ready_to_read(40)
88 end
89
90 fun read_command: String
91 do
92 var buff = new Buffer
93 while debugger_connection.ready_to_read(40) do buff.append(debugger_connection.read)
94 return buff.to_s
95 end
96
97 fun disconnect
98 do
99 debugger_connection.close
100 end
101
102 end
103
104 # Create a tool context to handle options and paths
105 var toolcontext = new ToolContext
106 toolcontext.tooldescription = "Usage: nitdbg_client [OPTION]...\nConnects to a nitdbg_server and controls it."
107 toolcontext.accept_no_arguments = true
108 toolcontext.process_options
109
110 var debug: DebugClient
111
112 # If the port value is not an Int between 0 and 65535 (Mandatory according to the norm)
113 # Print the usage
114 if toolcontext.opt_debug_port.value < 0 or toolcontext.opt_debug_port.value > 65535 then
115 toolcontext.option_context.usage
116 return
117 end
118
119 # An IPV4 address does always complies to this form : x.x.x.x
120 # Where x is an integer whose value is >=0 and <= 255
121 if toolcontext.opt_host_address.value != null then
122 if toolcontext.opt_host_address.value.is_valid_ipv4_address then
123 debug = new DebugClient(toolcontext.opt_host_address.value.as(not null), toolcontext.opt_debug_port.value)
124 else
125 toolcontext.option_context.usage
126 return
127 end
128 else
129 debug = new DebugClient("127.0.0.1", toolcontext.opt_debug_port.value)
130 end
131
132 var res = debug.debugger_connection.connect
133 print "Connecting ... " + res.to_s
134 if not res then exit 1
135
136 var recv_cmd: String
137
138 var written_cmd: String
139
140 var over = false
141
142 while not over do
143 if stdin.poll_in then
144 written_cmd = gets
145 debug.send_command(written_cmd)
146 if written_cmd == "kill" then
147 over = true
148 end
149 end
150
151 if not over and debug.ready then
152 recv_cmd = debug.read_command
153 var command_parts = recv_cmd.split("\n")
154 for i in command_parts do
155 if i == "DBG DONE WORK ON SELF" then
156 debug.send_command("CLIENT DBG DONE ACK")
157 over = true
158 end
159 print i
160 end
161 end
162 end
163
164 debug.disconnect