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

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.21.2.3! misho       6: * $Id: aitcli.c,v 1.21.2.2 2025/12/21 23:21:40 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.20      misho      15: Copyright 2004 - 2025
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
1.21.2.3! misho     101: rewindin(linebuffer_t * __restrict buf, int len)
        !           102: {
        !           103:        int ign __attribute__((unused));
        !           104: 
        !           105:        if (buf) {
        !           106:                if (len == -1)
        !           107:                        len = buf->line_posin;
        !           108:                while (len-- > 0)
        !           109:                        ign = write(buf->line_out, K_CTRL_H, 1);
        !           110:        }
        !           111: }
        !           112: 
        !           113: static inline void
        !           114: printfEOLin(linebuffer_t * __restrict buf)
        !           115: {
        !           116:        int ign __attribute__((unused));
        !           117: 
        !           118:        if (buf)
        !           119:                ign = write(buf->line_out, buf->line_input, buf->line_lenin);
        !           120: }
        !           121: 
        !           122: static inline void
1.3       misho     123: printfEOL(linebuffer_t * __restrict buf, int len, int prompt)
1.2       misho     124: {
1.19      misho     125:        int ign __attribute__((unused));
                    126: 
1.3       misho     127:        if (buf) {
1.21.2.3! misho     128:                ign = write(buf->line_out, K_CR, 1);
        !           129: 
        !           130:                if (prompt && buf->line_prompt)
1.19      misho     131:                        ign = write(buf->line_out, buf->line_prompt, buf->line_bol);
1.3       misho     132: 
1.19      misho     133:                ign = write(buf->line_out, buf->line_buf, len == -1 ? 
1.13      misho     134:                                buf->line_eol - buf->line_bol : len);
1.3       misho     135:        }
1.2       misho     136: }
                    137: 
1.3       misho     138: static inline void
                    139: printfCR(linebuffer_t * __restrict buf, int prompt)
1.2       misho     140: {
1.19      misho     141:        int ign __attribute__((unused));
                    142: 
1.21.2.3! misho     143:        ign = write(buf->line_out, K_CR, 1);
        !           144:        if (buf && prompt && buf->line_prompt)
1.19      misho     145:                ign = write(buf->line_out, buf->line_prompt, buf->line_bol);
1.3       misho     146: }
                    147: 
                    148: static inline void
                    149: printfNL(linebuffer_t * __restrict buf, int prompt)
                    150: {
1.19      misho     151:        int ign __attribute__((unused));
                    152: 
1.3       misho     153:        if (buf) {
1.19      misho     154:                ign = write(buf->line_out, K_ENTER, 1);
1.3       misho     155: 
                    156:                if (prompt)
                    157:                        if (prompt && buf->line_prompt)
1.19      misho     158:                                ign = write(buf->line_out, buf->line_prompt, buf->line_bol);
1.3       misho     159:        }
                    160: }
                    161: 
                    162: // ------------------------------------------------------------
                    163: 
                    164: static int
1.21.2.3! misho     165: bufCHARin(int idx, void * __restrict cli_buffer)
        !           166: {
        !           167:        linebuffer_t *buf = cli_buffer;
        !           168:        int pos;
        !           169:        int ign __attribute__((unused));
        !           170: 
        !           171:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
        !           172:                return RETCODE_ERR;
        !           173: 
        !           174:        pos = buf->line_posin;
        !           175: 
        !           176:        if (buf->line_mode == LINEMODE_INS)
        !           177:                memmove(buf->line_input + pos + buf->line_inkeys[idx].key_len, buf->line_input + pos, 
        !           178:                                buf->line_lenin - buf->line_posin);
        !           179:        if (buf->line_mode == LINEMODE_INS || buf->line_posin == buf->line_lenin)
        !           180:                buf->line_lenin += buf->line_inkeys[idx].key_len;
        !           181:        buf->line_posin += buf->line_inkeys[idx].key_len;
        !           182: 
        !           183:        memcpy(buf->line_input + pos, buf->line_inkeys[idx].key_ch, buf->line_inkeys[idx].key_len);
        !           184:        buf->line_input[buf->line_lenin] = 0;
        !           185: 
        !           186:        if (buf->line_mode == LINEMODE_INS) {
        !           187:                rewindin(buf, buf->line_posin - buf->line_inkeys[idx].key_len);
        !           188:                printfEOLin(buf);
        !           189:                rewindin(buf, buf->line_lenin - buf->line_posin);
        !           190:        }
        !           191:        return RETCODE_OK;
        !           192: }
        !           193: 
        !           194: static int
