Annotation of libaitcli/src/aitcli.c, revision 1.19

1.1       misho       1: /*************************************************************************
                      2: * (C) 2010 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
                      3: *  by Michael Pounov <misho@openbsd-bg.org>
                      4: *
                      5: * $Author: misho $
1.19    ! misho       6: * $Id: aitcli.c,v 1.18.2.2 2022/12/05 22:19:33 misho Exp $
1.1       misho       7: *
1.4       misho       8: **************************************************************************
                      9: The ELWIX and AITNET software is distributed under the following
                     10: terms:
                     11: 
                     12: All of the documentation and software included in the ELWIX and AITNET
                     13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
                     14: 
1.18      misho      15: Copyright 2004 - 2022
1.4       misho      16:        by Michael Pounov <misho@elwix.org>.  All rights reserved.
                     17: 
                     18: Redistribution and use in source and binary forms, with or without
                     19: modification, are permitted provided that the following conditions
                     20: are met:
                     21: 1. Redistributions of source code must retain the above copyright
                     22:    notice, this list of conditions and the following disclaimer.
                     23: 2. Redistributions in binary form must reproduce the above copyright
                     24:    notice, this list of conditions and the following disclaimer in the
                     25:    documentation and/or other materials provided with the distribution.
                     26: 3. All advertising materials mentioning features or use of this software
                     27:    must display the following acknowledgement:
                     28: This product includes software developed by Michael Pounov <misho@elwix.org>
                     29: ELWIX - Embedded LightWeight unIX and its contributors.
                     30: 4. Neither the name of AITNET nor the names of its contributors
                     31:    may be used to endorse or promote products derived from this software
                     32:    without specific prior written permission.
                     33: 
                     34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
                     35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     37: ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     44: SUCH DAMAGE.
                     45: */
1.1       misho      46: #include "global.h"
1.3       misho      47: #include "cli.h"
1.1       misho      48: 
                     49: 
                     50: #pragma GCC visibility push(hidden)
                     51: 
                     52: int cli_Errno;
                     53: char cli_Error[STRSIZ];
                     54: 
1.3       misho      55: #pragma GCC visibility pop
                     56: 
                     57: // cli_GetErrno() Get error code of last operation
1.6       misho      58: int
1.3       misho      59: cli_GetErrno()
                     60: {
                     61:        return cli_Errno;
                     62: }
                     63: 
1.6       misho      64: // cli_GetError() Get error text of last operation
                     65: const char *
1.3       misho      66: cli_GetError()
                     67: {
                     68:        return cli_Error;
                     69: }
                     70: 
                     71: // cli_SetErr() Set error to variables for internal use!!!
1.6       misho      72: void
1.3       misho      73: cli_SetErr(int eno, char *estr, ...)
                     74: {
                     75:        va_list lst;
                     76: 
                     77:        cli_Errno = eno;
1.6       misho      78:        memset(cli_Error, 0, sizeof cli_Error);
1.3       misho      79:        va_start(lst, estr);
1.6       misho      80:        vsnprintf(cli_Error, sizeof cli_Error, estr, lst);
1.3       misho      81:        va_end(lst);
                     82: }
1.2       misho      83: 
1.3       misho      84: // ------------------------------------------------------------
                     85: 
                     86: static inline void
                     87: clrscrEOL(linebuffer_t * __restrict buf)
                     88: {
                     89:        register int i;
1.19    ! misho      90:        int ign __attribute__((unused));
1.3       misho      91: 
1.9       misho      92:        if (buf && buf->line_prompt) {
1.19    ! misho      93:                ign = write(buf->line_out, K_CR, 1);
1.1       misho      94: 
1.3       misho      95:                for (i = 0; i < buf->line_len; i++)
1.19    ! misho      96:                        ign = write(buf->line_out, K_SPACE, 1);
1.3       misho      97:        }
                     98: }
1.1       misho      99: 
1.3       misho     100: static inline void
                    101: printfEOL(linebuffer_t * __restrict buf, int len, int prompt)
1.2       misho     102: {
1.19    ! misho     103:        int ign __attribute__((unused));
        !           104: 
1.3       misho     105:        if (buf) {
1.9       misho     106:                if (prompt && buf->line_prompt) {
1.19    ! misho     107:                        ign = write(buf->line_out, K_CR, 1);
        !           108:                        ign = write(buf->line_out, buf->line_prompt, buf->line_bol);
1.9       misho     109:                }
1.3       misho     110: 
1.19    ! misho     111:                ign = write(buf->line_out, buf->line_buf, len == -1 ? 
1.13      misho     112:                                buf->line_eol - buf->line_bol : len);
1.3       misho     113:        }
1.2       misho     114: }
                    115: 
1.3       misho     116: static inline void
                    117: printfCR(linebuffer_t * __restrict buf, int prompt)
1.2       misho     118: {
1.19    ! misho     119:        int ign __attribute__((unused));
        !           120: 
1.9       misho     121:        if (buf && prompt && buf->line_prompt) {
1.19    ! misho     122:                ign = write(buf->line_out, K_CR, 1);
        !           123:                ign = write(buf->line_out, buf->line_prompt, buf->line_bol);
1.2       misho     124:        }
1.3       misho     125: }
                    126: 
                    127: static inline void
                    128: printfNL(linebuffer_t * __restrict buf, int prompt)
                    129: {
1.19    ! misho     130:        int ign __attribute__((unused));
        !           131: 
1.3       misho     132:        if (buf) {
1.19    ! misho     133:                ign = write(buf->line_out, K_ENTER, 1);
1.3       misho     134: 
                    135:                if (prompt)
                    136:                        if (prompt && buf->line_prompt)
1.19    ! misho     137:                                ign = write(buf->line_out, buf->line_prompt, buf->line_bol);
1.3       misho     138:        }
                    139: }
                    140: 
                    141: // ------------------------------------------------------------
                    142: 
                    143: static int
