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

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.9! misho       6: * $Id: aitcli.c,v 1.21.2.8 2025/12/25 20:20:11 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;
1.21.2.9! misho     761:        int fd;
1.3       misho     762: 
                    763:        if (fmt) {
1.21.2.9! misho     764:                if ((fd = dup(cli_buffer->line_out)) == -1) {
        !           765:                        LOGERR;
        !           766:                        return;
        !           767:                }
        !           768:                f = fdopen(fd, "a");
1.3       misho     769:                if (!f) {
                    770:                        LOGERR;
                    771:                        return;
                    772:                }
                    773: 
                    774:                va_start(lst, fmt);
                    775:                vfprintf(f, fmt, lst);
                    776:                va_end(lst);
1.20      misho     777: 
                    778:                fclose(f);
1.3       misho     779:        } else
1.6       misho     780:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     781: }
                    782: 
                    783: /*
1.6       misho     784:  * cli_PrintHelp() - Print help screen
                    785:  *
1.7       misho     786:  * @cli_buffer = CLI buffer
1.3       misho     787:  * return: none
                    788: */
1.6       misho     789: void
1.7       misho     790: cli_PrintHelp(linebuffer_t * __restrict cli_buffer)
1.3       misho     791: {
1.7       misho     792:        if (cli_buffer) {
                    793:                bufHelp(0, cli_buffer);
                    794:                clrscrEOL(cli_buffer);
1.3       misho     795:        } else
1.6       misho     796:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     797: }
                    798: 
                    799: 
                    800: /*
1.6       misho     801:  * cli_BindKey() - Bind function to key
                    802:  *
1.3       misho     803:  * @key = key structure
1.7       misho     804:  * @cli_buffer = CLI buffer
1.3       misho     805:  * return: RETCODE_ERR error, RETCODE_OK ok, >0 bind at position
                    806: */
                    807: int
1.7       misho     808: cli_BindKey(bindkey_t * __restrict key, linebuffer_t * __restrict cli_buffer)
1.3       misho     809: {
                    810:        register int i;
                    811: 
1.7       misho     812:        if (!key || !cli_buffer) {
1.6       misho     813:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     814:                return RETCODE_ERR;
1.2       misho     815:        }
1.3       misho     816: 
                    817:        for (i = 0; i < MAX_BINDKEY; i++)
1.7       misho     818:                if (key->key_len == cli_buffer->line_keys[i].key_len && 
                    819:                                !memcmp(key->key_ch, cli_buffer->line_keys[i].key_ch, 
                    820:                                        key->key_len)) {
                    821:                        cli_buffer->line_keys[i].key_func = key->key_func;
1.3       misho     822:                        return i;
                    823:                }
                    824: 
                    825:        return RETCODE_OK;
1.2       misho     826: }
                    827: 
                    828: 
1.3       misho     829: /*
1.6       misho     830:  * cli_addCommand() - Add command to CLI session
                    831:  *
1.7       misho     832:  * @cli_buffer = CLI buffer
1.3       misho     833:  * @csCmd = Command name
1.9       misho     834:  * @cliLevel = Level in CLI, -1 view from all levels, 0 hidden, >0 mask levels
1.3       misho     835:  * @funcCmd = Callback function when user call command
                    836:  * @csInfo = Inline information for command
                    837:  * @csHelp = Help line when call help
                    838:  * return: RETCODE_ERR error, RETCODE_OK ok
                    839: */
                    840: int
1.7       misho     841: cli_addCommand(linebuffer_t * __restrict cli_buffer, const char *csCmd, 
                    842:                int cliLevel, cmd_func_t funcCmd, 
1.3       misho     843:                const char *csInfo, const char *csHelp)
1.1       misho     844: {
1.3       misho     845:        struct tagCommand *cmd;
                    846: 
1.7       misho     847:        if (!cli_buffer || !csCmd) {
1.6       misho     848:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     849:                return RETCODE_ERR;
                    850:        }
                    851: 
1.6       misho     852:        cmd = e_malloc(sizeof(struct tagCommand));
1.3       misho     853:        if (!cmd) {
                    854:                LOGERR;
                    855:                return RETCODE_ERR;
                    856:        } else
                    857:                memset(cmd, 0, sizeof(struct tagCommand));
                    858: 
                    859:        cmd->cmd_level = cliLevel;
                    860:        cmd->cmd_func = funcCmd;
                    861:        cmd->cmd_len = strlcpy(cmd->cmd_name, csCmd, STRSIZ);
                    862:        if (csInfo)
                    863:                strlcpy(cmd->cmd_info, csInfo, STRSIZ);
                    864:        if (csHelp)
                    865:                strlcpy(cmd->cmd_help, csHelp, STRSIZ);
1.7       misho     866:        SLIST_INSERT_HEAD(&cli_buffer->line_cmds, cmd, cmd_next);
1.3       misho     867:        return RETCODE_OK;
1.1       misho     868: }
                    869: 
1.3       misho     870: /*
1.6       misho     871:  * cli_delCommand() - Delete command from CLI session
                    872:  *
1.7       misho     873:  * @cli_buffer = CLI buffer
1.3       misho     874:  * @csCmd = Command name
1.9       misho     875:  * @cliLevel = Level in CLI, -1 view from all levels, 0 hidden, >0 mask levels
1.3       misho     876:  * return: RETCODE_ERR error, RETCODE_OK ok
                    877: */
                    878: int
1.7       misho     879: cli_delCommand(linebuffer_t * __restrict cli_buffer, const char *csCmd, int cliLevel)
1.1       misho     880: {
1.3       misho     881:        struct tagCommand *cmd;
                    882:        int ret = RETCODE_OK;
                    883: 
1.7       misho     884:        if (!cli_buffer || !csCmd) {
1.6       misho     885:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     886:                return RETCODE_ERR;
                    887:        }
                    888: 
1.7       misho     889:        SLIST_FOREACH(cmd, &cli_buffer->line_cmds, cmd_next) 
1.3       misho     890:                if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) {
                    891:                        ret = 1;
1.7       misho     892:                        SLIST_REMOVE(&cli_buffer->line_cmds, cmd, tagCommand, cmd_next);
1.6       misho     893:                        e_free(cmd);
1.3       misho     894:                        break;
                    895:                }
                    896: 
                    897:        return ret;
1.1       misho     898: }
                    899: 
1.3       misho     900: /*
1.6       misho     901:  * cli_updCommand() - Update command in CLI session
                    902:  *
1.7       misho     903:  * @cli_buffer = CLI buffer
1.3       misho     904:  * @csCmd = Command name
1.9       misho     905:  * @cliLevel = Level in CLI, -1 view from all levels, 0 hidden, >0 mask levels
1.3       misho     906:  * @funcCmd = Callback function when user call command
                    907:  * @csInfo = Inline information for command
                    908:  * @csHelp = Help line when call help
                    909:  * return: RETCODE_ERR error, RETCODE_OK ok
                    910: */
                    911: int
1.7       misho     912: cli_updCommand(linebuffer_t * __restrict cli_buffer, const char *csCmd, 
                    913:                int cliLevel, cmd_func_t funcCmd, 
1.3       misho     914:                const char *csInfo, const char *csHelp)
1.1       misho     915: {
1.3       misho     916:        struct tagCommand *cmd;
                    917:        int ret = RETCODE_OK;
                    918: 
1.7       misho     919:        if (!cli_buffer || !csCmd) {
1.6       misho     920:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     921:                return RETCODE_ERR;
                    922:        }
                    923: 
1.9       misho     924:        SLIST_FOREACH(cmd, &cli_buffer->line_cmds, cmd_next)
                    925:                if ((!cmd->cmd_level || cmd->cmd_level == cliLevel) && 
                    926:                                !strcmp(cmd->cmd_name, csCmd)) {
                    927:                        if (!cmd->cmd_level)
                    928:                                cmd->cmd_level = cliLevel;
1.3       misho     929:                        if (funcCmd)
                    930:                                cmd->cmd_func = funcCmd;
                    931:                        if (csInfo)
                    932:                                strlcpy(cmd->cmd_info, csInfo, STRSIZ);
                    933:                        if (csHelp)
                    934:                                strlcpy(cmd->cmd_help, csHelp, STRSIZ);
                    935: 
                    936:                        break;
                    937:                }
1.1       misho     938: 
1.3       misho     939:        return ret;
1.1       misho     940: }
                    941: 
                    942: 
                    943: /*
1.6       misho     944:  * cli_addHistory() - Add line to history
                    945:  *
1.7       misho     946:  * @cli_buffer = CLI buffer
1.3       misho     947:  * @str = Add custom text or if NULL use readed line from CLI buffer
                    948:  * return: RETCODE_ERR error, RETCODE_OK ok
1.1       misho     949: */
1.3       misho     950: int
1.7       misho     951: cli_addHistory(linebuffer_t * __restrict cli_buffer, const char * __restrict str)
1.1       misho     952: {
1.3       misho     953:        struct tagHistory *h;
                    954: 
1.7       misho     955:        if (!cli_buffer) {
1.6       misho     956:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     957:                return RETCODE_ERR;
                    958:        }
                    959: 
1.6       misho     960:        if (!(h = e_malloc(sizeof(struct tagHistory)))) {
1.3       misho     961:                LOGERR;
                    962:                return RETCODE_ERR;
                    963:        } else
                    964:                memset(h, 0, sizeof(struct tagHistory));
                    965: 
                    966:        if (str) {
                    967:                if (!*str) {
1.6       misho     968:                        e_free(h);
1.3       misho     969:                        return RETCODE_OK;
                    970:                }
                    971: 
                    972:                h->hist_len = strlcpy(h->hist_line, str, BUFSIZ);
                    973:        } else {
1.7       misho     974:                if (!*cli_buffer->line_buf || cli_buffer->line_len < 2) {
1.6       misho     975:                        e_free(h);
1.3       misho     976:                        return RETCODE_OK;
                    977:                }
                    978: 
1.7       misho     979:                memcpy(h->hist_line, cli_buffer->line_buf, (h->hist_len = cli_buffer->line_len));
1.6       misho     980:                str_Trim(h->hist_line);
1.3       misho     981:                h->hist_len = strlen(h->hist_line);
                    982:        }
1.1       misho     983: 
1.7       misho     984:        TAILQ_INSERT_HEAD(&cli_buffer->line_history, h, hist_next);
1.3       misho     985:        return h->hist_len;
                    986: }
