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