1.7       misho     144: bufCHAR(int idx, void * __restrict cli_buffer)
1.3       misho     145: {
1.7       misho     146:        linebuffer_t *buf = cli_buffer;
1.3       misho     147:        int pos;
1.19    ! misho     148:        int ign __attribute__((unused));
1.3       misho     149: 
1.7       misho     150:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     151:                return RETCODE_ERR;
                    152: 
                    153:        pos = buf->line_eol - buf->line_bol;
                    154: 
                    155:        if (buf->line_mode == LINEMODE_INS)
                    156:                memmove(buf->line_buf + pos + buf->line_keys[idx].key_len, buf->line_buf + pos, 
                    157:                                buf->line_len - buf->line_eol);
                    158:        if (buf->line_mode == LINEMODE_INS || buf->line_eol == buf->line_len - 1)
                    159:                buf->line_len += buf->line_keys[idx].key_len;
                    160:        buf->line_eol += buf->line_keys[idx].key_len;
                    161: 
                    162:        memcpy(buf->line_buf + pos, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
                    163:        buf->line_buf[buf->line_len - 1] = 0;
                    164: 
1.13      misho     165:        if (buf->line_prompt)
1.19    ! misho     166:                ign = write(buf->line_out, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
1.3       misho     167: 
                    168:        if (buf->line_mode == LINEMODE_INS) {
1.19    ! misho     169:                ign = write(buf->line_out, (const u_char*) buf->line_buf + pos + buf->line_keys[idx].key_len, 
1.3       misho     170:                                buf->line_len - buf->line_eol);
                    171:                printfEOL(buf, -1, 1);
1.2       misho     172:        }
1.3       misho     173:        return RETCODE_OK;
                    174: }
                    175: 
                    176: static int
1.7       misho     177: bufEOL(int idx, void * __restrict cli_buffer)
1.3       misho     178: {
1.7       misho     179:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     180:                return RETCODE_ERR;
                    181: 
1.7       misho     182:        printfCR(cli_buffer, 1);
1.3       misho     183:        return RETCODE_EOL;
                    184: }
                    185: 
                    186: static int
1.7       misho     187: bufEOF(int idx, void * __restrict cli_buffer)
1.3       misho     188: {
                    189:        /*
1.7       misho     190:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     191:                return RETCODE_ERR;
                    192:        */
                    193: 
                    194:        return RETCODE_EOF;
                    195: }
                    196: 
                    197: static int
1.7       misho     198: bufUP(int idx, void * __restrict cli_buffer)
1.3       misho     199: {
1.7       misho     200:        linebuffer_t *buf = cli_buffer;
1.3       misho     201:        int pos;
                    202: 
1.7       misho     203:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     204:                return RETCODE_ERR;
                    205: 
                    206:        if (!buf->line_h)
                    207:                buf->line_h = TAILQ_FIRST(&buf->line_history);
                    208:        else
                    209:                buf->line_h = TAILQ_NEXT(buf->line_h, hist_next);
                    210:        if (!buf->line_h)
                    211:                return RETCODE_OK;
                    212: 
                    213:        clrscrEOL(buf);
                    214:        cli_freeLine(buf);
                    215: 
                    216:        pos = buf->line_eol - buf->line_bol;
                    217: 
                    218:        buf->line_len += buf->line_h->hist_len;
                    219:        buf->line_eol += buf->line_h->hist_len;
                    220: 
                    221:        memcpy(buf->line_buf + pos, buf->line_h->hist_line, buf->line_h->hist_len);
                    222:        buf->line_buf[buf->line_len - 1] = 0;
                    223: 
                    224:        printfEOL(buf, -1, 1);
                    225:        return RETCODE_OK;
                    226: }
                    227: 
                    228: static int
1.7       misho     229: bufDOWN(int idx, void * __restrict cli_buffer)
1.3       misho     230: {
1.7       misho     231:        linebuffer_t *buf = cli_buffer;
1.3       misho     232:        int pos;
                    233: 
1.7       misho     234:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     235:                return RETCODE_ERR;
                    236: 
                    237:        if (!buf->line_h)
                    238:                buf->line_h = TAILQ_LAST(&buf->line_history, tqHistoryHead);
                    239:        else
                    240:                buf->line_h = TAILQ_PREV(buf->line_h, tqHistoryHead, hist_next);
                    241:        if (!buf->line_h)
                    242:                return RETCODE_OK;
                    243: 
                    244:        clrscrEOL(buf);
                    245:        cli_freeLine(buf);
                    246: 
                    247:        pos = buf->line_eol - buf->line_bol;
                    248: 
                    249:        buf->line_len += buf->line_h->hist_len;
                    250:        buf->line_eol += buf->line_h->hist_len;
                    251: 
                    252:        memcpy(buf->line_buf + pos, buf->line_h->hist_line, buf->line_h->hist_len);
                    253:        buf->line_buf[buf->line_len - 1] = 0;
                    254: 
                    255:        printfEOL(buf, -1, 1);
                    256:        return RETCODE_OK;
                    257: }
                    258: 
                    259: static int
1.7       misho     260: bufCLR(int idx, void * __restrict cli_buffer)
1.3       misho     261: {
1.7       misho     262:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     263:                return RETCODE_ERR;
                    264: 
1.7       misho     265:        clrscrEOL(cli_buffer);
                    266:        cli_freeLine(cli_buffer);
1.3       misho     267: 
1.7       misho     268:        printfCR(cli_buffer, 1);
1.3       misho     269:        return RETCODE_OK;
                    270: }
                    271: 
                    272: static int
1.7       misho     273: bufBS(int idx, void * __restrict cli_buffer)
1.3       misho     274: {
1.7       misho     275:        linebuffer_t *buf = cli_buffer;
1.3       misho     276: 
1.7       misho     277:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     278:                return RETCODE_ERR;
                    279: 
                    280:        if (buf->line_bol < buf->line_eol) {
                    281:                clrscrEOL(buf);
                    282: 
                    283:                buf->line_eol--;
                    284:                buf->line_len--;
                    285:                memmove(buf->line_buf + buf->line_eol - buf->line_bol, 
                    286:                                buf->line_buf + buf->line_eol - buf->line_bol + 1, 
                    287:                                buf->line_len - buf->line_eol);
                    288:                buf->line_buf[buf->line_len - 1] = 0;
                    289: 
                    290:                printfEOL(buf, buf->line_len - 1, 1);
                    291:                printfEOL(buf, -1, 1);
                    292:        }
                    293: 
                    294:        return RETCODE_OK;
                    295: }
                    296: 
                    297: static int
1.7       misho     298: bufBTAB(int idx, void * __restrict cli_buffer)
1.3       misho     299: {
1.7       misho     300:        linebuffer_t *buf = cli_buffer;
1.3       misho     301: 
1.7       misho     302:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     303:                return RETCODE_ERR;
                    304: 
                    305:        if (buf->line_bol < buf->line_eol) {
                    306:                clrscrEOL(buf);
                    307: 
                    308:                buf->line_len = buf->line_eol - buf->line_bol + 1;
                    309:                buf->line_buf[buf->line_len - 1] = 0;
                    310: 
                    311:                printfEOL(buf, -1, 1);
1.2       misho     312:        }
                    313: 
1.3       misho     314:        return RETCODE_OK;
                    315: }
                    316: 
                    317: static int
1.7       misho     318: bufMODE(int idx, void * __restrict cli_buffer)
1.3       misho     319: {
1.7       misho     320:        linebuffer_t *buf = cli_buffer;
1.3       misho     321: 
1.7       misho     322:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     323:                return RETCODE_ERR;
                    324: 
                    325:        buf->line_mode = !buf->line_mode ? LINEMODE_OVER : LINEMODE_INS;
                    326:        return RETCODE_OK;
                    327: }
                    328: 
                    329: static int
1.7       misho     330: bufBEGIN(int idx, void * __restrict cli_buffer)
1.3       misho     331: {
1.7       misho     332:        linebuffer_t *buf = cli_buffer;
1.3       misho     333: 
1.7       misho     334:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     335:                return RETCODE_ERR;
                    336: 
                    337:        buf->line_eol = buf->line_bol;
                    338: 
                    339:        printfCR(buf, 1);
                    340:        return RETCODE_OK;
                    341: }
                    342: 
                    343: static int
1.7       misho     344: bufEND(int idx, void * __restrict cli_buffer)
1.3       misho     345: {
1.7       misho     346:        linebuffer_t *buf = cli_buffer;
1.3       misho     347: 
1.7       misho     348:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     349:                return RETCODE_ERR;
                    350: 
                    351:        buf->line_eol = buf->line_len - 1;
                    352: 
                    353:        printfEOL(buf, -1, 1);
                    354:        return RETCODE_OK;
1.2       misho     355: }
                    356: 
1.3       misho     357: static int
1.7       misho     358: bufLEFT(int idx, void * __restrict cli_buffer)
1.2       misho     359: {
1.7       misho     360:        linebuffer_t *buf = cli_buffer;
1.3       misho     361: 
1.7       misho     362:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     363:                return RETCODE_ERR;
                    364: 
                    365:        if (buf->line_bol < buf->line_eol)
                    366:                printfEOL(buf, --buf->line_eol - buf->line_bol, 1);
                    367: 
                    368:        return RETCODE_OK;
                    369: }
1.2       misho     370: 
1.3       misho     371: static int
1.7       misho     372: bufRIGHT(int idx, void * __restrict cli_buffer)
1.3       misho     373: {
1.7       misho     374:        linebuffer_t *buf = cli_buffer;
1.3       misho     375: 
1.7       misho     376:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     377:                return RETCODE_ERR;
                    378: 
                    379:        if (buf->line_eol < buf->line_len - 1)
                    380:                printfEOL(buf, ++buf->line_eol - buf->line_bol, 1);
                    381: 
                    382:        return RETCODE_OK;
                    383: }
                    384: 
                    385: static int
1.7       misho     386: bufDEL(int idx, void * __restrict cli_buffer)
1.3       misho     387: {
1.7       misho     388:        linebuffer_t *buf = cli_buffer;
1.3       misho     389: 
1.7       misho     390:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     391:                return RETCODE_ERR;
                    392: 
                    393:        clrscrEOL(buf);
                    394: 
                    395:        buf->line_len--;
                    396:        memmove(buf->line_buf + buf->line_eol - buf->line_bol, 
                    397:                        buf->line_buf + buf->line_eol - buf->line_bol + 1, 
                    398:                        buf->line_len - buf->line_eol);
                    399:        buf->line_buf[buf->line_len - 1] = 0;
                    400: 
                    401:        printfEOL(buf, buf->line_len - 1, 1);
                    402:        printfEOL(buf, -1, 1);
                    403: 
                    404:        return RETCODE_OK;
                    405: }
                    406: 
                    407: static int
1.7       misho     408: bufComp(int idx, void * __restrict cli_buffer)
1.3       misho     409: {
1.7       misho     410:        linebuffer_t *buf = cli_buffer;
1.3       misho     411:        char *str, *s, **app, *items[MAX_PROMPT_ITEMS], szLine[STRSIZ];
                    412:        register int i, j;
                    413:        struct tagCommand *cmd, *c;
                    414:        int pos, ret = RETCODE_OK;
1.19    ! misho     415:        int ign __attribute__((unused));
1.3       misho     416: 
1.7       misho     417:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     418:                return RETCODE_ERR;
                    419: 
1.6       misho     420:        str = e_strdup(buf->line_buf);
1.3       misho     421:        if (!str)
                    422:                return RETCODE_ERR;
1.2       misho     423:        else {
1.3       misho     424:                s = str;
1.6       misho     425:                str_Trim(s);
1.3       misho     426:        }
                    427: 
                    428:        i = j = 0;
                    429:        c = NULL;
                    430:        memset(szLine, 0, STRSIZ);
                    431:        if (*s) {
                    432:                memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
1.9       misho     433:                for (app = items, i = 0; app < items + MAX_PROMPT_ITEMS - 1 && 
                    434:                                (*app = strsep(&s, " \t")); 
1.3       misho     435:                                *app ? i++ : i, *app ? app++ : app);
                    436: 
                    437:                if (i) {
                    438:                        SLIST_FOREACH(cmd, &buf->line_cmds, cmd_next) {
1.9       misho     439:                                if (cmd->cmd_level & (1 << buf->line_level) && 
                    440:                                                !strncmp(cmd->cmd_name, items[0], 
                    441:                                                        strlen(items[0]))) {
                    442:                                        if (strncmp(cmd->cmd_name, CLI_CMD_SEP, 
                    443:                                                                strlen(CLI_CMD_SEP))) {
1.3       misho     444:                                                j++;
                    445:                                                c = cmd;
                    446:                                                strlcat(szLine, " ", STRSIZ);
                    447:                                                strlcat(szLine, cmd->cmd_name, STRSIZ);
                    448:                                        }
                    449:                                }
                    450:                        }
1.2       misho     451: 
1.3       misho     452:                        if (i > 1 && c) {
                    453:                                /* we are on argument of command and has complition info */
                    454:                                j++;    // always must be j > 1 ;) for arguments
                    455:                                strlcpy(szLine, c->cmd_info, STRSIZ);
                    456:                        }
                    457:                } else {
                    458:                        /* we have valid char but i == 0, this case is illegal */
                    459:                        ret = RETCODE_ERR;
                    460:                        goto endcomp;
1.2       misho     461:                }
1.3       misho     462:        } else {
                    463:                /* we on 0 position of prompt, show commands for this level */
                    464:                SLIST_FOREACH(cmd, &buf->line_cmds, cmd_next) {
1.9       misho     465:                        if (cmd->cmd_level & (1 << buf->line_level))
1.3       misho     466:                                if (strncmp(cmd->cmd_name, CLI_CMD_SEP, strlen(CLI_CMD_SEP))) {
                    467:                                        j++;
                    468:                                        c = cmd;
                    469:                                        strlcat(szLine, " ", STRSIZ);
                    470:                                        strlcat(szLine, cmd->cmd_name, STRSIZ);
                    471:                                }
                    472:                }
                    473:        }
1.2       misho     474: 
1.3       misho     475:        /* completion show actions ... */
                    476:        if (j > 1 && c) {
                    477:                printfNL(buf, 0);
1.19    ! misho     478:                ign = write(buf->line_out, szLine, strlen(szLine));
1.3       misho     479:                printfNL(buf, 1);
                    480:                printfEOL(buf, buf->line_len - 1, 1);
                    481:                printfEOL(buf, -1, 1);
1.2       misho     482:        }
1.3       misho     483:        if (j == 1 && c) {
                    484:                clrscrEOL(buf);
                    485:                cli_freeLine(buf);
                    486: 
                    487:                pos = buf->line_eol - buf->line_bol;
                    488: 
                    489:                buf->line_len += c->cmd_len + 1;
                    490:                buf->line_eol += c->cmd_len + 1;
                    491: 
                    492:                memcpy(buf->line_buf + pos, c->cmd_name, c->cmd_len);
                    493:                buf->line_buf[pos + c->cmd_len] = (u_char) *K_SPACE;
                    494:                buf->line_buf[buf->line_len - 1] = 0;
1.2       misho     495: 
1.3       misho     496:                printfEOL(buf, -1, 1);
1.2       misho     497:        }
                    498: 
1.3       misho     499: endcomp:
1.6       misho     500:        e_free(str);
1.3       misho     501:        return ret;
                    502: }
                    503: 
                    504: static int
1.7       misho     505: bufHelp(int idx, void * __restrict cli_buffer)
1.3       misho     506: {
1.7       misho     507:        linebuffer_t *buf = cli_buffer;
1.3       misho     508: 
1.7       misho     509:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     510:                return RETCODE_ERR;
                    511: 
1.9       misho     512:        cli_Cmd_Help(buf, buf->line_level, NULL);
1.3       misho     513: 
                    514:        printfEOL(buf, buf->line_len - 1, 1);
                    515:        printfEOL(buf, -1, 1);
                    516:        return RETCODE_OK;
                    517: }
                    518: 
1.9       misho     519: static int
                    520: bufEndNode(int idx, void * __restrict cli_buffer)
                    521: {
                    522:        linebuffer_t *buf = cli_buffer;
                    523: 
                    524:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
                    525:                return RETCODE_ERR;
                    526: 
                    527:        if (buf->line_level > 0) {
                    528:                printfNL(cli_buffer, 0);
                    529:                buf->line_level--;
                    530:                cli_Printf(buf, "Enter to config level %d\n", buf->line_level);
                    531:        }
                    532: 
                    533:        return bufCLR(idx, cli_buffer);
                    534: }
                    535: 
1.3       misho     536: 
                    537: /*
1.6       misho     538:  * cli_Printf() - Send message to CLI session
                    539:  *
1.7       misho     540:  * @cli_buffer = CLI buffer
1.3       misho     541:  * @fmt = printf format string
                    542:  * @... = arguments defined in fmt
                    543:  * return: none
                    544: */
1.6       misho     545: void
1.7       misho     546: cli_Printf(linebuffer_t * __restrict cli_buffer, char *fmt, ...)
1.3       misho     547: {
                    548:        va_list lst;
                    549:        FILE *f;
                    550: 
                    551:        if (fmt) {
1.7       misho     552:                f = fdopen(cli_buffer->line_out, "a");
1.3       misho     553:                if (!f) {
                    554:                        LOGERR;
                    555:                        return;
                    556:                }
                    557: 
                    558:                va_start(lst, fmt);
                    559:                vfprintf(f, fmt, lst);
                    560:                va_end(lst);
                    561:        } else
1.6       misho     562:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     563: }
                    564: 
                    565: /*
1.6       misho     566:  * cli_PrintHelp() - Print help screen
                    567:  *
1.7       misho     568:  * @cli_buffer = CLI buffer
1.3       misho     569:  * return: none
                    570: */
1.6       misho     571: void
1.7       misho     572: cli_PrintHelp(linebuffer_t * __restrict cli_buffer)
1.3       misho     573: {
1.7       misho     574:        if (cli_buffer) {
                    575:                bufHelp(0, cli_buffer);
                    576:                clrscrEOL(cli_buffer);
1.3       misho     577:        } else
1.6       misho     578:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     579: }
                    580: 
                    581: 
                    582: /*
1.6       misho     583:  * cli_BindKey() - Bind function to key
                    584:  *
1.3       misho     585:  * @key = key structure
1.7       misho     586:  * @cli_buffer = CLI buffer
1.3       misho     587:  * return: RETCODE_ERR error, RETCODE_OK ok, >0 bind at position
                    588: */
                    589: int
1.7       misho     590: cli_BindKey(bindkey_t * __restrict key, linebuffer_t * __restrict cli_buffer)
1.3       misho     591: {
                    592:        register int i;
                    593: 
1.7       misho     594:        if (!key || !cli_buffer) {
1.6       misho     595:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     596:                return RETCODE_ERR;
1.2       misho     597:        }
1.3       misho     598: 
                    599:        for (i = 0; i < MAX_BINDKEY; i++)
1.7       misho     600:                if (key->key_len == cli_buffer->line_keys[i].key_len && 
                    601:                                !memcmp(key->key_ch, cli_buffer->line_keys[i].key_ch, 
                    602:                                        key->key_len)) {
                    603:                        cli_buffer->line_keys[i].key_func = key->key_func;
1.3       misho     604:                        return i;
                    605:                }
                    606: 
                    607:        return RETCODE_OK;
1.2       misho     608: }
                    609: 
                    610: 
1.3       misho     611: /*
1.6       misho     612:  * cli_addCommand() - Add command to CLI session
                    613:  *
1.7       misho     614:  * @cli_buffer = CLI buffer
1.3       misho     615:  * @csCmd = Command name
1.9       misho     616:  * @cliLevel = Level in CLI, -1 view from all levels, 0 hidden, >0 mask levels
1.3       misho     617:  * @funcCmd = Callback function when user call command
                    618:  * @csInfo = Inline information for command
                    619:  * @csHelp = Help line when call help
                    620:  * return: RETCODE_ERR error, RETCODE_OK ok
                    621: */
                    622: int
1.7       misho     623: cli_addCommand(linebuffer_t * __restrict cli_buffer, const char *csCmd, 
                    624:                int cliLevel, cmd_func_t funcCmd, 
1.3       misho     625:                const char *csInfo, const char *csHelp)
1.1       misho     626: {
1.3       misho     627:        struct tagCommand *cmd;
                    628: 
1.7       misho     629:        if (!cli_buffer || !csCmd) {
1.6       misho     630:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     631:                return RETCODE_ERR;
                    632:        }
                    633: 
1.6       misho     634:        cmd = e_malloc(sizeof(struct tagCommand));
1.3       misho     635:        if (!cmd) {
                    636:                LOGERR;
                    637:                return RETCODE_ERR;
                    638:        } else
                    639:                memset(cmd, 0, sizeof(struct tagCommand));
                    640: 
                    641:        cmd->cmd_level = cliLevel;
                    642:        cmd->cmd_func = funcCmd;
                    643:        cmd->cmd_len = strlcpy(cmd->cmd_name, csCmd, STRSIZ);
                    644:        if (csInfo)
                    645:                strlcpy(cmd->cmd_info, csInfo, STRSIZ);
                    646:        if (csHelp)
                    647:                strlcpy(cmd->cmd_help, csHelp, STRSIZ);
1.7       misho     648:        SLIST_INSERT_HEAD(&cli_buffer->line_cmds, cmd, cmd_next);
1.3       misho     649:        return RETCODE_OK;
1.1       misho     650: }
                    651: 
1.3       misho     652: /*
1.6       misho     653:  * cli_delCommand() - Delete command from CLI session
                    654:  *
1.7       misho     655:  * @cli_buffer = CLI buffer
1.3       misho     656:  * @csCmd = Command name
1.9       misho     657:  * @cliLevel = Level in CLI, -1 view from all levels, 0 hidden, >0 mask levels
1.3       misho     658:  * return: RETCODE_ERR error, RETCODE_OK ok
                    659: */
                    660: int
1.7       misho     661: cli_delCommand(linebuffer_t * __restrict cli_buffer, const char *csCmd, int cliLevel)
1.1       misho     662: {
1.3       misho     663:        struct tagCommand *cmd;
                    664:        int ret = RETCODE_OK;
                    665: 
1.7       misho     666:        if (!cli_buffer || !csCmd) {
1.6       misho     667:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     668:                return RETCODE_ERR;
                    669:        }
                    670: 
1.7       misho     671:        SLIST_FOREACH(cmd, &cli_buffer->line_cmds, cmd_next) 
1.3       misho     672:                if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) {
                    673:                        ret = 1;
1.7       misho     674:                        SLIST_REMOVE(&cli_buffer->line_cmds, cmd, tagCommand, cmd_next);
1.6       misho     675:                        e_free(cmd);
1.3       misho     676:                        break;
                    677:                }
                    678: 
                    679:        return ret;
1.1       misho     680: }
                    681: 
1.3       misho     682: /*
1.6       misho     683:  * cli_updCommand() - Update command in CLI session
                    684:  *
1.7       misho     685:  * @cli_buffer = CLI buffer
1.3       misho     686:  * @csCmd = Command name
1.9       misho     687:  * @cliLevel = Level in CLI, -1 view from all levels, 0 hidden, >0 mask levels
1.3       misho     688:  * @funcCmd = Callback function when user call command
                    689:  * @csInfo = Inline information for command
                    690:  * @csHelp = Help line when call help
                    691:  * return: RETCODE_ERR error, RETCODE_OK ok
                    692: */
                    693: int
1.7       misho     694: cli_updCommand(linebuffer_t * __restrict cli_buffer, const char *csCmd, 
                    695:                int cliLevel, cmd_func_t funcCmd, 
1.3       misho     696:                const char *csInfo, const char *csHelp)
1.1       misho     697: {
1.3       misho     698:        struct tagCommand *cmd;
                    699:        int ret = RETCODE_OK;
                    700: 
1.7       misho     701:        if (!cli_buffer || !csCmd) {
1.6       misho     702:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     703:                return RETCODE_ERR;
                    704:        }
                    705: 
1.9       misho     706:        SLIST_FOREACH(cmd, &cli_buffer->line_cmds, cmd_next)
                    707:                if ((!cmd->cmd_level || cmd->cmd_level == cliLevel) && 
                    708:                                !strcmp(cmd->cmd_name, csCmd)) {
                    709:                        if (!cmd->cmd_level)
                    710:                                cmd->cmd_level = cliLevel;
1.3       misho     711:                        if (funcCmd)
                    712:                                cmd->cmd_func = funcCmd;
                    713:                        if (csInfo)
                    714:                                strlcpy(cmd->cmd_info, csInfo, STRSIZ);
                    715:                        if (csHelp)
                    716:                                strlcpy(cmd->cmd_help, csHelp, STRSIZ);
                    717: 
                    718:                        break;
                    719:                }
1.1       misho     720: 
1.3       misho     721:        return ret;
1.1       misho     722: }
                    723: 
                    724: 
                    725: /*
1.6       misho     726:  * cli_addHistory() - Add line to history
                    727:  *
1.7       misho     728:  * @cli_buffer = CLI buffer
1.3       misho     729:  * @str = Add custom text or if NULL use readed line from CLI buffer
                    730:  * return: RETCODE_ERR error, RETCODE_OK ok
1.1       misho     731: */
1.3       misho     732: int
1.7       misho     733: cli_addHistory(linebuffer_t * __restrict cli_buffer, const char * __restrict str)
1.1       misho     734: {
1.3       misho     735:        struct tagHistory *h;
                    736: 
1.7       misho     737:        if (!cli_buffer) {
1.6       misho     738:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     739:                return RETCODE_ERR;
                    740:        }
                    741: 
1.6       misho     742:        if (!(h = e_malloc(sizeof(struct tagHistory)))) {
1.3       misho     743:                LOGERR;
                    744:                return RETCODE_ERR;
                    745:        } else
                    746:                memset(h, 0, sizeof(struct tagHistory));
                    747: 
                    748:        if (str) {
                    749:                if (!*str) {
1.6       misho     750:                        e_free(h);
1.3       misho     751:                        return RETCODE_OK;
                    752:                }
                    753: 
                    754:                h->hist_len = strlcpy(h->hist_line, str, BUFSIZ);
                    755:        } else {
1.7       misho     756:                if (!*cli_buffer->line_buf || cli_buffer->line_len < 2) {
1.6       misho     757:                        e_free(h);
1.3       misho     758:                        return RETCODE_OK;
                    759:                }
                    760: 
1.7       misho     761:                memcpy(h->hist_line, cli_buffer->line_buf, (h->hist_len = cli_buffer->line_len));
1.6       misho     762:                str_Trim(h->hist_line);
1.3       misho     763:                h->hist_len = strlen(h->hist_line);
                    764:        }
1.1       misho     765: 
1.7       misho     766:        TAILQ_INSERT_HEAD(&cli_buffer->line_history, h, hist_next);
1.3       misho     767:        return h->hist_len;
                    768: }
1.1       misho     769: 
1.3       misho     770: /*
1.6       misho     771:  * cli_saveHistory() - Save history to file
                    772:  *
1.7       misho     773:  * @cli_buffer = CLI buffer
1.3       misho     774:  * @histfile = History filename, if NULL will be use default name
                    775:  * @lines = Maximum history lines to save
                    776:  * return: RETCODE_ERR error, RETCODE_OK ok
                    777: */
                    778: int
1.7       misho     779: cli_saveHistory(linebuffer_t * __restrict cli_buffer, const char *histfile, int lines)
1.3       misho     780: {
                    781:        FILE *f;
                    782:        mode_t mode;
                    783:        char szFName[MAXPATHLEN];
                    784:        struct tagHistory *h;
                    785: 
1.7       misho     786:        if (!cli_buffer) {
1.6       misho     787:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     788:                return RETCODE_ERR;
                    789:        }
                    790:        if (!histfile)
                    791:                strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
                    792:        else
                    793:                strlcpy(szFName, histfile, MAXPATHLEN);
                    794: 
                    795:        mode = umask(0177);
                    796:        f = fopen(szFName, "w");
                    797:        if (!f) {
1.1       misho     798:                LOGERR;
1.3       misho     799:                return RETCODE_ERR;
                    800:        }
                    801: 
1.7       misho     802:        TAILQ_FOREACH(h, &cli_buffer->line_history, hist_next) {
1.3       misho     803:                fprintf(f, "%s\n", h->hist_line);
                    804: 
                    805:                if (lines)
                    806:                        lines--;
                    807:                else
                    808:                        break;
                    809:        }
1.1       misho     810: 
1.3       misho     811:        fclose(f);
                    812:        umask(mode);
                    813: 
                    814:        return RETCODE_OK;
1.1       misho     815: }
                    816: 
1.3       misho     817: /*
1.6       misho     818:  * cli_loadHistory() - Load history from file
                    819:  *
1.7       misho     820:  * @cli_buffer = CLI buffer
1.3       misho     821:  * @histfile = History filename, if NULL will be use default name
                    822:  * return: RETCODE_ERR error, RETCODE_OK ok
                    823: */
                    824: int
1.7       misho     825: cli_loadHistory(linebuffer_t * __restrict cli_buffer, const char *histfile)
1.3       misho     826: {
                    827:        FILE *f;
                    828:        char szFName[MAXPATHLEN], buf[BUFSIZ];
                    829:        struct tagHistory *h;
                    830: 
1.7       misho     831:        if (!cli_buffer) {
1.6       misho     832:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     833:                return RETCODE_ERR;
                    834:        }
                    835:        if (!histfile)
                    836:                strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
                    837:        else
                    838:                strlcpy(szFName, histfile, MAXPATHLEN);
                    839: 
                    840:        f = fopen(szFName, "r");
                    841:        if (!f)
                    842:                return RETCODE_OK;
                    843: 
                    844:        while (fgets(buf, BUFSIZ, f)) {
                    845:                if (!*buf || *buf == '#')
                    846:                        continue;
                    847:                else
1.6       misho     848:                        str_Trim(buf);
1.3       misho     849: 
1.6       misho     850:                if (!(h = e_malloc(sizeof(struct tagHistory)))) {
1.3       misho     851:                        LOGERR;
                    852:                        fclose(f);
                    853:                        return RETCODE_ERR;
                    854:                } else
                    855:                        memset(h, 0, sizeof(struct tagHistory));
                    856: 
                    857:                h->hist_len = strlcpy(h->hist_line, buf, BUFSIZ);
1.7       misho     858:                TAILQ_INSERT_TAIL(&cli_buffer->line_history, h, hist_next);
1.3       misho     859:        }
                    860: 
                    861:        fclose(f);
                    862: 
                    863:        return RETCODE_OK;
                    864: }
1.1       misho     865: 
                    866: /*
1.6       misho     867:  * cli_resetHistory() - Reset history search in CLI session
                    868:  *
1.7       misho     869:  * @cli_buffer = CLI buffer
1.1       misho     870:  * return: none
                    871: */
1.6       misho     872: void
1.7       misho     873: cli_resetHistory(linebuffer_t * __restrict cli_buffer)
1.1       misho     874: {
1.7       misho     875:        cli_buffer->line_h = NULL;
1.1       misho     876: }
                    877: 
1.3       misho     878: 
1.1       misho     879: /*
1.6       misho     880:  * cli_freeLine() - Clear entire line
                    881:  *
1.7       misho     882:  * @cli_buffer = CLI buffer
1.3       misho     883:  * return: RETCODE_ERR error, RETCODE_OK ok
1.2       misho     884: */
1.6       misho     885: int
1.7       misho     886: cli_freeLine(linebuffer_t * __restrict cli_buffer)
1.2       misho     887: {
1.3       misho     888:        int code = RETCODE_ERR;
1.2       misho     889: 
1.7       misho     890:        if (cli_buffer) {
                    891:                if (cli_buffer->line_buf)
                    892:                        e_free(cli_buffer->line_buf);
                    893: 
                    894:                cli_buffer->line_buf = e_malloc(BUFSIZ);
                    895:                if (cli_buffer->line_buf) {
                    896:                        memset(cli_buffer->line_buf, 0, BUFSIZ);
                    897:                        cli_buffer->line_eol = cli_buffer->line_bol;
                    898:                        cli_buffer->line_len = 1 + cli_buffer->line_eol;
1.2       misho     899: 
1.3       misho     900:                        code = RETCODE_OK;
                    901:                } else
                    902:                        LOGERR;
                    903:        } else
1.6       misho     904:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.2       misho     905: 
1.3       misho     906:        return code;
1.2       misho     907: }
                    908: 
                    909: /*
1.6       misho     910:  * cli_setPrompt() - Set new prompt for CLI session
                    911:  *
1.7       misho     912:  * @cli_buffer = CLI buffer
1.3       misho     913:  * @prompt = new text for prompt or if NULL disable prompt
                    914:  * return: none
1.2       misho     915: */
1.6       misho     916: void
1.7       misho     917: cli_setPrompt(linebuffer_t * __restrict cli_buffer, const char *prompt)
1.2       misho     918: {
1.7       misho     919:        if (cli_buffer) {
                    920:                if (cli_buffer->line_prompt) {
                    921:                        e_free(cli_buffer->line_prompt);
                    922:                        cli_buffer->line_prompt = NULL;
                    923:                        cli_buffer->line_bol = 0;
1.3       misho     924:                }
                    925: 
                    926:                if (prompt) {
1.7       misho     927:                        cli_buffer->line_prompt = e_strdup(prompt);
                    928:                        if (cli_buffer->line_prompt) {
                    929:                                cli_buffer->line_bol = strlen(cli_buffer->line_prompt);
                    930:                                cli_buffer->line_eol = cli_buffer->line_bol;
                    931:                                cli_buffer->line_len = 1 + cli_buffer->line_eol;
1.3       misho     932:                        } else
                    933:                                LOGERR;
                    934:                }
                    935:        } else
1.6       misho     936:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.2       misho     937: }
                    938: 
1.3       misho     939: 
1.2       misho     940: /*
1.6       misho     941:  * cliEnd() - Clear data, Free resources and close CLI session
                    942:  *
1.7       misho     943:  * @cli_buffer = CLI buffer
1.3       misho     944:  * return: RETCODE_ERR error, RETCODE_OK ok
1.2       misho     945: */
1.3       misho     946: void
1.7       misho     947: cliEnd(linebuffer_t * __restrict cli_buffer)
1.2       misho     948: {
1.3       misho     949:        struct tagHistory *h;
                    950:        struct tagCommand *c;
                    951: 
1.7       misho     952:        if (cli_buffer) {
                    953:                while ((c = SLIST_FIRST(&cli_buffer->line_cmds))) {
                    954:                        SLIST_REMOVE_HEAD(&cli_buffer->line_cmds, cmd_next);
1.6       misho     955:                        e_free(c);
1.3       misho     956:                }
1.7       misho     957:                while ((h = TAILQ_FIRST(&cli_buffer->line_history))) {
                    958:                        TAILQ_REMOVE(&cli_buffer->line_history, h, hist_next);
1.6       misho     959:                        e_free(h);
1.3       misho     960:                }
                    961: 
1.7       misho     962:                if (cli_buffer->line_prompt)
                    963:                        e_free(cli_buffer->line_prompt);
1.2       misho     964: 
1.7       misho     965:                if (cli_buffer->line_keys)
                    966:                        e_free(cli_buffer->line_keys);
                    967:                if (cli_buffer->line_buf)
                    968:                        e_free(cli_buffer->line_buf);
1.2       misho     969: 
1.7       misho     970:                e_free(cli_buffer);
                    971:                cli_buffer = NULL;
1.3       misho     972:        } else
1.6       misho     973:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     974: }
                    975: 
                    976: /*
1.6       misho     977:  * cliInit() - Start CLI session, allocate memory for resources and bind keys
                    978:  *
1.3       misho     979:  * @fin = Input device handle
                    980:  * @fout = Output device handle
                    981:  * @prompt = text for prompt, if NULL disable prompt
                    982:  * return: NULL if error or !=NULL CLI buffer
                    983: */
                    984: linebuffer_t *
                    985: cliInit(int fin, int fout, const char *prompt)
                    986: {
1.7       misho     987:        linebuffer_t *cli_buffer;
1.3       misho     988:        bindkey_t *keys;
                    989:        register int i;
1.18      misho     990:        char szPrompt[STRSIZ + 16] = {[0 ... STRSIZ + 15] = 0};
1.3       misho     991: 
                    992:        /* init buffer */
1.7       misho     993:        cli_buffer = e_malloc(sizeof(linebuffer_t));
                    994:        if (!cli_buffer) {
1.3       misho     995:                LOGERR;
                    996:                return NULL;
                    997:        } else {
1.7       misho     998:                memset(cli_buffer, 0, sizeof(linebuffer_t));
1.3       misho     999: 
1.7       misho    1000:                cli_buffer->line_in = fin;
                   1001:                cli_buffer->line_out = fout;
1.3       misho    1002: 
1.7       misho    1003:                TAILQ_INIT(&cli_buffer->line_history);
                   1004:                SLIST_INIT(&cli_buffer->line_cmds);
1.3       misho    1005: 
                   1006:                if (prompt) {
1.16      misho    1007:                        strlcpy(cli_buffer->line_porigin, prompt, sizeof cli_buffer->line_porigin);
                   1008:                        snprintf(szPrompt, sizeof szPrompt, "%s{%d}> ", cli_buffer->line_porigin, cli_buffer->line_level);
                   1009:                        cli_buffer->line_prompt = e_strdup(szPrompt);
1.7       misho    1010:                        if (!cli_buffer->line_prompt) {
1.3       misho    1011:                                LOGERR;
1.7       misho    1012:                                e_free(cli_buffer);
1.3       misho    1013:                                return NULL;
                   1014:                        } else
1.7       misho    1015:                                cli_buffer->line_eol = cli_buffer->line_bol = 
                   1016:                                        strlen(cli_buffer->line_prompt);
1.9       misho    1017:                } else
                   1018:                        cli_buffer->line_mode = LINEMODE_OVER;
1.3       misho    1019:        }
1.7       misho    1020:        cli_buffer->line_buf = e_malloc(BUFSIZ);
                   1021:        if (!cli_buffer->line_buf) {
1.3       misho    1022:                LOGERR;
1.7       misho    1023:                if (cli_buffer->line_prompt)
                   1024:                        e_free(cli_buffer->line_prompt);
                   1025:                e_free(cli_buffer);
1.3       misho    1026:                return NULL;
                   1027:        } else {
1.7       misho    1028:                memset(cli_buffer->line_buf, 0, BUFSIZ);
                   1029:                cli_buffer->line_len = 1 + cli_buffer->line_eol;
1.3       misho    1030:        }
1.6       misho    1031:        keys = e_calloc(MAX_BINDKEY + 1, sizeof(bindkey_t));
1.3       misho    1032:        if (!keys) {
                   1033:                LOGERR;
1.7       misho    1034:                if (cli_buffer->line_prompt)
                   1035:                        e_free(cli_buffer->line_prompt);
                   1036:                e_free(cli_buffer->line_buf);
                   1037:                e_free(cli_buffer);
1.3       misho    1038:                return NULL;
                   1039:        } else
                   1040:                memset(keys, 0, sizeof(bindkey_t) * (MAX_BINDKEY + 1));
                   1041: 
                   1042:        /* add helper functions */
1.9       misho    1043:        cli_addCommand(cli_buffer, "exit", 1, cli_Cmd_Exit, "exit <cr>", "Exit from console");
                   1044:        cli_addCommand(cli_buffer, "help", -1, cli_Cmd_Help, "help [command] <cr>", "Help screen");
                   1045:        cli_addCommand(cli_buffer, "-------", -1, NULL, "-------------------------", NULL);
                   1046:        cli_addCommand(cli_buffer, "where", -1, cli_Cmd_WhereAmI, "where <cr>", 
                   1047:                        "Query current level of console");
                   1048:        cli_addCommand(cli_buffer, "top", -1, cli_Cmd_Top, "top <cr>", "Top level of console");
                   1049:        cli_addCommand(cli_buffer, "end", -1, cli_Cmd_End, "end <cr>", "End level of console");
                   1050:        cli_addCommand(cli_buffer, "config", -1, cli_Cmd_Config, "config <cr>", 
                   1051:                        "Config next level of console");
                   1052:        cli_addCommand(cli_buffer, "-------", -1, NULL, "-------------------------", NULL);
1.3       misho    1053: 
                   1054:        /* fill key bindings */
1.6       misho    1055:        /* ascii chars & ctrl+chars */
1.3       misho    1056:        for (i = 0; i < 256; i++) {
                   1057:                *keys[i].key_ch = (u_char) i;
                   1058:                keys[i].key_len = 1;
                   1059: 
                   1060:                if (!i || i == *K_CTRL_D)
                   1061:                        keys[i].key_func = bufEOF;
                   1062:                if (i == *K_CTRL_M || i == *K_CTRL_J)
                   1063:                        keys[i].key_func = bufEOL;
1.9       misho    1064:                if (cli_buffer->line_prompt && (i == *K_CTRL_H || i == *K_BACKSPACE))
1.3       misho    1065:                        keys[i].key_func = bufBS;
1.13      misho    1066:                if (i == *K_CTRL_C)
1.3       misho    1067:                        keys[i].key_func = bufCLR;
1.9       misho    1068:                if (cli_buffer->line_prompt && i == *K_CTRL_A)
1.3       misho    1069:                        keys[i].key_func = bufBEGIN;
1.9       misho    1070:                if (cli_buffer->line_prompt && i == *K_CTRL_E)
1.3       misho    1071:                        keys[i].key_func = bufEND;
1.9       misho    1072:                if (cli_buffer->line_prompt && i == *K_TAB)
1.3       misho    1073:                        keys[i].key_func = bufComp;
1.13      misho    1074:                if (i == *K_CTRL_Z)
1.9       misho    1075:                        keys[i].key_func = bufEndNode;
1.3       misho    1076:                if (i >= *K_SPACE && i < *K_BACKSPACE)
                   1077:                        keys[i].key_func = bufCHAR;
                   1078:                if (i > *K_BACKSPACE && i < 0xff)
                   1079:                        keys[i].key_func = bufCHAR;
1.9       misho    1080:                if (cli_buffer->line_prompt && i == '?')
1.3       misho    1081:                        keys[i].key_func = bufHelp;
                   1082:        }
1.6       misho    1083:        /* alt+chars */
1.3       misho    1084:        for (i = 256; i < 512; i++) {
                   1085:                keys[i].key_ch[0] = 0x1b;
                   1086:                keys[i].key_ch[1] = (u_char) i - 256;
                   1087:                keys[i].key_len = 2;
                   1088:        }
                   1089: 
1.6       misho    1090:        /* 3 bytes */
1.3       misho    1091:        keys[i].key_len = sizeof K_F1 - 1;
                   1092:        memcpy(keys[i].key_ch, K_F1, keys[i].key_len);
                   1093:        i++;
                   1094:        keys[i].key_len = sizeof K_F2 - 1;
                   1095:        memcpy(keys[i].key_ch, K_F2, keys[i].key_len);
                   1096:        i++;
                   1097:        keys[i].key_len = sizeof K_F3 - 1;
                   1098:        memcpy(keys[i].key_ch, K_F3, keys[i].key_len);
                   1099:        i++;
                   1100:        keys[i].key_len = sizeof K_F4 - 1;
                   1101:        memcpy(keys[i].key_ch, K_F4, keys[i].key_len);
                   1102:        i++;
                   1103:        keys[i].key_len = sizeof K_CTRL_SH_F1 - 1;
                   1104:        memcpy(keys[i].key_ch, K_CTRL_SH_F1, keys[i].key_len);
                   1105:        i++;
                   1106:        keys[i].key_len = sizeof K_CTRL_SH_F2 - 1;
                   1107:        memcpy(keys[i].key_ch, K_CTRL_SH_F2, keys[i].key_len);
                   1108:        i++;
                   1109:        keys[i].key_len = sizeof K_CTRL_SH_F3 - 1;
                   1110:        memcpy(keys[i].key_ch, K_CTRL_SH_F3, keys[i].key_len);
                   1111:        i++;
                   1112:        keys[i].key_len = sizeof K_CTRL_SH_F4 - 1;
                   1113:        memcpy(keys[i].key_ch, K_CTRL_SH_F4, keys[i].key_len);
                   1114:        i++;
                   1115:        keys[i].key_len = sizeof K_CTRL_SH_F5 - 1;
                   1116:        memcpy(keys[i].key_ch, K_CTRL_SH_F5, keys[i].key_len);
                   1117:        i++;
                   1118:        keys[i].key_len = sizeof K_CTRL_SH_F6 - 1;
                   1119:        memcpy(keys[i].key_ch, K_CTRL_SH_F6, keys[i].key_len);
                   1120:        i++;
                   1121:        keys[i].key_len = sizeof K_CTRL_SH_F7 - 1;
                   1122:        memcpy(keys[i].key_ch, K_CTRL_SH_F7, keys[i].key_len);
                   1123:        i++;
                   1124:        keys[i].key_len = sizeof K_CTRL_SH_F8 - 1;
                   1125:        memcpy(keys[i].key_ch, K_CTRL_SH_F8, keys[i].key_len);
                   1126:        i++;
                   1127:        keys[i].key_len = sizeof K_CTRL_SH_F9 - 1;
                   1128:        memcpy(keys[i].key_ch, K_CTRL_SH_F9, keys[i].key_len);
                   1129:        i++;
                   1130:        keys[i].key_len = sizeof K_CTRL_SH_F10 - 1;
                   1131:        memcpy(keys[i].key_ch, K_CTRL_SH_F10, keys[i].key_len);
                   1132:        i++;
                   1133:        keys[i].key_len = sizeof K_CTRL_SH_F11 - 1;
                   1134:        memcpy(keys[i].key_ch, K_CTRL_SH_F11, keys[i].key_len);
                   1135:        i++;
                   1136:        keys[i].key_len = sizeof K_CTRL_SH_F12 - 1;
                   1137:        memcpy(keys[i].key_ch, K_CTRL_SH_F12, keys[i].key_len);
                   1138:        i++;
                   1139:        keys[i].key_len = sizeof K_CTRL_F1 - 1;
                   1140:        memcpy(keys[i].key_ch, K_CTRL_F1, keys[i].key_len);
                   1141:        i++;
                   1142:        keys[i].key_len = sizeof K_CTRL_F2 - 1;
                   1143:        memcpy(keys[i].key_ch, K_CTRL_F2, keys[i].key_len);
                   1144:        i++;
                   1145:        keys[i].key_len = sizeof K_CTRL_F3 - 1;
                   1146:        memcpy(keys[i].key_ch, K_CTRL_F3, keys[i].key_len);
                   1147:        i++;
                   1148:        keys[i].key_len = sizeof K_CTRL_F4 - 1;
                   1149:        memcpy(keys[i].key_ch, K_CTRL_F4, keys[i].key_len);
                   1150:        i++;
                   1151:        keys[i].key_len = sizeof K_CTRL_F5 - 1;
                   1152:        memcpy(keys[i].key_ch, K_CTRL_F5, keys[i].key_len);
                   1153:        i++;
                   1154:        keys[i].key_len = sizeof K_CTRL_F6 - 1;
                   1155:        memcpy(keys[i].key_ch, K_CTRL_F6, keys[i].key_len);
                   1156:        i++;
                   1157:        keys[i].key_len = sizeof K_CTRL_F7 - 1;
                   1158:        memcpy(keys[i].key_ch, K_CTRL_F7, keys[i].key_len);
                   1159:        i++;
                   1160:        keys[i].key_len = sizeof K_CTRL_F8 - 1;
                   1161:        memcpy(keys[i].key_ch, K_CTRL_F8, keys[i].key_len);
                   1162:        i++;
                   1163:        keys[i].key_len = sizeof K_CTRL_F9 - 1;
                   1164:        memcpy(keys[i].key_ch, K_CTRL_F9, keys[i].key_len);
                   1165:        i++;
                   1166:        keys[i].key_len = sizeof K_CTRL_F10 - 1;
                   1167:        memcpy(keys[i].key_ch, K_CTRL_F10, keys[i].key_len);
                   1168:        i++;
                   1169:        keys[i].key_len = sizeof K_CTRL_F11 - 1;
                   1170:        memcpy(keys[i].key_ch, K_CTRL_F11, keys[i].key_len);
                   1171:        i++;
                   1172:        keys[i].key_len = sizeof K_CTRL_F12 - 1;
                   1173:        memcpy(keys[i].key_ch, K_CTRL_F12, keys[i].key_len);
                   1174:        i++;
                   1175:        keys[i].key_len = sizeof K_HOME - 1;
1.9       misho    1176:        if (cli_buffer->line_prompt)
                   1177:                keys[i].key_func = bufBEGIN;
1.3       misho    1178:        memcpy(keys[i].key_ch, K_HOME, keys[i].key_len);
                   1179:        i++;
                   1180:        keys[i].key_len = sizeof K_END - 1;
1.9       misho    1181:        if (cli_buffer->line_prompt)
                   1182:                keys[i].key_func = bufEND;
1.3       misho    1183:        memcpy(keys[i].key_ch, K_END, keys[i].key_len);
                   1184:        i++;
                   1185:        keys[i].key_len = sizeof K_UP - 1;
1.9       misho    1186:        if (cli_buffer->line_prompt)
                   1187:                keys[i].key_func = bufUP;
1.3       misho    1188:        memcpy(keys[i].key_ch, K_UP, keys[i].key_len);
                   1189:        i++;
                   1190:        keys[i].key_len = sizeof K_DOWN - 1;
1.9       misho    1191:        if (cli_buffer->line_prompt)
                   1192:                keys[i].key_func = bufDOWN;
1.3       misho    1193:        memcpy(keys[i].key_ch, K_DOWN, keys[i].key_len);
                   1194:        i++;
                   1195:        keys[i].key_len = sizeof K_RIGHT - 1;
1.9       misho    1196:        if (cli_buffer->line_prompt)
                   1197:                keys[i].key_func = bufRIGHT;
1.3       misho    1198:        memcpy(keys[i].key_ch, K_RIGHT, keys[i].key_len);
                   1199:        i++;
                   1200:        keys[i].key_len = sizeof K_LEFT - 1;
1.9       misho    1201:        if (cli_buffer->line_prompt)
                   1202:                keys[i].key_func = bufLEFT;
1.3       misho    1203:        memcpy(keys[i].key_ch, K_LEFT, keys[i].key_len);
                   1204:        i++;
                   1205:        keys[i].key_len = sizeof K_BTAB - 1;
1.9       misho    1206:        if (cli_buffer->line_prompt)
                   1207:                keys[i].key_func = bufBTAB;
1.3       misho    1208:        memcpy(keys[i].key_ch, K_BTAB, keys[i].key_len);
                   1209:        i++;
1.6       misho    1210:        /* 4 bytes */
1.3       misho    1211:        keys[i].key_len = sizeof K_INS - 1;
1.9       misho    1212:        if (cli_buffer->line_prompt)
                   1213:                keys[i].key_func = bufMODE;
1.3       misho    1214:        memcpy(keys[i].key_ch, K_INS, keys[i].key_len);
                   1215:        i++;
                   1216:        keys[i].key_len = sizeof K_DEL - 1;
1.9       misho    1217:        if (cli_buffer->line_prompt)
                   1218:                keys[i].key_func = bufDEL;
1.3       misho    1219:        memcpy(keys[i].key_ch, K_DEL, keys[i].key_len);
                   1220:        i++;
                   1221:        keys[i].key_len = sizeof K_PGUP - 1;
                   1222:        memcpy(keys[i].key_ch, K_PGUP, keys[i].key_len);
                   1223:        i++;
                   1224:        keys[i].key_len = sizeof K_PGDN - 1;
                   1225:        memcpy(keys[i].key_ch, K_PGDN, keys[i].key_len);
                   1226:        i++;
1.6       misho    1227:        /* 5 bytes */
1.3       misho    1228:        keys[i].key_len = sizeof K_F5 - 1;
                   1229:        memcpy(keys[i].key_ch, K_F5, keys[i].key_len);
                   1230:        i++;
                   1231:        keys[i].key_len = sizeof K_F6 - 1;
                   1232:        memcpy(keys[i].key_ch, K_F6, keys[i].key_len);
                   1233:        i++;
                   1234:        keys[i].key_len = sizeof K_F7 - 1;
                   1235:        memcpy(keys[i].key_ch, K_F7, keys[i].key_len);
                   1236:        i++;
                   1237:        keys[i].key_len = sizeof K_F8 - 1;
                   1238:        memcpy(keys[i].key_ch, K_F8, keys[i].key_len);
                   1239:        i++;
                   1240:        keys[i].key_len = sizeof K_F9 - 1;
                   1241:        memcpy(keys[i].key_ch, K_F9, keys[i].key_len);
                   1242:        i++;
                   1243:        keys[i].key_len = sizeof K_F10 - 1;
                   1244:        memcpy(keys[i].key_ch, K_F10, keys[i].key_len);
                   1245:        i++;
                   1246:        keys[i].key_len = sizeof K_F11 - 1;
                   1247:        memcpy(keys[i].key_ch, K_F11, keys[i].key_len);
                   1248:        i++;
                   1249:        keys[i].key_len = sizeof K_F12 - 1;
                   1250:        memcpy(keys[i].key_ch, K_F12, keys[i].key_len);
                   1251:        i++;
                   1252: 
1.7       misho    1253:        cli_buffer->line_keys = keys;
                   1254:        return cli_buffer;
1.2       misho    1255: }
                   1256: 
                   1257: /*
1.18      misho    1258:  * cliSetLine() - Set CLI input line terminal
1.6       misho    1259:  *
1.7       misho    1260:  * @cli_buffer = CLI buffer
1.18      misho    1261:  * @old = Old terminal settings
                   1262:  * return: -1 error or 0 ok
1.2       misho    1263: */
1.3       misho    1264: int
1.18      misho    1265: cliSetLine(linebuffer_t * __restrict cli_buffer, struct termios * __restrict old)
1.2       misho    1266: {
                   1267:        struct termios t;
                   1268: 
                   1269:        memset(&t, 0, sizeof t);
1.7       misho    1270:        tcgetattr(cli_buffer->line_in, &t);
1.18      misho    1271:        if (old)
                   1272:                memcpy(old, &t, sizeof(struct termios));
1.9       misho    1273:        t.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO | 
                   1274:                        ECHOCTL | ECHOE | ECHOK | ECHOKE | ECHONL | ECHOPRT);
1.2       misho    1275:        t.c_iflag |= IGNBRK;
                   1276:        t.c_cc[VMIN] = 1;
                   1277:        t.c_cc[VTIME] = 0;
1.7       misho    1278:        return tcsetattr(cli_buffer->line_in, TCSANOW, &t);
1.3       misho    1279: }
                   1280: 
                   1281: /*
1.18      misho    1282:  * cliResetLine() - Reset CLI input line terminal
                   1283:  *
                   1284:  * @cli_buffer = CLI buffer
                   1285:  * @old = Original terminal settings
                   1286:  * return: -1 error or 0 ok
                   1287: */
                   1288: int
                   1289: cliResetLine(linebuffer_t * __restrict cli_buffer, struct termios * __restrict orig)
                   1290: {
                   1291:        return tcsetattr(cli_buffer->line_in, TCSANOW, orig);
                   1292: }
                   1293: 
                   1294: /*
1.6       misho    1295:  * cliReadLine() - Read line from opened CLI session
                   1296:  *
1.7       misho    1297:  * @cli_buffer = CLI buffer
1.10      misho    1298:  * @timeout = Session timeout (-1 infinit)
1.6       misho    1299:  * return: NULL if error or !=NULL readed line, must be e_free after use!
1.3       misho    1300: */
                   1301: char *
