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