diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f419f6acb..531846e62 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -319,7 +319,7 @@ level, e.g.: } ``` -If the case bock does not break, then it is strongly recommended to add a +If the case block does not break, then it is strongly recommended to add a comment containing "fallthrough" to indicate it. Modern compilers can also be configured to require such comment (see gcc `-Wimplicit-fallthrough`). diff --git a/console.c b/console.c index 4470bbd27..3745c9666 100644 --- a/console.c +++ b/console.c @@ -405,6 +405,7 @@ static bool do_web(int argc, char *argv[]) web_fd = web_open(port); if (web_fd > 0) { printf("listen on port %d, fd is %d\n", port, web_fd); + line_set_eventmux_callback(web_eventmux); use_linenoise = false; } else { perror("ERROR"); @@ -560,13 +561,13 @@ static int cmd_select(int nfds, fd_set *exceptfds, struct timeval *timeout) { - int infd; fd_set local_readset; if (cmd_done()) return 0; if (!block_flag) { + int infd; /* Process any commands in input buffer */ if (!readfds) readfds = &local_readset; @@ -581,51 +582,18 @@ static int cmd_select(int nfds, FD_SET(web_fd, readfds); if (infd == STDIN_FILENO && prompt_flag) { - printf("%s", prompt); + char *cmdline = linenoise(prompt); + if (cmdline) + interpret_cmd(cmdline); fflush(stdout); prompt_flag = true; + } else if (infd != STDIN_FILENO) { + char *cmdline = readline(); + if (cmdline) + interpret_cmd(cmdline); } - - if (infd >= nfds) - nfds = infd + 1; - if (web_fd >= nfds) - nfds = web_fd + 1; - } - if (nfds == 0) - return 0; - - int result = select(nfds, readfds, writefds, exceptfds, timeout); - if (result <= 0) - return result; - - infd = buf_stack->fd; - if (readfds && FD_ISSET(infd, readfds)) { - /* Commandline input available */ - FD_CLR(infd, readfds); - result--; - - set_echo(0); - char *cmdline = readline(); - if (cmdline) - interpret_cmd(cmdline); - } else if (readfds && FD_ISSET(web_fd, readfds)) { - FD_CLR(web_fd, readfds); - result--; - struct sockaddr_in clientaddr; - socklen_t clientlen = sizeof(clientaddr); - web_connfd = - accept(web_fd, (struct sockaddr *) &clientaddr, &clientlen); - - char *p = web_recv(web_connfd, &clientaddr); - char *buffer = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n"; - web_send(web_connfd, buffer); - - if (p) - interpret_cmd(p); - free(p); - close(web_connfd); } - return result; + return 0; } bool finish_cmd() diff --git a/linenoise.c b/linenoise.c index aa1f362e8..69048e9e6 100644 --- a/linenoise.c +++ b/linenoise.c @@ -124,6 +124,7 @@ static char *unsupported_term[] = {"dumb", "cons25", "emacs", NULL}; static line_completion_callback_t *completion_callback = NULL; static line_hints_callback_t *hints_callback = NULL; static line_free_hints_callback_t *free_hints_callback = NULL; +static line_eventmux_callback_t *eventmux_callback = NULL; static struct termios orig_termios; /* In order to restore at exit.*/ static bool maskmode = false; /* Show "***" instead of input. For passwords. */ @@ -472,6 +473,20 @@ void line_set_free_hints_callback(line_free_hints_callback_t *fn) free_hints_callback = fn; } +/* Register a function to perform I/O multiplexing to monitor multiple file + * descriptor from different input at the same time, so we can allow the ability + * of receiving commands from different input sources and still provides the + * command-line auto-complete feature of this package. For example, the main + * loop of this package can only deal with standard input file descriptor + * originally. When this callback function is invoked, it allows the main loop + * of this package to deal with multiple file descriptors from different input + * alongside with the origin feature to deal with the standard input. + */ +void line_set_eventmux_callback(line_eventmux_callback_t *fn) +{ + eventmux_callback = fn; +} + /* This function is used by the callback function registered by the user * in order to add completion options given the input string when the * user typed . @@ -932,6 +947,12 @@ static int line_edit(int stdin_fd, int nread; char seq[5]; + if (eventmux_callback != NULL) { + int result = eventmux_callback(l.buf); + if (result != 0) + return result; + } + nread = read(l.ifd, &c, 1); if (nread <= 0) return l.len; diff --git a/linenoise.h b/linenoise.h index 4468e8bbd..0e61e125a 100644 --- a/linenoise.h +++ b/linenoise.h @@ -54,9 +54,11 @@ typedef struct { typedef void(line_completion_callback_t)(const char *, line_completions_t *); typedef char *(line_hints_callback_t)(const char *, int *color, int *bold); typedef void(line_free_hints_callback_t)(void *); +typedef int(line_eventmux_callback_t)(char *); void line_set_completion_callback(line_completion_callback_t *); void line_set_hints_callback(line_hints_callback_t *); void line_set_free_hints_callback(line_free_hints_callback_t *); +void line_set_eventmux_callback(line_eventmux_callback_t *); void line_add_completion(line_completions_t *, const char *); /* clang-format on */ diff --git a/queue.h b/queue.h index bbea8ec4d..09dd3adfb 100644 --- a/queue.h +++ b/queue.h @@ -239,9 +239,9 @@ int q_descend(struct list_head *head); * This function merge the second to the last queues in the chain into the first * queue. The queues are guaranteed to be sorted before this function is called. * No effect if there is only one queue in the chain. Allocation is disallowed - * in this function. There is no need to free the 'qcontext_t' and its member - * 'q' since they will be released externally. However, q_merge() is responsible - * for making the queues to be NULL-queue, except the first one. + * in this function. There is no need to free the 'queue_contex_t' and its + * member 'q' since they will be released externally. However, q_merge() is + * responsible for making the queues to be NULL-queue, except the first one. * * Reference: * https://leetcode.com/problems/merge-k-sorted-lists/ diff --git a/scripts/checksums b/scripts/checksums index 5effd9900..521c3774e 100644 --- a/scripts/checksums +++ b/scripts/checksums @@ -1,2 +1,2 @@ -fc83d2142cdebd29bf8dbf01d2c21c59f8c6a7ce queue.h +444bab14cb8ad4c949f61b3c10a22a3ed2401425 queue.h 3337dbccc33eceedda78e36cc118d5a374838ec7 list.h diff --git a/scripts/pre-commit.hook b/scripts/pre-commit.hook index f8467cc75..4f45a7628 100755 --- a/scripts/pre-commit.hook +++ b/scripts/pre-commit.hook @@ -5,6 +5,8 @@ for f in *.c; do CPPCHECK_unmatched="$CPPCHECK_unmatched --suppress=unmatchedSuppression:$f" done +# We suppress the checkLevelNormal warning for Cppcheck versions 2.11 and above. +# Please refer to issues/153 for more details. CPPCHECK_suppresses="--inline-suppr harness.c \ --suppress=missingIncludeSystem \ --suppress=noValidConfiguration \ diff --git a/web.c b/web.c index 0994a47f5..30b336276 100644 --- a/web.c +++ b/web.c @@ -23,6 +23,8 @@ #define TCP_CORK TCP_NOPUSH #endif +static int server_fd; + typedef struct { int fd; /* descriptor for this buf */ int count; /* unread byte in this buf */ @@ -153,6 +155,9 @@ int web_open(int port) /* Make it a listening socket ready to accept connection requests */ if (listen(listenfd, LISTENQ) < 0) return -1; + + server_fd = listenfd; + return listenfd; } @@ -228,3 +233,38 @@ char *web_recv(int fd, struct sockaddr_in *clientaddr) return ret; } + +int web_eventmux(char *buf) +{ + fd_set listenset; + + FD_ZERO(&listenset); + FD_SET(STDIN_FILENO, &listenset); + int max_fd = STDIN_FILENO; + if (server_fd > 0) { + FD_SET(server_fd, &listenset); + max_fd = max_fd > server_fd ? max_fd : server_fd; + } + int result = select(max_fd + 1, &listenset, NULL, NULL, NULL); + if (result < 0) + return -1; + + if (server_fd > 0 && FD_ISSET(server_fd, &listenset)) { + FD_CLR(server_fd, &listenset); + struct sockaddr_in clientaddr; + socklen_t clientlen = sizeof(clientaddr); + int web_connfd = + accept(server_fd, (struct sockaddr *) &clientaddr, &clientlen); + + char *p = web_recv(web_connfd, &clientaddr); + char *buffer = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n"; + web_send(web_connfd, buffer); + strncpy(buf, p, strlen(p) + 1); + free(p); + close(web_connfd); + return strlen(buf); + } + + FD_CLR(STDIN_FILENO, &listenset); + return 0; +} diff --git a/web.h b/web.h index b04bc179d..6b6b8ab04 100644 --- a/web.h +++ b/web.h @@ -9,4 +9,6 @@ char *web_recv(int fd, struct sockaddr_in *clientaddr); void web_send(int out_fd, char *buffer); +int web_eventmux(char *buf); + #endif