* sim/ucsim/cmd.src/newcmdposix.cc, sim/ucsim/cmd.src/newcmdposixcl.h,
[fw/sdcc] / sim / ucsim / cmd.src / newcmdposix.cc
1 /*\r
2  * Simulator of microcontrollers (cmd.src/newcmdposix.cc)\r
3  *\r
4  * Copyright (C) 1999,99 Drotos Daniel, Talker Bt.\r
5  * Copyright (C) 2006, Borut Razem - borut.razem@siol.net\r
6  *\r
7  * To contact author send email to drdani@mazsola.iit.uni-miskolc.hu\r
8  *\r
9  */\r
10 \r
11 /* This file is part of microcontroller simulator: ucsim.\r
12 \r
13 UCSIM is free software; you can redistribute it and/or modify\r
14 it under the terms of the GNU General Public License as published by\r
15 the Free Software Foundation; either version 2 of the License, or\r
16 (at your option) any later version.\r
17 \r
18 UCSIM is distributed in the hope that it will be useful,\r
19 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
21 GNU General Public License for more details.\r
22 \r
23 You should have received a copy of the GNU General Public License\r
24 along with UCSIM; see the file COPYING.  If not, write to the Free\r
25 Software Foundation, 59 Temple Place - Suite 330, Boston, MA\r
26 02111-1307, USA. */\r
27 /*@1@*/\r
28 \r
29 #include "ddconfig.h"\r
30 \r
31 #include <stdio.h>\r
32 #include <errno.h>\r
33 #include <stdarg.h>\r
34 #include <stdlib.h>\r
35 #include <sys/types.h>\r
36 #include <sys/time.h>\r
37 #ifdef SOCKET_AVAIL\r
38 # include HEADER_SOCKET\r
39 # if defined HAVE_SYS_SOCKET_H\r
40 #  include <netinet/in.h>\r
41 #  include <arpa/inet.h>\r
42 #  include <netdb.h>\r
43 # endif\r
44 #endif\r
45 #if FD_HEADER_OK\r
46 # include HEADER_FD\r
47 #endif\r
48 #ifdef HAVE_UNISTD_H\r
49 # include <unistd.h>\r
50 #endif\r
51 #include "i_string.h"\r
52 \r
53 #include "cmdlexcl.h"\r
54 #include "cmdpars.h"\r
55 \r
56 // prj\r
57 #include "globals.h"\r
58 #include "utils.h"\r
59 \r
60 // sim\r
61 #include "simcl.h"\r
62 #include "argcl.h"\r
63 #include "appcl.h"\r
64 \r
65 // local\r
66 #include "newcmdposixcl.h"\r
67 \r
68 \r
69 /*\r
70  * Command console\r
71  *____________________________________________________________________________\r
72  */\r
73 \r
74 cl_console::cl_console(char *fin, char *fout, class cl_app *the_app)\r
75 {\r
76   FILE *f;\r
77 \r
78   app= the_app;\r
79   in= 0;\r
80   if (fin)\r
81     if (f= fopen(fin, "r"), in= f, !f)\r
82       fprintf(stderr, "Can't open `%s': %s\n", fin, strerror(errno));\r
83   out= 0;\r
84   if (fout)\r
85     if (f= fopen(fout, "w"), out= f, !f)\r
86       fprintf(stderr, "Can't open `%s': %s\n", fout, strerror(errno));\r
87   prompt= 0;\r
88   flags= CONS_NONE;\r
89   if (is_tty())\r
90     flags|= CONS_INTERACTIVE;\r
91   else\r
92     ;//fprintf(stderr, "Warning: non-interactive console\n");\r
93   rout= 0;\r
94   id= 0;\r
95   lines_printed= new cl_ustrings(100, 100, "console_cache");\r
96 }\r
97 \r
98 cl_console::cl_console(FILE *fin, FILE *fout, class cl_app *the_app)\r
99 {\r
100   app= the_app;\r
101   in = fin;\r
102   out= fout;\r
103   prompt= 0;\r
104   flags= CONS_NONE;\r
105   if (is_tty())\r
106     flags|= CONS_INTERACTIVE;\r
107   else\r
108     ;//fprintf(stderr, "Warning: non-interactive console\n");\r
109   rout= 0;\r
110   id= 0;\r
111   lines_printed= new cl_ustrings(100, 100, "console_cache");\r
112 }\r
113 \r
114 class cl_console *\r
115 cl_console::clone_for_exec(char *fin)\r
116 {\r
117   FILE *fi= 0, *fo= 0;\r
118 \r
119   if (!fin)\r
120     return(0);\r
121   if (fi= fopen(fin, "r"), !fi)\r
122     {\r
123       fprintf(stderr, "Can't open `%s': %s\n", fin, strerror(errno));\r
124       return(0);\r
125     }\r
126   if ((fo= fdopen(dup(fileno(out)), "a")) == 0)\r
127     {\r
128       fclose(fi);\r
129       fprintf(stderr, "Can't re-open output file: %s\n", strerror(errno));\r
130       return(0);\r
131     }\r
132   class cl_console *con= new cl_sub_console(this, fi, fo, app);\r
133   return(con);\r
134 }\r
135 \r
136 cl_console::~cl_console(void)\r
137 {\r
138   if (in)\r
139     fclose(in);\r
140   un_redirect();\r
141   if (out)\r
142     {\r
143       if (flags & CONS_PROMPT)\r
144         fprintf(out, "\n");\r
145       fflush(out);\r
146       fclose(out);\r
147     }\r
148   delete prompt_option;\r
149   delete null_prompt_option;\r
150   delete debug_option;\r
151 #ifdef SOCKET_AVAIL\r
152   /*  if (sock)\r
153     {\r
154       shutdown(sock, 2);\r
155       close(sock);\r
156       }*/\r
157 #endif\r
158 }\r
159 \r
160 \r
161 /*\r
162  * Output functions\r
163  */\r
164 \r
165 void\r
166 cl_console::redirect(char *fname, char *mode)\r
167 {\r
168   if ((rout= fopen(fname, mode)) == NULL)\r
169     dd_printf("Unable to open file '%s' for %s: %s\n",\r
170               fname, (mode[0]=='w')?"write":"append", strerror(errno));\r
171 }\r
172 \r
173 void\r
174 cl_console::un_redirect(void)\r
175 {\r
176   if (!rout)\r
177     return;\r
178   fclose(rout);\r
179   rout = NULL;\r
180 }\r
181 \r
182 int\r
183 cl_console::cmd_do_print(char *format, va_list ap)\r
184 {\r
185   int ret;\r
186   FILE *f = get_out();\r
187 \r
188   if (f)\r
189    {\r
190       ret= vfprintf(f, format, ap);\r
191       fflush(f);\r
192     }\r
193   else\r
194     ret = 0;\r
195 \r
196   return ret;\r
197 }\r
198 \r
199 /*\r
200  * Input functions\r
201  */\r
202 \r
203 char *\r
204 cl_console::read_line(void)\r
205 {\r
206   char *s= NULL;\r
207 \r
208 #ifdef HAVE_GETLINE\r
209   if (getline(&s, 0, in) < 0)\r
210     return(0);\r
211 #elif defined HAVE_GETDELIM\r
212   size_t n= 30;\r
213   s= (char *)malloc(n);\r
214   if (getdelim(&s, &n, '\n', in) < 0)\r
215     {\r
216       free(s);\r
217       return(0);\r
218     }\r
219 #elif defined HAVE_FGETS\r
220   s= (char *)malloc(300);\r
221   if (fgets(s, 300, in) == NULL)\r
222     {\r
223       free(s);\r
224       return(0);\r
225     }\r
226 #endif\r
227   s[strlen(s)-1]= '\0';\r
228   if (s[strlen(s)-1] == '\r')\r
229     s[strlen(s)-1]= '\0';\r
230   flags&= ~CONS_PROMPT;\r
231   return(s);\r
232 }\r
233 \r
234 \r
235 /*\r
236  * This console listen on a socket and can accept connection requests\r
237  */\r
238 #ifdef SOCKET_AVAIL\r
239 \r
240 cl_listen_console::cl_listen_console(int serverport, class cl_app *the_app)\r
241 {\r
242   app= the_app;\r
243   if ((sock= make_server_socket(serverport)) >= 0)\r
244     {\r
245       if (listen(sock, 10) < 0)\r
246         fprintf(stderr, "Listen on port %d: %s\n",\r
247                 serverport, strerror(errno));\r
248     }\r
249   in= out= rout= 0;\r
250 }\r
251 \r
252 int\r
253 cl_listen_console::proc_input(class cl_cmdset *cmdset)\r
254 {\r
255   int newsock;\r
256   ACCEPT_SOCKLEN_T size;\r
257   struct sockaddr_in sock_addr;\r
258   class cl_commander_base *cmd;\r
259   FILE *in, *out;\r
260 \r
261   cmd= app->get_commander();\r
262   size= sizeof(struct sockaddr);\r
263   newsock= accept(sock, (struct sockaddr*)&sock_addr, &size);\r
264   if (newsock < 0)\r
265     {\r
266       perror("accept");\r
267       return(0);\r
268     }\r
269   if (!(in= fdopen(newsock, "r")))\r
270     fprintf(stderr, "cannot open port for input\n");\r
271   if (!(out= fdopen(newsock, "w")))\r
272     fprintf(stderr, "cannot open port for output\n");\r
273   class cl_console_base *c= new cl_console(in, out, app);\r
274   c->flags|= CONS_INTERACTIVE;\r
275   cmd->add_console(c);\r
276   return(0);\r
277 }\r
278 \r
279 #endif /* SOCKET_AVAIL */\r
280 \r
281 \r
282 /*\r
283  * Sub-console\r
284  */\r
285 \r
286 cl_sub_console::cl_sub_console(class cl_console_base *the_parent,\r
287                                FILE *fin, FILE *fout, class cl_app *the_app):\r
288   cl_console(fin, fout, the_app)\r
289 {\r
290   parent= the_parent;\r
291 }\r
292 \r
293 cl_sub_console::~cl_sub_console(void)\r
294 {\r
295   class cl_commander_base *c= app->get_commander();\r
296 \r
297   if (parent && c)\r
298     {\r
299       c->activate_console(parent);\r
300     }\r
301 }\r
302 \r
303 int\r
304 cl_sub_console::init(void)\r
305 {\r
306   class cl_commander_base *c= app->get_commander();\r
307 \r
308   if (parent && c)\r
309     {\r
310       c->deactivate_console(parent);\r
311     }\r
312   cl_console::init();\r
313   flags|= CONS_ECHO;\r
314   return(0);\r
315 }\r
316 \r
317 \r
318 /*\r
319  * Command interpreter\r
320  *____________________________________________________________________________\r
321  */\r
322 \r
323 int\r
324 cl_commander::init(void)\r
325 {\r
326   class cl_optref console_on_option(this);\r
327   class cl_optref config_file_option(this);\r
328   class cl_optref port_number_option(this);\r
329   class cl_console_base *con;\r
330 \r
331   console_on_option.init();\r
332   console_on_option.use("console_on");\r
333   config_file_option.init();\r
334   config_file_option.use("config_file");\r
335   port_number_option.init();\r
336 \r
337   cl_base::init();\r
338   set_name("Commander");\r
339 \r
340   bool need_config= DD_TRUE;\r
341 \r
342 #ifdef SOCKET_AVAIL\r
343   if (port_number_option.use("port_number"))\r
344     add_console(new cl_listen_console(port_number_option.get_value((long)0), app));\r
345 #endif\r
346 \r
347   /* The following code is commented out because it produces gcc warnings\r
348    * newcmd.cc: In member function `virtual int cl_commander::init()':\r
349    * newcmd.cc:785: warning: 'Config' might be used uninitialized in this function\r
350    * newcmd.cc:786: warning: 'cn' might be used uninitialized in this function\r
351    */\r
352   /*\r
353   char *Config= config_file_option.get_value(Config);\r
354   char *cn= console_on_option.get_value(cn);\r
355    */\r
356   /* Here shoud probably be something else, but is still better then the former code... */\r
357   char *Config= config_file_option.get_value("");\r
358   char *cn= console_on_option.get_value("");\r
359 \r
360   if (cn)\r
361     {\r
362       add_console(con= new cl_console(cn, cn, app));\r
363       exec_on(con, Config);\r
364       need_config= DD_FALSE;\r
365     }\r
366   if (cons->get_count() == 0)\r
367     {\r
368       add_console(con= new cl_console(stdin, stdout, app));\r
369       exec_on(con, Config);\r
370       need_config= DD_FALSE;\r
371     }\r
372   if (need_config &&\r
373       Config &&\r
374       *Config)\r
375     {\r
376       FILE *fc= fopen(Config, "r");\r
377       if (!fc)\r
378         fprintf(stderr, "Can't open `%s': %s\n", Config, strerror(errno));\r
379       else\r
380         {\r
381           con= new cl_console(fc, stderr, app);\r
382           con->flags|= CONS_NOWELCOME|CONS_ECHO;\r
383           add_console(con);\r
384         }\r
385     }\r
386   return(0);\r
387 }\r
388 \r
389 void\r
390 cl_commander::set_fd_set(void)\r
391 {\r
392   int i;\r
393 \r
394   FD_ZERO(&read_set);\r
395   fd_num = 0;\r
396   for (i = 0; i < cons->count; i++)\r
397     {\r
398       class cl_console *c= dynamic_cast<class cl_console*>((class cl_console_base*)(cons->at(i)));\r
399 \r
400       if (c->input_active())\r
401         {\r
402           UCSOCKET_T fd = c->get_in_fd();\r
403           assert(0 <= fd);\r
404 \r
405           FD_SET(fd, &read_set);\r
406           if (fd > fd_num)\r
407             fd_num = fd;\r
408         }\r
409     }\r
410   fd_num++;\r
411 }\r
412 \r
413 int\r
414 cl_commander::input_avail(void)\r
415 {\r
416   struct timeval tv = {0, 0};\r
417   active_set = read_set;\r
418 \r
419   int i = select(fd_num, &active_set, NULL, NULL, &tv);\r
420   if (i < 0)\r
421     perror("select");\r
422 \r
423   return i;\r
424 }\r
425 \r
426 int\r
427 cl_commander::wait_input(void)\r
428 {\r
429   prompt();\r
430   active_set = read_set;\r
431   int i = select(fd_num, &active_set, NULL, NULL, NULL);\r
432   return i;\r
433 }\r
434 \r
435 int\r
436 cl_commander::proc_input(void)\r
437 {\r
438   for (int j = 0; j < cons->count; j++)\r
439     {\r
440       class cl_console *c = dynamic_cast<class cl_console*>((class cl_console_base*)(cons->at(j)));\r
441 \r
442       if (c->input_active())\r
443         {\r
444           UCSOCKET_T fd = c->get_in_fd();\r
445           assert(0 <= fd);\r
446 \r
447           if (FD_ISSET(fd, &active_set))\r
448             {\r
449               actual_console = c;\r
450               int retval = c->proc_input(cmdset);\r
451               if (retval)\r
452                 {\r
453                   del_console(c);\r
454                   delete c;\r
455                 }\r
456               actual_console = 0;\r
457               return(0 == cons->count);\r
458             }\r
459         }\r
460     }\r
461   return 0;\r
462 }\r
463 \r
464 \r
465 /* End of cmd.src/newcmdposix.cc */\r