1.1       misho     987: 
1.3       misho     988: /*
1.6       misho     989:  * cli_saveHistory() - Save history to file
                    990:  *
1.7       misho     991:  * @cli_buffer = CLI buffer
1.3       misho     992:  * @histfile = History filename, if NULL will be use default name
                    993:  * @lines = Maximum history lines to save
                    994:  * return: RETCODE_ERR error, RETCODE_OK ok
                    995: */
                    996: int
1.7       misho     997: cli_saveHistory(linebuffer_t * __restrict cli_buffer, const char *histfile, int lines)
1.3       misho     998: {
                    999:        FILE *f;
                   1000:        mode_t mode;
                   1001:        char szFName[MAXPATHLEN];
                   1002:        struct tagHistory *h;
                   1003: 
1.7       misho    1004:        if (!cli_buffer) {
1.6       misho    1005:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho    1006:                return RETCODE_ERR;
                   1007:        }
                   1008:        if (!histfile)
                   1009:                strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
                   1010:        else
                   1011:                strlcpy(szFName, histfile, MAXPATHLEN);
                   1012: 
                   1013:        mode = umask(0177);
                   1014:        f = fopen(szFName, "w");
                   1015:        if (!f) {
1.1       misho    1016:                LOGERR;
1.3       misho    1017:                return RETCODE_ERR;
                   1018:        }
                   1019: 
1.7       misho    1020:        TAILQ_FOREACH(h, &cli_buffer->line_history, hist_next) {
1.3       misho    1021:                fprintf(f, "%s\n", h->hist_line);
                   1022: 
                   1023:                if (lines)
                   1024:                        lines--;
                   1025:                else
                   1026:                        break;
                   1027:        }
1.1       misho    1028: 
1.3       misho    1029:        fclose(f);
                   1030:        umask(mode);
                   1031: 
                   1032:        return RETCODE_OK;
1.1       misho    1033: }
                   1034: 
1.3       misho    1035: /*
1.6       misho    1036:  * cli_loadHistory() - Load history from file
                   1037:  *
1.7       misho    1038:  * @cli_buffer = CLI buffer
1.3       misho    1039:  * @histfile = History filename, if NULL will be use default name
                   1040:  * return: RETCODE_ERR error, RETCODE_OK ok
                   1041: */
                   1042: int
1.7       misho    1043: cli_loadHistory(linebuffer_t * __restrict cli_buffer, const char *histfile)
1.3       misho    1044: {
                   1045:        FILE *f;
                   1046:        char szFName[MAXPATHLEN], buf[BUFSIZ];
                   1047:        struct tagHistory *h;
                   1048: 
1.7       misho    1049:        if (!cli_buffer) {
1.6       misho    1050:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho    1051:                return RETCODE_ERR;
                   1052:        }
                   1053:        if (!histfile)
                   1054:                strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
                   1055:        else
                   1056:                strlcpy(szFName, histfile, MAXPATHLEN);
                   1057: 
                   1058:        f = fopen(szFName, "r");
                   1059:        if (!f)
                   1060:                return RETCODE_OK;
                   1061: 
                   1062:        while (fgets(buf, BUFSIZ, f)) {
                   1063:                if (!*buf || *buf == '#')
                   1064:                        continue;
                   1065:                else
1.6       misho    1066:                        str_Trim(buf);
1.3       misho    1067: 
1.6       misho    1068:                if (!(h = e_malloc(sizeof(struct tagHistory)))) {
1.3       misho    1069:                        LOGERR;
                   1070:                        fclose(f);
                   1071:                        return RETCODE_ERR;
                   1072:                } else
                   1073:                        memset(h, 0, sizeof(struct tagHistory));
                   1074: 
                   1075:                h->hist_len = strlcpy(h->hist_line, buf, BUFSIZ);
1.7       misho    1076:                TAILQ_INSERT_TAIL(&cli_buffer->line_history, h, hist_next);
1.3       misho    1077:        }
                   1078: 
                   1079:        fclose(f);
                   1080: 
                   1081:        return RETCODE_OK;
                   1082: }
1.1       misho    1083: 
                   1084: /*
1.6       misho    1085:  * cli_resetHistory() - Reset history search in CLI session
                   1086:  *
1.7       misho    1087:  * @cli_buffer = CLI buffer
1.1       misho    1088:  * return: none
                   1089: */
1.6       misho    1090: void
1.7       misho    1091: cli_resetHistory(linebuffer_t * __restrict cli_buffer)
1.1       misho    1092: {
1.7       misho    1093:        cli_buffer->line_h = NULL;
1.1       misho    1094: }
                   1095: 
1.3       misho    1096: 
1.1       misho    1097: /*
1.21.2.3  misho    1098:  * cli_freeInput() - Clear entire input
                   1099:  *
                   1100:  * @cli_buffer = CLI buffer
                   1101:  * return: RETCODE_ERR error, RETCODE_OK ok
                   1102: */
                   1103: int
                   1104: cli_freeInput(linebuffer_t * __restrict cli_buffer)
                   1105: {
                   1106:        int code = RETCODE_ERR;
                   1107: 
                   1108:        if (cli_buffer) {
                   1109:                memset(cli_buffer->line_input, 0, BUFSIZ);
                   1110:                cli_buffer->line_posin ^= cli_buffer->line_posin;
                   1111:                cli_buffer->line_lenin ^= cli_buffer->line_lenin;
                   1112: 
                   1113:                code = RETCODE_OK;
                   1114:        } else
                   1115:                cli_SetErr(EINVAL, "Invalid input parameters ...");
                   1116: 
                   1117:        return code;
                   1118: }
                   1119: /*
1.6       misho    1120:  * cli_freeLine() - Clear entire line
                   1121:  *
1.7       misho    1122:  * @cli_buffer = CLI buffer
1.3       misho    1123:  * return: RETCODE_ERR error, RETCODE_OK ok
1.2       misho    1124: */
1.6       misho    1125: int
1.7       misho    1126: cli_freeLine(linebuffer_t * __restrict cli_buffer)
1.2       misho    1127: {
1.3       misho    1128:        int code = RETCODE_ERR;
1.2       misho    1129: 
1.7       misho    1130:        if (cli_buffer) {
1.21.2.3  misho    1131:                memset(cli_buffer->line_buf, 0, BUFSIZ);
                   1132:                cli_buffer->line_eol = cli_buffer->line_bol;
                   1133:                cli_buffer->line_len = 1 + cli_buffer->line_eol;
1.2       misho    1134: 
1.21.2.3  misho    1135:                code = RETCODE_OK;
1.3       misho    1136:        } else
1.6       misho    1137:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.2       misho    1138: 
1.3       misho    1139:        return code;
1.2       misho    1140: }
                   1141: 
                   1142: /*
1.6       misho    1143:  * cli_setPrompt() - Set new prompt for CLI session
                   1144:  *
1.7       misho    1145:  * @cli_buffer = CLI buffer
1.3       misho    1146:  * @prompt = new text for prompt or if NULL disable prompt
                   1147:  * return: none
1.2       misho    1148: */
1.6       misho    1149: void
1.7       misho    1150: cli_setPrompt(linebuffer_t * __restrict cli_buffer, const char *prompt)
1.2       misho    1151: {
1.7       misho    1152:        if (cli_buffer) {
                   1153:                if (cli_buffer->line_prompt) {
                   1154:                        e_free(cli_buffer->line_prompt);
                   1155:                        cli_buffer->line_prompt = NULL;
                   1156:                        cli_buffer->line_bol = 0;
1.3       misho    1157:                }
                   1158: 
                   1159:                if (prompt) {
1.7       misho    1160:                        cli_buffer->line_prompt = e_strdup(prompt);
                   1161:                        if (cli_buffer->line_prompt) {
                   1162:                                cli_buffer->line_bol = strlen(cli_buffer->line_prompt);
                   1163:                                cli_buffer->line_eol = cli_buffer->line_bol;
                   1164:                                cli_buffer->line_len = 1 + cli_buffer->line_eol;
1.3       misho    1165:                        } else
                   1166:                                LOGERR;
                   1167:                }
                   1168:        } else
1.6       misho    1169:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.2       misho    1170: }
                   1171: 