1.7       misho     195: bufCHAR(int idx, void * __restrict cli_buffer)
1.3       misho     196: {
1.7       misho     197:        linebuffer_t *buf = cli_buffer;
1.3       misho     198:        int pos;
1.19      misho     199:        int ign __attribute__((unused));
1.3       misho     200: 
1.7       misho     201:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     202:                return RETCODE_ERR;
                    203: 
                    204:        pos = buf->line_eol - buf->line_bol;
                    205: 
                    206:        if (buf->line_mode == LINEMODE_INS)
                    207:                memmove(buf->line_buf + pos + buf->line_keys[idx].key_len, buf->line_buf + pos, 
                    208:                                buf->line_len - buf->line_eol);
                    209:        if (buf->line_mode == LINEMODE_INS || buf->line_eol == buf->line_len - 1)
                    210:                buf->line_len += buf->line_keys[idx].key_len;
                    211:        buf->line_eol += buf->line_keys[idx].key_len;
                    212: 
                    213:        memcpy(buf->line_buf + pos, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
                    214:        buf->line_buf[buf->line_len - 1] = 0;
                    215: 
1.13      misho     216:        if (buf->line_prompt)
1.19      misho     217:                ign = write(buf->line_out, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
1.3       misho     218: 
                    219:        if (buf->line_mode == LINEMODE_INS) {
1.19      misho     220:                ign = write(buf->line_out, (const u_char*) buf->line_buf + pos + buf->line_keys[idx].key_len, 
1.3       misho     221:                                buf->line_len - buf->line_eol);
                    222:                printfEOL(buf, -1, 1);
1.2       misho     223:        }
1.3       misho     224:        return RETCODE_OK;
                    225: }
                    226: 
                    227: static int
1.21.2.3! misho     228: bufEOLin(int idx, void * __restrict cli_buffer)
        !           229: {
        !           230:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
        !           231:                return RETCODE_ERR;
        !           232: 
        !           233:        return RETCODE_EOL;
        !           234: }
        !           235: 
        !           236: static int
1.7       misho     237: bufEOL(int idx, void * __restrict cli_buffer)
1.3       misho     238: {
1.7       misho     239:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     240:                return RETCODE_ERR;
                    241: 
1.7       misho     242:        printfCR(cli_buffer, 1);
1.3       misho     243:        return RETCODE_EOL;
                    244: }
                    245: 
                    246: static int
1.7       misho     247: bufEOF(int idx, void * __restrict cli_buffer)
1.3       misho     248: {
1.20      misho     249:        int ret;
                    250: 
1.3       misho     251:        /*
1.7       misho     252:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     253:                return RETCODE_ERR;
                    254:        */
                    255: 
1.20      misho     256:        printfNL(cli_buffer, 0);
                    257:        ret = cli_Cmd_End(cli_buffer, idx, NULL);
                    258:        printfCR(cli_buffer, (ret != RETCODE_EOF));
                    259: 
                    260:        return ret;
1.3       misho     261: }
                    262: 
                    263: static int
1.7       misho     264: bufUP(int idx, void * __restrict cli_buffer)
1.3       misho     265: {
1.7       misho     266:        linebuffer_t *buf = cli_buffer;
1.3       misho     267:        int pos;
                    268: 
1.7       misho     269:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     270:                return RETCODE_ERR;
                    271: 
                    272:        if (!buf->line_h)
                    273:                buf->line_h = TAILQ_FIRST(&buf->line_history);
                    274:        else
                    275:                buf->line_h = TAILQ_NEXT(buf->line_h, hist_next);
                    276:        if (!buf->line_h)
                    277:                return RETCODE_OK;
                    278: 
                    279:        clrscrEOL(buf);
                    280:        cli_freeLine(buf);
                    281: 
                    282:        pos = buf->line_eol - buf->line_bol;
                    283: 
                    284:        buf->line_len += buf->line_h->hist_len;
                    285:        buf->line_eol += buf->line_h->hist_len;
                    286: 
                    287:        memcpy(buf->line_buf + pos, buf->line_h->hist_line, buf->line_h->hist_len);
                    288:        buf->line_buf[buf->line_len - 1] = 0;
                    289: 
                    290:        printfEOL(buf, -1, 1);
                    291:        return RETCODE_OK;
                    292: }
                    293: 
                    294: static int
1.7       misho     295: bufDOWN(int idx, void * __restrict cli_buffer)
1.3       misho     296: {
1.7       misho     297:        linebuffer_t *buf = cli_buffer;
1.3       misho     298:        int pos;
                    299: 
1.7       misho     300:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     301:                return RETCODE_ERR;
                    302: 
                    303:        if (!buf->line_h)
                    304:                buf->line_h = TAILQ_LAST(&buf->line_history, tqHistoryHead);
                    305:        else
                    306:                buf->line_h = TAILQ_PREV(buf->line_h, tqHistoryHead, hist_next);
                    307:        if (!buf->line_h)
                    308:                return RETCODE_OK;
                    309: 
                    310:        clrscrEOL(buf);
                    311:        cli_freeLine(buf);
                    312: 
                    313:        pos = buf->line_eol - buf->line_bol;
                    314: 
                    315:        buf->line_len += buf->line_h->hist_len;
                    316:        buf->line_eol += buf->line_h->hist_len;
                    317: 
                    318:        memcpy(buf->line_buf + pos, buf->line_h->hist_line, buf->line_h->hist_len);
                    319:        buf->line_buf[buf->line_len - 1] = 0;
                    320: 
                    321:        printfEOL(buf, -1, 1);
                    322:        return RETCODE_OK;
                    323: }
                    324: 
                    325: static int
1.21.2.3! misho     326: bufCLRin(int idx, void * __restrict cli_buffer)
        !           327: {
        !           328:        linebuffer_t *buf = cli_buffer;
        !           329: 
        !           330:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
        !           331:                return RETCODE_ERR;
        !           332: 
        !           333:        memset(buf->line_input, ' ', buf->line_lenin);
        !           334:        rewindin(buf, -1);
        !           335:        printfEOLin(buf);
        !           336:        rewindin(buf, -1);
        !           337:        cli_freeInput(cli_buffer);
        !           338:        return RETCODE_OK;
        !           339: }
        !           340: 
        !           341: static int
1.7       misho     342: bufCLR(int idx, void * __restrict cli_buffer)
1.3       misho     343: {
1.7       misho     344:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     345:                return RETCODE_ERR;
                    346: 
1.7       misho     347:        clrscrEOL(cli_buffer);
                    348:        cli_freeLine(cli_buffer);
1.3       misho     349: 
1.7       misho     350:        printfCR(cli_buffer, 1);
1.3       misho     351:        return RETCODE_OK;
                    352: }
                    353: 
                    354: static int
1.7       misho     355: bufBS(int idx, void * __restrict cli_buffer)
1.3       misho     356: {
1.7       misho     357:        linebuffer_t *buf = cli_buffer;
1.3       misho     358: 
1.7       misho     359:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     360:                return RETCODE_ERR;
                    361: 
                    362:        if (buf->line_bol < buf->line_eol) {
                    363:                clrscrEOL(buf);
                    364: 
                    365:                buf->line_eol--;
                    366:                buf->line_len--;
                    367:                memmove(buf->line_buf + buf->line_eol - buf->line_bol, 
                    368:                                buf->line_buf + buf->line_eol - buf->line_bol + 1, 
                    369:                                buf->line_len - buf->line_eol);
                    370:                buf->line_buf[buf->line_len - 1] = 0;
                    371: 
                    372:                printfEOL(buf, buf->line_len - 1, 1);
                    373:                printfEOL(buf, -1, 1);
                    374:        }
                    375: 
                    376:        return RETCODE_OK;
                    377: }
                    378: 
                    379: static int
1.7       misho     380: bufBTAB(int idx, void * __restrict cli_buffer)
1.3       misho     381: {
1.7       misho     382:        linebuffer_t *buf = cli_buffer;
1.3       misho     383: 
1.7       misho     384:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     385:                return RETCODE_ERR;
                    386: 
                    387:        if (buf->line_bol < buf->line_eol) {
                    388:                clrscrEOL(buf);
                    389: 
                    390:                buf->line_len = buf->line_eol - buf->line_bol + 1;
                    391:                buf->line_buf[buf->line_len - 1] = 0;
                    392: 
                    393:                printfEOL(buf, -1, 1);
1.2       misho     394:        }
                    395: 
1.3       misho     396:        return RETCODE_OK;
                    397: }
                    398: 
                    399: static int
1.7       misho     400: bufMODE(int idx, void * __restrict cli_buffer)
1.3       misho     401: {
1.7       misho     402:        linebuffer_t *buf = cli_buffer;
1.3       misho     403: 
1.7       misho     404:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     405:                return RETCODE_ERR;
                    406: 
                    407:        buf->line_mode = !buf->line_mode ? LINEMODE_OVER : LINEMODE_INS;
                    408:        return RETCODE_OK;
                    409: }
                    410: 
                    411: static int
1.21.2.3! misho     412: bufBEGINin(int idx, void * __restrict cli_buffer)
        !           413: {
        !           414:        linebuffer_t *buf = cli_buffer;
        !           415: 
        !           416:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
        !           417:                return RETCODE_ERR;
        !           418: 
        !           419:        rewindin(buf, -1);
        !           420:        buf->line_posin ^= buf->line_posin;
        !           421: 
        !           422:        return RETCODE_OK;
        !           423: }
        !           424: 
        !           425: static int
1.7       misho     426: bufBEGIN(int idx, void * __restrict cli_buffer)
1.3       misho     427: {
1.7       misho     428:        linebuffer_t *buf = cli_buffer;
1.3       misho     429: 
1.7       misho     430:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     431:                return RETCODE_ERR;
                    432: 
                    433:        buf->line_eol = buf->line_bol;
                    434: 
                    435:        printfCR(buf, 1);
                    436:        return RETCODE_OK;
                    437: }
                    438: 
                    439: static int
1.21.2.3! misho     440: bufENDin(int idx, void * __restrict cli_buffer)
        !           441: {
        !           442:        linebuffer_t *buf = cli_buffer;
        !           443: 
        !           444:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
        !           445:                return RETCODE_ERR;
        !           446: 
        !           447:        rewindin(buf, -1);
        !           448:        printfEOLin(buf);
        !           449:        buf->line_posin = buf->line_lenin;
        !           450: 
        !           451:        return RETCODE_OK;
        !           452: }
        !           453: 
        !           454: static int
1.7       misho     455: bufEND(int idx, void * __restrict cli_buffer)
1.3       misho     456: {
1.7       misho     457:        linebuffer_t *buf = cli_buffer;
1.3       misho     458: 
1.7       misho     459:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     460:                return RETCODE_ERR;
                    461: 
                    462:        buf->line_eol = buf->line_len - 1;
                    463: 
                    464:        printfEOL(buf, -1, 1);
                    465:        return RETCODE_OK;
1.2       misho     466: }
                    467: 
1.3       misho     468: static int
1.7       misho     469: bufLEFT(int idx, void * __restrict cli_buffer)
1.2       misho     470: {
1.7       misho     471:        linebuffer_t *buf = cli_buffer;
1.3       misho     472: 
1.7       misho     473:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     474:                return RETCODE_ERR;
                    475: 
                    476:        if (buf->line_bol < buf->line_eol)
                    477:                printfEOL(buf, --buf->line_eol - buf->line_bol, 1);
                    478: 
                    479:        return RETCODE_OK;
                    480: }
1.2       misho     481: 
1.3       misho     482: static int
1.7       misho     483: bufRIGHT(int idx, void * __restrict cli_buffer)
1.3       misho     484: {
1.7       misho     485:        linebuffer_t *buf = cli_buffer;
1.3       misho     486: 
1.7       misho     487:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     488:                return RETCODE_ERR;
                    489: 
                    490:        if (buf->line_eol < buf->line_len - 1)
                    491:                printfEOL(buf, ++buf->line_eol - buf->line_bol, 1);
                    492: 
                    493:        return RETCODE_OK;
                    494: }
                    495: 
                    496: static int
1.7       misho     497: bufDEL(int idx, void * __restrict cli_buffer)
1.3       misho     498: {
1.7       misho     499:        linebuffer_t *buf = cli_buffer;
1.3       misho     500: 
1.7       misho     501:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     502:                return RETCODE_ERR;
                    503: 
                    504:        clrscrEOL(buf);
                    505: 
                    506:        buf->line_len--;
                    507:        memmove(buf->line_buf + buf->line_eol - buf->line_bol, 
                    508:                        buf->line_buf + buf->line_eol - buf->line_bol + 1, 
                    509:                        buf->line_len - buf->line_eol);
                    510:        buf->line_buf[buf->line_len - 1] = 0;
                    511: 
                    512:        printfEOL(buf, buf->line_len - 1, 1);
                    513:        printfEOL(buf, -1, 1);
                    514: 
                    515:        return RETCODE_OK;
                    516: }
                    517: 
                    518: static int
1.7       misho     519: bufComp(int idx, void * __restrict cli_buffer)
1.3       misho     520: {
1.7       misho     521:        linebuffer_t *buf = cli_buffer;
1.3       misho     522:        char *str, *s, **app, *items[MAX_PROMPT_ITEMS], szLine[STRSIZ];
                    523:        register int i, j;
                    524:        struct tagCommand *cmd, *c;
                    525:        int pos, ret = RETCODE_OK;
1.19      misho     526:        int ign __attribute__((unused));
1.3       misho     527: 
1.7       misho     528:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     529:                return RETCODE_ERR;
                    530: 
1.6       misho     531:        str = e_strdup(buf->line_buf);
1.3       misho     532:        if (!str)
                    533:                return RETCODE_ERR;
1.2       misho     534:        else {
1.3       misho     535:                s = str;
1.6       misho     536:                str_Trim(s);
1.3       misho     537:        }
                    538: 
1.20      misho     539:        j = 0;
1.3       misho     540:        c = NULL;
                    541:        memset(szLine, 0, STRSIZ);
                    542:        if (*s) {
                    543:                memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
1.9       misho     544:                for (app = items, i = 0; app < items + MAX_PROMPT_ITEMS - 1 && 
                    545:                                (*app = strsep(&s, " \t")); 
1.3       misho     546:                                *app ? i++ : i, *app ? app++ : app);
                    547: 
                    548:                if (i) {
                    549:                        SLIST_FOREACH(cmd, &buf->line_cmds, cmd_next) {
1.9       misho     550:                                if (cmd->cmd_level & (1 << buf->line_level) && 
                    551:                                                !strncmp(cmd->cmd_name, items[0], 
                    552:                                                        strlen(items[0]))) {
                    553:                                        if (strncmp(cmd->cmd_name, CLI_CMD_SEP, 
                    554:                                                                strlen(CLI_CMD_SEP))) {
1.3       misho     555:                                                j++;
                    556:                                                c = cmd;
                    557:                                                strlcat(szLine, " ", STRSIZ);
                    558:                                                strlcat(szLine, cmd->cmd_name, STRSIZ);
                    559:                                        }
                    560:                                }
                    561:                        }
1.2       misho     562: 
1.3       misho     563:                        if (i > 1 && c) {
                    564:                                /* we are on argument of command and has complition info */
                    565:                                j++;    // always must be j > 1 ;) for arguments
                    566:                                strlcpy(szLine, c->cmd_info, STRSIZ);
                    567:                        }
                    568:                } else {
                    569:                        /* we have valid char but i == 0, this case is illegal */
                    570:                        ret = RETCODE_ERR;
                    571:                        goto endcomp;
1.2       misho     572:                }
1.3       misho     573:        } else {
                    574:                /* we on 0 position of prompt, show commands for this level */
                    575:                SLIST_FOREACH(cmd, &buf->line_cmds, cmd_next) {
1.9       misho     576:                        if (cmd->cmd_level & (1 << buf->line_level))
1.3       misho     577:                                if (strncmp(cmd->cmd_name, CLI_CMD_SEP, strlen(CLI_CMD_SEP))) {
                    578:                                        j++;
                    579:                                        c = cmd;
                    580:                                        strlcat(szLine, " ", STRSIZ);
                    581:                                        strlcat(szLine, cmd->cmd_name, STRSIZ);
                    582:                                }
                    583:                }
                    584:        }
1.2       misho     585: 
1.3       misho     586:        /* completion show actions ... */
                    587:        if (j > 1 && c) {
                    588:                printfNL(buf, 0);
1.19      misho     589:                ign = write(buf->line_out, szLine, strlen(szLine));
1.3       misho     590:                printfNL(buf, 1);
                    591:                printfEOL(buf, buf->line_len - 1, 1);
                    592:                printfEOL(buf, -1, 1);
1.2       misho     593:        }
1.3       misho     594:        if (j == 1 && c) {
                    595:                clrscrEOL(buf);
                    596:                cli_freeLine(buf);
                    597: 
                    598:                pos = buf->line_eol - buf->line_bol;
                    599: 
                    600:                buf->line_len += c->cmd_len + 1;
                    601:                buf->line_eol += c->cmd_len + 1;
                    602: 
                    603:                memcpy(buf->line_buf + pos, c->cmd_name, c->cmd_len);
                    604:                buf->line_buf[pos + c->cmd_len] = (u_char) *K_SPACE;
                    605:                buf->line_buf[buf->line_len - 1] = 0;
1.2       misho     606: 
1.3       misho     607:                printfEOL(buf, -1, 1);
1.2       misho     608:        }
                    609: 
1.3       misho     610: endcomp:
1.6       misho     611:        e_free(str);
1.3       misho     612:        return ret;
                    613: }
                    614: 
                    615: static int
1.7       misho     616: bufHelp(int idx, void * __restrict cli_buffer)
1.3       misho     617: {
1.7       misho     618:        linebuffer_t *buf = cli_buffer;
1.3       misho     619: 
1.7       misho     620:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     621:                return RETCODE_ERR;
                    622: 
1.9       misho     623:        cli_Cmd_Help(buf, buf->line_level, NULL);
1.3       misho     624: 
                    625:        printfEOL(buf, buf->line_len - 1, 1);
                    626:        printfEOL(buf, -1, 1);
                    627:        return RETCODE_OK;
                    628: }
                    629: 
1.9       misho     630: static int
                    631: bufEndNode(int idx, void * __restrict cli_buffer)
                    632: {
                    633:        linebuffer_t *buf = cli_buffer;
1.20      misho     634:        char szPrompt[STRSIZ + 16] = {[0 ... STRSIZ + 15] = 0};
1.9       misho     635: 
                    636:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
                    637:                return RETCODE_ERR;
                    638: 
                    639:        if (buf->line_level > 0) {
                    640:                printfNL(cli_buffer, 0);
                    641:                buf->line_level--;
1.20      misho     642:                snprintf(szPrompt, sizeof szPrompt, "%s{%d}> ", buf->line_porigin, buf->line_level);
                    643:                cli_setPrompt(buf, szPrompt);
1.9       misho     644:                cli_Printf(buf, "Enter to config level %d\n", buf->line_level);
                    645:        }
                    646: 
                    647:        return bufCLR(idx, cli_buffer);
                    648: }
                    649: 
1.3       misho     650: 
                    651: /*
1.6       misho     652:  * cli_Printf() - Send message to CLI session
                    653:  *
1.7       misho     654:  * @cli_buffer = CLI buffer
1.3       misho     655:  * @fmt = printf format string
                    656:  * @... = arguments defined in fmt
                    657:  * return: none
                    658: */
1.6       misho     659: void
1.7       misho     660: cli_Printf(linebuffer_t * __restrict cli_buffer, char *fmt, ...)
1.3       misho     661: {
                    662:        va_list lst;
                    663:        FILE *f;
                    664: 
                    665:        if (fmt) {
1.21      misho     666:                f = fdopen(dup(cli_buffer->line_out), "a");
1.3       misho     667:                if (!f) {
                    668:                        LOGERR;
                    669:                        return;
                    670:                }
                    671: 
                    672:                va_start(lst, fmt);
                    673:                vfprintf(f, fmt, lst);
                    674:                va_end(lst);
1.20      misho     675: 
                    676:                fclose(f);
1.3       misho     677:        } else
1.6       misho     678:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     679: }
                    680: 
                    681: /*
1.6       misho     682:  * cli_PrintHelp() - Print help screen
                    683:  *
1.7       misho     684:  * @cli_buffer = CLI buffer
1.3       misho     685:  * return: none
                    686: */
1.6       misho     687: void
1.7       misho     688: cli_PrintHelp(linebuffer_t * __restrict cli_buffer)
1.3       misho     689: {
1.7       misho     690:        if (cli_buffer) {
                    691:                bufHelp(0, cli_buffer);
                    692:                clrscrEOL(cli_buffer);
1.3       misho     693:        } else
1.6       misho     694:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     695: }
                    696: 
                    697: 
                    698: /*
1.6       misho     699:  * cli_BindKey() - Bind function to key
                    700:  *
1.3       misho     701:  * @key = key structure
1.7       misho     702:  * @cli_buffer = CLI buffer
1.3       misho     703:  * return: RETCODE_ERR error, RETCODE_OK ok, >0 bind at position
                    704: */
                    705: int
1.7       misho     706: cli_BindKey(bindkey_t * __restrict key, linebuffer_t * __restrict cli_buffer)
1.3       misho     707: {
                    708:        register int i;
                    709: 
1.7       misho     710:        if (!key || !cli_buffer) {
1.6       misho     711:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     712:                return RETCODE_ERR;
1.2       misho     713:        }
1.3       misho     714: 
                    715:        for (i = 0; i < MAX_BINDKEY; i++)
1.7       misho     716:                if (key->key_len == cli_buffer->line_keys[i].key_len && 
                    717:                                !memcmp(key->key_ch, cli_buffer->line_keys[i].key_ch, 
                    718:                                        key->key_len)) {
                    719:                        cli_buffer->line_keys[i].key_func = key->key_func;
1.3       misho     720:                        return i;
                    721:                }
                    722: 
                    723:        return RETCODE_OK;
1.2       misho     724: }
                    725: 
                    726: 
1.3       misho     727: /*
1.6       misho     728:  * cli_addCommand() - Add command to CLI session
                    729:  *
1.7       misho     730:  * @cli_buffer = CLI buffer
1.3       misho     731:  * @csCmd = Command name
1.9       misho     732:  * @cliLevel = Level in CLI, -1 view from all levels, 0 hidden, >0 mask levels
1.3       misho     733:  * @funcCmd = Callback function when user call command
                    734:  * @csInfo = Inline information for command
                    735:  * @csHelp = Help line when call help
                    736:  * return: RETCODE_ERR error, RETCODE_OK ok
                    737: */
                    738: int
1.7       misho     739: cli_addCommand(linebuffer_t * __restrict cli_buffer, const char *csCmd, 
                    740:                int cliLevel, cmd_func_t funcCmd, 
1.3       misho     741:                const char *csInfo, const char *csHelp)
1.1       misho     742: {
1.3       misho     743:        struct tagCommand *cmd;
                    744: 
1.7       misho     745:        if (!cli_buffer || !csCmd) {
1.6       misho     746:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     747:                return RETCODE_ERR;
                    748:        }
                    749: 
1.6       misho     750:        cmd = e_malloc(sizeof(struct tagCommand));
1.3       misho     751:        if (!cmd) {
                    752:                LOGERR;
                    753:                return RETCODE_ERR;
                    754:        } else
                    755:                memset(cmd, 0, sizeof(struct tagCommand));
                    756: 
                    757:        cmd->cmd_level = cliLevel;
                    758:        cmd->cmd_func = funcCmd;
                    759:        cmd->cmd_len = strlcpy(cmd->cmd_name, csCmd, STRSIZ);
                    760:        if (csInfo)
                    761:                strlcpy(cmd->cmd_info, csInfo, STRSIZ);
                    762:        if (csHelp)
                    763:                strlcpy(cmd->cmd_help, csHelp, STRSIZ);
1.7       misho     764:        SLIST_INSERT_HEAD(&cli_buffer->line_cmds, cmd, cmd_next);
1.3       misho     765:        return RETCODE_OK;
1.1       misho     766: }
                    767: 
1.3       misho     768: /*
1.6       misho     769:  * cli_delCommand() - Delete command from CLI session
                    770:  *
1.7       misho     771:  * @cli_buffer = CLI buffer
1.3       misho     772:  * @csCmd = Command name
1.9       misho     773:  * @cliLevel = Level in CLI, -1 view from all levels, 0 hidden, >0 mask levels
1.3       misho     774:  * return: RETCODE_ERR error, RETCODE_OK ok
                    775: */
                    776: int
1.7       misho     777: cli_delCommand(linebuffer_t * __restrict cli_buffer, const char *csCmd, int cliLevel)
1.1       misho     778: {
1.3       misho     779:        struct tagCommand *cmd;
                    780:        int ret = RETCODE_OK;
                    781: 
1.7       misho     782:        if (!cli_buffer || !csCmd) {
1.6       misho     783:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     784:                return RETCODE_ERR;
                    785:        }
                    786: 
1.7       misho     787:        SLIST_FOREACH(cmd, &cli_buffer->line_cmds, cmd_next) 
1.3       misho     788:                if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) {
                    789:                        ret = 1;
1.7       misho     790:                        SLIST_REMOVE(&cli_buffer->line_cmds, cmd, tagCommand, cmd_next);
1.6       misho     791:                        e_free(cmd);
1.3       misho     792:                        break;
                    793:                }
                    794: 
                    795:        return ret;
1.1       misho     796: }
                    797: 
1.3       misho     798: /*
1.6       misho     799:  * cli_updCommand() - Update command in CLI session
                    800:  *
1.7       misho     801:  * @cli_buffer = CLI buffer
1.3       misho     802:  * @csCmd = Command name
1.9       misho     803:  * @cliLevel = Level in CLI, -1 view from all levels, 0 hidden, >0 mask levels
1.3       misho     804:  * @funcCmd = Callback function when user call command
                    805:  * @csInfo = Inline information for command
                    806:  * @csHelp = Help line when call help
                    807:  * return: RETCODE_ERR error, RETCODE_OK ok
                    808: */
                    809: int
1.7       misho     810: cli_updCommand(linebuffer_t * __restrict cli_buffer, const char *csCmd, 
                    811:                int cliLevel, cmd_func_t funcCmd, 
1.3       misho     812:                const char *csInfo, const char *csHelp)
1.1       misho     813: {
1.3       misho     814:        struct tagCommand *cmd;
                    815:        int ret = RETCODE_OK;
                    816: 
1.7       misho     817:        if (!cli_buffer || !csCmd) {
1.6       misho     818:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     819:                return RETCODE_ERR;
                    820:        }
                    821: 
1.9       misho     822:        SLIST_FOREACH(cmd, &cli_buffer->line_cmds, cmd_next)
                    823:                if ((!cmd->cmd_level || cmd->cmd_level == cliLevel) && 
                    824:                                !strcmp(cmd->cmd_name, csCmd)) {
                    825:                        if (!cmd->cmd_level)
                    826:                                cmd->cmd_level = cliLevel;
1.3       misho     827:                        if (funcCmd)
                    828:                                cmd->cmd_func = funcCmd;
                    829:                        if (csInfo)
                    830:                                strlcpy(cmd->cmd_info, csInfo, STRSIZ);
                    831:                        if (csHelp)
                    832:                                strlcpy(cmd->cmd_help, csHelp, STRSIZ);
                    833: 
                    834:                        break;
                    835:                }
1.1       misho     836: 
1.3       misho     837:        return ret;
1.1       misho     838: }
                    839: 
                    840: 
                    841: /*
1.6       misho     842:  * cli_addHistory() - Add line to history
                    843:  *
1.7       misho     844:  * @cli_buffer = CLI buffer
1.3       misho     845:  * @str = Add custom text or if NULL use readed line from CLI buffer
                    846:  * return: RETCODE_ERR error, RETCODE_OK ok
1.1       misho     847: */
1.3       misho     848: int
1.7       misho     849: cli_addHistory(linebuffer_t * __restrict cli_buffer, const char * __restrict str)
1.1       misho     850: {
1.3       misho     851:        struct tagHistory *h;
                    852: 
1.7       misho     853:        if (!cli_buffer) {
1.6       misho     854:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     855:                return RETCODE_ERR;
                    856:        }
                    857: 
1.6       misho     858:        if (!(h = e_malloc(sizeof(struct tagHistory)))) {
1.3       misho     859:                LOGERR;
                    860:                return RETCODE_ERR;
                    861:        } else
                    862:                memset(h, 0, sizeof(struct tagHistory));
                    863: 
                    864:        if (str) {
                    865:                if (!*str) {
1.6       misho     866:                        e_free(h);
1.3       misho     867:                        return RETCODE_OK;
                    868:                }
                    869: 
                    870:                h->hist_len = strlcpy(h->hist_line, str, BUFSIZ);
                    871:        } else {
1.7       misho     872:                if (!*cli_buffer->line_buf || cli_buffer->line_len < 2) {
1.6       misho     873:                        e_free(h);
1.3       misho     874:                        return RETCODE_OK;
                    875:                }
                    876: 
1.7       misho     877:                memcpy(h->hist_line, cli_buffer->line_buf, (h->hist_len = cli_buffer->line_len));
1.6       misho     878:                str_Trim(h->hist_line);
1.3       misho     879:                h->hist_len = strlen(h->hist_line);
                    880:        }
1.1       misho     881: 
1.7       misho     882:        TAILQ_INSERT_HEAD(&cli_buffer->line_history, h, hist_next);
1.3       misho     883:        return h->hist_len;
                    884: }
1.1       misho     885: 
1.3       misho     886: /*
1.6       misho     887:  * cli_saveHistory() - Save history to file
                    888:  *
1.7       misho     889:  * @cli_buffer = CLI buffer
1.3       misho     890:  * @histfile = History filename, if NULL will be use default name
                    891:  * @lines = Maximum history lines to save
                    892:  * return: RETCODE_ERR error, RETCODE_OK ok
                    893: */
                    894: int
1.7       misho     895: cli_saveHistory(linebuffer_t * __restrict cli_buffer, const char *histfile, int lines)
1.3       misho     896: {
                    897:        FILE *f;
                    898:        mode_t mode;
                    899:        char szFName[MAXPATHLEN];
                    900:        struct tagHistory *h;
                    901: 
1.7       misho     902:        if (!cli_buffer) {
1.6       misho     903:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     904:                return RETCODE_ERR;
                    905:        }
                    906:        if (!histfile)
                    907:                strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
                    908:        else
                    909:                strlcpy(szFName, histfile, MAXPATHLEN);
                    910: 
                    911:        mode = umask(0177);
                    912:        f = fopen(szFName, "w");
                    913:        if (!f) {
1.1       misho     914:                LOGERR;
1.3       misho     915:                return RETCODE_ERR;
                    916:        }
                    917: 
1.7       misho     918:        TAILQ_FOREACH(h, &cli_buffer->line_history, hist_next) {
1.3       misho     919:                fprintf(f, "%s\n", h->hist_line);
                    920: 
                    921:                if (lines)
                    922:                        lines--;
                    923:                else
                    924:                        break;
                    925:        }
1.1       misho     926: 
1.3       misho     927:        fclose(f);
                    928:        umask(mode);
                    929: 
                    930:        return RETCODE_OK;
1.1       misho     931: }
                    932: 
1.3       misho     933: /*
1.6       misho     934:  * cli_loadHistory() - Load history from file
                    935:  *
1.7       misho     936:  * @cli_buffer = CLI buffer
1.3       misho     937:  * @histfile = History filename, if NULL will be use default name
                    938:  * return: RETCODE_ERR error, RETCODE_OK ok
                    939: */
                    940: int
1.7       misho     941: cli_loadHistory(linebuffer_t * __restrict cli_buffer, const char *histfile)
1.3       misho     942: {
                    943:        FILE *f;
                    944:        char szFName[MAXPATHLEN], buf[BUFSIZ];
                    945:        struct tagHistory *h;
                    946: 
1.7       misho     947:        if (!cli_buffer) {
1.6       misho     948:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     949:                return RETCODE_ERR;
                    950:        }
                    951:        if (!histfile)
                    952:                strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
                    953:        else
                    954:                strlcpy(szFName, histfile, MAXPATHLEN);
                    955: 
                    956:        f = fopen(szFName, "r");
                    957:        if (!f)
                    958:                return RETCODE_OK;
                    959: 
                    960:        while (fgets(buf, BUFSIZ, f)) {
                    961:                if (!*buf || *buf == '#')
                    962:                        continue;
                    963:                else
1.6       misho     964:                        str_Trim(buf);
1.3       misho     965: 
1.6       misho     966:                if (!(h = e_malloc(sizeof(struct tagHistory)))) {
1.3       misho     967:                        LOGERR;
                    968:                        fclose(f);
                    969:                        return RETCODE_ERR;
                    970:                } else
                    971:                        memset(h, 0, sizeof(struct tagHistory));
                    972: 
                    973:                h->hist_len = strlcpy(h->hist_line, buf, BUFSIZ);
1.7       misho     974:                TAILQ_INSERT_TAIL(&cli_buffer->line_history, h, hist_next);
1.3       misho     975:        }
                    976: 
                    977:        fclose(f);
                    978: 
                    979:        return RETCODE_OK;
                    980: }
1.1       misho     981: 
                    982: /*
1.6       misho     983:  * cli_resetHistory() - Reset history search in CLI session
                    984:  *
1.7       misho     985:  * @cli_buffer = CLI buffer
1.1       misho     986:  * return: none
                    987: */
1.6       misho     988: void
1.7       misho     989: cli_resetHistory(linebuffer_t * __restrict cli_buffer)
1.1       misho     990: {
1.7       misho     991:        cli_buffer->line_h = NULL;
1.1       misho     992: }
                    993: 
1.3       misho     994: 
1.1       misho     995: /*
1.21.2.3! misho     996:  * cli_freeInput() - Clear entire input
        !           997:  *
        !           998:  * @cli_buffer = CLI buffer
        !           999:  * return: RETCODE_ERR error, RETCODE_OK ok
        !          1000: */
        !          1001: int
        !          1002: cli_freeInput(linebuffer_t * __restrict cli_buffer)
        !          1003: {
        !          1004:        int code = RETCODE_ERR;
        !          1005: 
        !          1006:        if (cli_buffer) {
        !          1007:                memset(cli_buffer->line_input, 0, BUFSIZ);
        !          1008:                cli_buffer->line_posin ^= cli_buffer->line_posin;
        !          1009:                cli_buffer->line_lenin ^= cli_buffer->line_lenin;
        !          1010: 
        !          1011:                code = RETCODE_OK;
        !          1012:        } else
        !          1013:                cli_SetErr(EINVAL, "Invalid input parameters ...");
        !          1014: 
        !          1015:        return code;
        !          1016: }
        !          1017: /*
1.6       misho    1018:  * cli_freeLine() - Clear entire line
                   1019:  *
1.7       misho    1020:  * @cli_buffer = CLI buffer
1.3       misho    1021:  * return: RETCODE_ERR error, RETCODE_OK ok
1.2       misho    1022: */
1.6       misho    1023: int
1.7       misho    1024: cli_freeLine(linebuffer_t * __restrict cli_buffer)
1.2       misho    1025: {
1.3       misho    1026:        int code = RETCODE_ERR;
1.2       misho    1027: 
1.7       misho    1028:        if (cli_buffer) {
1.21.2.3! misho    1029:                memset(cli_buffer->line_buf, 0, BUFSIZ);
        !          1030:                cli_buffer->line_eol = cli_buffer->line_bol;
        !          1031:                cli_buffer->line_len = 1 + cli_buffer->line_eol;
1.2       misho    1032: 
1.21.2.3! misho    1033:                code = RETCODE_OK;
1.3       misho    1034:        } else
1.6       misho    1035:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.2       misho    1036: 
1.3       misho    1037:        return code;
1.2       misho    1038: }
                   1039: 
                   1040: /*
1.6       misho    1041:  * cli_setPrompt() - Set new prompt for CLI session
                   1042:  *
1.7       misho    1043:  * @cli_buffer = CLI buffer
1.3       misho    1044:  * @prompt = new text for prompt or if NULL disable prompt
                   1045:  * return: none
1.2       misho    1046: */
1.6       misho    1047: void
1.7       misho    1048: cli_setPrompt(linebuffer_t * __restrict cli_buffer, const char *prompt)
1.2       misho    1049: {
1.7       misho    1050:        if (cli_buffer) {
                   1051:                if (cli_buffer->line_prompt) {
                   1052:                        e_free(cli_buffer->line_prompt);
                   1053:                        cli_buffer->line_prompt = NULL;
                   1054:                        cli_buffer->line_bol = 0;
1.3       misho    1055:                }
                   1056: 
                   1057:                if (prompt) {
1.7       misho    1058:                        cli_buffer->line_prompt = e_strdup(prompt);
                   1059:                        if (cli_buffer->line_prompt) {
                   1060:                                cli_buffer->line_bol = strlen(cli_buffer->line_prompt);
                   1061:                                cli_buffer->line_eol = cli_buffer->line_bol;
                   1062:                                cli_buffer->line_len = 1 + cli_buffer->line_eol;
1.3       misho    1063:                        } else
                   1064:                                LOGERR;
                   1065:                }
                   1066:        } else
1.6       misho    1067:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.2       misho    1068: }
                   1069: 
1.3       misho    1070: 
1.2       misho    1071: /*
1.6       misho    1072:  * cliEnd() - Clear data, Free resources and close CLI session
                   1073:  *
1.7       misho    1074:  * @cli_buffer = CLI buffer
1.3       misho    1075:  * return: RETCODE_ERR error, RETCODE_OK ok
1.2       misho    1076: */
1.3       misho    1077: void
1.7       misho    1078: cliEnd(linebuffer_t * __restrict cli_buffer)
1.2       misho    1079: {
1.3       misho    1080:        struct tagHistory *h;
                   1081:        struct tagCommand *c;
                   1082: 
1.7       misho    1083:        if (cli_buffer) {
                   1084:                while ((c = SLIST_FIRST(&cli_buffer->line_cmds))) {
                   1085:                        SLIST_REMOVE_HEAD(&cli_buffer->line_cmds, cmd_next);
1.6       misho    1086:                        e_free(c);
1.3       misho    1087:                }
1.7       misho    1088:                while ((h = TAILQ_FIRST(&cli_buffer->line_history))) {
                   1089:                        TAILQ_REMOVE(&cli_buffer->line_history, h, hist_next);
1.6       misho    1090:                        e_free(h);
1.3       misho    1091:                }
                   1092: 
1.7       misho    1093:                if (cli_buffer->line_prompt)
                   1094:                        e_free(cli_buffer->line_prompt);
1.2       misho    1095: 
1.7       misho    1096:                if (cli_buffer->line_keys)
                   1097:                        e_free(cli_buffer->line_keys);
                   1098:                if (cli_buffer->line_buf)
                   1099:                        e_free(cli_buffer->line_buf);
1.2       misho    1100: 
1.21.2.2  misho    1101:                if (cli_buffer->line_inkeys)
                   1102:                        e_free(cli_buffer->line_inkeys);
                   1103:                if (cli_buffer->line_input)
                   1104:                        e_free(cli_buffer->line_input);
                   1105: 
1.7       misho    1106:                e_free(cli_buffer);
                   1107:                cli_buffer = NULL;
1.3       misho    1108:        } else
1.6       misho    1109:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho    1110: }
                   1111: 
                   1112: /*
1.6       misho    1113:  * cliInit() - Start CLI session, allocate memory for resources and bind keys
                   1114:  *
1.3       misho    1115:  * @fin = Input device handle
                   1116:  * @fout = Output device handle
                   1117:  * @prompt = text for prompt, if NULL disable prompt
                   1118:  * return: NULL if error or !=NULL CLI buffer
                   1119: */
                   1120: linebuffer_t *
                   1121: cliInit(int fin, int fout, const char *prompt)
                   1122: {
1.7       misho    1123:        linebuffer_t *cli_buffer;
1.21.2.2  misho    1124:        bindkey_t *keys, *inkeys;
1.3       misho    1125:        register int i;
1.18      misho    1126:        char szPrompt[STRSIZ + 16] = {[0 ... STRSIZ + 15] = 0};
1.3       misho    1127: 
                   1128:        /* init buffer */
1.7       misho    1129:        cli_buffer = e_malloc(sizeof(linebuffer_t));
                   1130:        if (!cli_buffer) {
1.3       misho    1131:                LOGERR;
                   1132:                return NULL;
                   1133:        } else {
1.7       misho    1134:                memset(cli_buffer, 0, sizeof(linebuffer_t));
1.3       misho    1135: 
1.7       misho    1136:                cli_buffer->line_in = fin;
                   1137:                cli_buffer->line_out = fout;
1.3       misho    1138: 
1.7       misho    1139:                TAILQ_INIT(&cli_buffer->line_history);
                   1140:                SLIST_INIT(&cli_buffer->line_cmds);
1.3       misho    1141: 
                   1142:                if (prompt) {
1.16      misho    1143:                        strlcpy(cli_buffer->line_porigin, prompt, sizeof cli_buffer->line_porigin);
                   1144:                        snprintf(szPrompt, sizeof szPrompt, "%s{%d}> ", cli_buffer->line_porigin, cli_buffer->line_level);
                   1145:                        cli_buffer->line_prompt = e_strdup(szPrompt);
1.7       misho    1146:                        if (!cli_buffer->line_prompt) {
1.3       misho    1147:                                LOGERR;
1.7       misho    1148:                                e_free(cli_buffer);
1.3       misho    1149:                                return NULL;
                   1150:                        } else
1.7       misho    1151:                                cli_buffer->line_eol = cli_buffer->line_bol = 
                   1152:                                        strlen(cli_buffer->line_prompt);
1.9       misho    1153:                } else
                   1154:                        cli_buffer->line_mode = LINEMODE_OVER;
1.3       misho    1155:        }
1.7       misho    1156:        cli_buffer->line_buf = e_malloc(BUFSIZ);
                   1157:        if (!cli_buffer->line_buf) {
1.3       misho    1158:                LOGERR;
1.7       misho    1159:                if (cli_buffer->line_prompt)
                   1160:                        e_free(cli_buffer->line_prompt);
                   1161:                e_free(cli_buffer);
1.3       misho    1162:                return NULL;
                   1163:        } else {
1.7       misho    1164:                memset(cli_buffer->line_buf, 0, BUFSIZ);
                   1165:                cli_buffer->line_len = 1 + cli_buffer->line_eol;
1.3       misho    1166:        }
1.21.2.3! misho    1167:        cli_buffer->line_input = e_malloc(BUFSIZ);
        !          1168:        if (!cli_buffer->line_input) {
        !          1169:                LOGERR;
        !          1170:                if (cli_buffer->line_prompt)
        !          1171:                        e_free(cli_buffer->line_prompt);
        !          1172:                e_free(cli_buffer->line_buf);
        !          1173:                e_free(cli_buffer);
        !          1174:                return NULL;
        !          1175:        } else {
        !          1176:                memset(cli_buffer->line_input, 0, BUFSIZ);
        !          1177:                cli_buffer->line_lenin = cli_buffer->line_posin;
        !          1178:        }
1.6       misho    1179:        keys = e_calloc(MAX_BINDKEY + 1, sizeof(bindkey_t));
1.3       misho    1180:        if (!keys) {
                   1181:                LOGERR;
1.7       misho    1182:                if (cli_buffer->line_prompt)
                   1183:                        e_free(cli_buffer->line_prompt);
1.21.2.3! misho    1184:                e_free(cli_buffer->line_input);
1.7       misho    1185:                e_free(cli_buffer->line_buf);
                   1186:                e_free(cli_buffer);
1.3       misho    1187:                return NULL;
                   1188:        } else
                   1189:                memset(keys, 0, sizeof(bindkey_t) * (MAX_BINDKEY + 1));
1.21.2.2  misho    1190:        inkeys = e_calloc(MAX_BINDKEY + 1, sizeof(bindkey_t));
                   1191:        if (!inkeys) {
                   1192:                LOGERR;
                   1193:                e_free(keys);
                   1194:                if (cli_buffer->line_prompt)
                   1195:                        e_free(cli_buffer->line_prompt);
1.21.2.3! misho    1196:                e_free(cli_buffer->line_input);
1.21.2.2  misho    1197:                e_free(cli_buffer->line_buf);
                   1198:                e_free(cli_buffer);
                   1199:                return NULL;
                   1200:        } else
                   1201:                memset(inkeys, 0, sizeof(bindkey_t) * (MAX_BINDKEY + 1));
1.3       misho    1202: 
                   1203:        /* add helper functions */
1.9       misho    1204:        cli_addCommand(cli_buffer, "exit", 1, cli_Cmd_Exit, "exit <cr>", "Exit from console");
                   1205:        cli_addCommand(cli_buffer, "help", -1, cli_Cmd_Help, "help [command] <cr>", "Help screen");
                   1206:        cli_addCommand(cli_buffer, "-------", -1, NULL, "-------------------------", NULL);
                   1207:        cli_addCommand(cli_buffer, "where", -1, cli_Cmd_WhereAmI, "where <cr>", 
                   1208:                        "Query current level of console");
                   1209:        cli_addCommand(cli_buffer, "top", -1, cli_Cmd_Top, "top <cr>", "Top level of console");
                   1210:        cli_addCommand(cli_buffer, "end", -1, cli_Cmd_End, "end <cr>", "End level of console");
                   1211:        cli_addCommand(cli_buffer, "config", -1, cli_Cmd_Config, "config <cr>", 
                   1212:                        "Config next level of console");
                   1213:        cli_addCommand(cli_buffer, "-------", -1, NULL, "-------------------------", NULL);
1.3       misho    1214: 
                   1215:        /* fill key bindings */
1.6       misho    1216:        /* ascii chars & ctrl+chars */
1.3       misho    1217:        for (i = 0; i < 256; i++) {
1.21.2.2  misho    1218:                *keys[i].key_ch = *inkeys[i].key_ch = (u_char) i;
                   1219:                keys[i].key_len = inkeys[i].key_len = 1;
1.3       misho    1220: 
                   1221:                if (!i || i == *K_CTRL_D)
                   1222:                        keys[i].key_func = bufEOF;
1.21.2.3! misho    1223:                if (i == *K_CTRL_M || i == *K_CTRL_J) {
1.3       misho    1224:                        keys[i].key_func = bufEOL;
1.21.2.3! misho    1225:                        inkeys[i].key_func = bufEOLin;
        !          1226:                }
1.9       misho    1227:                if (cli_buffer->line_prompt && (i == *K_CTRL_H || i == *K_BACKSPACE))
1.3       misho    1228:                        keys[i].key_func = bufBS;
1.21.2.3! misho    1229:                if (i == *K_CTRL_C) {
1.3       misho    1230:                        keys[i].key_func = bufCLR;
1.21.2.3! misho    1231:                        inkeys[i].key_func = bufCLRin;
        !          1232:                }
        !          1233:                if (i == *K_CTRL_A) {
        !          1234:                        if (cli_buffer->line_prompt)
        !          1235:                                keys[i].key_func = bufBEGIN;
        !          1236:                        inkeys[i].key_func = bufBEGINin;
        !          1237:                }
        !          1238:                if (i == *K_CTRL_E) {
        !          1239:                        if (cli_buffer->line_prompt)
        !          1240:                                keys[i].key_func = bufEND;
        !          1241:                        inkeys[i].key_func = bufENDin;
        !          1242:                }
1.9       misho    1243:                if (cli_buffer->line_prompt && i == *K_TAB)
1.3       misho    1244:                        keys[i].key_func = bufComp;
1.13      misho    1245:                if (i == *K_CTRL_Z)
1.9       misho    1246:                        keys[i].key_func = bufEndNode;
1.21.2.3! misho    1247:                if (i >= *K_SPACE && i < *K_BACKSPACE) {
1.3       misho    1248:                        keys[i].key_func = bufCHAR;
1.21.2.3! misho    1249:                        inkeys[i].key_func = bufCHARin;
        !          1250:                }
        !          1251:                if (i > *K_BACKSPACE && i < 0xff) {
1.3       misho    1252:                        keys[i].key_func = bufCHAR;
1.21.2.3! misho    1253:                        inkeys[i].key_func = bufCHARin;
        !          1254:                }
1.9       misho    1255:                if (cli_buffer->line_prompt && i == '?')
1.3       misho    1256:                        keys[i].key_func = bufHelp;
                   1257:        }
1.6       misho    1258:        /* alt+chars */
1.3       misho    1259:        for (i = 256; i < 512; i++) {
1.21.2.2  misho    1260:                keys[i].key_ch[0] = inkeys[i].key_ch[0] = 0x1b;
                   1261:                keys[i].key_ch[1] = inkeys[i].key_ch[1] = (u_char) i - 256;
                   1262:                keys[i].key_len = inkeys[i].key_len = 2;
1.3       misho    1263:        }
                   1264: 
1.6       misho    1265:        /* 3 bytes */
1.21.2.2  misho    1266:        keys[i].key_len = inkeys[i].key_len = sizeof K_F1 - 1;
1.3       misho    1267:        memcpy(keys[i].key_ch, K_F1, keys[i].key_len);
1.21.2.2  misho    1268:        memcpy(inkeys[i].key_ch, K_F1, inkeys[i].key_len);
1.3       misho    1269:        i++;
1.21.2.2  misho    1270:        keys[i].key_len = inkeys[i].key_len = sizeof K_F2 - 1;
1.3       misho    1271:        memcpy(keys[i].key_ch, K_F2, keys[i].key_len);
1.21.2.2  misho    1272:        memcpy(inkeys[i].key_ch, K_F2, inkeys[i].key_len);
1.3       misho    1273:        i++;
1.21.2.2  misho    1274:        keys[i].key_len = inkeys[i].key_len = sizeof K_F3 - 1;
1.3       misho    1275:        memcpy(keys[i].key_ch, K_F3, keys[i].key_len);
1.21.2.2  misho    1276:        memcpy(inkeys[i].key_ch, K_F3, inkeys[i].key_len);
1.3       misho    1277:        i++;
1.21.2.2  misho    1278:        keys[i].key_len = inkeys[i].key_len = sizeof K_F4 - 1;
1.3       misho    1279:        memcpy(keys[i].key_ch, K_F4, keys[i].key_len);
1.21.2.2  misho    1280:        memcpy(inkeys[i].key_ch, K_F4, inkeys[i].key_len);
1.3       misho    1281:        i++;
1.21.2.2  misho    1282:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F1 - 1;
1.3       misho    1283:        memcpy(keys[i].key_ch, K_CTRL_SH_F1, keys[i].key_len);
1.21.2.2  misho    1284:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F1, inkeys[i].key_len);
1.3       misho    1285:        i++;
1.21.2.2  misho    1286:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F2 - 1;
1.3       misho    1287:        memcpy(keys[i].key_ch, K_CTRL_SH_F2, keys[i].key_len);
1.21.2.2  misho    1288:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F2, inkeys[i].key_len);
1.3       misho    1289:        i++;
1.21.2.2  misho    1290:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F3 - 1;
1.3       misho    1291:        memcpy(keys[i].key_ch, K_CTRL_SH_F3, keys[i].key_len);
1.21.2.2  misho    1292:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F3, inkeys[i].key_len);
1.3       misho    1293:        i++;
1.21.2.2  misho    1294:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F4 - 1;
1.3       misho    1295:        memcpy(keys[i].key_ch, K_CTRL_SH_F4, keys[i].key_len);
1.21.2.2  misho    1296:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F4, inkeys[i].key_len);
1.3       misho    1297:        i++;
1.21.2.2  misho    1298:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F5 - 1;
1.3       misho    1299:        memcpy(keys[i].key_ch, K_CTRL_SH_F5, keys[i].key_len);
1.21.2.2  misho    1300:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F5, inkeys[i].key_len);
1.3       misho    1301:        i++;
1.21.2.2  misho    1302:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F6 - 1;
1.3       misho    1303:        memcpy(keys[i].key_ch, K_CTRL_SH_F6, keys[i].key_len);
1.21.2.2  misho    1304:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F6, inkeys[i].key_len);
1.3       misho    1305:        i++;
1.21.2.2  misho    1306:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F7 - 1;
1.3       misho    1307:        memcpy(keys[i].key_ch, K_CTRL_SH_F7, keys[i].key_len);
1.21.2.2  misho    1308:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F7, inkeys[i].key_len);
1.3       misho    1309:        i++;
1.21.2.2  misho    1310:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F8 - 1;
1.3       misho    1311:        memcpy(keys[i].key_ch, K_CTRL_SH_F8, keys[i].key_len);
1.21.2.2  misho    1312:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F8, inkeys[i].key_len);
1.3       misho    1313:        i++;
1.21.2.2  misho    1314:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F9 - 1;
1.3       misho    1315:        memcpy(keys[i].key_ch, K_CTRL_SH_F9, keys[i].key_len);
1.21.2.2  misho    1316:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F9, inkeys[i].key_len);
1.3       misho    1317:        i++;
1.21.2.2  misho    1318:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F10 - 1;
1.3       misho    1319:        memcpy(keys[i].key_ch, K_CTRL_SH_F10, keys[i].key_len);
1.21.2.2  misho    1320:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F10, inkeys[i].key_len);
1.3       misho    1321:        i++;
1.21.2.2  misho    1322:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F11 - 1;
1.3       misho    1323:        memcpy(keys[i].key_ch, K_CTRL_SH_F11, keys[i].key_len);
1.21.2.2  misho    1324:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F11, inkeys[i].key_len);
1.3       misho    1325:        i++;
1.21.2.2  misho    1326:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F12 - 1;
1.3       misho    1327:        memcpy(keys[i].key_ch, K_CTRL_SH_F12, keys[i].key_len);
1.21.2.2  misho    1328:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F12, inkeys[i].key_len);
1.3       misho    1329:        i++;
1.21.2.2  misho    1330:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F1 - 1;
1.3       misho    1331:        memcpy(keys[i].key_ch, K_CTRL_F1, keys[i].key_len);
1.21.2.2  misho    1332:        memcpy(inkeys[i].key_ch, K_CTRL_F1, inkeys[i].key_len);
1.3       misho    1333:        i++;
1.21.2.2  misho    1334:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F2 - 1;
1.3       misho    1335:        memcpy(keys[i].key_ch, K_CTRL_F2, keys[i].key_len);
1.21.2.2  misho    1336:        memcpy(inkeys[i].key_ch, K_CTRL_F2, inkeys[i].key_len);
1.3       misho    1337:        i++;
1.21.2.2  misho    1338:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F3 - 1;
1.3       misho    1339:        memcpy(keys[i].key_ch, K_CTRL_F3, keys[i].key_len);
1.21.2.2  misho    1340:        memcpy(inkeys[i].key_ch, K_CTRL_F3, inkeys[i].key_len);
1.3       misho    1341:        i++;
1.21.2.2  misho    1342:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F4 - 1;
1.3       misho    1343:        memcpy(keys[i].key_ch, K_CTRL_F4, keys[i].key_len);
1.21.2.2  misho    1344:        memcpy(inkeys[i].key_ch, K_CTRL_F4, inkeys[i].key_len);
1.3       misho    1345:        i++;
1.21.2.2  misho    1346:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F5 - 1;
1.3       misho    1347:        memcpy(keys[i].key_ch, K_CTRL_F5, keys[i].key_len);
1.21.2.2  misho    1348:        memcpy(inkeys[i].key_ch, K_CTRL_F5, inkeys[i].key_len);
1.3       misho    1349:        i++;
1.21.2.2  misho    1350:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F6 - 1;
1.3       misho    1351:        memcpy(keys[i].key_ch, K_CTRL_F6, keys[i].key_len);
1.21.2.2  misho    1352:        memcpy(inkeys[i].key_ch, K_CTRL_F6, inkeys[i].key_len);
1.3       misho    1353:        i++;
1.21.2.2  misho    1354:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F7 - 1;
1.3       misho    1355:        memcpy(keys[i].key_ch, K_CTRL_F7, keys[i].key_len);
1.21.2.2  misho    1356:        memcpy(inkeys[i].key_ch, K_CTRL_F7, inkeys[i].key_len);
1.3       misho    1357:        i++;
1.21.2.2  misho    1358:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F8 - 1;
1.3       misho    1359:        memcpy(keys[i].key_ch, K_CTRL_F8, keys[i].key_len);
1.21.2.2  misho    1360:        memcpy(inkeys[i].key_ch, K_CTRL_F8, inkeys[i].key_len);
1.3       misho    1361:        i++;
1.21.2.2  misho    1362:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F9 - 1;
1.3       misho    1363:        memcpy(keys[i].key_ch, K_CTRL_F9, keys[i].key_len);
1.21.2.2  misho    1364:        memcpy(inkeys[i].key_ch, K_CTRL_F9, inkeys[i].key_len);
1.3       misho    1365:        i++;
1.21.2.2  misho    1366:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F10 - 1;
1.3       misho    1367:        memcpy(keys[i].key_ch, K_CTRL_F10, keys[i].key_len);
1.21.2.2  misho    1368:        memcpy(inkeys[i].key_ch, K_CTRL_F10, inkeys[i].key_len);
1.3       misho    1369:        i++;
1.21.2.2  misho    1370:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F11 - 1;
1.3       misho    1371:        memcpy(keys[i].key_ch, K_CTRL_F11, keys[i].key_len);
1.21.2.2  misho    1372:        memcpy(inkeys[i].key_ch, K_CTRL_F11, inkeys[i].key_len);
1.3       misho    1373:        i++;
1.21.2.2  misho    1374:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F12 - 1;
1.3       misho    1375:        memcpy(keys[i].key_ch, K_CTRL_F12, keys[i].key_len);
1.21.2.2  misho    1376:        memcpy(inkeys[i].key_ch, K_CTRL_F12, inkeys[i].key_len);
1.3       misho    1377:        i++;
1.21.2.2  misho    1378:        keys[i].key_len = inkeys[i].key_len = sizeof K_HOME - 1;
1.9       misho    1379:        if (cli_buffer->line_prompt)
                   1380:                keys[i].key_func = bufBEGIN;