1.12      misho    1302: cliReadLine(linebuffer_t * __restrict cli_buffer, int timeout)
1.3       misho    1303: {
1.10      misho    1304:        int code, readLen, ret;
1.3       misho    1305:        register int i;
                   1306:        struct pollfd fds;
                   1307:        char buf[BUFSIZ], *str = NULL;
1.2       misho    1308: 
1.7       misho    1309:        if (!cli_buffer) {
1.6       misho    1310:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho    1311:                return NULL;
1.11      misho    1312:        } else if (timeout > 0)
1.10      misho    1313:                timeout *= 1000;        /* convert from sec to ms */
1.2       misho    1314: 
1.3       misho    1315:        memset(&fds, 0, sizeof fds);
1.7       misho    1316:        fds.fd = cli_buffer->line_in;
1.3       misho    1317:        fds.events = POLLIN;
                   1318: 
1.7       misho    1319:        printfCR(cli_buffer, 1);
1.3       misho    1320:        while (42) {
1.10      misho    1321:                if ((ret = poll(&fds, 1, timeout)) < 1) {
                   1322:                        if (!ret) {
1.12      misho    1323:                                cli_buffer->line_kill = 1;
                   1324:                                if (str) {
1.10      misho    1325:                                        e_free(str);
1.12      misho    1326:                                        str = NULL;
                   1327:                                }
1.10      misho    1328:                        } else
                   1329:                                LOGERR;
1.3       misho    1330:                        return str;
                   1331:                }
                   1332: 
                   1333:                memset(buf, 0, sizeof buf);
1.7       misho    1334:                readLen = read(cli_buffer->line_in, buf, BUFSIZ);
1.14      misho    1335:                if (readLen < 1) {
                   1336:                        if (readLen)
                   1337:                                LOGERR;
                   1338:                        return NULL;
1.3       misho    1339:                }
                   1340: 
                   1341: recheck:
                   1342:                for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--)
1.7       misho    1343:                        if (readLen >= cli_buffer->line_keys[i].key_len && 
                   1344:                                        !memcmp(cli_buffer->line_keys[i].key_ch, buf, 
                   1345:                                                cli_buffer->line_keys[i].key_len)) {
                   1346:                                readLen -= cli_buffer->line_keys[i].key_len;
1.3       misho    1347:                                if (readLen)
1.7       misho    1348:                                        memmove(buf, buf + cli_buffer->line_keys[i].key_len, readLen);
1.3       misho    1349:                                else
1.7       misho    1350:                                        memset(buf, 0, cli_buffer->line_keys[i].key_len);
1.3       misho    1351: 
1.7       misho    1352:                                if (cli_buffer->line_keys[i].key_func)
                   1353:                                        if ((code = cli_buffer->line_keys[i].key_func(i, cli_buffer)))
1.3       misho    1354:                                                readLen = 0;
                   1355: 
                   1356:                                if (readLen)
                   1357:                                        goto recheck;
                   1358:                                else
                   1359:                                        break;
                   1360:                        }
                   1361: 
                   1362:                if (code)
                   1363:                        break;
                   1364:        }