1.3       misho    1172: 
1.2       misho    1173: /*
1.6       misho    1174:  * cliEnd() - Clear data, Free resources and close CLI session
                   1175:  *
1.7       misho    1176:  * @cli_buffer = CLI buffer
1.3       misho    1177:  * return: RETCODE_ERR error, RETCODE_OK ok
1.2       misho    1178: */
1.3       misho    1179: void
1.7       misho    1180: cliEnd(linebuffer_t * __restrict cli_buffer)
1.2       misho    1181: {
1.3       misho    1182:        struct tagHistory *h;
                   1183:        struct tagCommand *c;
                   1184: 
1.7       misho    1185:        if (cli_buffer) {
                   1186:                while ((c = SLIST_FIRST(&cli_buffer->line_cmds))) {
                   1187:                        SLIST_REMOVE_HEAD(&cli_buffer->line_cmds, cmd_next);
1.6       misho    1188:                        e_free(c);
1.3       misho    1189:                }
1.7       misho    1190:                while ((h = TAILQ_FIRST(&cli_buffer->line_history))) {
                   1191:                        TAILQ_REMOVE(&cli_buffer->line_history, h, hist_next);
1.6       misho    1192:                        e_free(h);
1.3       misho    1193:                }
                   1194: 
1.7       misho    1195:                if (cli_buffer->line_prompt)
                   1196:                        e_free(cli_buffer->line_prompt);
1.2       misho    1197: 
1.7       misho    1198:                if (cli_buffer->line_keys)
                   1199:                        e_free(cli_buffer->line_keys);
                   1200:                if (cli_buffer->line_buf)
                   1201:                        e_free(cli_buffer->line_buf);
1.2       misho    1202: 
1.21.2.2  misho    1203:                if (cli_buffer->line_inkeys)
                   1204:                        e_free(cli_buffer->line_inkeys);
                   1205:                if (cli_buffer->line_input)
                   1206:                        e_free(cli_buffer->line_input);
                   1207: 
1.7       misho    1208:                e_free(cli_buffer);
                   1209:                cli_buffer = NULL;
1.3       misho    1210:        } else
1.6       misho    1211:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho    1212: }
                   1213: 
                   1214: /*
1.6       misho    1215:  * cliInit() - Start CLI session, allocate memory for resources and bind keys
                   1216:  *
1.3       misho    1217:  * @fin = Input device handle
                   1218:  * @fout = Output device handle
                   1219:  * @prompt = text for prompt, if NULL disable prompt
                   1220:  * return: NULL if error or !=NULL CLI buffer
                   1221: */
                   1222: linebuffer_t *
                   1223: cliInit(int fin, int fout, const char *prompt)
                   1224: {
1.7       misho    1225:        linebuffer_t *cli_buffer;
1.21.2.2  misho    1226:        bindkey_t *keys, *inkeys;
1.3       misho    1227:        register int i;
1.18      misho    1228:        char szPrompt[STRSIZ + 16] = {[0 ... STRSIZ + 15] = 0};
1.3       misho    1229: 
                   1230:        /* init buffer */
1.7       misho    1231:        cli_buffer = e_malloc(sizeof(linebuffer_t));
                   1232:        if (!cli_buffer) {
1.3       misho    1233:                LOGERR;
                   1234:                return NULL;
                   1235:        } else {
1.7       misho    1236:                memset(cli_buffer, 0, sizeof(linebuffer_t));
1.3       misho    1237: 
1.7       misho    1238:                cli_buffer->line_in = fin;
                   1239:                cli_buffer->line_out = fout;
1.3       misho    1240: 
1.7       misho    1241:                TAILQ_INIT(&cli_buffer->line_history);
                   1242:                SLIST_INIT(&cli_buffer->line_cmds);
1.3       misho    1243: 
                   1244:                if (prompt) {
1.16      misho    1245:                        strlcpy(cli_buffer->line_porigin, prompt, sizeof cli_buffer->line_porigin);
                   1246:                        snprintf(szPrompt, sizeof szPrompt, "%s{%d}> ", cli_buffer->line_porigin, cli_buffer->line_level);
                   1247:                        cli_buffer->line_prompt = e_strdup(szPrompt);
1.7       misho    1248:                        if (!cli_buffer->line_prompt) {
1.3       misho    1249:                                LOGERR;
1.7       misho    1250:                                e_free(cli_buffer);
1.3       misho    1251:                                return NULL;
                   1252:                        } else
1.7       misho    1253:                                cli_buffer->line_eol = cli_buffer->line_bol = 
                   1254:                                        strlen(cli_buffer->line_prompt);
1.9       misho    1255:                } else
                   1256:                        cli_buffer->line_mode = LINEMODE_OVER;
1.3       misho    1257:        }
1.7       misho    1258:        cli_buffer->line_buf = e_malloc(BUFSIZ);
                   1259:        if (!cli_buffer->line_buf) {
1.3       misho    1260:                LOGERR;
1.7       misho    1261:                if (cli_buffer->line_prompt)
                   1262:                        e_free(cli_buffer->line_prompt);
                   1263:                e_free(cli_buffer);
1.3       misho    1264:                return NULL;
                   1265:        } else {
1.7       misho    1266:                memset(cli_buffer->line_buf, 0, BUFSIZ);
                   1267:                cli_buffer->line_len = 1 + cli_buffer->line_eol;
1.3       misho    1268:        }
1.21.2.3  misho    1269:        cli_buffer->line_input = e_malloc(BUFSIZ);
                   1270:        if (!cli_buffer->line_input) {
                   1271:                LOGERR;
                   1272:                if (cli_buffer->line_prompt)
                   1273:                        e_free(cli_buffer->line_prompt);
                   1274:                e_free(cli_buffer->line_buf);
                   1275:                e_free(cli_buffer);
                   1276:                return NULL;
                   1277:        } else {
                   1278:                memset(cli_buffer->line_input, 0, BUFSIZ);
                   1279:                cli_buffer->line_lenin = cli_buffer->line_posin;
                   1280:        }
1.6       misho    1281:        keys = e_calloc(MAX_BINDKEY + 1, sizeof(bindkey_t));
1.3       misho    1282:        if (!keys) {
                   1283:                LOGERR;
1.7       misho    1284:                if (cli_buffer->line_prompt)
                   1285:                        e_free(cli_buffer->line_prompt);
1.21.2.3  misho    1286:                e_free(cli_buffer->line_input);
1.7       misho    1287:                e_free(cli_buffer->line_buf);
                   1288:                e_free(cli_buffer);
1.3       misho    1289:                return NULL;
                   1290:        } else
                   1291:                memset(keys, 0, sizeof(bindkey_t) * (MAX_BINDKEY + 1));
1.21.2.2  misho    1292:        inkeys = e_calloc(MAX_BINDKEY + 1, sizeof(bindkey_t));
                   1293:        if (!inkeys) {
                   1294:                LOGERR;
                   1295:                e_free(keys);
                   1296:                if (cli_buffer->line_prompt)
                   1297:                        e_free(cli_buffer->line_prompt);
1.21.2.3  misho    1298:                e_free(cli_buffer->line_input);
1.21.2.2  misho    1299:                e_free(cli_buffer->line_buf);
                   1300:                e_free(cli_buffer);
                   1301:                return NULL;
                   1302:        } else
                   1303:                memset(inkeys, 0, sizeof(bindkey_t) * (MAX_BINDKEY + 1));
1.3       misho    1304: 
                   1305:        /* add helper functions */
1.9       misho    1306:        cli_addCommand(cli_buffer, "exit", 1, cli_Cmd_Exit, "exit <cr>", "Exit from console");
                   1307:        cli_addCommand(cli_buffer, "help", -1, cli_Cmd_Help, "help [command] <cr>", "Help screen");
                   1308:        cli_addCommand(cli_buffer, "-------", -1, NULL, "-------------------------", NULL);
                   1309:        cli_addCommand(cli_buffer, "where", -1, cli_Cmd_WhereAmI, "where <cr>", 
                   1310:                        "Query current level of console");
                   1311:        cli_addCommand(cli_buffer, "top", -1, cli_Cmd_Top, "top <cr>", "Top level of console");
                   1312:        cli_addCommand(cli_buffer, "end", -1, cli_Cmd_End, "end <cr>", "End level of console");
                   1313:        cli_addCommand(cli_buffer, "config", -1, cli_Cmd_Config, "config <cr>", 
                   1314:                        "Config next level of console");
                   1315:        cli_addCommand(cli_buffer, "-------", -1, NULL, "-------------------------", NULL);
1.3       misho    1316: 
                   1317:        /* fill key bindings */
1.6       misho    1318:        /* ascii chars & ctrl+chars */
1.3       misho    1319:        for (i = 0; i < 256; i++) {
1.21.2.2  misho    1320:                *keys[i].key_ch = *inkeys[i].key_ch = (u_char) i;
                   1321:                keys[i].key_len = inkeys[i].key_len = 1;
1.3       misho    1322: 
                   1323:                if (!i || i == *K_CTRL_D)
                   1324:                        keys[i].key_func = bufEOF;
1.21.2.3  misho    1325:                if (i == *K_CTRL_M || i == *K_CTRL_J) {
1.3       misho    1326:                        keys[i].key_func = bufEOL;
1.21.2.3  misho    1327:                        inkeys[i].key_func = bufEOLin;
                   1328:                }
1.21.2.4  misho    1329:                if (i == *K_CTRL_H || i == *K_BACKSPACE) {
                   1330:                        if (cli_buffer->line_prompt)
                   1331:                                keys[i].key_func = bufBS;
                   1332:                        inkeys[i].key_func = bufBSin;
                   1333:                }
1.21.2.3  misho    1334:                if (i == *K_CTRL_C) {
1.3       misho    1335:                        keys[i].key_func = bufCLR;
1.21.2.3  misho    1336:                        inkeys[i].key_func = bufCLRin;
                   1337:                }
                   1338:                if (i == *K_CTRL_A) {
                   1339:                        if (cli_buffer->line_prompt)
                   1340:                                keys[i].key_func = bufBEGIN;
                   1341:                        inkeys[i].key_func = bufBEGINin;
                   1342:                }
                   1343:                if (i == *K_CTRL_E) {
                   1344:                        if (cli_buffer->line_prompt)
                   1345:                                keys[i].key_func = bufEND;
                   1346:                        inkeys[i].key_func = bufENDin;
                   1347:                }
1.9       misho    1348:                if (cli_buffer->line_prompt && i == *K_TAB)
1.3       misho    1349:                        keys[i].key_func = bufComp;
1.13      misho    1350:                if (i == *K_CTRL_Z)
1.9       misho    1351:                        keys[i].key_func = bufEndNode;
1.21.2.3  misho    1352:                if (i >= *K_SPACE && i < *K_BACKSPACE) {
1.3       misho    1353:                        keys[i].key_func = bufCHAR;
1.21.2.3  misho    1354:                        inkeys[i].key_func = bufCHARin;
                   1355:                }
                   1356:                if (i > *K_BACKSPACE && i < 0xff) {
1.3       misho    1357:                        keys[i].key_func = bufCHAR;
1.21.2.3  misho    1358:                        inkeys[i].key_func = bufCHARin;
                   1359:                }
1.9       misho    1360:                if (cli_buffer->line_prompt && i == '?')
1.3       misho    1361:                        keys[i].key_func = bufHelp;
                   1362:        }
1.6       misho    1363:        /* alt+chars */
1.3       misho    1364:        for (i = 256; i < 512; i++) {
1.21.2.2  misho    1365:                keys[i].key_ch[0] = inkeys[i].key_ch[0] = 0x1b;
                   1366:                keys[i].key_ch[1] = inkeys[i].key_ch[1] = (u_char) i - 256;
                   1367:                keys[i].key_len = inkeys[i].key_len = 2;
1.3       misho    1368:        }
                   1369: 
1.6       misho    1370:        /* 3 bytes */
1.21.2.2  misho    1371:        keys[i].key_len = inkeys[i].key_len = sizeof K_F1 - 1;
1.3       misho    1372:        memcpy(keys[i].key_ch, K_F1, keys[i].key_len);
1.21.2.2  misho    1373:        memcpy(inkeys[i].key_ch, K_F1, inkeys[i].key_len);
1.3       misho    1374:        i++;
1.21.2.2  misho    1375:        keys[i].key_len = inkeys[i].key_len = sizeof K_F2 - 1;
1.3       misho    1376:        memcpy(keys[i].key_ch, K_F2, keys[i].key_len);
1.21.2.2  misho    1377:        memcpy(inkeys[i].key_ch, K_F2, inkeys[i].key_len);
1.3       misho    1378:        i++;
1.21.2.2  misho    1379:        keys[i].key_len = inkeys[i].key_len = sizeof K_F3 - 1;
1.3       misho    1380:        memcpy(keys[i].key_ch, K_F3, keys[i].key_len);
1.21.2.2  misho    1381:        memcpy(inkeys[i].key_ch, K_F3, inkeys[i].key_len);
1.3       misho    1382:        i++;
1.21.2.2  misho    1383:        keys[i].key_len = inkeys[i].key_len = sizeof K_F4 - 1;
1.3       misho    1384:        memcpy(keys[i].key_ch, K_F4, keys[i].key_len);
1.21.2.2  misho    1385:        memcpy(inkeys[i].key_ch, K_F4, inkeys[i].key_len);
1.3       misho    1386:        i++;
1.21.2.2  misho    1387:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F1 - 1;
1.3       misho    1388:        memcpy(keys[i].key_ch, K_CTRL_SH_F1, keys[i].key_len);
1.21.2.2  misho    1389:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F1, inkeys[i].key_len);
1.3       misho    1390:        i++;
1.21.2.2  misho    1391:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F2 - 1;
1.3       misho    1392:        memcpy(keys[i].key_ch, K_CTRL_SH_F2, keys[i].key_len);
1.21.2.2  misho    1393:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F2, inkeys[i].key_len);
1.3       misho    1394:        i++;
1.21.2.2  misho    1395:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F3 - 1;
1.3       misho    1396:        memcpy(keys[i].key_ch, K_CTRL_SH_F3, keys[i].key_len);
1.21.2.2  misho    1397:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F3, inkeys[i].key_len);
1.3       misho    1398:        i++;
1.21.2.2  misho    1399:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F4 - 1;
1.3       misho    1400:        memcpy(keys[i].key_ch, K_CTRL_SH_F4, keys[i].key_len);
1.21.2.2  misho    1401:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F4, inkeys[i].key_len);
1.3       misho    1402:        i++;
1.21.2.2  misho    1403:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F5 - 1;
1.3       misho    1404:        memcpy(keys[i].key_ch, K_CTRL_SH_F5, keys[i].key_len);
1.21.2.2  misho    1405:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F5, inkeys[i].key_len);
1.3       misho    1406:        i++;
1.21.2.2  misho    1407:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F6 - 1;
1.3       misho    1408:        memcpy(keys[i].key_ch, K_CTRL_SH_F6, keys[i].key_len);
1.21.2.2  misho    1409:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F6, inkeys[i].key_len);
1.3       misho    1410:        i++;
1.21.2.2  misho    1411:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F7 - 1;
1.3       misho    1412:        memcpy(keys[i].key_ch, K_CTRL_SH_F7, keys[i].key_len);
1.21.2.2  misho    1413:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F7, inkeys[i].key_len);
1.3       misho    1414:        i++;
1.21.2.2  misho    1415:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F8 - 1;
1.3       misho    1416:        memcpy(keys[i].key_ch, K_CTRL_SH_F8, keys[i].key_len);
1.21.2.2  misho    1417:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F8, inkeys[i].key_len);
1.3       misho    1418:        i++;
1.21.2.2  misho    1419:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F9 - 1;
1.3       misho    1420:        memcpy(keys[i].key_ch, K_CTRL_SH_F9, keys[i].key_len);
1.21.2.2  misho    1421:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F9, inkeys[i].key_len);
1.3       misho    1422:        i++;
1.21.2.2  misho    1423:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F10 - 1;
1.3       misho    1424:        memcpy(keys[i].key_ch, K_CTRL_SH_F10, keys[i].key_len);
1.21.2.2  misho    1425:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F10, inkeys[i].key_len);
1.3       misho    1426:        i++;
1.21.2.2  misho    1427:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F11 - 1;
1.3       misho    1428:        memcpy(keys[i].key_ch, K_CTRL_SH_F11, keys[i].key_len);
1.21.2.2  misho    1429:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F11, inkeys[i].key_len);
1.3       misho    1430:        i++;
1.21.2.2  misho    1431:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F12 - 1;
1.3       misho    1432:        memcpy(keys[i].key_ch, K_CTRL_SH_F12, keys[i].key_len);
1.21.2.2  misho    1433:        memcpy(inkeys[i].key_ch, K_CTRL_SH_F12, inkeys[i].key_len);
1.3       misho    1434:        i++;
1.21.2.2  misho    1435:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F1 - 1;
1.3       misho    1436:        memcpy(keys[i].key_ch, K_CTRL_F1, keys[i].key_len);
1.21.2.2  misho    1437:        memcpy(inkeys[i].key_ch, K_CTRL_F1, inkeys[i].key_len);
1.3       misho    1438:        i++;
1.21.2.2  misho    1439:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F2 - 1;
1.3       misho    1440:        memcpy(keys[i].key_ch, K_CTRL_F2, keys[i].key_len);
1.21.2.2  misho    1441:        memcpy(inkeys[i].key_ch, K_CTRL_F2, inkeys[i].key_len);
1.3       misho    1442:        i++;
1.21.2.2  misho    1443:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F3 - 1;
1.3       misho    1444:        memcpy(keys[i].key_ch, K_CTRL_F3, keys[i].key_len);
1.21.2.2  misho    1445:        memcpy(inkeys[i].key_ch, K_CTRL_F3, inkeys[i].key_len);
1.3       misho    1446:        i++;
1.21.2.2  misho    1447:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F4 - 1;
1.3       misho    1448:        memcpy(keys[i].key_ch, K_CTRL_F4, keys[i].key_len);
1.21.2.2  misho    1449:        memcpy(inkeys[i].key_ch, K_CTRL_F4, inkeys[i].key_len);
1.3       misho    1450:        i++;
1.21.2.2  misho    1451:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F5 - 1;
1.3       misho    1452:        memcpy(keys[i].key_ch, K_CTRL_F5, keys[i].key_len);
1.21.2.2  misho    1453:        memcpy(inkeys[i].key_ch, K_CTRL_F5, inkeys[i].key_len);
1.3       misho    1454:        i++;
1.21.2.2  misho    1455:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F6 - 1;
1.3       misho    1456:        memcpy(keys[i].key_ch, K_CTRL_F6, keys[i].key_len);
1.21.2.2  misho    1457:        memcpy(inkeys[i].key_ch, K_CTRL_F6, inkeys[i].key_len);
1.3       misho    1458:        i++;
1.21.2.2  misho    1459:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F7 - 1;
1.3       misho    1460:        memcpy(keys[i].key_ch, K_CTRL_F7, keys[i].key_len);
1.21.2.2  misho    1461:        memcpy(inkeys[i].key_ch, K_CTRL_F7, inkeys[i].key_len);
1.3       misho    1462:        i++;
1.21.2.2  misho    1463:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F8 - 1;
1.3       misho    1464:        memcpy(keys[i].key_ch, K_CTRL_F8, keys[i].key_len);
1.21.2.2  misho    1465:        memcpy(inkeys[i].key_ch, K_CTRL_F8, inkeys[i].key_len);
1.3       misho    1466:        i++;
1.21.2.2  misho    1467:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F9 - 1;
1.3       misho    1468:        memcpy(keys[i].key_ch, K_CTRL_F9, keys[i].key_len);
1.21.2.2  misho    1469:        memcpy(inkeys[i].key_ch, K_CTRL_F9, inkeys[i].key_len);
1.3       misho    1470:        i++;
1.21.2.2  misho    1471:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F10 - 1;
1.3       misho    1472:        memcpy(keys[i].key_ch, K_CTRL_F10, keys[i].key_len);
1.21.2.2  misho    1473:        memcpy(inkeys[i].key_ch, K_CTRL_F10, inkeys[i].key_len);
1.3       misho    1474:        i++;
1.21.2.2  misho    1475:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F11 - 1;
1.3       misho    1476:        memcpy(keys[i].key_ch, K_CTRL_F11, keys[i].key_len);
1.21.2.2  misho    1477:        memcpy(inkeys[i].key_ch, K_CTRL_F11, inkeys[i].key_len);
1.3       misho    1478:        i++;
1.21.2.2  misho    1479:        keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F12 - 1;
1.3       misho    1480:        memcpy(keys[i].key_ch, K_CTRL_F12, keys[i].key_len);
1.21.2.2  misho    1481:        memcpy(inkeys[i].key_ch, K_CTRL_F12, inkeys[i].key_len);
1.3       misho    1482:        i++;
1.21.2.2  misho    1483:        keys[i].key_len = inkeys[i].key_len = sizeof K_HOME - 1;
1.9       misho    1484:        if (cli_buffer->line_prompt)
                   1485:                keys[i].key_func = bufBEGIN;