1.3       misho    1381:        memcpy(keys[i].key_ch, K_HOME, keys[i].key_len);
1.21.2.2  misho    1382:        memcpy(inkeys[i].key_ch, K_HOME, inkeys[i].key_len);
1.3       misho    1383:        i++;
1.21.2.2  misho    1384:        keys[i].key_len = inkeys[i].key_len = sizeof K_END - 1;
1.9       misho    1385:        if (cli_buffer->line_prompt)
                   1386:                keys[i].key_func = bufEND;
1.3       misho    1387:        memcpy(keys[i].key_ch, K_END, keys[i].key_len);
1.21.2.2  misho    1388:        memcpy(inkeys[i].key_ch, K_END, inkeys[i].key_len);
1.3       misho    1389:        i++;
1.21.2.2  misho    1390:        keys[i].key_len = inkeys[i].key_len = sizeof K_UP - 1;
1.9       misho    1391:        if (cli_buffer->line_prompt)
                   1392:                keys[i].key_func = bufUP;
1.3       misho    1393:        memcpy(keys[i].key_ch, K_UP, keys[i].key_len);
1.21.2.2  misho    1394:        memcpy(inkeys[i].key_ch, K_UP, inkeys[i].key_len);
1.3       misho    1395:        i++;
1.21.2.2  misho    1396:        keys[i].key_len = inkeys[i].key_len = sizeof K_DOWN - 1;
1.9       misho    1397:        if (cli_buffer->line_prompt)
                   1398:                keys[i].key_func = bufDOWN;