1.2       misho    1365: 
1.7       misho    1366:        if (code != RETCODE_ERR && code != RETCODE_EOF && cli_buffer->line_buf)
                   1367:                str = e_strdup(cli_buffer->line_buf);
1.3       misho    1368:        return str;
1.2       misho    1369: }
                   1370: 
1.3       misho    1371: 
1.2       misho    1372: /*
1.6       misho    1373:  * cliNetLoop() - CLI network main loop binded to socket
                   1374:  *
1.7       misho    1375:  * @cli_buffer = CLI buffer
1.3       misho    1376:  * @csHistFile = History file name
1.2       misho    1377:  * @sock = client socket
1.10      misho    1378:  * @timeout = Session timeout (-1 infinit)
1.3       misho    1379:  * return: RETCODE_ERR error, RETCODE_OK ok
1.2       misho    1380: */
1.3       misho    1381: int
1.10      misho    1382: cliNetLoop(linebuffer_t * __restrict cli_buffer, const char *csHistFile, 
1.12      misho    1383:                int sock, int timeout)
1.2       misho    1384: {
1.3       misho    1385:        u_char buf[BUFSIZ];
1.15      misho    1386:        int pid, stat, pty, s, alen, flg, attrlen = 0, ret = 0;
1.2       misho    1387:        fd_set fds;
                   1388:        struct timeval tv = { DEFAULT_SOCK_TIMEOUT, 0 };
                   1389:        struct telnetAttrs *a, Attr[10];
                   1390: 
1.3       misho    1391:        switch ((pid = forkpty(&pty, NULL, NULL, NULL))) {
1.2       misho    1392:                case -1:
                   1393:                        LOGERR;
                   1394:                        return -1;
                   1395:                case 0:
1.7       misho    1396:                        if (!cli_buffer) {
1.6       misho    1397:                                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho    1398:                                return -1;
                   1399:                        } else
                   1400:                                close(sock);
1.2       misho    1401: 
1.12      misho    1402:                        ret = cliLoop(cli_buffer, csHistFile, timeout) < 0 ? 1 : 0;
1.7       misho    1403:                        cliEnd(cli_buffer);
1.2       misho    1404: 
1.8       misho    1405:                        _exit(ret);
1.2       misho    1406:                default:
1.4       misho    1407:                        cli_telnet_SetCmd(Attr + 0, DO, TELOPT_TTYPE);
                   1408:                        cli_telnet_SetCmd(Attr + 1, WILL, TELOPT_ECHO);
                   1409:                        cli_telnet_Set_SubOpt(Attr + 2, TELOPT_LFLOW, LFLOW_OFF, NULL, 0);
                   1410:                        cli_telnet_Set_SubOpt(Attr + 3, TELOPT_LFLOW, LFLOW_RESTART_XON, NULL, 0);
                   1411:                        cli_telnet_SetCmd(Attr + 4, DO, TELOPT_LINEMODE);
                   1412:                        if ((ret = cli_telnetSend(sock, Attr, 5, NULL, 0, 0)) == -1)
1.2       misho    1413:                                return -1;
1.4       misho    1414:                        else
1.2       misho    1415:                                flg = 0;
                   1416: 
                   1417:                        while (42) {
1.3       misho    1418:                                if (waitpid(pid, &stat, WNOHANG))
                   1419:                                        break;
                   1420: 
1.2       misho    1421:                                FD_ZERO(&fds);
                   1422:                                FD_SET(sock, &fds);
                   1423:                                FD_SET(pty, &fds);
                   1424:                                if ((ret = select(FD_SETSIZE, &fds, NULL, NULL, &tv)) < 1) {
                   1425:                                        if (!ret)
                   1426:                                                cli_SetErr(ETIMEDOUT, "Client session timeout ...");
                   1427: 
                   1428:                                        break;
                   1429:                                }
                   1430: 
                   1431:                                s = FD_ISSET(sock, &fds) ? pty : sock;
                   1432: 
1.3       misho    1433:                                if (FD_ISSET(sock, &fds)) {
                   1434:                                        memset(buf, 0, BUFSIZ);
1.4       misho    1435:                                        if ((ret = cli_telnetRecv(sock, &a, &alen, buf, BUFSIZ)) < 0) {
1.3       misho    1436:                                                if (a)
1.6       misho    1437:                                                        e_free(a);
1.3       misho    1438: 
                   1439:                                                if (-2 == ret)
                   1440:                                                        continue;
                   1441:                                                // EOF
                   1442:                                                if (-3 == ret)
                   1443:                                                        shutdown(sock, SHUT_RD);
                   1444:                                                break;
                   1445:                                        }
                   1446:                                        attrlen = 0;
                   1447:                                        if (1 == flg && alen) {
1.4       misho    1448:                                                cli_telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_SGA);
                   1449:                                                cli_telnet_SetCmd(&Attr[attrlen++], DO, TELOPT_ECHO);
1.3       misho    1450:                                        }
                   1451:                                        if (2 == flg && alen) {
1.4       misho    1452:                                                cli_telnet_SetCmd(&Attr[attrlen++], WILL, TELOPT_ECHO);
                   1453:                                                cli_telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW, 
1.3       misho    1454:                                                                LFLOW_OFF, NULL, 0);
1.4       misho    1455:                                                cli_telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW, 
1.3       misho    1456:                                                                LFLOW_RESTART_XON, NULL, 0);
1.4       misho    1457:                                                cli_telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_LINEMODE);
1.3       misho    1458:                                        }
1.2       misho    1459:                                        if (a)
1.6       misho    1460:                                                e_free(a);
1.2       misho    1461: 
1.3       misho    1462:                                        if ((ret = write(pty, buf, ret)) == -1) {
                   1463:                                                LOGERR;
                   1464:                                                break;
                   1465:                                        }
                   1466:                                }
                   1467: 
                   1468:                                if (FD_ISSET(pty, &fds)) {
                   1469:                                        memset(buf, 0, BUFSIZ);
1.14      misho    1470:                                        if ((ret = read(pty, buf, BUFSIZ)) < 1) {
                   1471:                                                if (ret)
                   1472:                                                        LOGERR;
1.3       misho    1473:                                                break;
                   1474:                                        }
                   1475: 
1.4       misho    1476:                                        if ((ret = cli_telnetSend(sock, Attr, pty == s ? 0 : attrlen, 
                   1477:                                                                        buf, ret, 0)) == -1)
1.3       misho    1478:                                                break;
1.4       misho    1479:                                        else
1.3       misho    1480:                                                flg++;
1.2       misho    1481:                                }
                   1482:                        }
                   1483: 
                   1484:                        close(pty);
                   1485:        }
                   1486: 
                   1487:        return ret;
                   1488: }
                   1489: 
                   1490: /*
1.17      misho    1491:  * cliRun() - CLI run command line
                   1492:  *
                   1493:  * @cli_buffer = CLI buffer
                   1494:  * @psInput = Input command line
                   1495:  * @prompt = Display prompt after command
                   1496:  * return: RETCODE_ERR error, RETCODE_OK ok
                   1497: */
                   1498: int
                   1499: cliRun(linebuffer_t * __restrict cli_buffer, char *psInput, int prompt)
                   1500: {
                   1501:        char *line, *s, *t, **app, *items[MAX_PROMPT_ITEMS];
                   1502:        register int i;
                   1503:        int ret = RETCODE_OK;
                   1504:        struct tagCommand *cmd;
                   1505: 
                   1506:        if (!psInput)
                   1507:                return RETCODE_ERR;
                   1508:        else
                   1509:                line = psInput;
                   1510: 
                   1511:        // clear whitespaces
                   1512:        for (s = line; isspace((int) *s); s++);
                   1513:        if (*s) {
                   1514:                for (t = s + strlen(s) - 1; t > s && isspace((int) *t); t--);
                   1515:                *++t = 0;
                   1516:        }
                   1517: 
                   1518:        if (*s) {
                   1519:                memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
                   1520:                for (app = items; app < items + MAX_PROMPT_ITEMS - 1 && 
                   1521:                                (*app = strsep(&s, " \t")); *app ? app++ : app);
                   1522: 
                   1523:                // exec_cmd ...
                   1524:                i = 0;
                   1525:                SLIST_FOREACH(cmd, &cli_buffer->line_cmds, cmd_next) {
                   1526:                        if (!(cmd->cmd_level & (1 << cli_buffer->line_level)))
                   1527:                                continue;
                   1528:                        if (*items[0] && !strncmp(cmd->cmd_name, items[0], strlen(items[0])))
                   1529:                                break;
                   1530:                        else
                   1531:                                i++;
                   1532:                }
                   1533: 
                   1534:                if (!cmd) {
                   1535:                        cli_Printf(cli_buffer, "%sCommand '%s' not found!\n", 
                   1536:                                        cli_buffer->line_prompt ? "\n" : "", items[0]);
                   1537:                        ret = RETCODE_ERR;
                   1538:                } else
                   1539:                        if (cmd->cmd_func) {
                   1540:                                if (prompt && cli_buffer->line_prompt)
                   1541:                                        cli_Printf(cli_buffer, "\n");
                   1542:                                ret = cmd->cmd_func(cli_buffer, 
                   1543:                                                cli_buffer->line_level, items);
                   1544:                        } else if (prompt) {
                   1545:                                clrscrEOL(cli_buffer);
                   1546:                                printfCR(cli_buffer, 1);
                   1547:                        }
                   1548:        }
                   1549: 
                   1550:        return ret;
                   1551: }
                   1552: 
                   1553: /*
1.6       misho    1554:  * cliLoop() - CLI main loop
                   1555:  *
1.7       misho    1556:  * @cli_buffer = CLI buffer
1.3       misho    1557:  * @csHistFile = History file name
1.10      misho    1558:  * @timeout = Session timeout (-1 infinit)
1.3       misho    1559:  * return: RETCODE_ERR error, RETCODE_OK ok
1.1       misho    1560: */
1.3       misho    1561: int
1.12      misho    1562: cliLoop(linebuffer_t * __restrict cli_buffer, const char *csHistFile, int timeout)
1.1       misho    1563: {
1.17      misho    1564:        char *line;
1.3       misho    1565:        int ret = RETCODE_OK;
1.18      misho    1566:        struct termios t;
1.1       misho    1567: 
                   1568:        /* --- main body of CLI --- */
1.18      misho    1569:        cliSetLine(cli_buffer, &t);
1.1       misho    1570: 
1.7       misho    1571:        if (cli_loadHistory(cli_buffer, csHistFile) == RETCODE_ERR)
1.3       misho    1572:                return RETCODE_ERR;
1.1       misho    1573: 
                   1574:        do {
1.12      misho    1575:                line = cliReadLine(cli_buffer, timeout);
1.3       misho    1576:                if (!line) {
1.7       misho    1577:                        printfNL(cli_buffer, 0);
1.1       misho    1578:                        break;
1.3       misho    1579:                } else
1.7       misho    1580:                        cli_addHistory(cli_buffer, NULL);
1.3       misho    1581: 
1.17      misho    1582:                ret = cliRun(cli_buffer, line, 42);
1.1       misho    1583: 
1.7       misho    1584:                cli_freeLine(cli_buffer);
                   1585:                cli_resetHistory(cli_buffer);
1.6       misho    1586:                e_free(line);
1.19    ! misho    1587:        } while (!cli_buffer->line_kill);
1.1       misho    1588: 
1.7       misho    1589:        cli_saveHistory(cli_buffer, csHistFile, HISTORY_LINES);
1.18      misho    1590: 
                   1591:        /* --- restore tty --- */
                   1592:        cliResetLine(cli_buffer, &t);
                   1593: 
1.1       misho    1594:        return ret;
                   1595: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>