HepLib
Process.cpp
Go to the documentation of this file.
1 
6 #include "BASIC.h"
7 #include <fstream>
8 
9 inline bool file_exists(const char* fn) {
10  return (access(fn,F_OK)!=-1);
11 }
12 
13 namespace HepLib {
14 
15  //-----------------------------------------------------------
16  // Fermat Class
17  //-----------------------------------------------------------
18  #define ENTER endl<<endl<<endl
19 
21 
22  void Fermat::Exit() {
23  if(getpid()!=pid) return;
24  if(inited) {
25  ostringstream script;
26  script << "&q;" << endl << "&x;" << ENTER;
27  string istr = script.str();
28  write(P2C[1], istr.c_str(), istr.length());
29  int st;
30  waitpid(fpid, &st, WUNTRACED);
31  inited = false;
32  exited = true;
33  }
34  }
35 
36  void Fermat::Init(string fer_path) {
37  if(inited) return;
38  inited = true;
39  pid = getpid();
40 
41  if (pipe(P2C)==-1 || pipe(C2P)==-1) {
42  throw Error("pipe failed in Fermat::Init.");
43  }
44 
45  fpid = fork();
46  if (fpid == 0) { // child process
47  if(setpgid(0,0)) throw Error("setpgid failed in Fermat::Init.");
48  close(P2C[1]);
49  close(C2P[0]);
50  dup2(C2P[1], 1);
51  close(C2P[1]);
52  dup2(P2C[0], 0);
53  close(P2C[0]);
54  execlp(fer_path.c_str(), fer_path.c_str(), NULL);
55  exit(0);
56  }
57 
58  // parent process
59  close(P2C[0]); // P2C[1] for write
60  close(C2P[1]); // C2P[0] for read
61 
62  ostringstream script;
63  script << "&(_d=90000);" << endl; // width of the display on the window
64  script << "&d" << endl << "0;" << endl; // off floating point representation
65  script << "&(_t=0);" << endl; // off a certain fast probabalistic algorithm
66  script << "&(t=0);" << endl; // off timing
67  script << "&(_s=0);" << endl;
68  script << "&(_o=1000);" << endl; // http://home.bway.net/lewis/fer64mono.html
69  script << "&(M=' ');" << endl; // prompt
70  script << "!('" << Sentinel << "');" << ENTER;
71  string istr = script.str();
72  write(P2C[1], istr.c_str(), istr.length());
73 
74  string ostr;
75  int n = 1024;
76  char buffer[n+1]; // make sure the last one is '\0'
77  int nio;
78  while(true) {
79  for(int i=0; i<n+1; i++) buffer[i] = '\0';
80  nio = read(C2P[0], buffer, n);
81  if(nio>0) ostr += buffer;
82  else throw Error(ostr);
83  auto cpos = ostr.find(Sentinel);
84  if(cpos!=string::npos) {
85  const char* WhiteSpace = " \t\v\r\n";
86  auto lpos = ostr.find_last_not_of(WhiteSpace);
87  if(ostr[lpos]!='0') read(C2P[0], buffer, n); // last 0, due to Sentinel
88  ostr.erase(cpos);
89  break;
90  }
91  }
92 
93  string_replace_all(ostr, "*** entry > 30 or < 5 means turn off mono multiply.", "");
94  string_replace_all(ostr, "*** Fermat Warning. Early exit from mod_multivar_Chinese.", "");
95  if(ostr.find("***")!=string::npos) {
96  cout << "Fermat script: " << endl << istr << endl << endl;
97  throw Error(ostr.c_str());
98  }
99  }
100 
101  // out string still contains the last number
102  string Fermat::Execute(string expr) {
103  if(exited) throw Error("Fermat has already exited.");
104  if(getpid() != pid) throw Error("Fermat: can not Execute on child process.");
105  ostringstream script;
106  script << expr << endl;
107  script << "!('" << Sentinel << "')" << ENTER;
108  string istr = script.str();
109  write(P2C[1], istr.c_str(), istr.length());
110 
111  string ostr;
112  int n = buffer_size;
113  char buffer[n+1]; // make sure the last one is '\0'
114  int nio;
115  while(true) {
116  for(int i=0; i<n+1; i++) buffer[i] = '\0';
117  nio = read(C2P[0], buffer, n);
118  if(nio>0) ostr += buffer;
119  else throw Error(ostr);
120  auto cpos = ostr.find(Sentinel);
121  if(cpos!=string::npos) {
122  const char* WhiteSpace = " \t\v\r\n";
123  auto lpos = ostr.find_last_not_of(WhiteSpace);
124  if(ostr[lpos]!='0') read(C2P[0], buffer, n); // last 0, due to Sentinel
125  ostr.erase(cpos);
126  break;
127  }
128  }
129  string_replace_all(ostr, "`", "");
130  string_trim(ostr);
131 
132  if(ostr.find("***")!=string::npos) {
133  cout << endl << expr << endl << endl;
134  throw Error(ostr.c_str());
135  }
136  return ostr;
137  }
138 
139  //-----------------------------------------------------------
140  // Form Class
141  //-----------------------------------------------------------
142  Form::~Form() { Exit(); }
143 
144  void Form::Exit() {
145  if(getpid()!=pid) return;
146  if(inited && !exited) {
147  string exit_cmd = "\n.end\n" + Prompt +"\n";
148  write(io[0][1], exit_cmd.c_str(), exit_cmd.length());
149  char buffer[8];
150  read(io[1][0], buffer, 8);
151  int st;
152  waitpid(fpid, &st, WUNTRACED);
153  }
154  inited = false;
155  exited = true;
156  }
157 
158  void Form::Init(string form_path) {
159  if(inited) return;
160  inited = true;
161  pid = getpid();
162 
163  if (pipe(io[0])==-1 || pipe(io[1])==-1 || pipe(stdo)==-1) {
164  inited = false;
165  exited = true;
166  throw Error("pipe failed in Form::Init.");
167  }
168 
169  fpid = fork();
170  if (fpid == 0) {
171  if(setpgid(0,0)) throw Error("setpgid failed in Form::Init.");
172  close(io[0][1]);
173  close(io[1][0]);
174  close(stdo[0]);
175  dup2(stdo[1], 1);
176 
177  auto cpid = getpid(); // current process id
178  ostringstream oss;
179  oss << "init-" << cpid << ".frm";
180 
181  std::ofstream ofs;
182  ofs.open(oss.str().c_str(), ios::out);
183  if (!ofs) {
184  inited = false;
185  exited = true;
186  throw Error("failed to open init.frm file!");
187  }
188  ofs << "Off Statistics;" << endl;
189  ofs << "#ifndef `PIPES_'" << endl;
190  ofs << " #message \"No pipes found\";" << endl;
191  ofs << " .end;" << endl;
192  ofs << "#endif" << endl;
193  ofs << "#if (`PIPES_' <= 0)" << endl;
194  ofs << " #message \"No pipes found\";" << endl;
195  ofs << " .end;" << endl;
196  ofs << "#endif" << endl;
197  ofs << "#procedure put(mexp)" << endl;
198  ofs << " Format Nospaces;" << endl;
199  ofs << " ON NoSpacesInNumbers;" << endl;
200  ofs << " #write \""<<Sentinel<<"\\n\"" << endl;
201  ofs << " #toexternal \"%E\", `mexp'" << endl;
202  ofs << " #toexternal \""<<Sentinel<<"\"" << endl;
203  ofs << " #toexternal \"\\n\"" << endl;
204  ofs << "#endprocedure" << endl;
205  ofs << "#setexternal `PIPE1_';" << endl;
206  ofs << "#toexternal \"OK\"" << endl;
207  ofs << "Local [o]=0;" << endl;
208  ofs << ".sort" << endl;
209  ofs << "Format Mathematica;" << endl;
210  ofs << "#prompt \"" << Prompt << "\"" << endl;
211  ofs << "#fromexternal-" << endl;
212  ofs << ".end" << endl;
213  ofs.close();
214 
215  execlp(form_path.c_str(), form_path.c_str(),
216  "-pipe",
217  (to_string(io[0][0])+","+to_string(io[1][1])).c_str(),
218  "-M", ("init-"+to_string(cpid)).c_str(),
219  NULL);
220  exit(0);
221  }
222 
223  close(io[0][0]);
224  close(io[1][1]);
225  close(stdo[1]);
226 
227  char buffer[1024];
228  read(io[1][0], buffer, sizeof(buffer));
229  char* p = strstr(buffer, "\n");
230  if(p==NULL){
231  inited = false;
232  exited = true;
233  cout << "the return is: <|" << buffer << "|>" << endl;
234  throw Error("Init Failed: Expect a Line break!");
235  }
236  sprintf(p, ",%d\n\n", fpid);
237  write(io[0][1], buffer, strlen(buffer));
238  read(io[1][0], buffer, sizeof(buffer));
239  p = strstr(buffer, "OK");
240  if(p==NULL || p!=buffer) {
241  inited = false;
242  exited = true;
243  throw Error("Init Failed: Expect OK!");
244  }
245 
246  ostringstream oss;
247  oss << "init-" << fpid << ".frm";
248  if(file_exists(oss.str().c_str())) remove(oss.str().c_str());
249 
250  if(true) { // read the terminal output
251  string estr;
252  int n = 1024;
253  char buffer[n+1]; // make sure the last one is '\0'
254  int nio;
255  while(true) {
256  for(int i=0; i<n+1; i++) buffer[i] = '\0';
257  nio = read(stdo[0], buffer, n);
258  if(nio>0) estr += buffer;
259  auto cpos = estr.find(Sentinel);
260  if(cpos!=string::npos) break;
261  cpos = estr.find("-->");
262  if(cpos!=string::npos) {
263  inited = false;
264  exited = true;
265  throw Error(estr);
266  }
267  }
268  }
269  }
270 
271  string Form::Execute(const string & script, const string & out_var) {
272  if(exited) throw Error("Form has already exited.");
273  if(getpid() != pid) throw Error("Form: can not Execute on child process.");
274  string istr = script;
275  istr += "\n.sort\n#call put(";
276  istr += out_var;
277  istr += ")\n.sort\n";
278  istr += Prompt + "\n"; // prompt
279 
280  write(io[0][1], istr.c_str(), istr.length());
281 
282  string ostr;
283  int n = buffer_size;
284  char buffer[n+1]; // make sure the last one is '\0'
285  int nio;
286 
287  string estr;
288  while(true) {
289  for(int i=0; i<n+1; i++) buffer[i] = '\0';
290  nio = read(stdo[0], buffer, n);
291  if(nio>0) estr += buffer;
292  auto cpos = estr.find("-->");
293  if(cpos!=string::npos) {
294  inited = false;
295  exited = true;
296  throw Error(estr);
297  }
298  cpos = estr.find(Sentinel);
299  if(cpos!=string::npos) break;
300  }
301 
302  while(true) {
303  for(int i=0; i<n+1; i++) buffer[i] = '\0';
304  nio = read(io[1][0], buffer, n);
305  if(nio>0) ostr += buffer;
306  else {
307  string estr;
308  while(true) {
309  for(int i=0; i<n+1; i++) buffer[i] = '\0';
310  nio = read(stdo[0], buffer, n);
311  if(nio<=0) break;
312  estr += buffer;
313  }
314  inited = false;
315  exited = true;
316  throw Error(estr.c_str());
317  }
318  auto cpos = ostr.find(Sentinel);
319  if(cpos!=string::npos) {
320  ostr.replace(cpos, Sentinel.length(), "");
321  break;
322  }
323  }
324 
325  return ostr;
326  }
327 
328 
329 }
Basic header file.
bool file_exists(const char *fn)
Definition: Process.cpp:9
#define ENTER
Definition: Process.cpp:18
class used to wrap error message
Definition: BASIC.h:242
void Exit()
Definition: Process.cpp:22
static int buffer_size
Definition: BASIC.h:800
string Sentinel
Definition: BASIC.h:801
void Init(string fer_path="fer64")
Definition: Process.cpp:36
string Execute(string)
Definition: Process.cpp:102
void Exit()
Definition: Process.cpp:144
string Sentinel
Definition: BASIC.h:823
void Init(string form_path="form")
Definition: Process.cpp:158
static int buffer_size
Definition: BASIC.h:822
string Prompt
Definition: BASIC.h:824
string Execute(const string &script, const string &out_var="[o]")
Definition: Process.cpp:271
HepLib namespace.
Definition: BASIC.cpp:17
bool file_exists(string fn)
Definition: BASIC.h:289
void string_replace_all(string &str, const string &from, const string &to)
Definition: Functions.cpp:148
void string_trim(string &str)
Definition: Functions.cpp:156