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

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

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