1.3       misho    1399:        memcpy(keys[i].key_ch, K_DOWN, keys[i].key_len);
1.21.2.2  misho    1400:        memcpy(inkeys[i].key_ch, K_DOWN, inkeys[i].key_len);
1.3       misho    1401:        i++;
1.21.2.2  misho    1402:        keys[i].key_len = inkeys[i].key_len = sizeof K_RIGHT - 1;
1.9       misho    1403:        if (cli_buffer->line_prompt)
                   1404:                keys[i].key_func = bufRIGHT;
1.3       misho    1405:        memcpy(keys[i].key_ch, K_RIGHT, keys[i].key_len);
1.21.2.2  misho    1406:        memcpy(inkeys[i].key_ch, K_RIGHT, inkeys[i].key_len);
1.3       misho    1407:        i++;
1.21.2.2  misho    1408:        keys[i].key_len = inkeys[i].key_len = sizeof K_LEFT - 1;
1.9       misho    1409:        if (cli_buffer->line_prompt)
                   1410:                keys[i].key_func = bufLEFT;
1.3       misho    1411:        memcpy(keys[i].key_ch, K_LEFT, keys[i].key_len);
1.21.2.2  misho    1412:        memcpy(inkeys[i].key_ch, K_LEFT, inkeys[i].key_len);
1.3       misho    1413:        i++;
1.21.2.2  misho    1414:        keys[i].key_len = inkeys[i].key_len = sizeof K_BTAB - 1;
1.9       misho    1415:        if (cli_buffer->line_prompt)
                   1416:                keys[i].key_func = bufBTAB;