1.3       misho    1486:        memcpy(keys[i].key_ch, K_HOME, keys[i].key_len);
1.21.2.2  misho    1487:        memcpy(inkeys[i].key_ch, K_HOME, inkeys[i].key_len);
1.3       misho    1488:        i++;
1.21.2.2  misho    1489:        keys[i].key_len = inkeys[i].key_len = sizeof K_END - 1;
1.9       misho    1490:        if (cli_buffer->line_prompt)
                   1491:                keys[i].key_func = bufEND;
1.3       misho    1492:        memcpy(keys[i].key_ch, K_END, keys[i].key_len);
1.21.2.2  misho    1493:        memcpy(inkeys[i].key_ch, K_END, inkeys[i].key_len);
1.3       misho    1494:        i++;
1.21.2.2  misho    1495:        keys[i].key_len = inkeys[i].key_len = sizeof K_UP - 1;
1.9       misho    1496:        if (cli_buffer->line_prompt)
                   1497:                keys[i].key_func = bufUP;
1.3       misho    1498:        memcpy(keys[i].key_ch, K_UP, keys[i].key_len);
1.21.2.2  misho    1499:        memcpy(inkeys[i].key_ch, K_UP, inkeys[i].key_len);
1.3       misho    1500:        i++;
1.21.2.2  misho    1501:        keys[i].key_len = inkeys[i].key_len = sizeof K_DOWN - 1;
1.9       misho    1502:        if (cli_buffer->line_prompt)
                   1503:                keys[i].key_func = bufDOWN;
