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

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

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