CEBL  2.1
RController.cpp
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <signal.h>
6 #include <iostream>
7 #include <sstream>
8 #include <boost/regex.hpp>
9 #include <boost/lexical_cast.hpp>
10 
11 #include "RController.hpp"
12 
13 using namespace std;
14 
15 namespace CEBL
16 {
17  RController::RController()
18  {
19  this->child_pid = -1;
20  this->connected = false;
21  this->read_pipe = -1;
22  this->write_pipe = -1;
23  this->cleared = false;
24  this->temp_filename = "";
25  }
26 
27  RController::~RController()
28  {
29  this->rProcessKill();
30  if(temp_filename != "")
31  {
32  remove(temp_filename.c_str());
33  remove(temp_dir.c_str());
34  }
35  }
36 
37  //----------------------------------------------------------------------
38 
39  bool RController::rProcessStart()
40  {
41  //pipe
42  int child_read_pipe[2];
43  int child_write_pipe[2];
44 
45  //try to create pipes
46  if(pipe(child_read_pipe) < 0)
47  {
48  perror("pipe");
49  return false;
50  }
51  if(pipe(child_write_pipe) < 0)
52  {
53  close(child_read_pipe[0]);
54  close(child_read_pipe[1]);
55  perror("pipe");
56  return false;
57  }
58 
59  //try to create child
60  pid_t pid = fork();
61  if(pid < 0)
62  {
63  cerr << "Failed to fork a child process.\n";
64  perror("fork");
65  return false;
66  }
67 
68  //--------------------------------------------------
69  //CHILD:
70  else if(pid == 0)
71  {
72  close(child_read_pipe[1]); //close writing side of pipe
73  dup2(child_read_pipe[0], STDIN_FILENO); //replace stdin
74  close(child_read_pipe[0]); //close old pipe read end
75 
76  close(child_write_pipe[0]); //close reading side of pipe
77  dup2(child_write_pipe[1], STDOUT_FILENO);//replace stdout
78  close(child_write_pipe[1]); //close old pipe read end
79 
80  const char * program = "R";
81  execlp(program,
82  program,
83  "--no-save","--no-restore","--quiet",
84  NULL);
85 
86  //if we get here, there was an error loading R
87  cerr << "Failed to execute.\n";
88  perror("execlp");
89  exit(1);
90  }
91 
92 
93  //--------------------------------------------------
94  //PARENT
95  close(child_read_pipe[0]); //close read end of child read pipe
96  close(child_write_pipe[1]); //close write end of child write pipe
97  this->read_pipe = child_write_pipe[0];
98  this->write_pipe = child_read_pipe[1];
99  this->child_pid = pid;
100  this->connected = true;
101  return true;
102  }
103 
104 
105  //----------------------------------------------------------------------
106 
107 
108  void RController::rProcessKill()
109  {
110  kill(this->child_pid,9);
111  this->connected = false;
112  }
113 
114  //----------------------------------------------------------------------
115 
116 
117  bool RController::start()
118  {
119 
120  if(!rProcessStart())
121  {
122  cerr << "Failed to create R child process.\n";
123  return false;
124  }
125  else
126  {
127  return true;
128  }
129  }
130 
131  void RController::stop()
132  {
133  rProcessKill();
134  }
135 
136  //----------------------------------------------------------------------
137 
138 
139  string RController::pipeReadAll()
140  {
141  string result = "";
142  char buffer[1024];
143  memset(buffer, 0, sizeof (buffer));
144 
145  // read result
146  unsigned bytes = 0;
147  int total_bytes = 0;
148  while(true)
149  {
150  bytes = read(read_pipe, buffer, sizeof(buffer));
151  total_bytes += bytes;
152  //put the result into return string
153  result += buffer;
154  memset(buffer, 0, sizeof (buffer));
155 
156  if(bytes < sizeof(buffer))
157  {
158  break;
159  }
160  }
161  this->cleared = true;
162  return result;
163  }
164 
165  void RController::pipeWriteCommand(string command)
166  {
167  command += "\n";
168  const char * temp = command.c_str();
169  write(write_pipe,temp,command.length());
170  this->cleared = false;
171  }
172 
173  void RController::sendCommand(string command, bool clear)
174  {
175 
176  if(clear && !cleared)
177  {
178  sleep(1);
179  pipeReadAll();
180  }
181 
182  //replace all tokens
183  // %f token
184  if(regex_search(command,boost::regex("%f")))
185  {
186  createTempFilename();
187  command = regex_replace(command,
188  boost::regex("%f"),
189  temp_filename);
190  }
191 
192  pipeWriteCommand(command);
193  }
194 
195  string RController::getResponse()
196  {
197  //read until we encounter an R prompt again
198  boost::regex prompt_regexp("^> $");
199  bool cont = true;
200  string result,line,full_response;
201  char buffer[1024];
202  full_response = "";
203 
204  //continue reading from pipe until we reach a prompt
205  while(cont)
206  {
207 
208  result = pipeReadAll();
209  full_response += result;
210 
211  // split result into lines
212  stringstream temp;
213  temp << result;
214  // loop through lines to check if we have reached a prompt
215  while(!temp.eof())
216  {
217  temp.getline(buffer,sizeof(buffer),'\n');
218  line = buffer;
219  if(regex_search(line,prompt_regexp))
220  {
221  cont = false;
222  break;
223  }
224  }
225  sleep(1);
226  }
227  return full_response;
228  }
229 
230  //----------------------------------------------------------------------
231  void RController::createTempFilename()
232  {
233  if(temp_filename == "")
234  {
235  char dir[] = "/tmp/CEBLXXXXXX";
236  mkdtemp(dir);
237  this->temp_dir = dir;
238  this->temp_filename = string(dir) + "/matrix";
239  }
240  }
241 
242  //----------------------------------------------------------------------
243  // R Parsing
244 
245  string RController::trimResponse(string response)
246  {
247  boost::regex prompt_regexp("^> *");
248  string ret = "";
249  char buffer[1024];
250  string line;
251  stringstream temp;
252  temp << response;
253  // loop through lines adding them to new string
254  int i = 0;
255  while(!temp.eof())
256  {
257  temp.getline(buffer,sizeof(buffer),'\n');
258  if(i > 0)
259  {
260  line = buffer;
261  if(!regex_search(line,prompt_regexp))
262  {
263  ret += line + "\n";
264  }
265  }
266  i++;
267  }
268  return ret;
269  }
270 
271  ublas::matrix<double> RController::readMatrixFromTempFile()
272  {
273  return cppR::readTable<double>(this->temp_filename);
274  }
275 
276  void RController::writeMatrixToTempFile(ublas::matrix<double> mat)
277  {
278  createTempFilename();
279  cout << temp_filename << "\n";
280  cppR::writeTable(mat,this->temp_filename);
281  }
282 
283 }