1.3       misho    1417:        memcpy(keys[i].key_ch, K_BTAB, keys[i].key_len);
1.21.2.2  misho    1418:        memcpy(inkeys[i].key_ch, K_BTAB, inkeys[i].key_len);
1.3       misho    1419:        i++;
1.6       misho    1420:        /* 4 bytes */
1.21.2.2  misho    1421:        keys[i].key_len = inkeys[i].key_len = sizeof K_INS - 1;
1.9       misho    1422:        if (cli_buffer->line_prompt)
                   1423:                keys[i].key_func = bufMODE;
1.3       misho    1424:        memcpy(keys[i].key_ch, K_INS, keys[i].key_len);
1.21.2.2  misho    1425:        memcpy(inkeys[i].key_ch, K_INS, inkeys[i].key_len);
1.3       misho    1426:        i++;
1.21.2.2  misho    1427:        keys[i].key_len = inkeys[i].key_len = sizeof K_DEL - 1;
1.9       misho    1428:        if (cli_buffer->line_prompt)
                   1429:                keys[i].key_func = bufDEL;
1.3       misho    1430:        memcpy(keys[i].key_ch, K_DEL, keys[i].key_len);
1.21.2.2  misho    1431:        memcpy(inkeys[i].key_ch, K_DEL, inkeys[i].key_len);
1.3       misho    1432:        i++;
1.21.2.2  misho    1433:        keys[i].key_len = inkeys[i].key_len = sizeof K_PGUP - 1;
1.3       misho    1434:        memcpy(keys[i].key_ch, K_PGUP, keys[i].key_len);
1.21.2.2  misho    1435:        memcpy(inkeys[i].key_ch, K_PGUP, inkeys[i].key_len);
1.3       misho    1436:        i++;
1.21.2.2  misho    1437:        keys[i].key_len = inkeys[i].key_len = sizeof K_PGDN - 1;
1.3       misho    1438:        memcpy(keys[i].key_ch, K_PGDN, keys[i].key_len);
1.21.2.2  misho    1439:        memcpy(inkeys[i].key_ch, K_PGDN, inkeys[i].key_len);
1.3       misho    1440:        i++;
1.6       misho    1441:        /* 5 bytes */
1.21.2.2  misho    1442:        keys[i].key_len = inkeys[i].key_len = sizeof K_F5 - 1;
1.3       misho    1443:        memcpy(keys[i].key_ch, K_F5, keys[i].key_len);
1.21.2.2  misho    1444:        memcpy(inkeys[i].key_ch, K_F5, inkeys[i].key_len);
1.3       misho    1445:        i++;
1.21.2.2  misho    1446:        keys[i].key_len = inkeys[i].key_len = sizeof K_F6 - 1;
1.3       misho    1447:        memcpy(keys[i].key_ch, K_F6, keys[i].key_len);
1.21.2.2  misho    1448:        memcpy(inkeys[i].key_ch, K_F6, inkeys[i].key_len);
1.3       misho    1449:        i++;
1.21.2.2  misho    1450:        keys[i].key_len = inkeys[i].key_len = sizeof K_F7 - 1;
1.3       misho    1451:        memcpy(keys[i].key_ch, K_F7, keys[i].key_len);
1.21.2.2  misho    1452:        memcpy(inkeys[i].key_ch, K_F7, inkeys[i].key_len);
1.3       misho    1453:        i++;
1.21.2.2  misho    1454:        keys[i].key_len = inkeys[i].key_len = sizeof K_F8 - 1;
1.3       misho    1455:        memcpy(keys[i].key_ch, K_F8, keys[i].key_len);
1.21.2.2  misho    1456:        memcpy(inkeys[i].key_ch, K_F8, inkeys[i].key_len);
1.3       misho    1457:        i++;
1.21.2.2  misho    1458:        keys[i].key_len = inkeys[i].key_len = sizeof K_F9 - 1;
1.3       misho    1459:        memcpy(keys[i].key_ch, K_F9, keys[i].key_len);
1.21.2.2  misho    1460:        memcpy(inkeys[i].key_ch, K_F9, inkeys[i].key_len);
1.3       misho    1461:        i++;
1.21.2.2  misho    1462:        keys[i].key_len = inkeys[i].key_len = sizeof K_F10 - 1;
1.3       misho    1463:        memcpy(keys[i].key_ch, K_F10, keys[i].key_len);
1.21.2.2  misho    1464:        memcpy(inkeys[i].key_ch, K_F10, inkeys[i].key_len);
1.3       misho    1465:        i++;
1.21.2.2  misho    1466:        keys[i].key_len = inkeys[i].key_len = sizeof K_F11 - 1;
1.3       misho    1467:        memcpy(keys[i].key_ch, K_F11, keys[i].key_len);
1.21.2.2  misho    1468:        memcpy(inkeys[i].key_ch, K_F11, inkeys[i].key_len);
1.3       misho    1469:        i++;
1.21.2.2  misho    1470:        keys[i].key_len = inkeys[i].key_len = sizeof K_F12 - 1;
1.3       misho    1471:        memcpy(keys[i].key_ch, K_F12, keys[i].key_len);
1.21.2.2  misho    1472:        memcpy(inkeys[i].key_ch, K_F12, inkeys[i].key_len);
1.3       misho    1473:        i++;
                   1474: 