1.3       misho    1504:        memcpy(keys[i].key_ch, K_DOWN, keys[i].key_len);
1.21.2.2  misho    1505:        memcpy(inkeys[i].key_ch, K_DOWN, inkeys[i].key_len);
1.3       misho    1506:        i++;
1.21.2.2  misho    1507:        keys[i].key_len = inkeys[i].key_len = sizeof K_RIGHT - 1;
1.9       misho    1508:        if (cli_buffer->line_prompt)
                   1509:                keys[i].key_func = bufRIGHT;
1.21.2.5  misho    1510:        inkeys[i].key_func = bufRIGHTin;
1.3       misho    1511:        memcpy(keys[i].key_ch, K_RIGHT, keys[i].key_len);
1.21.2.2  misho    1512:        memcpy(inkeys[i].key_ch, K_RIGHT, inkeys[i].key_len);
1.3       misho    1513:        i++;
1.21.2.2  misho    1514:        keys[i].key_len = inkeys[i].key_len = sizeof K_LEFT - 1;
1.9       misho    1515:        if (cli_buffer->line_prompt)
                   1516:                keys[i].key_func = bufLEFT;
1.21.2.5  misho    1517:        inkeys[i].key_func = bufLEFTin;
1.3       misho    1518:        memcpy(keys[i].key_ch, K_LEFT, keys[i].key_len);
1.21.2.2  misho    1519:        memcpy(inkeys[i].key_ch, K_LEFT, inkeys[i].key_len);
1.3       misho    1520:        i++;
1.21.2.2  misho    1521:        keys[i].key_len = inkeys[i].key_len = sizeof K_BTAB - 1;
1.9       misho    1522:        if (cli_buffer->line_prompt)
                   1523:                keys[i].key_func = bufBTAB;
1.3       misho    1524:        memcpy(keys[i].key_ch, K_BTAB, keys[i].key_len);
1.21.2.2  misho    1525:        memcpy(inkeys[i].key_ch, K_BTAB, inkeys[i].key_len);
1.3       misho    1526:        i++;
1.6       misho    1527:        /* 4 bytes */
1.21.2.2  misho    1528:        keys[i].key_len = inkeys[i].key_len = sizeof K_INS - 1;
1.9       misho    1529:        if (cli_buffer->line_prompt)
                   1530:                keys[i].key_func = bufMODE;
