Imported Upstream version 2.9.0
[debian/cc1111] / sim / ucsim / cmd.src / newcmdwin32.cc
1 /*
2  * Simulator of microcontrollers (cmd.src/newcmdwin32.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 #include <assert.h>
38 #include <fcntl.h>
39 #include <windows.h>
40
41 #include "i_string.h"
42
43 #include "cmdlexcl.h"
44 #include "cmdpars.h"
45
46 // prj
47 #include "globals.h"
48 #include "utils.h"
49
50 // sim
51 #include "simcl.h"
52 #include "argcl.h"
53 #include "appcl.h"
54
55 // local
56 #include "newcmdwin32cl.h"
57
58
59 /*
60  * Channel
61  *____________________________________________________________________________
62  */
63
64 inline void
65 cl_channel::set(void)
66 {
67   fp = 0;
68   handle = INVALID_HANDLE_VALUE;
69   type = CH_UNDEF;
70 }
71
72 inline void
73 cl_channel::set(HANDLE _handle, e_handle_type _type)
74 {
75   assert(INVALID_HANDLE_VALUE != _handle);
76
77   fp = 0;
78   handle = _handle;
79   type = (_type == CH_UNDEF) ? guess_type() : _type;
80 }
81
82 inline void
83 cl_channel::set(FILE *_fp, e_handle_type _type)
84 {
85   assert(_fp);
86   fp = _fp;
87   handle = (HANDLE)_get_osfhandle(fileno(fp));
88   assert(INVALID_HANDLE_VALUE != handle);
89   type = (_type == CH_UNDEF) ? guess_type() : _type;
90 }
91
92 void
93 cl_channel::close(void)
94 {
95   assert(INVALID_HANDLE_VALUE != handle);
96
97   if (CH_SOCKET == type)
98     {
99       shutdown((SOCKET)handle, SD_BOTH);
100       closesocket((SOCKET)handle);
101     }
102   if (fp)
103     fclose(fp);
104   else if (CH_SOCKET != type)
105     CloseHandle(handle);
106
107   fp = 0;
108   handle = INVALID_HANDLE_VALUE;
109   type = CH_UNDEF;
110 }
111
112 /*
113  * Command console
114  *____________________________________________________________________________
115  */
116
117 cl_console::cl_console(const char *fin, const char *fout, class cl_app *the_app)
118 {
119   FILE *f;
120
121   app = the_app;
122   if (fin)
123     {
124       if (!(f = fopen(fin, "r")))
125         fprintf(stderr, "Can't open `%s': %s\n", fin, strerror(errno));
126       in.set(f, CH_FILE);
127     }
128
129   if (fout)
130     {
131       if (!(f = fopen(fout, "w")))
132         fprintf(stderr, "Can't open `%s': %s\n", fout, strerror(errno));
133       out.set(f, CH_FILE);
134     }
135
136   prompt = 0;
137   flags = CONS_NONE;
138   if (in.is_tty())
139     flags |= CONS_INTERACTIVE;
140   else
141     ;//fprintf(stderr, "Warning: non-interactive console\n");
142   id = 0;
143   lines_printed = new cl_ustrings(100, 100, "console_cache");
144 }
145
146 cl_console::cl_console(FILE *fin, FILE *fout, class cl_app *the_app)
147 {
148   app = the_app;
149   in.set(fin);
150   out.set(fout);
151
152   prompt = 0;
153   flags = CONS_NONE;
154   if (in.is_tty())
155     flags |= CONS_INTERACTIVE;
156   else
157     ;//fprintf(stderr, "Warning: non-interactive console\n");
158   id = 0;
159   lines_printed = new cl_ustrings(100, 100, "console_cache");
160 }
161
162 cl_console::cl_console(cl_channel _in, cl_channel _out, class cl_app *the_app)
163 {
164   app = the_app;
165   in = _in;
166   out = _out;
167
168   prompt = 0;
169   flags = CONS_NONE;
170   if (in.is_tty())
171     flags |= CONS_INTERACTIVE;
172   else
173     ;//fprintf(stderr, "Warning: non-interactive console\n");
174   id = 0;
175   lines_printed= new cl_ustrings(100, 100, "console_cache");
176 }
177
178 class cl_console *
179 cl_console::clone_for_exec(char *fin)
180 {
181   FILE *fi;
182   if (!fin)
183     return 0;
184
185   if (!(fi = fopen(fin, "r")))
186     {
187       fprintf(stderr, "Can't open `%s': %s\n", fin, strerror(errno));
188       return 0;
189     }
190   cl_channel ch_in = cl_channel(fi, CH_FILE);
191   class cl_console *con= new cl_sub_console(this, ch_in, out, app);
192   return con;
193 }
194
195 cl_console::~cl_console(void)
196 {
197   if (CH_UNDEF != in.get_type())
198     in.close();
199   un_redirect();
200   if (CH_UNDEF != out.get_type())
201     {
202       if (flags & CONS_PROMPT)
203         dd_printf("\n");
204       out.close();
205     }
206   delete prompt_option;
207   delete null_prompt_option;
208   delete debug_option;
209 }
210
211
212 /*
213  * Output functions
214  */
215
216 void
217 cl_console::redirect(char *fname, char *mode)
218 {
219   FILE *fp = fopen(fname, mode);
220   if (!fp)
221     dd_printf("Unable to open file '%s' for %s: %s\n",
222       fname, (mode[0]=='w') ? "write" : "append", strerror(errno));
223   out.set(fp, CH_FILE);
224 }
225
226 void
227 cl_console::un_redirect(void)
228 {
229   if (CH_UNDEF != rout.get_type())
230     out.close();
231 }
232
233 int
234 cl_console::cmd_do_print(const char *format, va_list ap)
235 {
236   FILE *f = get_out()->get_fp();
237
238   if (f)
239    {
240       int ret = vfprintf(f, format, ap);
241       fflush(f);
242       return ret;
243     }
244   else
245     return 0;
246 }
247
248 /*
249  * Input functions
250  */
251
252 char *
253 cl_console::read_line(void)
254 {
255 #define BUF_LEN 1024
256
257   TRACE("%d-%s\n", get_id(), __PRETTY_FUNCTION__);
258
259   char *s = NULL;
260   FILE *fp = in.get_fp();
261   assert(fp);
262
263 #ifdef HAVE_GETLINE
264   if (getline(&s, 0, fp) < 0)
265     return(0);
266 #elif defined HAVE_GETDELIM
267   size_t n = BUF_LEN;
268   s = (char *)malloc(n);
269   if (getdelim(&s, &n, '\n', fp) < 0)
270     {
271       free(s);
272       return(0);
273     }
274 #elif defined HAVE_FGETS
275   s = (char *)malloc(BUF_LEN);
276   if (fgets(s, BUF_LEN, fp) == NULL)
277     {
278       free(s);
279       return(0);
280     }
281 #endif
282   s[strlen(s)-1]= '\0';
283   if (s[strlen(s)-1] == '\r')
284     s[strlen(s)-1]= '\0';
285   flags&= ~CONS_PROMPT;
286   return(s);
287 }
288
289
290 /*
291  * This console cl_listen_console on a socket and can accept connection requests
292  */
293
294 cl_listen_console::cl_listen_console(int serverport, class cl_app *the_app)
295 {
296   SOCKET sock;
297   app = the_app;
298
299   if (INVALID_SOCKET != (sock = make_server_socket(serverport)))
300     {
301       if (SOCKET_ERROR == listen(sock, 10))
302         fprintf(stderr, "Can't listen on port %d: %d\n", serverport, WSAGetLastError());
303     }
304   in.set((HANDLE)sock, CH_SOCKET);
305 }
306
307 int
308 cl_listen_console::proc_input(class cl_cmdset *cmdset)
309 {
310   class cl_commander_base *cmd = app->get_commander();
311
312   struct sockaddr_in sock_addr;
313   ACCEPT_SOCKLEN_T size = sizeof(struct sockaddr);
314   SOCKET newsock = accept((SOCKET)get_in_fd(), (struct sockaddr*)&sock_addr, &size);
315
316   if (INVALID_SOCKET == newsock)
317     {
318       fprintf(stderr, "Can't accept: %d\n", WSAGetLastError());
319       return(0);
320     }
321
322   int fh = _open_osfhandle((intptr_t)newsock, _O_TEXT);
323   if (-1 == fh)
324     {
325       fprintf(stderr, "Can't _open_osfhandle\n");
326     }
327   FILE *fp = fdopen(fh, "r");
328   if (!fp)
329     fprintf(stderr, "Can't open port for input\n");
330   cl_channel ch_in = cl_channel(fp, CH_SOCKET);
331
332   fh = _open_osfhandle((intptr_t)newsock, _O_TEXT);
333   if (-1 == fh)
334     {
335       fprintf(stderr, "Can't _open_osfhandle\n");
336     }
337   fp = fdopen(fh, "w");
338   if (!fp)
339     fprintf(stderr, "Can't open port for output\n");
340   cl_channel ch_out = cl_channel(fp, CH_SOCKET);
341
342   class cl_console_base *c = new cl_console(ch_in, ch_out, app);
343   c->flags |= CONS_INTERACTIVE;
344   cmd->add_console(c);
345
346   return 0;
347 }
348
349
350 /*
351  * Sub-console
352  */
353
354 cl_sub_console::cl_sub_console(class cl_console_base *the_parent,
355   cl_channel _in, cl_channel _out, class cl_app *the_app):
356   cl_console(_in, _out, the_app)
357 {
358   parent = the_parent;
359 }
360
361 cl_sub_console::~cl_sub_console(void)
362 {
363   class cl_commander_base *c = app->get_commander();
364
365   if (parent && c)
366     {
367       c->activate_console(parent);
368     }
369 }
370
371 int
372 cl_sub_console::init(void)
373 {
374   class cl_commander_base *c = app->get_commander();
375
376   if (parent && c)
377     {
378       c->deactivate_console(parent);
379     }
380   cl_console::init();
381   flags |= CONS_ECHO;
382   return 0;
383 }
384
385
386 /*
387  * Command interpreter
388  *____________________________________________________________________________
389  */
390
391 int
392 cl_commander::init(void)
393 {
394   TRACE("%s\n", __PRETTY_FUNCTION__);
395
396   class cl_optref console_on_option(this);
397   class cl_optref config_file_option(this);
398   class cl_optref port_number_option(this);
399   class cl_console_base *con;
400
401   console_on_option.init();
402   console_on_option.use("console_on");
403   config_file_option.init();
404   config_file_option.use("config_file");
405   port_number_option.init();
406
407   cl_base::init();
408   set_name("Commander");
409
410   bool need_config = DD_TRUE;
411
412   if (port_number_option.use("port_number"))
413     add_console(new cl_listen_console(port_number_option.get_value((long)0), app));
414
415   /* The following code is commented out because it produces gcc warnings
416    * newcmd.cc: In member function `virtual int cl_commander::init()':
417    * newcmd.cc:785: warning: 'Config' might be used uninitialized in this function
418    * newcmd.cc:786: warning: 'cn' might be used uninitialized in this function
419    */
420   /*
421   char *Config= config_file_option.get_value(Config);
422   char *cn= console_on_option.get_value(cn);
423    */
424   /* Here shoud probably be something else, but is still better then the former code... */
425   char *Config = config_file_option.get_value("");
426   char *cn = console_on_option.get_value("");
427
428   if (cn)
429     {
430       add_console(con = new cl_console(cn, cn, app));
431       exec_on(con, Config);
432       need_config = DD_FALSE;
433     }
434   if (cons->get_count() == 0)
435     {
436       add_console(con = new cl_console(stdin, stdout, app));
437       exec_on(con, Config);
438       need_config = DD_FALSE;
439     }
440   if (need_config && Config && *Config)
441     {
442       FILE *fc = fopen(Config, "r");
443       if (!fc)
444         fprintf(stderr, "Can't open `%s': %s\n", Config, strerror(errno));
445       else
446         {
447           con = new cl_console(fc, stderr, app);
448           con->flags |= CONS_NOWELCOME | CONS_ECHO;
449           add_console(con);
450         }
451     }
452   return(0);
453 }
454
455 void
456 cl_commander::set_fd_set(void)
457 {
458   TRACE("%s\n", __PRETTY_FUNCTION__);
459
460   int i;
461
462   FD_ZERO(&read_set);
463
464   for (i = 0; i < cons->count; i++)
465     {
466       class cl_console *c= dynamic_cast<class cl_console*>((class cl_console_base*)(cons->at(i)));
467
468       if (c->input_active() && CH_SOCKET == c->in.get_type())
469         {
470           HANDLE fd = c->get_in_fd();
471           assert(INVALID_HANDLE_VALUE != fd);
472
473           FD_SET((SOCKET)fd, &read_set);
474         }
475     }
476 }
477
478 int
479 cl_commander::console_count(void)
480 {
481   int i = 0;
482
483   for (int j = 0; j < cons->count; j++)
484     {
485       class cl_console *c = dynamic_cast<class cl_console*>((class cl_console_base*)(cons->at(j)));
486
487       if (c->input_active())
488         {
489           switch (c->in.get_type())
490             {
491             case CH_CONSOLE:
492             case CH_FILE:
493             case CH_SERIAL:
494               ++i;
495               break;
496
497             default:
498               break;
499             }
500         }
501     }
502
503   return i;
504 }
505
506 int
507 cl_commander::console_input_avail(void)
508 {
509   int i = 0;
510
511   FD_ZERO(&console_active_set);
512   for (int j = 0; j < cons->count; j++)
513     {
514       class cl_console *c = dynamic_cast<class cl_console*>((class cl_console_base*)(cons->at(j)));
515
516       if (c->input_avail())
517         {
518           HANDLE fd = c->get_in_fd();
519           assert(INVALID_HANDLE_VALUE != fd);
520
521           switch (c->in.get_type())
522             {
523             case CH_CONSOLE:
524             case CH_FILE:
525             case CH_SERIAL:
526               FD_SET((SOCKET)fd, &console_active_set);
527               ++i;
528               break;
529
530             default:
531               break;
532             }
533         }
534     }
535
536   return i;
537 }
538
539 int
540 cl_commander::socket_input_avail(long timeout, bool sleep)
541 {
542   active_set = read_set;
543
544   if (active_set.fd_count)
545     {
546       struct timeval tv = {0, 0};
547
548       struct timeval *tvp = sleep ? NULL : &tv;
549
550       int i = select(0, &active_set, NULL, NULL, tvp);
551       if (SOCKET_ERROR == i)
552         {
553           fprintf(stderr, "Can't select: %d\n", WSAGetLastError());
554           return 0;
555         }
556
557       return i;
558     }
559   else
560     {
561       Sleep(timeout / 1000);
562       return 0;
563     }
564 }
565
566 int
567 cl_commander::input_avail_timeout(long timeout)
568 {
569   TRACE("%s\n", __PRETTY_FUNCTION__);
570
571   int n;
572   if (0 != (n = console_input_avail()))
573     FD_ZERO(&active_set);
574   else
575         n = socket_input_avail(timeout, false);
576
577   return n;
578 }
579
580 #define CONSOLE_TIMEOUT 300000
581
582 int
583 cl_commander::wait_input(void)
584 {
585   TRACE("%s\n", __PRETTY_FUNCTION__);
586
587   prompt();
588
589   if (0 < console_count())
590     {
591       int n;
592
593       while (0 == (n = input_avail_timeout(CONSOLE_TIMEOUT)))
594         ;
595
596       return n;
597     }
598   else
599     {
600       FD_ZERO(&console_active_set);
601       return socket_input_avail(0, true);
602     }
603 }
604
605 int
606 cl_commander::proc_input(void)
607 {
608   TRACE("%s\n", __PRETTY_FUNCTION__);
609
610   for (int j = 0; j < cons->count; j++)
611     {
612       class cl_console *c = dynamic_cast<class cl_console*>((class cl_console_base*)(cons->at(j)));
613
614       if (c->input_active())
615         {
616           HANDLE fd = c->get_in_fd();
617           assert(INVALID_HANDLE_VALUE != fd);
618
619           if (FD_ISSET(fd, &active_set) || FD_ISSET(fd, &console_active_set))
620             {
621               actual_console = c;
622               if (c->proc_input(cmdset))
623                 {
624                   del_console(c);
625                   delete c;
626                 }
627               actual_console = 0;
628               return 0 == cons->count;
629             }
630         }
631     }
632   return 0;
633 }
634
635
636 /* End of cmd.src/newcmdwin32.cc */