1.7       misho    1475:        cli_buffer->line_keys = keys;
1.21.2.2  misho    1476:        cli_buffer->line_inkeys = inkeys;
1.7       misho    1477:        return cli_buffer;
1.2       misho    1478: }
                   1479: 
                   1480: /*
1.18      misho    1481:  * cliSetLine() - Set CLI input line terminal
1.6       misho    1482:  *
1.7       misho    1483:  * @cli_buffer = CLI buffer
1.18      misho    1484:  * @old = Old terminal settings
                   1485:  * return: -1 error or 0 ok
1.2       misho    1486: */
1.3       misho    1487: int
1.18      misho    1488: cliSetLine(linebuffer_t * __restrict cli_buffer, struct termios * __restrict old)
1.2       misho    1489: {
                   1490:        struct termios t;
                   1491: 
                   1492:        memset(&t, 0, sizeof t);
1.7       misho    1493:        tcgetattr(cli_buffer->line_in, &t);
1.18      misho    1494:        if (old)
                   1495:                memcpy(old, &t, sizeof(struct termios));
1.9       misho    1496:        t.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO | 
                   1497:                        ECHOCTL | ECHOE | ECHOK | ECHOKE | ECHONL | ECHOPRT);
1.2       misho    1498:        t.c_iflag |= IGNBRK;
                   1499:        t.c_cc[VMIN] = 1;
                   1500:        t.c_cc[VTIME] = 0;