1.21.2.6  misho    1531:        inkeys[i].key_func = bufMODE;
1.3       misho    1532:        memcpy(keys[i].key_ch, K_INS, keys[i].key_len);
1.21.2.2  misho    1533:        memcpy(inkeys[i].key_ch, K_INS, inkeys[i].key_len);
1.3       misho    1534:        i++;
1.21.2.2  misho    1535:        keys[i].key_len = inkeys[i].key_len = sizeof K_DEL - 1;
1.9       misho    1536:        if (cli_buffer->line_prompt)
                   1537:                keys[i].key_func = bufDEL;
1.21.2.6  misho    1538:        inkeys[i].key_func = bufDELin;
1.3       misho    1539:        memcpy(keys[i].key_ch, K_DEL, keys[i].key_len);
1.21.2.2  misho    1540:        memcpy(inkeys[i].key_ch, K_DEL, inkeys[i].key_len);
1.3       misho    1541:        i++;
1.21.2.2  misho    1542:        keys[i].key_len = inkeys[i].key_len = sizeof K_PGUP - 1;
1.3       misho    1543:        memcpy(keys[i].key_ch, K_PGUP, keys[i].key_len);
1.21.2.2  misho    1544:        memcpy(inkeys[i].key_ch, K_PGUP, inkeys[i].key_len);
1.3       misho    1545:        i++;
1.21.2.2  misho    1546:        keys[i].key_len = inkeys[i].key_len = sizeof K_PGDN - 1;
1.3       misho    1547:        memcpy(keys[i].key_ch, K_PGDN, keys[i].key_len);
1.21.2.2  misho    1548:        memcpy(inkeys[i].key_ch, K_PGDN, inkeys[i].key_len);
1.3       misho    1549:        i++;
1.6       misho    1550:        /* 5 bytes */
1.21.2.2  misho    1551:        keys[i].key_len = inkeys[i].key_len = sizeof K_F5 - 1;
1.3       misho    1552:        memcpy(keys[i].key_ch, K_F5, keys[i].key_len);
1.21.2.2  misho    1553:        memcpy(inkeys[i].key_ch, K_F5, inkeys[i].key_len);
1.3       misho    1554:        i++;
1.21.2.2  misho    1555:        keys[i].key_len = inkeys[i].key_len = sizeof K_F6 - 1;
1.3       misho    1556:        memcpy(keys[i].key_ch, K_F6, keys[i].key_len);
1.21.2.2  misho    1557:        memcpy(inkeys[i].key_ch, K_F6, inkeys[i].key_len);
1.3       misho    1558:        i++;
1.21.2.2  misho    1559:        keys[i].key_len = inkeys[i].key_len = sizeof K_F7 - 1;
1.3       misho    1560:        memcpy(keys[i].key_ch, K_F7, keys[i].key_len);
1.21.2.2  misho    1561:        memcpy(inkeys[i].key_ch, K_F7, inkeys[i].key_len);
1.3       misho    1562:        i++;
1.21.2.2  misho    1563:        keys[i].key_len = inkeys[i].key_len = sizeof K_F8 - 1;
1.3       misho    1564:        memcpy(keys[i].key_ch, K_F8, keys[i].key_len);
1.21.2.2  misho    1565:        memcpy(inkeys[i].key_ch, K_F8, inkeys[i].key_len);
1.3       misho    1566:        i++;
1.21.2.2  misho    1567:        keys[i].key_len = inkeys[i].key_len = sizeof K_F9 - 1;
1.3       misho    1568:        memcpy(keys[i].key_ch, K_F9, keys[i].key_len);
1.21.2.2  misho    1569:        memcpy(inkeys[i].key_ch, K_F9, inkeys[i].key_len);
1.3       misho    1570:        i++;
1.21.2.2  misho    1571:        keys[i].key_len = inkeys[i].key_len = sizeof K_F10 - 1;
1.3       misho    1572:        memcpy(keys[i].key_ch, K_F10, keys[i].key_len);
1.21.2.2  misho    1573:        memcpy(inkeys[i].key_ch, K_F10, inkeys[i].key_len);
1.3       misho    1574:        i++;
1.21.2.2  misho    1575:        keys[i].key_len = inkeys[i].key_len = sizeof K_F11 - 1;
1.3       misho    1576:        memcpy(keys[i].key_ch, K_F11, keys[i].key_len);
1.21.2.2  misho    1577:        memcpy(inkeys[i].key_ch, K_F11, inkeys[i].key_len);
1.3       misho    1578:        i++;
1.21.2.2  misho    1579:        keys[i].key_len = inkeys[i].key_len = sizeof K_F12 - 1;
1.3       misho    1580:        memcpy(keys[i].key_ch, K_F12, keys[i].key_len);
1.21.2.2  misho    1581:        memcpy(inkeys[i].key_ch, K_F12, inkeys[i].key_len);
1.3       misho    1582:        i++;
                   1583: 
1.7       misho    1584:        cli_buffer->line_keys = keys;
1.21.2.2  misho    1585:        cli_buffer->line_inkeys = inkeys;
1.7       misho    1586:        return cli_buffer;
1.2       misho    1587: }
                   1588: 
                   1589: /*
1.18      misho    1590:  * cliSetLine() - Set CLI input line terminal
1.6       misho    1591:  *
1.7       misho    1592:  * @cli_buffer = CLI buffer
1.18      misho    1593:  * @old = Old terminal settings
                   1594:  * return: -1 error or 0 ok
1.2       misho    1595: */
1.3       misho    1596: int
1.18      misho    1597: cliSetLine(linebuffer_t * __restrict cli_buffer, struct termios * __restrict old)
1.2       misho    1598: {
                   1599:        struct termios t;
                   1600: 
                   1601:        memset(&t, 0, sizeof t);
1.7       misho    1602:        tcgetattr(cli_buffer->line_in, &t);
1.18      misho    1603:        if (old)
                   1604:                memcpy(old, &t, sizeof(struct termios));
1.9       misho    1605:        t.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO | 
                   1606:                        ECHOCTL | ECHOE | ECHOK | ECHOKE | ECHONL | ECHOPRT);
1.2       misho    1607:        t.c_iflag |= IGNBRK;
                   1608:        t.c_cc[VMIN] = 1;
                   1609:        t.c_cc[VTIME] = 0;
1.7       misho    1610:        return tcsetattr(cli_buffer->line_in, TCSANOW, &t);
1.3       misho    1611: }
                   1612: 
                   1613: /*
1.18      misho    1614:  * cliResetLine() - Reset CLI input line terminal
                   1615:  *
                   1616:  * @cli_buffer = CLI buffer
                   1617:  * @old = Original terminal settings
                   1618:  * return: -1 error or 0 ok
                   1619: */
                   1620: int
                   1621: cliResetLine(linebuffer_t * __restrict cli_buffer, struct termios * __restrict orig)
                   1622: {
                   1623:        return tcsetattr(cli_buffer->line_in, TCSANOW, orig);
                   1624: }
                   1625: 
                   1626: /*
1.21.2.1  misho    1627:  * cliEcho() - Switch echo on or off
                   1628:  *
                   1629:  * @cli_buffer = CLI buffer
                   1630:  * @on = On or off for echo on input handler
                   1631:  * return: -1 error or 0 ok
                   1632: */
                   1633: int
                   1634: cliEcho(linebuffer_t * __restrict cli_buffer, int on)
                   1635: {
                   1636:        struct termios t;
                   1637: 
                   1638:        if (tcgetattr(cli_buffer->line_in, &t) == -1) {
                   1639:                cli_SetErr(errno, "tcgetattr(%d) - %s", cli_buffer->line_in, strerror(errno));
                   1640:                return -1;
                   1641:        }
                   1642: 
                   1643:        if (on)
                   1644:                t.c_lflag |= (ECHO);
                   1645:        else
                   1646:                t.c_lflag &= ~(ECHO);
                   1647: 
                   1648:        return tcsetattr(cli_buffer->line_in, TCSANOW, &t);
                   1649: }
                   1650: 
                   1651: /*
1.6       misho    1652:  * cliReadLine() - Read line from opened CLI session
                   1653:  *
1.7       misho    1654:  * @cli_buffer = CLI buffer
1.10      misho    1655:  * @timeout = Session timeout (-1 infinit)
1.6       misho    1656:  * return: NULL if error or !=NULL readed line, must be e_free after use!
1.3       misho    1657: */
                   1658: char *
