Check in polyglot-1.4w10UCIb15
[polyglot.git] / engine.cpp
1 #ifndef _WIN32\r
2 \r
3 // engine.cpp\r
4 \r
5 // includes\r
6 \r
7 #include <cerrno>\r
8 #include <cstdarg>\r
9 #include <cstdio>\r
10 #include <cstdlib>\r
11 #include <cstring>\r
12 \r
13 #include <sys/types.h>\r
14 #include <unistd.h>\r
15 \r
16 #include "engine.h"\r
17 #include "io.h"\r
18 #include "option.h"\r
19 #include "util.h"\r
20 \r
21 \r
22 // constants\r
23 \r
24 static const int StringSize = 4096;\r
25 \r
26 // variables\r
27 \r
28 engine_t Engine[1];\r
29 \r
30 // prototypes\r
31 \r
32 static void my_close (int fd);\r
33 static void my_dup2  (int old_fd, int new_fd);\r
34 \r
35 // functions\r
36 \r
37 // engine_is_ok()\r
38 \r
39 bool engine_is_ok(const engine_t * engine) {\r
40 \r
41    if (engine == NULL) return false;\r
42 \r
43    if (!io_is_ok(engine->io)) return false;\r
44 \r
45    return true;\r
46 }\r
47 \r
48 // engine_open()\r
49 \r
50 void engine_open(engine_t * engine) {\r
51 \r
52    const char * dir, * command;\r
53    char string[StringSize];\r
54    int argc;\r
55    char * ptr;\r
56    char * argv[256];\r
57    int from_engine[2], to_engine[2];\r
58    pid_t pid;\r
59 \r
60    ASSERT(engine!=NULL);\r
61 \r
62    // init\r
63 \r
64    dir = option_get_string("EngineDir");\r
65    my_log("POLYGLOT Dir \"%s\"\n",dir);\r
66 \r
67    command = option_get_string("EngineCommand");\r
68    my_log("POLYGLOT Command \"%s\"\n",command);\r
69 \r
70    // parse the command line and create the argument list\r
71 \r
72    if (strlen(command) >= StringSize) my_fatal("engine_open(): buffer overflow\n");\r
73    strcpy(string,command);\r
74 \r
75    argc = 0;\r
76 \r
77    for (ptr = strtok(string," "); ptr != NULL; ptr = strtok(NULL," ")) {\r
78       argv[argc++] = ptr;\r
79    }\r
80 \r
81    argv[argc] = NULL;\r
82 \r
83    // create the pipes\r
84 \r
85    if (pipe(from_engine) == -1) {\r
86       my_fatal("engine_open(): pipe(): %s\n",strerror(errno));\r
87    }\r
88 \r
89    if (pipe(to_engine) == -1) {\r
90       my_fatal("engine_open(): pipe(): %s\n",strerror(errno));\r
91    }\r
92 \r
93    // create the child process\r
94 \r
95    pid = fork();\r
96 \r
97    if (pid == -1) {\r
98 \r
99       my_fatal("engine_open(): fork(): %s\n",strerror(errno));\r
100 \r
101    } else if (pid == 0) {\r
102 \r
103       // child = engine\r
104 \r
105       // close unused pipe descriptors to avoid deadlocks\r
106 \r
107       my_close(from_engine[0]);\r
108       my_close(to_engine[1]);\r
109 \r
110       // attach the pipe to standard input\r
111 \r
112       my_dup2(to_engine[0],STDIN_FILENO);\r
113       my_close(to_engine[0]);\r
114 \r
115       // attach the pipe to standard output\r
116 \r
117       my_dup2(from_engine[1],STDOUT_FILENO);\r
118       my_close(from_engine[1]);\r
119 \r
120       // attach standard error to standard output\r
121 \r
122       my_dup2(STDOUT_FILENO,STDERR_FILENO);\r
123 \r
124       // set a low priority\r
125 \r
126       if (option_get_bool("UseNice"))\r
127       {\r
128           my_log("POLYGLOT Adjust Engine Piority");\r
129           nice(+option_get_int("NiceValue"));\r
130       }\r
131 \r
132       // change the current directory\r
133 \r
134       if (dir[0] != '\0' && chdir(dir) == -1) {\r
135          my_fatal("engine_open(): chdir(): %s\n",strerror(errno));\r
136       }\r
137 \r
138       // launch the new executable file\r
139 \r
140       execvp(argv[0],&argv[0]);\r
141 \r
142       // execvp() only returns when an error has occured\r
143 \r
144       my_fatal("engine_open(): execvp(): %s\n",strerror(errno));\r
145 \r
146    } else { // pid > 0\r
147 \r
148       ASSERT(pid>0);\r
149 \r
150       // parent = PolyGlot\r
151 \r
152       // close unused pipe descriptors to avoid deadlocks\r
153 \r
154       my_close(from_engine[1]);\r
155       my_close(to_engine[0]);\r
156 \r
157       // fill in the engine struct\r
158 \r
159       engine->io->in_fd = from_engine[0];\r
160       engine->io->out_fd = to_engine[1];\r
161       engine->io->name = "Engine";\r
162 \r
163       io_init(engine->io);\r
164    }\r
165 }\r
166 \r
167 // engine_close()\r
168 \r
169 void engine_close(engine_t * engine) {\r
170 \r
171    ASSERT(engine_is_ok(engine));\r
172 \r
173    io_close(engine->io);\r
174 }\r
175 \r
176 // engine_get()\r
177 \r
178 void engine_get(engine_t * engine, char string[], int size) {\r
179 \r
180    ASSERT(engine_is_ok(engine));\r
181    ASSERT(string!=NULL);\r
182    ASSERT(size>=256);\r
183 \r
184    while (!io_line_ready(engine->io)) {\r
185       io_get_update(engine->io);\r
186    }\r
187 \r
188    if (!io_get_line(engine->io,string,size)) { // EOF\r
189        my_log("POLYGLOT *** EOF from Engine ***\n");\r
190       exit(EXIT_SUCCESS);\r
191    }\r
192 }\r
193 \r
194 // engine_send()\r
195 \r
196 void engine_send(engine_t * engine, const char format[], ...) {\r
197 \r
198    va_list arg_list;\r
199    char string[StringSize];\r
200 \r
201    ASSERT(engine_is_ok(engine));\r
202    ASSERT(format!=NULL);\r
203 \r
204    // format\r
205 \r
206    va_start(arg_list,format);\r
207    vsprintf(string,format,arg_list);\r
208    va_end(arg_list);\r
209 \r
210    // send\r
211 \r
212    io_send(engine->io,"%s",string);\r
213 }\r
214 \r
215 // engine_send_queue()\r
216 \r
217 void engine_send_queue(engine_t * engine, const char format[], ...) {\r
218 \r
219    va_list arg_list;\r
220    char string[StringSize];\r
221 \r
222    ASSERT(engine_is_ok(engine));\r
223    ASSERT(format!=NULL);\r
224 \r
225    // format\r
226 \r
227    va_start(arg_list,format);\r
228    vsprintf(string,format,arg_list);\r
229    va_end(arg_list);\r
230 \r
231    // send\r
232 \r
233    io_send_queue(engine->io,"%s",string);\r
234 }\r
235 \r
236 // my_close()\r
237 \r
238 static void my_close(int fd) {\r
239 \r
240    ASSERT(fd>=0);\r
241 \r
242    if (close(fd) == -1) my_fatal("my_close(): close(): %s\n",strerror(errno));\r
243 }\r
244 \r
245 // my_dup2()\r
246 \r
247 static void my_dup2(int old_fd, int new_fd) {\r
248 \r
249    ASSERT(old_fd>=0);\r
250    ASSERT(new_fd>=0);\r
251 \r
252    if (dup2(old_fd,new_fd) == -1) my_fatal("my_dup2(): dup2(): %s\n",strerror(errno));\r
253 }\r
254 \r
255 // end of posix part\r
256 #else\r
257 \r
258 // WIN32 part\r
259 \r
260 // includes\r
261 \r
262 #include <stdlib.h>\r
263 #include <string.h>\r
264 #include <windows.h>\r
265 #include <direct.h>\r
266 \r
267 \r
268 \r
269 #include "engine.h"\r
270 #include "option.h"\r
271 #include "pipe.h"\r
272 #include "posix.h"\r
273 \r
274 // constants\r
275 \r
276 static const int StringSize = 4096;\r
277 \r
278 // variables\r
279 \r
280 static int nQueuePtr = 0;\r
281 static char szQueueString[StringSize];\r
282 engine_t Engine[1];\r
283 \r
284 // functions\r
285 \r
286 DWORD GetWin32Priority(int nice)\r
287 {\r
288 /*\r
289 REALTIME_PRIORITY_CLASS     0x00000100\r
290 HIGH_PRIORITY_CLASS         0x00000080\r
291 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000\r
292 NORMAL_PRIORITY_CLASS       0x00000020\r
293 BELOW_NORMAL_PRIORITY_CLASS 0x00004000\r
294 IDLE_PRIORITY_CLASS         0x00000040\r
295 */\r
296         if (nice < -15) return 0x00000080;\r
297         if (nice < 0)   return 0x00008000;\r
298         if (nice == 0)  return 0x00000020;\r
299         if (nice < 15)  return 0x00004000;\r
300         return 0x00000040;\r
301 }\r
302 \r
303 \r
304 \r
305 void set_affinity(engine_t *engine, int affin){\r
306         if(affin==-1) return;\r
307     SetProcessAffinityMask((engine->pipeEngine).hProcess,affin);\r
308 }\r
309 \r
310 \r
311 \r
312 void engine_send_queue(engine_t * engine,const char *szFormat, ...) {\r
313   nQueuePtr += vsprintf(szQueueString + nQueuePtr, szFormat, (va_list) (&szFormat + 1));\r
314 }\r
315 \r
316 void engine_send(engine_t * engine, const char *szFormat, ...) {\r
317     vsprintf(szQueueString + nQueuePtr, szFormat, (va_list) (&szFormat + 1));\r
318     (engine->pipeEngine).LineOutput(szQueueString);\r
319     my_log("Adapter->Engine: %s\n",szQueueString);\r
320     nQueuePtr = 0;\r
321 }\r
322 \r
323 void engine_close(engine_t * engine){\r
324     (engine->pipeEngine).Close();\r
325 }\r
326 \r
327 \r
328 void engine_open(engine_t * engine){\r
329    int affinity;\r
330     char *my_dir;\r
331     if( (my_dir = _getcwd( NULL, 0 )) == NULL )\r
332         my_fatal("Can't build path: %s\n",strerror(errno));\r
333     SetCurrentDirectory(option_get_string("EngineDir"));\r
334     (engine->pipeEngine).Open(option_get_string("EngineCommand"));\r
335         //play with affinity (bad idea) \r
336     affinity=option_get_int("Affinity");\r
337     if(affinity!=-1) set_affinity(engine,affinity); //AAA\r
338         //lets go back\r
339     SetCurrentDirectory(my_dir);\r
340         // set a low priority\r
341     if (option_get_bool("UseNice")){\r
342           my_log("POLYGLOT Adjust Engine Piority\n");\r
343           SetPriorityClass((engine->pipeEngine).hProcess,\r
344                            GetWin32Priority(option_get_int("NiceValue")));\r
345     }\r
346     \r
347 }\r
348 \r
349 bool engine_get_non_blocking(engine_t * engine, char *szLineStr, int size){\r
350         if ((engine->pipeEngine).LineInput(szLineStr)) {\r
351         my_log("Engine->Adapter: %s\n",szLineStr);\r
352         return true;\r
353     } else {\r
354         szLineStr[0]='\0';\r
355         return false;\r
356     }\r
357 }\r
358 \r
359 void engine_get(engine_t * engine, char *szLineStr, int size){\r
360     bool data_available;\r
361     while(true){\r
362         data_available=engine_get_non_blocking(engine,szLineStr,size);\r
363         if(!data_available){\r
364             Idle();\r
365         }else{\r
366             break;\r
367         }\r
368     }\r
369 }\r
370 \r
371 \r
372 #endif\r