1.7       misho    1501:        return tcsetattr(cli_buffer->line_in, TCSANOW, &t);
1.3       misho    1502: }
                   1503: 
                   1504: /*
1.18      misho    1505:  * cliResetLine() - Reset CLI input line terminal
                   1506:  *
                   1507:  * @cli_buffer = CLI buffer
                   1508:  * @old = Original terminal settings
                   1509:  * return: -1 error or 0 ok
                   1510: */
                   1511: int
                   1512: cliResetLine(linebuffer_t * __restrict cli_buffer, struct termios * __restrict orig)
                   1513: {
                   1514:        return tcsetattr(cli_buffer->line_in, TCSANOW, orig);
                   1515: }
                   1516: 
                   1517: /*
1.21.2.1  misho    1518:  * cliEcho() - Switch echo on or off
                   1519:  *
                   1520:  * @cli_buffer = CLI buffer
                   1521:  * @on = On or off for echo on input handler
                   1522:  * return: -1 error or 0 ok
                   1523: */
                   1524: int
                   1525: cliEcho(linebuffer_t * __restrict cli_buffer, int on)
                   1526: {
                   1527:        struct termios t;
                   1528: 
                   1529:        if (tcgetattr(cli_buffer->line_in, &t) == -1) {
                   1530:                cli_SetErr(errno, "tcgetattr(%d) - %s", cli_buffer->line_in, strerror(errno));
                   1531:                return -1;
                   1532:        }
                   1533: 
                   1534:        if (on)
                   1535:                t.c_lflag |= (ECHO);
                   1536:        else
                   1537:                t.c_lflag &= ~(ECHO);
                   1538: 
                   1539:        return tcsetattr(cli_buffer->line_in, TCSANOW, &t);
                   1540: }
                   1541: 
                   1542: /*
1.6       misho    1543:  * cliReadLine() - Read line from opened CLI session
                   1544:  *
1.7       misho    1545:  * @cli_buffer = CLI buffer
1.10      misho    1546:  * @timeout = Session timeout (-1 infinit)
1.6       misho    1547:  * return: NULL if error or !=NULL readed line, must be e_free after use!
1.3       misho    1548: */
                   1549: char *
1.12      misho    1550: cliReadLine(linebuffer_t * __restrict cli_buffer, int timeout)
1.3       misho    1551: {
1.10      misho    1552:        int code, readLen, ret;
1.3       misho    1553:        register int i;
                   1554:        struct pollfd fds;
                   1555:        char buf[BUFSIZ], *str = NULL;
1.2       misho    1556: 
1.7       misho    1557:        if (!cli_buffer) {
1.6       misho    1558:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho    1559:                return NULL;
1.11      misho    1560:        } else if (timeout > 0)
1.10      misho    1561:                timeout *= 1000;        /* convert from sec to ms */
1.2       misho    1562: 
1.3       misho    1563:        memset(&fds, 0, sizeof fds);
1.7       misho    1564:        fds.fd = cli_buffer->line_in;
1.3       misho    1565:        fds.events = POLLIN;
                   1566: 
1.7       misho    1567:        printfCR(cli_buffer, 1);
1.3       misho    1568:        while (42) {
1.10      misho    1569:                if ((ret = poll(&fds, 1, timeout)) < 1) {
1.21.2.3! misho    1570:                        if (!ret)
1.12      misho    1571:                                cli_buffer->line_kill = 1;
1.21.2.3! misho    1572:                        else
1.10      misho    1573:                                LOGERR;
1.21.2.3! misho    1574:                        return NULL;
1.3       misho    1575:                }
                   1576: 
                   1577:                memset(buf, 0, sizeof buf);
1.21.2.3! misho    1578:                readLen = read(cli_buffer->line_in, buf, sizeof buf - 1);
1.14      misho    1579:                if (readLen < 1) {
                   1580:                        if (readLen)
                   1581:                                LOGERR;
                   1582:                        return NULL;
1.3       misho    1583:                }
                   1584: 
1.21.2.3! misho    1585:                while (readLen)
        !          1586:                        for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--)
        !          1587:                                if (readLen >= cli_buffer->line_keys[i].key_len && 
        !          1588:                                                !memcmp(cli_buffer->line_keys[i].key_ch, buf, 
        !          1589:                                                        cli_buffer->line_keys[i].key_len)) {
        !          1590:                                        readLen -= cli_buffer->line_keys[i].key_len;
        !          1591:                                        if (readLen)
        !          1592:                                                memmove(buf, buf + cli_buffer->line_keys[i].key_len, readLen);
        !          1593:                                        else
        !          1594:                                                memset(buf, 0, cli_buffer->line_keys[i].key_len);
        !          1595: 
        !          1596:                                        if (cli_buffer->line_keys[i].key_func)
        !          1597:                                                if ((code = cli_buffer->line_keys[i].key_func(i, cli_buffer)))
        !          1598:                                                        readLen = 0;
        !          1599:                                }
1.3       misho    1600: 
                   1601:                if (code)
                   1602:                        break;
                   1603:        }
1.2       misho    1604: 
1.7       misho    1605:        if (code != RETCODE_ERR && code != RETCODE_EOF && cli_buffer->line_buf)
                   1606:                str = e_strdup(cli_buffer->line_buf);
1.3       misho    1607:        return str;
1.2       misho    1608: }
                   1609: 
1.21.2.3! misho    1610: /*
        !          1611:  * cliInputLine() - Input line from opened CLI session
        !          1612:  *
        !          1613:  * @cli_buffer = CLI buffer
        !          1614:  * @timeout = Session timeout (-1 infinit)
        !          1615:  * return: NULL if error or !=NULL readed line, must be e_free after use!
        !          1616: */
        !          1617: char *
        !          1618: cliInputLine(linebuffer_t * __restrict cli_buffer, int timeout)
        !          1619: {
        !          1620:        int code, readLen, ret;
        !          1621:        register int i;
        !          1622:        struct pollfd fds;
        !          1623:        char buf[BUFSIZ], *str = NULL;
        !          1624: 
        !          1625:        if (!cli_buffer) {
        !          1626:                cli_SetErr(EINVAL, "Invalid input parameters ...");
        !          1627:                return NULL;
        !          1628:        } else if (timeout > 0)
        !          1629:                timeout *= 1000;        /* convert from sec to ms */
        !          1630: 
        !          1631:        memset(&fds, 0, sizeof fds);
        !          1632:        fds.fd = cli_buffer->line_in;
        !          1633:        fds.events = POLLIN;
        !          1634: 
        !          1635:        while (42) {
        !          1636:                if ((ret = poll(&fds, 1, timeout)) < 1) {
        !          1637:                        if (ret == -1)
        !          1638:                                LOGERR;
        !          1639:                        return NULL;
        !          1640:                }
        !          1641: 
        !          1642:                memset(buf, 0, sizeof buf);
        !          1643:                readLen = read(cli_buffer->line_in, buf, sizeof buf - 1);
        !          1644:                if (readLen < 1) {
        !          1645:                        if (readLen)
        !          1646:                                LOGERR;
        !          1647:                        return NULL;
        !          1648:                }
        !          1649: 
        !          1650:                while (readLen)
        !          1651:                        for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--)
        !          1652:                                if (readLen >= cli_buffer->line_inkeys[i].key_len && 
        !          1653:                                                !memcmp(cli_buffer->line_inkeys[i].key_ch, buf, 
        !          1654:                                                        cli_buffer->line_inkeys[i].key_len)) {
        !          1655:                                        readLen -= cli_buffer->line_inkeys[i].key_len;
        !          1656:                                        if (readLen)
        !          1657:                                                memmove(buf, buf + cli_buffer->line_inkeys[i].key_len, readLen);
        !          1658:                                        else
        !          1659:                                                memset(buf, 0, cli_buffer->line_inkeys[i].key_len);
        !          1660: 
        !          1661:                                        if (cli_buffer->line_inkeys[i].key_func)
        !          1662:                                                if ((code = cli_buffer->line_inkeys[i].key_func(i, cli_buffer)))
        !          1663:                                                        readLen = 0;
        !          1664:                                }
        !          1665: 
        !          1666:                if (code)
        !          1667:                        break;
        !          1668:        }
        !          1669: 
        !          1670:        if (code != RETCODE_ERR && code != RETCODE_EOF && cli_buffer->line_input)
        !          1671:                str = e_strdup(cli_buffer->line_input);
        !          1672:        return str;
        !          1673: }
        !          1674: 
