+/*\r
+ * Simulator of microcontrollers (cmd.src/newcmdwin32.cc)\r
+ *\r
+ * Copyright (C) 1999,99 Drotos Daniel, Talker Bt.\r
+ * Copyright (C) 2006, Borut Razem - borut.razem@siol.net\r
+ *\r
+ * To contact author send email to drdani@mazsola.iit.uni-miskolc.hu\r
+ *\r
+ */\r
+\r
+/* This file is part of microcontroller simulator: ucsim.\r
+\r
+UCSIM is free software; you can redistribute it and/or modify\r
+it under the terms of the GNU General Public License as published by\r
+the Free Software Foundation; either version 2 of the License, or\r
+(at your option) any later version.\r
+\r
+UCSIM is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with UCSIM; see the file COPYING. If not, write to the Free\r
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA\r
+02111-1307, USA. */\r
+/*@1@*/\r
+\r
+#include "ddconfig.h"\r
+\r
+#include <stdio.h>\r
+#include <errno.h>\r
+#include <stdarg.h>\r
+#include <stdlib.h>\r
+#include <sys/types.h>\r
+#include <sys/time.h>\r
+#include <assert.h>\r
+#include <fcntl.h>\r
+#include <windows.h>\r
+\r
+#include "i_string.h"\r
+\r
+#include "cmdlexcl.h"\r
+#include "cmdpars.h"\r
+\r
+// prj\r
+#include "globals.h"\r
+#include "utils.h"\r
+\r
+// sim\r
+#include "simcl.h"\r
+#include "argcl.h"\r
+#include "appcl.h"\r
+\r
+// local\r
+#include "newcmdwin32cl.h"\r
+\r
+\r
+/*\r
+ * Channel\r
+ *____________________________________________________________________________\r
+ */\r
+\r
+inline void\r
+cl_channel::set(void)\r
+{\r
+ fp = 0;\r
+ handle = INVALID_HANDLE_VALUE;\r
+ type = CH_UNDEF;\r
+}\r
+\r
+inline void\r
+cl_channel::set(HANDLE _handle, e_handle_type _type)\r
+{\r
+ assert(INVALID_HANDLE_VALUE != _handle);\r
+\r
+ fp = 0;\r
+ handle = _handle;\r
+ type = (_type == CH_UNDEF) ? guess_type() : _type;\r
+}\r
+\r
+inline void\r
+cl_channel::set(FILE *_fp, e_handle_type _type)\r
+{\r
+ assert(_fp);\r
+ fp = _fp;\r
+ handle = (HANDLE)_get_osfhandle(fileno(fp));\r
+ assert(INVALID_HANDLE_VALUE != handle);\r
+ type = (_type == CH_UNDEF) ? guess_type() : _type;\r
+}\r
+\r
+void\r
+cl_channel::close(void)\r
+{\r
+ assert(INVALID_HANDLE_VALUE != handle);\r
+\r
+ if (CH_SOCKET == type)\r
+ {\r
+ shutdown((SOCKET)handle, SD_BOTH);\r
+ closesocket((SOCKET)handle);\r
+ }\r
+ if (fp)\r
+ fclose(fp);\r
+ else if (CH_SOCKET != type)\r
+ CloseHandle(handle);\r
+\r
+ fp = 0;\r
+ handle = INVALID_HANDLE_VALUE;\r
+ type = CH_UNDEF;\r
+}\r
+\r
+/*\r
+ * Command console\r
+ *____________________________________________________________________________\r
+ */\r
+\r
+cl_console::cl_console(char *fin, char *fout, class cl_app *the_app)\r
+{\r
+ FILE *f;\r
+\r
+ app = the_app;\r
+ if (fin)\r
+ {\r
+ if (!(f = fopen(fin, "r")))\r
+ fprintf(stderr, "Can't open `%s': %s\n", fin, strerror(errno));\r
+ in.set(f, CH_FILE);\r
+ }\r
+\r
+ if (fout)\r
+ {\r
+ if (!(f = fopen(fout, "w")))\r
+ fprintf(stderr, "Can't open `%s': %s\n", fout, strerror(errno));\r
+ out.set(f, CH_FILE);\r
+ }\r
+\r
+ prompt = 0;\r
+ flags = CONS_NONE;\r
+ if (in.is_tty())\r
+ flags |= CONS_INTERACTIVE;\r
+ else\r
+ ;//fprintf(stderr, "Warning: non-interactive console\n");\r
+ id = 0;\r
+ lines_printed = new cl_ustrings(100, 100, "console_cache");\r
+}\r
+\r
+cl_console::cl_console(FILE *fin, FILE *fout, class cl_app *the_app)\r
+{\r
+ app = the_app;\r
+ in.set(fin);\r
+ out.set(fout);\r
+\r
+ prompt = 0;\r
+ flags = CONS_NONE;\r
+ if (in.is_tty())\r
+ flags |= CONS_INTERACTIVE;\r
+ else\r
+ ;//fprintf(stderr, "Warning: non-interactive console\n");\r
+ id = 0;\r
+ lines_printed = new cl_ustrings(100, 100, "console_cache");\r
+}\r
+\r
+cl_console::cl_console(cl_channel _in, cl_channel _out, class cl_app *the_app)\r
+{\r
+ app = the_app;\r
+ in = _in;\r
+ out = _out;\r
+\r
+ prompt = 0;\r
+ flags = CONS_NONE;\r
+ if (in.is_tty())\r
+ flags |= CONS_INTERACTIVE;\r
+ else\r
+ ;//fprintf(stderr, "Warning: non-interactive console\n");\r
+ id = 0;\r
+ lines_printed= new cl_ustrings(100, 100, "console_cache");\r
+}\r
+\r
+class cl_console *\r
+cl_console::clone_for_exec(char *fin)\r
+{\r
+ FILE *fi;\r
+ if (!fin)\r
+ return 0;\r
+\r
+ if (!(fi = fopen(fin, "r")))\r
+ {\r
+ fprintf(stderr, "Can't open `%s': %s\n", fin, strerror(errno));\r
+ return 0;\r
+ }\r
+ cl_channel ch_in = cl_channel(fi, CH_FILE);\r
+ class cl_console *con= new cl_sub_console(this, ch_in, out, app);\r
+ return con;\r
+}\r
+\r
+cl_console::~cl_console(void)\r
+{\r
+ if (CH_UNDEF != in.get_type())\r
+ in.close();\r
+ un_redirect();\r
+ if (CH_UNDEF != out.get_type())\r
+ {\r
+ if (flags & CONS_PROMPT)\r
+ dd_printf("\n");\r
+ out.close();\r
+ }\r
+ delete prompt_option;\r
+ delete null_prompt_option;\r
+ delete debug_option;\r
+}\r
+\r
+\r
+/*\r
+ * Output functions\r
+ */\r
+\r
+void\r
+cl_console::redirect(char *fname, char *mode)\r
+{\r
+ FILE *fp = fopen(fname, mode);\r
+ if (!fp)\r
+ dd_printf("Unable to open file '%s' for %s: %s\n",\r
+ fname, (mode[0]=='w') ? "write" : "append", strerror(errno));\r
+ out.set(fp, CH_FILE);\r
+}\r
+\r
+void\r
+cl_console::un_redirect(void)\r
+{\r
+ if (CH_UNDEF != rout.get_type())\r
+ out.close();\r
+}\r
+\r
+int\r
+cl_console::cmd_do_print(char *format, va_list ap)\r
+{\r
+ FILE *f = get_out()->get_fp();\r
+\r
+ if (f)\r
+ {\r
+ int ret = vfprintf(f, format, ap);\r
+ fflush(f);\r
+ return ret;\r
+ }\r
+ else\r
+ return 0;\r
+}\r
+\r
+/*\r
+ * Input functions\r
+ */\r
+\r
+char *\r
+cl_console::read_line(void)\r
+{\r
+#define BUF_LEN 1024\r
+\r
+ TRACE("%d-%s\n", get_id(), __PRETTY_FUNCTION__);\r
+\r
+ char *s = NULL;\r
+ FILE *fp = in.get_fp();\r
+ assert(fp);\r
+\r
+#ifdef HAVE_GETLINE\r
+ if (getline(&s, 0, fp) < 0)\r
+ return(0);\r
+#elif defined HAVE_GETDELIM\r
+ size_t n = BUF_LEN;\r
+ s = (char *)malloc(n);\r
+ if (getdelim(&s, &n, '\n', fp) < 0)\r
+ {\r
+ free(s);\r
+ return(0);\r
+ }\r
+#elif defined HAVE_FGETS\r
+ s = (char *)malloc(BUF_LEN);\r
+ if (fgets(s, BUF_LEN, fp) == NULL)\r
+ {\r
+ free(s);\r
+ return(0);\r
+ }\r
+#endif\r
+ s[strlen(s)-1]= '\0';\r
+ if (s[strlen(s)-1] == '\r')\r
+ s[strlen(s)-1]= '\0';\r
+ flags&= ~CONS_PROMPT;\r
+ return(s);\r
+}\r
+\r
+\r
+/*\r
+ * This console cl_listen_console on a socket and can accept connection requests\r
+ */\r
+\r
+cl_listen_console::cl_listen_console(int serverport, class cl_app *the_app)\r
+{\r
+ SOCKET sock;\r
+ app = the_app;\r
+\r
+ if (INVALID_SOCKET != (sock = make_server_socket(serverport)))\r
+ {\r
+ if (SOCKET_ERROR == listen(sock, 10))\r
+ fprintf(stderr, "Can't listen on port %d: %d\n", serverport, WSAGetLastError());\r
+ }\r
+ in.set((HANDLE)sock, CH_SOCKET);\r
+}\r
+\r
+int\r
+cl_listen_console::proc_input(class cl_cmdset *cmdset)\r
+{\r
+ class cl_commander_base *cmd = app->get_commander();\r
+\r
+ struct sockaddr_in sock_addr;\r
+ ACCEPT_SOCKLEN_T size = sizeof(struct sockaddr);\r
+ SOCKET newsock = accept((SOCKET)get_in_fd(), (struct sockaddr*)&sock_addr, &size);\r
+\r
+ if (INVALID_SOCKET == newsock)\r
+ {\r
+ fprintf(stderr, "Can't accept: %d\n", WSAGetLastError());\r
+ return(0);\r
+ }\r
+\r
+ int fh = _open_osfhandle((intptr_t)newsock, _O_TEXT);\r
+ if (-1 == fh)\r
+ {\r
+ fprintf(stderr, "Can't _open_osfhandle\n");\r
+ }\r
+ FILE *fp = fdopen(fh, "r");\r
+ if (!fp)\r
+ fprintf(stderr, "Can't open port for input\n");\r
+ cl_channel ch_in = cl_channel(fp, CH_SOCKET);\r
+\r
+ fh = _open_osfhandle((intptr_t)newsock, _O_TEXT);\r
+ if (-1 == fh)\r
+ {\r
+ fprintf(stderr, "Can't _open_osfhandle\n");\r
+ }\r
+ fp = fdopen(fh, "w");\r
+ if (!fp)\r
+ fprintf(stderr, "Can't open port for output\n");\r
+ cl_channel ch_out = cl_channel(fp, CH_SOCKET);\r
+\r
+ class cl_console_base *c = new cl_console(ch_in, ch_out, app);\r
+ c->flags |= CONS_INTERACTIVE;\r
+ cmd->add_console(c);\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+/*\r
+ * Sub-console\r
+ */\r
+\r
+cl_sub_console::cl_sub_console(class cl_console_base *the_parent,\r
+ cl_channel _in, cl_channel _out, class cl_app *the_app):\r
+ cl_console(_in, _out, the_app)\r
+{\r
+ parent = the_parent;\r
+}\r
+\r
+cl_sub_console::~cl_sub_console(void)\r
+{\r
+ class cl_commander_base *c = app->get_commander();\r
+\r
+ if (parent && c)\r
+ {\r
+ c->activate_console(parent);\r
+ }\r
+}\r
+\r
+int\r
+cl_sub_console::init(void)\r
+{\r
+ class cl_commander_base *c = app->get_commander();\r
+\r
+ if (parent && c)\r
+ {\r
+ c->deactivate_console(parent);\r
+ }\r
+ cl_console::init();\r
+ flags |= CONS_ECHO;\r
+ return 0;\r
+}\r
+\r
+\r
+/*\r
+ * Command interpreter\r
+ *____________________________________________________________________________\r
+ */\r
+\r
+int\r
+cl_commander::init(void)\r
+{\r
+ TRACE("%s\n", __PRETTY_FUNCTION__);\r
+\r
+ class cl_optref console_on_option(this);\r
+ class cl_optref config_file_option(this);\r
+ class cl_optref port_number_option(this);\r
+ class cl_console_base *con;\r
+\r
+ console_on_option.init();\r
+ console_on_option.use("console_on");\r
+ config_file_option.init();\r
+ config_file_option.use("config_file");\r
+ port_number_option.init();\r
+\r
+ cl_base::init();\r
+ set_name("Commander");\r
+\r
+ bool need_config = DD_TRUE;\r
+\r
+ if (port_number_option.use("port_number"))\r
+ add_console(new cl_listen_console(port_number_option.get_value((long)0), app));\r
+\r
+ /* The following code is commented out because it produces gcc warnings\r
+ * newcmd.cc: In member function `virtual int cl_commander::init()':\r
+ * newcmd.cc:785: warning: 'Config' might be used uninitialized in this function\r
+ * newcmd.cc:786: warning: 'cn' might be used uninitialized in this function\r
+ */\r
+ /*\r
+ char *Config= config_file_option.get_value(Config);\r
+ char *cn= console_on_option.get_value(cn);\r
+ */\r
+ /* Here shoud probably be something else, but is still better then the former code... */\r
+ char *Config = config_file_option.get_value("");\r
+ char *cn = console_on_option.get_value("");\r
+\r
+ if (cn)\r
+ {\r
+ add_console(con = new cl_console(cn, cn, app));\r
+ exec_on(con, Config);\r
+ need_config = DD_FALSE;\r
+ }\r
+ if (cons->get_count() == 0)\r
+ {\r
+ add_console(con = new cl_console(stdin, stdout, app));\r
+ exec_on(con, Config);\r
+ need_config = DD_FALSE;\r
+ }\r
+ if (need_config && Config && *Config)\r
+ {\r
+ FILE *fc = fopen(Config, "r");\r
+ if (!fc)\r
+ fprintf(stderr, "Can't open `%s': %s\n", Config, strerror(errno));\r
+ else\r
+ {\r
+ con = new cl_console(fc, stderr, app);\r
+ con->flags |= CONS_NOWELCOME | CONS_ECHO;\r
+ add_console(con);\r
+ }\r
+ }\r
+ return(0);\r
+}\r
+\r
+void\r
+cl_commander::set_fd_set(void)\r
+{\r
+ TRACE("%s\n", __PRETTY_FUNCTION__);\r
+\r
+ int i;\r
+\r
+ FD_ZERO(&read_set);\r
+\r
+ for (i = 0; i < cons->count; i++)\r
+ {\r
+ class cl_console *c= dynamic_cast<class cl_console*>((class cl_console_base*)(cons->at(i)));\r
+\r
+ if (c->input_active() && CH_SOCKET == c->in.get_type())\r
+ {\r
+ HANDLE fd = c->get_in_fd();\r
+ assert(INVALID_HANDLE_VALUE != fd);\r
+\r
+ FD_SET((SOCKET)fd, &read_set);\r
+ }\r
+ }\r
+}\r
+\r
+int\r
+cl_commander::console_count(void)\r
+{\r
+ int i = 0;\r
+\r
+ for (int j = 0; j < cons->count; j++)\r
+ {\r
+ class cl_console *c = dynamic_cast<class cl_console*>((class cl_console_base*)(cons->at(j)));\r
+\r
+ if (c->input_active())\r
+ {\r
+ switch (c->in.get_type())\r
+ {\r
+ case CH_CONSOLE:\r
+ case CH_FILE:\r
+ case CH_SERIAL:\r
+ ++i;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ return i;\r
+}\r
+\r
+int\r
+cl_commander::console_input_avail(void)\r
+{\r
+ int i = 0;\r
+\r
+ FD_ZERO(&console_active_set);\r
+ for (int j = 0; j < cons->count; j++)\r
+ {\r
+ class cl_console *c = dynamic_cast<class cl_console*>((class cl_console_base*)(cons->at(j)));\r
+\r
+ if (c->input_avail())\r
+ {\r
+ HANDLE fd = c->get_in_fd();\r
+ assert(INVALID_HANDLE_VALUE != fd);\r
+\r
+ switch (c->in.get_type())\r
+ {\r
+ case CH_CONSOLE:\r
+ case CH_FILE:\r
+ case CH_SERIAL:\r
+ FD_SET((SOCKET)fd, &console_active_set);\r
+ ++i;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ return i;\r
+}\r
+\r
+int\r
+cl_commander::socket_input_avail(long timeout, bool sleep)\r
+{\r
+ active_set = read_set;\r
+\r
+ if (active_set.fd_count)\r
+ {\r
+ struct timeval tv = {0, 0};\r
+\r
+ struct timeval *tvp = sleep ? NULL : &tv;\r
+\r
+ int i = select(0, &active_set, NULL, NULL, tvp);\r
+ if (SOCKET_ERROR == i)\r
+ {\r
+ fprintf(stderr, "Can't select: %d\n", WSAGetLastError());\r
+ return 0;\r
+ }\r
+\r
+ return i;\r
+ }\r
+ else\r
+ {\r
+ Sleep(timeout / 1000);\r
+ return 0;\r
+ }\r
+}\r
+\r
+int\r
+cl_commander::input_avail_timeout(long timeout)\r
+{\r
+ TRACE("%s\n", __PRETTY_FUNCTION__);\r
+\r
+ int n;\r
+ if (0 != (n = console_input_avail()))\r
+ FD_ZERO(&active_set);\r
+ else\r
+ n = socket_input_avail(timeout, false);\r
+\r
+ return n;\r
+}\r
+\r
+#define CONSOLE_TIMEOUT 300000\r
+\r
+int\r
+cl_commander::wait_input(void)\r
+{\r
+ TRACE("%s\n", __PRETTY_FUNCTION__);\r
+\r
+ prompt();\r
+\r
+ if (0 < console_count())\r
+ {\r
+ int n;\r
+\r
+ while (0 == (n = input_avail_timeout(CONSOLE_TIMEOUT)))\r
+ ;\r
+\r
+ return n;\r
+ }\r
+ else\r
+ {\r
+ FD_ZERO(&console_active_set);\r
+ return socket_input_avail(0, true);\r
+ }\r
+}\r
+\r
+int\r
+cl_commander::proc_input(void)\r
+{\r
+ TRACE("%s\n", __PRETTY_FUNCTION__);\r
+\r
+ for (int j = 0; j < cons->count; j++)\r
+ {\r
+ class cl_console *c = dynamic_cast<class cl_console*>((class cl_console_base*)(cons->at(j)));\r
+\r
+ if (c->input_active())\r
+ {\r
+ HANDLE fd = c->get_in_fd();\r
+ assert(INVALID_HANDLE_VALUE != fd);\r
+\r
+ if (FD_ISSET(fd, &active_set) || FD_ISSET(fd, &console_active_set))\r
+ {\r
+ actual_console = c;\r
+ if (c->proc_input(cmdset))\r
+ {\r
+ del_console(c);\r
+ delete c;\r
+ }\r
+ actual_console = 0;\r
+ return 0 == cons->count;\r
+ }\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+\r
+\r
+/* End of cmd.src/newcmdwin32.cc */\r