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

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

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