1.12      misho    1659: cliReadLine(linebuffer_t * __restrict cli_buffer, int timeout)
1.3       misho    1660: {
1.10      misho    1661:        int code, readLen, ret;
1.3       misho    1662:        register int i;
                   1663:        struct pollfd fds;
                   1664:        char buf[BUFSIZ], *str = NULL;
1.2       misho    1665: 
1.7       misho    1666:        if (!cli_buffer) {
1.6       misho    1667:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho    1668:                return NULL;
1.11      misho    1669:        } else if (timeout > 0)
1.10      misho    1670:                timeout *= 1000;        /* convert from sec to ms */
1.2       misho    1671: 
1.3       misho    1672:        memset(&fds, 0, sizeof fds);
1.7       misho    1673:        fds.fd = cli_buffer->line_in;
1.3       misho    1674:        fds.events = POLLIN;
                   1675: 
1.7       misho    1676:        printfCR(cli_buffer, 1);
1.3       misho    1677:        while (42) {
1.10      misho    1678:                if ((ret = poll(&fds, 1, timeout)) < 1) {
1.21.2.3  misho    1679:                        if (!ret)
1.12      misho    1680:                                cli_buffer->line_kill = 1;
1.21.2.3  misho    1681:                        else
1.10      misho    1682:                                LOGERR;
1.21.2.3  misho    1683:                        return NULL;
1.3       misho    1684:                }
                   1685: 
                   1686:                memset(buf, 0, sizeof buf);
1.21.2.3  misho    1687:                readLen = read(cli_buffer->line_in, buf, sizeof buf - 1);
1.14      misho    1688:                if (readLen < 1) {
                   1689:                        if (readLen)
                   1690:                                LOGERR;
                   1691:                        return NULL;
1.3       misho    1692:                }
                   1693: 
1.21.2.3  misho    1694:                while (readLen)
                   1695:                        for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--)
                   1696:                                if (readLen >= cli_buffer->line_keys[i].key_len && 
                   1697:                                                !memcmp(cli_buffer->line_keys[i].key_ch, buf, 
                   1698:                                                        cli_buffer->line_keys[i].key_len)) {
                   1699:                                        readLen -= cli_buffer->line_keys[i].key_len;
                   1700:                                        if (readLen)
                   1701:                                                memmove(buf, buf + cli_buffer->line_keys[i].key_len, readLen);
                   1702:                                        else
                   1703:                                                memset(buf, 0, cli_buffer->line_keys[i].key_len);
                   1704: 
                   1705:                                        if (cli_buffer->line_keys[i].key_func)
                   1706:                                                if ((code = cli_buffer->line_keys[i].key_func(i, cli_buffer)))
                   1707:                                                        readLen = 0;
                   1708:                                }
1.3       misho    1709: 
                   1710:                if (code)
                   1711:                        break;
                   1712:        }
1.2       misho    1713: 
1.7       misho    1714:        if (code != RETCODE_ERR && code != RETCODE_EOF && cli_buffer->line_buf)
                   1715:                str = e_strdup(cli_buffer->line_buf);
1.3       misho    1716:        return str;
1.2       misho    1717: }
                   1718: 
1.21.2.3  misho    1719: /*
                   1720:  * cliInputLine() - Input line from opened CLI session
                   1721:  *
                   1722:  * @cli_buffer = CLI buffer
                   1723:  * @timeout = Session timeout (-1 infinit)
                   1724:  * return: NULL if error or !=NULL readed line, must be e_free after use!
                   1725: */
                   1726: char *
                   1727: cliInputLine(linebuffer_t * __restrict cli_buffer, int timeout)
                   1728: {
                   1729:        int code, readLen, ret;
                   1730:        register int i;
                   1731:        struct pollfd fds;
                   1732:        char buf[BUFSIZ], *str = NULL;
                   1733: 
                   1734:        if (!cli_buffer) {
                   1735:                cli_SetErr(EINVAL, "Invalid input parameters ...");
                   1736:                return NULL;
                   1737:        } else if (timeout > 0)
                   1738:                timeout *= 1000;        /* convert from sec to ms */
                   1739: 
                   1740:        memset(&fds, 0, sizeof fds);
                   1741:        fds.fd = cli_buffer->line_in;
                   1742:        fds.events = POLLIN;
                   1743: 
                   1744:        while (42) {
                   1745:                if ((ret = poll(&fds, 1, timeout)) < 1) {
                   1746:                        if (ret == -1)
                   1747:                                LOGERR;
                   1748:                        return NULL;
                   1749:                }
                   1750: 
                   1751:                memset(buf, 0, sizeof buf);
                   1752:                readLen = read(cli_buffer->line_in, buf, sizeof buf - 1);
                   1753:                if (readLen < 1) {
                   1754:                        if (readLen)
                   1755:                                LOGERR;
                   1756:                        return NULL;
                   1757:                }
                   1758: 
                   1759:                while (readLen)
                   1760:                        for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--)
                   1761:                                if (readLen >= cli_buffer->line_inkeys[i].key_len && 
                   1762:                                                !memcmp(cli_buffer->line_inkeys[i].key_ch, buf, 
                   1763:                                                        cli_buffer->line_inkeys[i].key_len)) {
                   1764:                                        readLen -= cli_buffer->line_inkeys[i].key_len;
                   1765:                                        if (readLen)
                   1766:                                                memmove(buf, buf + cli_buffer->line_inkeys[i].key_len, readLen);
                   1767:                                        else
                   1768:                                                memset(buf, 0, cli_buffer->line_inkeys[i].key_len);
                   1769: 
                   1770:                                        if (cli_buffer->line_inkeys[i].key_func)
                   1771:                                                if ((code = cli_buffer->line_inkeys[i].key_func(i, cli_buffer)))
                   1772:                                                        readLen = 0;
                   1773:                                }
                   1774: 
                   1775:                if (code)
                   1776:                        break;
                   1777:        }
                   1778: 
                   1779:        if (code != RETCODE_ERR && code != RETCODE_EOF && cli_buffer->line_input)
                   1780:                str = e_strdup(cli_buffer->line_input);
                   1781:        return str;
                   1782: }
                   1783: 
