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