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

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

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