--- libaitcli/src/aitcli.c 2025/12/21 23:21:40 1.21.2.2 +++ libaitcli/src/aitcli.c 2025/12/23 23:11:13 1.21.2.3 @@ -3,7 +3,7 @@ * by Michael Pounov * * $Author: misho $ -* $Id: aitcli.c,v 1.21.2.2 2025/12/21 23:21:40 misho Exp $ +* $Id: aitcli.c,v 1.21.2.3 2025/12/23 23:11:13 misho Exp $ * ************************************************************************** The ELWIX and AITNET software is distributed under the following @@ -98,15 +98,37 @@ clrscrEOL(linebuffer_t * __restrict buf) } static inline void +rewindin(linebuffer_t * __restrict buf, int len) +{ + int ign __attribute__((unused)); + + if (buf) { + if (len == -1) + len = buf->line_posin; + while (len-- > 0) + ign = write(buf->line_out, K_CTRL_H, 1); + } +} + +static inline void +printfEOLin(linebuffer_t * __restrict buf) +{ + int ign __attribute__((unused)); + + if (buf) + ign = write(buf->line_out, buf->line_input, buf->line_lenin); +} + +static inline void printfEOL(linebuffer_t * __restrict buf, int len, int prompt) { int ign __attribute__((unused)); if (buf) { - if (prompt && buf->line_prompt) { - ign = write(buf->line_out, K_CR, 1); + ign = write(buf->line_out, K_CR, 1); + + if (prompt && buf->line_prompt) ign = write(buf->line_out, buf->line_prompt, buf->line_bol); - } ign = write(buf->line_out, buf->line_buf, len == -1 ? buf->line_eol - buf->line_bol : len); @@ -118,10 +140,9 @@ printfCR(linebuffer_t * __restrict buf, int prompt) { int ign __attribute__((unused)); - if (buf && prompt && buf->line_prompt) { - ign = write(buf->line_out, K_CR, 1); + ign = write(buf->line_out, K_CR, 1); + if (buf && prompt && buf->line_prompt) ign = write(buf->line_out, buf->line_prompt, buf->line_bol); - } } static inline void @@ -141,6 +162,36 @@ printfNL(linebuffer_t * __restrict buf, int prompt) // ------------------------------------------------------------ static int +bufCHARin(int idx, void * __restrict cli_buffer) +{ + linebuffer_t *buf = cli_buffer; + int pos; + int ign __attribute__((unused)); + + if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY) + return RETCODE_ERR; + + pos = buf->line_posin; + + if (buf->line_mode == LINEMODE_INS) + memmove(buf->line_input + pos + buf->line_inkeys[idx].key_len, buf->line_input + pos, + buf->line_lenin - buf->line_posin); + if (buf->line_mode == LINEMODE_INS || buf->line_posin == buf->line_lenin) + buf->line_lenin += buf->line_inkeys[idx].key_len; + buf->line_posin += buf->line_inkeys[idx].key_len; + + memcpy(buf->line_input + pos, buf->line_inkeys[idx].key_ch, buf->line_inkeys[idx].key_len); + buf->line_input[buf->line_lenin] = 0; + + if (buf->line_mode == LINEMODE_INS) { + rewindin(buf, buf->line_posin - buf->line_inkeys[idx].key_len); + printfEOLin(buf); + rewindin(buf, buf->line_lenin - buf->line_posin); + } + return RETCODE_OK; +} + +static int bufCHAR(int idx, void * __restrict cli_buffer) { linebuffer_t *buf = cli_buffer; @@ -174,6 +225,15 @@ bufCHAR(int idx, void * __restrict cli_buffer) } static int +bufEOLin(int idx, void * __restrict cli_buffer) +{ + if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY) + return RETCODE_ERR; + + return RETCODE_EOL; +} + +static int bufEOL(int idx, void * __restrict cli_buffer) { if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY) @@ -263,6 +323,22 @@ bufDOWN(int idx, void * __restrict cli_buffer) } static int +bufCLRin(int idx, void * __restrict cli_buffer) +{ + linebuffer_t *buf = cli_buffer; + + if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY) + return RETCODE_ERR; + + memset(buf->line_input, ' ', buf->line_lenin); + rewindin(buf, -1); + printfEOLin(buf); + rewindin(buf, -1); + cli_freeInput(cli_buffer); + return RETCODE_OK; +} + +static int bufCLR(int idx, void * __restrict cli_buffer) { if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY) @@ -333,6 +409,20 @@ bufMODE(int idx, void * __restrict cli_buffer) } static int +bufBEGINin(int idx, void * __restrict cli_buffer) +{ + linebuffer_t *buf = cli_buffer; + + if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY) + return RETCODE_ERR; + + rewindin(buf, -1); + buf->line_posin ^= buf->line_posin; + + return RETCODE_OK; +} + +static int bufBEGIN(int idx, void * __restrict cli_buffer) { linebuffer_t *buf = cli_buffer; @@ -347,6 +437,21 @@ bufBEGIN(int idx, void * __restrict cli_buffer) } static int +bufENDin(int idx, void * __restrict cli_buffer) +{ + linebuffer_t *buf = cli_buffer; + + if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY) + return RETCODE_ERR; + + rewindin(buf, -1); + printfEOLin(buf); + buf->line_posin = buf->line_lenin; + + return RETCODE_OK; +} + +static int bufEND(int idx, void * __restrict cli_buffer) { linebuffer_t *buf = cli_buffer; @@ -888,6 +993,28 @@ cli_resetHistory(linebuffer_t * __restrict cli_buffer) /* + * cli_freeInput() - Clear entire input + * + * @cli_buffer = CLI buffer + * return: RETCODE_ERR error, RETCODE_OK ok +*/ +int +cli_freeInput(linebuffer_t * __restrict cli_buffer) +{ + int code = RETCODE_ERR; + + if (cli_buffer) { + memset(cli_buffer->line_input, 0, BUFSIZ); + cli_buffer->line_posin ^= cli_buffer->line_posin; + cli_buffer->line_lenin ^= cli_buffer->line_lenin; + + code = RETCODE_OK; + } else + cli_SetErr(EINVAL, "Invalid input parameters ..."); + + return code; +} +/* * cli_freeLine() - Clear entire line * * @cli_buffer = CLI buffer @@ -899,18 +1026,11 @@ cli_freeLine(linebuffer_t * __restrict cli_buffer) int code = RETCODE_ERR; if (cli_buffer) { - if (cli_buffer->line_buf) - e_free(cli_buffer->line_buf); + memset(cli_buffer->line_buf, 0, BUFSIZ); + cli_buffer->line_eol = cli_buffer->line_bol; + cli_buffer->line_len = 1 + cli_buffer->line_eol; - cli_buffer->line_buf = e_malloc(BUFSIZ); - if (cli_buffer->line_buf) { - memset(cli_buffer->line_buf, 0, BUFSIZ); - cli_buffer->line_eol = cli_buffer->line_bol; - cli_buffer->line_len = 1 + cli_buffer->line_eol; - - code = RETCODE_OK; - } else - LOGERR; + code = RETCODE_OK; } else cli_SetErr(EINVAL, "Invalid input parameters ..."); @@ -1044,11 +1164,24 @@ cliInit(int fin, int fout, const char *prompt) memset(cli_buffer->line_buf, 0, BUFSIZ); cli_buffer->line_len = 1 + cli_buffer->line_eol; } + cli_buffer->line_input = e_malloc(BUFSIZ); + if (!cli_buffer->line_input) { + LOGERR; + if (cli_buffer->line_prompt) + e_free(cli_buffer->line_prompt); + e_free(cli_buffer->line_buf); + e_free(cli_buffer); + return NULL; + } else { + memset(cli_buffer->line_input, 0, BUFSIZ); + cli_buffer->line_lenin = cli_buffer->line_posin; + } keys = e_calloc(MAX_BINDKEY + 1, sizeof(bindkey_t)); if (!keys) { LOGERR; if (cli_buffer->line_prompt) e_free(cli_buffer->line_prompt); + e_free(cli_buffer->line_input); e_free(cli_buffer->line_buf); e_free(cli_buffer); return NULL; @@ -1060,6 +1193,7 @@ cliInit(int fin, int fout, const char *prompt) e_free(keys); if (cli_buffer->line_prompt) e_free(cli_buffer->line_prompt); + e_free(cli_buffer->line_input); e_free(cli_buffer->line_buf); e_free(cli_buffer); return NULL; @@ -1086,24 +1220,38 @@ cliInit(int fin, int fout, const char *prompt) if (!i || i == *K_CTRL_D) keys[i].key_func = bufEOF; - if (i == *K_CTRL_M || i == *K_CTRL_J) + if (i == *K_CTRL_M || i == *K_CTRL_J) { keys[i].key_func = bufEOL; + inkeys[i].key_func = bufEOLin; + } if (cli_buffer->line_prompt && (i == *K_CTRL_H || i == *K_BACKSPACE)) keys[i].key_func = bufBS; - if (i == *K_CTRL_C) + if (i == *K_CTRL_C) { keys[i].key_func = bufCLR; - if (cli_buffer->line_prompt && i == *K_CTRL_A) - keys[i].key_func = bufBEGIN; - if (cli_buffer->line_prompt && i == *K_CTRL_E) - keys[i].key_func = bufEND; + inkeys[i].key_func = bufCLRin; + } + if (i == *K_CTRL_A) { + if (cli_buffer->line_prompt) + keys[i].key_func = bufBEGIN; + inkeys[i].key_func = bufBEGINin; + } + if (i == *K_CTRL_E) { + if (cli_buffer->line_prompt) + keys[i].key_func = bufEND; + inkeys[i].key_func = bufENDin; + } if (cli_buffer->line_prompt && i == *K_TAB) keys[i].key_func = bufComp; if (i == *K_CTRL_Z) keys[i].key_func = bufEndNode; - if (i >= *K_SPACE && i < *K_BACKSPACE) + if (i >= *K_SPACE && i < *K_BACKSPACE) { keys[i].key_func = bufCHAR; - if (i > *K_BACKSPACE && i < 0xff) + inkeys[i].key_func = bufCHARin; + } + if (i > *K_BACKSPACE && i < 0xff) { keys[i].key_func = bufCHAR; + inkeys[i].key_func = bufCHARin; + } if (cli_buffer->line_prompt && i == '?') keys[i].key_func = bufHelp; } @@ -1419,52 +1567,108 @@ cliReadLine(linebuffer_t * __restrict cli_buffer, int printfCR(cli_buffer, 1); while (42) { if ((ret = poll(&fds, 1, timeout)) < 1) { - if (!ret) { + if (!ret) cli_buffer->line_kill = 1; - if (str) { - e_free(str); - str = NULL; - } - } else + else LOGERR; - return str; + return NULL; } memset(buf, 0, sizeof buf); - readLen = read(cli_buffer->line_in, buf, BUFSIZ); + readLen = read(cli_buffer->line_in, buf, sizeof buf - 1); if (readLen < 1) { if (readLen) LOGERR; return NULL; } -recheck: - for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--) - if (readLen >= cli_buffer->line_keys[i].key_len && - !memcmp(cli_buffer->line_keys[i].key_ch, buf, - cli_buffer->line_keys[i].key_len)) { - readLen -= cli_buffer->line_keys[i].key_len; - if (readLen) - memmove(buf, buf + cli_buffer->line_keys[i].key_len, readLen); - else - memset(buf, 0, cli_buffer->line_keys[i].key_len); + while (readLen) + for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--) + if (readLen >= cli_buffer->line_keys[i].key_len && + !memcmp(cli_buffer->line_keys[i].key_ch, buf, + cli_buffer->line_keys[i].key_len)) { + readLen -= cli_buffer->line_keys[i].key_len; + if (readLen) + memmove(buf, buf + cli_buffer->line_keys[i].key_len, readLen); + else + memset(buf, 0, cli_buffer->line_keys[i].key_len); - if (cli_buffer->line_keys[i].key_func) - if ((code = cli_buffer->line_keys[i].key_func(i, cli_buffer))) - readLen = 0; + if (cli_buffer->line_keys[i].key_func) + if ((code = cli_buffer->line_keys[i].key_func(i, cli_buffer))) + readLen = 0; + } - if (readLen) - goto recheck; - else - break; - } - if (code) break; } if (code != RETCODE_ERR && code != RETCODE_EOF && cli_buffer->line_buf) str = e_strdup(cli_buffer->line_buf); + return str; +} + +/* + * cliInputLine() - Input line from opened CLI session + * + * @cli_buffer = CLI buffer + * @timeout = Session timeout (-1 infinit) + * return: NULL if error or !=NULL readed line, must be e_free after use! +*/ +char * +cliInputLine(linebuffer_t * __restrict cli_buffer, int timeout) +{ + int code, readLen, ret; + register int i; + struct pollfd fds; + char buf[BUFSIZ], *str = NULL; + + if (!cli_buffer) { + cli_SetErr(EINVAL, "Invalid input parameters ..."); + return NULL; + } else if (timeout > 0) + timeout *= 1000; /* convert from sec to ms */ + + memset(&fds, 0, sizeof fds); + fds.fd = cli_buffer->line_in; + fds.events = POLLIN; + + while (42) { + if ((ret = poll(&fds, 1, timeout)) < 1) { + if (ret == -1) + LOGERR; + return NULL; + } + + memset(buf, 0, sizeof buf); + readLen = read(cli_buffer->line_in, buf, sizeof buf - 1); + if (readLen < 1) { + if (readLen) + LOGERR; + return NULL; + } + + while (readLen) + for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--) + if (readLen >= cli_buffer->line_inkeys[i].key_len && + !memcmp(cli_buffer->line_inkeys[i].key_ch, buf, + cli_buffer->line_inkeys[i].key_len)) { + readLen -= cli_buffer->line_inkeys[i].key_len; + if (readLen) + memmove(buf, buf + cli_buffer->line_inkeys[i].key_len, readLen); + else + memset(buf, 0, cli_buffer->line_inkeys[i].key_len); + + if (cli_buffer->line_inkeys[i].key_func) + if ((code = cli_buffer->line_inkeys[i].key_func(i, cli_buffer))) + readLen = 0; + } + + if (code) + break; + } + + if (code != RETCODE_ERR && code != RETCODE_EOF && cli_buffer->line_input) + str = e_strdup(cli_buffer->line_input); return str; }