1.3       misho    1784: 
1.2       misho    1785: /*
1.6       misho    1786:  * cliNetLoop() - CLI network main loop binded to socket
                   1787:  *
1.7       misho    1788:  * @cli_buffer = CLI buffer
1.3       misho    1789:  * @csHistFile = History file name
1.2       misho    1790:  * @sock = client socket
1.10      misho    1791:  * @timeout = Session timeout (-1 infinit)
1.3       misho    1792:  * return: RETCODE_ERR error, RETCODE_OK ok
1.2       misho    1793: */
1.3       misho    1794: int
1.10      misho    1795: cliNetLoop(linebuffer_t * __restrict cli_buffer, const char *csHistFile, 
1.12      misho    1796:                int sock, int timeout)
1.2       misho    1797: {
1.3       misho    1798:        u_char buf[BUFSIZ];
1.15      misho    1799:        int pid, stat, pty, s, alen, flg, attrlen = 0, ret = 0;
1.2       misho    1800:        fd_set fds;
                   1801:        struct timeval tv = { DEFAULT_SOCK_TIMEOUT, 0 };
                   1802:        struct telnetAttrs *a, Attr[10];
                   1803: 
1.3       misho    1804:        switch ((pid = forkpty(&pty, NULL, NULL, NULL))) {
1.2       misho    1805:                case -1:
                   1806:                        LOGERR;
                   1807:                        return -1;
                   1808:                case 0:
1.7       misho    1809:                        if (!cli_buffer) {
1.6       misho    1810:                                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho    1811:                                return -1;
                   1812:                        } else
                   1813:                                close(sock);
1.2       misho    1814: 
1.12      misho    1815:                        ret = cliLoop(cli_buffer, csHistFile, timeout) < 0 ? 1 : 0;
1.7       misho    1816:                        cliEnd(cli_buffer);
1.2       misho    1817: 
1.8       misho    1818:                        _exit(ret);
1.2       misho    1819:                default:
1.4       misho    1820:                        cli_telnet_SetCmd(Attr + 0, DO, TELOPT_TTYPE);
                   1821:                        cli_telnet_SetCmd(Attr + 1, WILL, TELOPT_ECHO);
                   1822:                        cli_telnet_Set_SubOpt(Attr + 2, TELOPT_LFLOW, LFLOW_OFF, NULL, 0);
                   1823:                        cli_telnet_Set_SubOpt(Attr + 3, TELOPT_LFLOW, LFLOW_RESTART_XON, NULL, 0);
                   1824:                        cli_telnet_SetCmd(Attr + 4, DO, TELOPT_LINEMODE);
                   1825:                        if ((ret = cli_telnetSend(sock, Attr, 5, NULL, 0, 0)) == -1)
1.2       misho    1826:                                return -1;
1.4       misho    1827:                        else
1.2       misho    1828:                                flg = 0;
                   1829: 
                   1830:                        while (42) {
1.3       misho    1831:                                if (waitpid(pid, &stat, WNOHANG))
                   1832:                                        break;
                   1833: 
1.2       misho    1834:                                FD_ZERO(&fds);
                   1835:                                FD_SET(sock, &fds);
                   1836:                                FD_SET(pty, &fds);
                   1837:                                if ((ret = select(FD_SETSIZE, &fds, NULL, NULL, &tv)) < 1) {
                   1838:                                        if (!ret)
                   1839:                                                cli_SetErr(ETIMEDOUT, "Client session timeout ...");
                   1840: 
                   1841:                                        break;
                   1842:                                }
                   1843: 
                   1844:                                s = FD_ISSET(sock, &fds) ? pty : sock;
                   1845: 
1.3       misho    1846:                                if (FD_ISSET(sock, &fds)) {
                   1847:                                        memset(buf, 0, BUFSIZ);
1.4       misho    1848:                                        if ((ret = cli_telnetRecv(sock, &a, &alen, buf, BUFSIZ)) < 0) {
1.3       misho    1849:                                                if (a)
1.6       misho    1850:                                                        e_free(a);
1.3       misho    1851: 
                   1852:                                                if (-2 == ret)
                   1853:                                                        continue;
                   1854:                                                // EOF
                   1855:                                                if (-3 == ret)
                   1856:                                                        shutdown(sock, SHUT_RD);
                   1857:                                                break;
                   1858:                                        }
                   1859:                                        attrlen = 0;
                   1860:                                        if (1 == flg && alen) {
1.4       misho    1861:                                                cli_telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_SGA);
                   1862:                                                cli_telnet_SetCmd(&Attr[attrlen++], DO, TELOPT_ECHO);
1.3       misho    1863:                                        }
                   1864:                                        if (2 == flg && alen) {
1.4       misho    1865:                                                cli_telnet_SetCmd(&Attr[attrlen++], WILL, TELOPT_ECHO);
                   1866:                                                cli_telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW, 
1.3       misho    1867:                                                                LFLOW_OFF, NULL, 0);
1.4       misho    1868:                                                cli_telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW, 
1.3       misho    1869:                                                                LFLOW_RESTART_XON, NULL, 0);
1.4       misho    1870:                                                cli_telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_LINEMODE);
1.3       misho    1871:                                        }
1.2       misho    1872:                                        if (a)
1.6       misho    1873:                                                e_free(a);
1.2       misho    1874: 
1.3       misho    1875:                                        if ((ret = write(pty, buf, ret)) == -1) {
                   1876:                                                LOGERR;
                   1877:                                                break;
                   1878:                                        }
                   1879:                                }
                   1880: 
                   1881:                                if (FD_ISSET(pty, &fds)) {
                   1882:                                        memset(buf, 0, BUFSIZ);
1.14      misho    1883:                                        if ((ret = read(pty, buf, BUFSIZ)) < 1) {
                   1884:                                                if (ret)
                   1885:                                                        LOGERR;
1.3       misho    1886:                                                break;
                   1887:                                        }
                   1888: 
1.4       misho    1889:                                        if ((ret = cli_telnetSend(sock, Attr, pty == s ? 0 : attrlen, 
                   1890:                                                                        buf, ret, 0)) == -1)
1.3       misho    1891:                                                break;
1.4       misho    1892:                                        else
1.3       misho    1893:                                                flg++;
1.2       misho    1894:                                }
                   1895:                        }
                   1896: 
                   1897:                        close(pty);
                   1898:        }
                   1899: 
                   1900:        return ret;
                   1901: }
                   1902: 
                   1903: /*
1.17      misho    1904:  * cliRun() - CLI run command line
                   1905:  *
                   1906:  * @cli_buffer = CLI buffer
                   1907:  * @psInput = Input command line
                   1908:  * @prompt = Display prompt after command
                   1909:  * return: RETCODE_ERR error, RETCODE_OK ok
                   1910: */
                   1911: int
                   1912: cliRun(linebuffer_t * __restrict cli_buffer, char *psInput, int prompt)
                   1913: {
                   1914:        char *line, *s, *t, **app, *items[MAX_PROMPT_ITEMS];
                   1915:        int ret = RETCODE_OK;
                   1916:        struct tagCommand *cmd;
                   1917: 
                   1918:        if (!psInput)
                   1919:                return RETCODE_ERR;
                   1920:        else
                   1921:                line = psInput;
                   1922: 
                   1923:        // clear whitespaces
                   1924:        for (s = line; isspace((int) *s); s++);
                   1925:        if (*s) {
                   1926:                for (t = s + strlen(s) - 1; t > s && isspace((int) *t); t--);
                   1927:                *++t = 0;
                   1928:        }
                   1929: 
                   1930:        if (*s) {
                   1931:                memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
                   1932:                for (app = items; app < items + MAX_PROMPT_ITEMS - 1 && 
                   1933:                                (*app = strsep(&s, " \t")); *app ? app++ : app);
                   1934: 
                   1935:                // exec_cmd ...
                   1936:                SLIST_FOREACH(cmd, &cli_buffer->line_cmds, cmd_next) {
                   1937:                        if (!(cmd->cmd_level & (1 << cli_buffer->line_level)))
                   1938:                                continue;
                   1939:                        if (*items[0] && !strncmp(cmd->cmd_name, items[0], strlen(items[0])))
                   1940:                                break;
                   1941:                }
                   1942: 
                   1943:                if (!cmd) {
                   1944:                        cli_Printf(cli_buffer, "%sCommand '%s' not found!\n", 
                   1945:                                        cli_buffer->line_prompt ? "\n" : "", items[0]);
                   1946:                        ret = RETCODE_ERR;
                   1947:                } else
                   1948:                        if (cmd->cmd_func) {
                   1949:                                if (prompt && cli_buffer->line_prompt)
                   1950:                                        cli_Printf(cli_buffer, "\n");
                   1951:                                ret = cmd->cmd_func(cli_buffer, 
                   1952:                                                cli_buffer->line_level, items);
                   1953:                        } else if (prompt) {
                   1954:                                clrscrEOL(cli_buffer);
                   1955:                                printfCR(cli_buffer, 1);
                   1956:                        }
                   1957:        }
                   1958: 
                   1959:        return ret;
                   1960: }
                   1961: 
                   1962: /*
1.6       misho    1963:  * cliLoop() - CLI main loop
                   1964:  *
1.7       misho    1965:  * @cli_buffer = CLI buffer
1.3       misho    1966:  * @csHistFile = History file name
1.10      misho    1967:  * @timeout = Session timeout (-1 infinit)
1.3       misho    1968:  * return: RETCODE_ERR error, RETCODE_OK ok
1.1       misho    1969: */
1.3       misho    1970: int
1.12      misho    1971: cliLoop(linebuffer_t * __restrict cli_buffer, const char *csHistFile, int timeout)
1.1       misho    1972: {
1.17      misho    1973:        char *line;
1.3       misho    1974:        int ret = RETCODE_OK;
1.18      misho    1975:        struct termios t;
1.1       misho    1976: 
                   1977:        /* --- main body of CLI --- */
1.18      misho    1978:        cliSetLine(cli_buffer, &t);
1.1       misho    1979: 
1.7       misho    1980:        if (cli_loadHistory(cli_buffer, csHistFile) == RETCODE_ERR)
1.3       misho    1981:                return RETCODE_ERR;
1.1       misho    1982: 
                   1983:        do {
1.12      misho    1984:                line = cliReadLine(cli_buffer, timeout);
1.3       misho    1985:                if (!line) {
1.7       misho    1986:                        printfNL(cli_buffer, 0);
1.1       misho    1987:                        break;
1.3       misho    1988:                } else
1.7       misho    1989:                        cli_addHistory(cli_buffer, NULL);
1.3       misho    1990: 
1.17      misho    1991:                ret = cliRun(cli_buffer, line, 42);
1.1       misho    1992: 
1.7       misho    1993:                cli_freeLine(cli_buffer);
                   1994:                cli_resetHistory(cli_buffer);
1.6       misho    1995:                e_free(line);
1.19      misho    1996:        } while (!cli_buffer->line_kill);
1.1       misho    1997: 
1.7       misho    1998:        cli_saveHistory(cli_buffer, csHistFile, HISTORY_LINES);
1.18      misho    1999: 
                   2000:        /* --- restore tty --- */
                   2001:        cliResetLine(cli_buffer, &t);
                   2002: 
1.1       misho    2003:        return ret;
                   2004: }

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