1.3       misho    1675: 
1.2       misho    1676: /*
1.6       misho    1677:  * cliNetLoop() - CLI network main loop binded to socket
                   1678:  *
1.7       misho    1679:  * @cli_buffer = CLI buffer
1.3       misho    1680:  * @csHistFile = History file name
1.2       misho    1681:  * @sock = client socket
1.10      misho    1682:  * @timeout = Session timeout (-1 infinit)
1.3       misho    1683:  * return: RETCODE_ERR error, RETCODE_OK ok
1.2       misho    1684: */
1.3       misho    1685: int
1.10      misho    1686: cliNetLoop(linebuffer_t * __restrict cli_buffer, const char *csHistFile, 
1.12      misho    1687:                int sock, int timeout)
1.2       misho    1688: {
1.3       misho    1689:        u_char buf[BUFSIZ];
1.15      misho    1690:        int pid, stat, pty, s, alen, flg, attrlen = 0, ret = 0;
1.2       misho    1691:        fd_set fds;
                   1692:        struct timeval tv = { DEFAULT_SOCK_TIMEOUT, 0 };
                   1693:        struct telnetAttrs *a, Attr[10];
                   1694: 
1.3       misho    1695:        switch ((pid = forkpty(&pty, NULL, NULL, NULL))) {
1.2       misho    1696:                case -1:
                   1697:                        LOGERR;
                   1698:                        return -1;
                   1699:                case 0:
1.7       misho    1700:                        if (!cli_buffer) {
1.6       misho    1701:                                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho    1702:                                return -1;
                   1703:                        } else
                   1704:                                close(sock);
1.2       misho    1705: 
1.12      misho    1706:                        ret = cliLoop(cli_buffer, csHistFile, timeout) < 0 ? 1 : 0;
1.7       misho    1707:                        cliEnd(cli_buffer);
1.2       misho    1708: 
1.8       misho    1709:                        _exit(ret);
1.2       misho    1710:                default:
1.4       misho    1711:                        cli_telnet_SetCmd(Attr + 0, DO, TELOPT_TTYPE);
                   1712:                        cli_telnet_SetCmd(Attr + 1, WILL, TELOPT_ECHO);
                   1713:                        cli_telnet_Set_SubOpt(Attr + 2, TELOPT_LFLOW, LFLOW_OFF, NULL, 0);
                   1714:                        cli_telnet_Set_SubOpt(Attr + 3, TELOPT_LFLOW, LFLOW_RESTART_XON, NULL, 0);
                   1715:                        cli_telnet_SetCmd(Attr + 4, DO, TELOPT_LINEMODE);
                   1716:                        if ((ret = cli_telnetSend(sock, Attr, 5, NULL, 0, 0)) == -1)
1.2       misho    1717:                                return -1;
1.4       misho    1718:                        else
1.2       misho    1719:                                flg = 0;
                   1720: 
                   1721:                        while (42) {
1.3       misho    1722:                                if (waitpid(pid, &stat, WNOHANG))
                   1723:                                        break;
                   1724: 
1.2       misho    1725:                                FD_ZERO(&fds);
                   1726:                                FD_SET(sock, &fds);
                   1727:                                FD_SET(pty, &fds);
                   1728:                                if ((ret = select(FD_SETSIZE, &fds, NULL, NULL, &tv)) < 1) {
                   1729:                                        if (!ret)
                   1730:                                                cli_SetErr(ETIMEDOUT, "Client session timeout ...");
                   1731: 
                   1732:                                        break;
                   1733:                                }
                   1734: 
                   1735:                                s = FD_ISSET(sock, &fds) ? pty : sock;
                   1736: 
1.3       misho    1737:                                if (FD_ISSET(sock, &fds)) {
                   1738:                                        memset(buf, 0, BUFSIZ);
1.4       misho    1739:                                        if ((ret = cli_telnetRecv(sock, &a, &alen, buf, BUFSIZ)) < 0) {
1.3       misho    1740:                                                if (a)
1.6       misho    1741:                                                        e_free(a);
1.3       misho    1742: 
                   1743:                                                if (-2 == ret)
                   1744:                                                        continue;
                   1745:                                                // EOF
                   1746:                                                if (-3 == ret)
                   1747:                                                        shutdown(sock, SHUT_RD);
                   1748:                                                break;
                   1749:                                        }
                   1750:                                        attrlen = 0;
                   1751:                                        if (1 == flg && alen) {
1.4       misho    1752:                                                cli_telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_SGA);
                   1753:                                                cli_telnet_SetCmd(&Attr[attrlen++], DO, TELOPT_ECHO);
1.3       misho    1754:                                        }
                   1755:                                        if (2 == flg && alen) {
1.4       misho    1756:                                                cli_telnet_SetCmd(&Attr[attrlen++], WILL, TELOPT_ECHO);
                   1757:                                                cli_telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW, 
1.3       misho    1758:                                                                LFLOW_OFF, NULL, 0);
1.4       misho    1759:                                                cli_telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW, 
1.3       misho    1760:                                                                LFLOW_RESTART_XON, NULL, 0);
1.4       misho    1761:                                                cli_telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_LINEMODE);
1.3       misho    1762:                                        }
1.2       misho    1763:                                        if (a)
1.6       misho    1764:                                                e_free(a);
1.2       misho    1765: 
1.3       misho    1766:                                        if ((ret = write(pty, buf, ret)) == -1) {
                   1767:                                                LOGERR;
                   1768:                                                break;
                   1769:                                        }
                   1770:                                }
                   1771: 
                   1772:                                if (FD_ISSET(pty, &fds)) {
                   1773:                                        memset(buf, 0, BUFSIZ);
1.14      misho    1774:                                        if ((ret = read(pty, buf, BUFSIZ)) < 1) {
                   1775:                                                if (ret)
                   1776:                                                        LOGERR;
1.3       misho    1777:                                                break;
                   1778:                                        }
                   1779: 
1.4       misho    1780:                                        if ((ret = cli_telnetSend(sock, Attr, pty == s ? 0 : attrlen, 
                   1781:                                                                        buf, ret, 0)) == -1)
1.3       misho    1782:                                                break;
1.4       misho    1783:                                        else
1.3       misho    1784:                                                flg++;
1.2       misho    1785:                                }
                   1786:                        }
                   1787: 
                   1788:                        close(pty);
                   1789:        }
                   1790: 
                   1791:        return ret;
                   1792: }
                   1793: 
                   1794: /*
1.17      misho    1795:  * cliRun() - CLI run command line
                   1796:  *
                   1797:  * @cli_buffer = CLI buffer
                   1798:  * @psInput = Input command line
                   1799:  * @prompt = Display prompt after command
                   1800:  * return: RETCODE_ERR error, RETCODE_OK ok
                   1801: */
                   1802: int
                   1803: cliRun(linebuffer_t * __restrict cli_buffer, char *psInput, int prompt)
                   1804: {
                   1805:        char *line, *s, *t, **app, *items[MAX_PROMPT_ITEMS];
                   1806:        int ret = RETCODE_OK;
                   1807:        struct tagCommand *cmd;
                   1808: 
                   1809:        if (!psInput)
                   1810:                return RETCODE_ERR;
                   1811:        else
                   1812:                line = psInput;
                   1813: 
                   1814:        // clear whitespaces
                   1815:        for (s = line; isspace((int) *s); s++);
                   1816:        if (*s) {
                   1817:                for (t = s + strlen(s) - 1; t > s && isspace((int) *t); t--);
                   1818:                *++t = 0;
                   1819:        }
                   1820: 
                   1821:        if (*s) {
                   1822:                memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
                   1823:                for (app = items; app < items + MAX_PROMPT_ITEMS - 1 && 
                   1824:                                (*app = strsep(&s, " \t")); *app ? app++ : app);
                   1825: 
                   1826:                // exec_cmd ...
                   1827:                SLIST_FOREACH(cmd, &cli_buffer->line_cmds, cmd_next) {
                   1828:                        if (!(cmd->cmd_level & (1 << cli_buffer->line_level)))
                   1829:                                continue;
                   1830:                        if (*items[0] && !strncmp(cmd->cmd_name, items[0], strlen(items[0])))
                   1831:                                break;
                   1832:                }
                   1833: 
                   1834:                if (!cmd) {
                   1835:                        cli_Printf(cli_buffer, "%sCommand '%s' not found!\n", 
                   1836:                                        cli_buffer->line_prompt ? "\n" : "", items[0]);
                   1837:                        ret = RETCODE_ERR;
                   1838:                } else
                   1839:                        if (cmd->cmd_func) {
                   1840:                                if (prompt && cli_buffer->line_prompt)
                   1841:                                        cli_Printf(cli_buffer, "\n");
                   1842:                                ret = cmd->cmd_func(cli_buffer, 
                   1843:                                                cli_buffer->line_level, items);
                   1844:                        } else if (prompt) {
                   1845:                                clrscrEOL(cli_buffer);
                   1846:                                printfCR(cli_buffer, 1);
                   1847:                        }
                   1848:        }
                   1849: 
                   1850:        return ret;
                   1851: }
                   1852: 
                   1853: /*
1.6       misho    1854:  * cliLoop() - CLI main loop
                   1855:  *
1.7       misho    1856:  * @cli_buffer = CLI buffer
1.3       misho    1857:  * @csHistFile = History file name
1.10      misho    1858:  * @timeout = Session timeout (-1 infinit)
1.3       misho    1859:  * return: RETCODE_ERR error, RETCODE_OK ok
1.1       misho    1860: */
1.3       misho    1861: int
1.12      misho    1862: cliLoop(linebuffer_t * __restrict cli_buffer, const char *csHistFile, int timeout)
1.1       misho    1863: {
1.17      misho    1864:        char *line;
1.3       misho    1865:        int ret = RETCODE_OK;
1.18      misho    1866:        struct termios t;
1.1       misho    1867: 
                   1868:        /* --- main body of CLI --- */
1.18      misho    1869:        cliSetLine(cli_buffer, &t);
1.1       misho    1870: 
1.7       misho    1871:        if (cli_loadHistory(cli_buffer, csHistFile) == RETCODE_ERR)
1.3       misho    1872:                return RETCODE_ERR;
1.1       misho    1873: 
                   1874:        do {
1.12      misho    1875:                line = cliReadLine(cli_buffer, timeout);
1.3       misho    1876:                if (!line) {
1.7       misho    1877:                        printfNL(cli_buffer, 0);
1.1       misho    1878:                        break;
1.3       misho    1879:                } else
1.7       misho    1880:                        cli_addHistory(cli_buffer, NULL);
1.3       misho    1881: 
1.17      misho    1882:                ret = cliRun(cli_buffer, line, 42);
1.1       misho    1883: 
1.7       misho    1884:                cli_freeLine(cli_buffer);
                   1885:                cli_resetHistory(cli_buffer);
1.6       misho    1886:                e_free(line);
1.19      misho    1887:        } while (!cli_buffer->line_kill);
1.1       misho    1888: 
1.7       misho    1889:        cli_saveHistory(cli_buffer, csHistFile, HISTORY_LINES);
1.18      misho    1890: 
                   1891:        /* --- restore tty --- */
                   1892:        cliResetLine(cli_buffer, &t);
                   1893: 
1.1       misho    1894:        return ret;
                   1895: }

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