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

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.8.2.7 ! misho       6: * $Id: aitcli.c,v 1.8.2.6 2013/10/08 09:41:20 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.6       misho      15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
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;
                     90: 
1.8.2.1   misho      91:        if (buf && buf->line_prompt) {
1.3       misho      92:                write(buf->line_out, K_CR, 1);
1.1       misho      93: 
1.3       misho      94:                for (i = 0; i < buf->line_len; i++)
                     95:                        write(buf->line_out, K_SPACE, 1);
                     96:        }
                     97: }
1.1       misho      98: 
1.3       misho      99: static inline void
                    100: printfEOL(linebuffer_t * __restrict buf, int len, int prompt)
1.2       misho     101: {
1.3       misho     102:        if (buf) {
1.8.2.1   misho     103:                if (prompt && buf->line_prompt) {
                    104:                        write(buf->line_out, K_CR, 1);
1.3       misho     105:                        write(buf->line_out, buf->line_prompt, buf->line_bol);
1.8.2.1   misho     106:                }
1.3       misho     107: 
1.8.2.1   misho     108:                write(buf->line_out, buf->line_buf, len == -1 ? 
                    109:                                buf->line_eol - buf->line_bol: len);
1.3       misho     110:        }
1.2       misho     111: }
                    112: 
1.3       misho     113: static inline void
                    114: printfCR(linebuffer_t * __restrict buf, int prompt)
1.2       misho     115: {
1.8.2.1   misho     116:        if (buf && prompt && buf->line_prompt) {
1.3       misho     117:                write(buf->line_out, K_CR, 1);
1.8.2.1   misho     118:                write(buf->line_out, buf->line_prompt, buf->line_bol);
1.2       misho     119:        }
1.3       misho     120: }
                    121: 
                    122: static inline void
                    123: printfNL(linebuffer_t * __restrict buf, int prompt)
                    124: {
                    125:        if (buf) {
                    126:                write(buf->line_out, K_ENTER, 1);
                    127: 
1.8.2.3   misho     128:                if (prompt)
1.3       misho     129:                        if (prompt && buf->line_prompt)
                    130:                                write(buf->line_out, buf->line_prompt, buf->line_bol);
                    131:        }
                    132: }
                    133: 
                    134: // ------------------------------------------------------------
                    135: 
                    136: static int
1.7       misho     137: bufCHAR(int idx, void * __restrict cli_buffer)
1.3       misho     138: {
1.7       misho     139:        linebuffer_t *buf = cli_buffer;
1.3       misho     140:        int pos;
                    141: 
1.7       misho     142:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     143:                return RETCODE_ERR;
                    144: 
                    145:        pos = buf->line_eol - buf->line_bol;
                    146: 
                    147:        if (buf->line_mode == LINEMODE_INS)
                    148:                memmove(buf->line_buf + pos + buf->line_keys[idx].key_len, buf->line_buf + pos, 
                    149:                                buf->line_len - buf->line_eol);
                    150:        if (buf->line_mode == LINEMODE_INS || buf->line_eol == buf->line_len - 1)
                    151:                buf->line_len += buf->line_keys[idx].key_len;
                    152:        buf->line_eol += buf->line_keys[idx].key_len;
                    153: 
                    154:        memcpy(buf->line_buf + pos, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
                    155:        buf->line_buf[buf->line_len - 1] = 0;
                    156: 
                    157:        write(buf->line_out, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
                    158: 
                    159:        if (buf->line_mode == LINEMODE_INS) {
                    160:                write(buf->line_out, (const u_char*) buf->line_buf + pos + buf->line_keys[idx].key_len, 
                    161:                                buf->line_len - buf->line_eol);
                    162:                printfEOL(buf, -1, 1);
1.2       misho     163:        }
1.3       misho     164:        return RETCODE_OK;
                    165: }
                    166: 
                    167: static int
1.7       misho     168: bufEOL(int idx, void * __restrict cli_buffer)
1.3       misho     169: {
1.7       misho     170:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     171:                return RETCODE_ERR;
                    172: 
1.7       misho     173:        printfCR(cli_buffer, 1);
1.3       misho     174:        return RETCODE_EOL;
                    175: }
                    176: 
                    177: static int
1.7       misho     178: bufEOF(int idx, void * __restrict cli_buffer)
1.3       misho     179: {
                    180:        /*
1.7       misho     181:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     182:                return RETCODE_ERR;
                    183:        */
                    184: 
                    185:        return RETCODE_EOF;
                    186: }
                    187: 
                    188: static int
1.7       misho     189: bufUP(int idx, void * __restrict cli_buffer)
1.3       misho     190: {
1.7       misho     191:        linebuffer_t *buf = cli_buffer;
1.3       misho     192:        int pos;
                    193: 
1.7       misho     194:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     195:                return RETCODE_ERR;
                    196: 
                    197:        if (!buf->line_h)
                    198:                buf->line_h = TAILQ_FIRST(&buf->line_history);
                    199:        else
                    200:                buf->line_h = TAILQ_NEXT(buf->line_h, hist_next);
                    201:        if (!buf->line_h)
                    202:                return RETCODE_OK;
                    203: 
                    204:        clrscrEOL(buf);
                    205:        cli_freeLine(buf);
                    206: 
                    207:        pos = buf->line_eol - buf->line_bol;
                    208: 
                    209:        buf->line_len += buf->line_h->hist_len;
                    210:        buf->line_eol += buf->line_h->hist_len;
                    211: 
                    212:        memcpy(buf->line_buf + pos, buf->line_h->hist_line, buf->line_h->hist_len);
                    213:        buf->line_buf[buf->line_len - 1] = 0;
                    214: 
                    215:        printfEOL(buf, -1, 1);
                    216:        return RETCODE_OK;
                    217: }
                    218: 
                    219: static int
1.7       misho     220: bufDOWN(int idx, void * __restrict cli_buffer)
1.3       misho     221: {
1.7       misho     222:        linebuffer_t *buf = cli_buffer;
1.3       misho     223:        int pos;
                    224: 
1.7       misho     225:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     226:                return RETCODE_ERR;
                    227: 
                    228:        if (!buf->line_h)
                    229:                buf->line_h = TAILQ_LAST(&buf->line_history, tqHistoryHead);
                    230:        else
                    231:                buf->line_h = TAILQ_PREV(buf->line_h, tqHistoryHead, hist_next);
                    232:        if (!buf->line_h)
                    233:                return RETCODE_OK;
                    234: 
                    235:        clrscrEOL(buf);
                    236:        cli_freeLine(buf);
                    237: 
                    238:        pos = buf->line_eol - buf->line_bol;
                    239: 
                    240:        buf->line_len += buf->line_h->hist_len;
                    241:        buf->line_eol += buf->line_h->hist_len;
                    242: 
                    243:        memcpy(buf->line_buf + pos, buf->line_h->hist_line, buf->line_h->hist_len);
                    244:        buf->line_buf[buf->line_len - 1] = 0;
                    245: 
                    246:        printfEOL(buf, -1, 1);
                    247:        return RETCODE_OK;
                    248: }
                    249: 
                    250: static int
1.7       misho     251: bufCLR(int idx, void * __restrict cli_buffer)
1.3       misho     252: {
1.7       misho     253:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     254:                return RETCODE_ERR;
                    255: 
1.7       misho     256:        clrscrEOL(cli_buffer);
                    257:        cli_freeLine(cli_buffer);
1.3       misho     258: 
1.7       misho     259:        printfCR(cli_buffer, 1);
1.3       misho     260:        return RETCODE_OK;
                    261: }
                    262: 
                    263: static int
1.7       misho     264: bufBS(int idx, void * __restrict cli_buffer)
1.3       misho     265: {
1.7       misho     266:        linebuffer_t *buf = 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: 
                    271:        if (buf->line_bol < buf->line_eol) {
                    272:                clrscrEOL(buf);
                    273: 
                    274:                buf->line_eol--;
                    275:                buf->line_len--;
                    276:                memmove(buf->line_buf + buf->line_eol - buf->line_bol, 
                    277:                                buf->line_buf + buf->line_eol - buf->line_bol + 1, 
                    278:                                buf->line_len - buf->line_eol);
                    279:                buf->line_buf[buf->line_len - 1] = 0;
                    280: 
                    281:                printfEOL(buf, buf->line_len - 1, 1);
                    282:                printfEOL(buf, -1, 1);
                    283:        }
                    284: 
                    285:        return RETCODE_OK;
                    286: }
                    287: 
                    288: static int
1.7       misho     289: bufBTAB(int idx, void * __restrict cli_buffer)
1.3       misho     290: {
1.7       misho     291:        linebuffer_t *buf = cli_buffer;
1.3       misho     292: 
1.7       misho     293:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     294:                return RETCODE_ERR;
                    295: 
                    296:        if (buf->line_bol < buf->line_eol) {
                    297:                clrscrEOL(buf);
                    298: 
                    299:                buf->line_len = buf->line_eol - buf->line_bol + 1;
                    300:                buf->line_buf[buf->line_len - 1] = 0;
                    301: 
                    302:                printfEOL(buf, -1, 1);
1.2       misho     303:        }
                    304: 
1.3       misho     305:        return RETCODE_OK;
                    306: }
                    307: 
                    308: static int
1.7       misho     309: bufMODE(int idx, void * __restrict cli_buffer)
1.3       misho     310: {
1.7       misho     311:        linebuffer_t *buf = cli_buffer;
1.3       misho     312: 
1.7       misho     313:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     314:                return RETCODE_ERR;
                    315: 
                    316:        buf->line_mode = !buf->line_mode ? LINEMODE_OVER : LINEMODE_INS;
                    317:        return RETCODE_OK;
                    318: }
                    319: 
                    320: static int
1.7       misho     321: bufBEGIN(int idx, void * __restrict cli_buffer)
1.3       misho     322: {
1.7       misho     323:        linebuffer_t *buf = cli_buffer;
1.3       misho     324: 
1.7       misho     325:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     326:                return RETCODE_ERR;
                    327: 
                    328:        buf->line_eol = buf->line_bol;
                    329: 
                    330:        printfCR(buf, 1);
                    331:        return RETCODE_OK;
                    332: }
                    333: 
                    334: static int
1.7       misho     335: bufEND(int idx, void * __restrict cli_buffer)
1.3       misho     336: {
1.7       misho     337:        linebuffer_t *buf = cli_buffer;
1.3       misho     338: 
1.7       misho     339:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     340:                return RETCODE_ERR;
                    341: 
                    342:        buf->line_eol = buf->line_len - 1;
                    343: 
                    344:        printfEOL(buf, -1, 1);
                    345:        return RETCODE_OK;
1.2       misho     346: }
                    347: 
1.3       misho     348: static int
1.7       misho     349: bufLEFT(int idx, void * __restrict cli_buffer)
1.2       misho     350: {
1.7       misho     351:        linebuffer_t *buf = cli_buffer;
1.3       misho     352: 
1.7       misho     353:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     354:                return RETCODE_ERR;
                    355: 
                    356:        if (buf->line_bol < buf->line_eol)
                    357:                printfEOL(buf, --buf->line_eol - buf->line_bol, 1);
                    358: 
                    359:        return RETCODE_OK;
                    360: }
1.2       misho     361: 
1.3       misho     362: static int
1.7       misho     363: bufRIGHT(int idx, void * __restrict cli_buffer)
1.3       misho     364: {
1.7       misho     365:        linebuffer_t *buf = cli_buffer;
1.3       misho     366: 
1.7       misho     367:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     368:                return RETCODE_ERR;
                    369: 
                    370:        if (buf->line_eol < buf->line_len - 1)
                    371:                printfEOL(buf, ++buf->line_eol - buf->line_bol, 1);
                    372: 
                    373:        return RETCODE_OK;
                    374: }
                    375: 
                    376: static int
1.7       misho     377: bufDEL(int idx, void * __restrict cli_buffer)
1.3       misho     378: {
1.7       misho     379:        linebuffer_t *buf = cli_buffer;
1.3       misho     380: 
1.7       misho     381:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     382:                return RETCODE_ERR;
                    383: 
                    384:        clrscrEOL(buf);
                    385: 
                    386:        buf->line_len--;
                    387:        memmove(buf->line_buf + buf->line_eol - buf->line_bol, 
                    388:                        buf->line_buf + buf->line_eol - buf->line_bol + 1, 
                    389:                        buf->line_len - buf->line_eol);
                    390:        buf->line_buf[buf->line_len - 1] = 0;
                    391: 
                    392:        printfEOL(buf, buf->line_len - 1, 1);
                    393:        printfEOL(buf, -1, 1);
                    394: 
                    395:        return RETCODE_OK;
                    396: }
                    397: 
                    398: static int
1.7       misho     399: bufComp(int idx, void * __restrict cli_buffer)
1.3       misho     400: {
1.7       misho     401:        linebuffer_t *buf = cli_buffer;
1.3       misho     402:        char *str, *s, **app, *items[MAX_PROMPT_ITEMS], szLine[STRSIZ];
                    403:        register int i, j;
                    404:        struct tagCommand *cmd, *c;
                    405:        int pos, ret = RETCODE_OK;
                    406: 
1.7       misho     407:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     408:                return RETCODE_ERR;
                    409: 
1.6       misho     410:        str = e_strdup(buf->line_buf);
1.3       misho     411:        if (!str)
                    412:                return RETCODE_ERR;
1.2       misho     413:        else {
1.3       misho     414:                s = str;
1.6       misho     415:                str_Trim(s);
1.3       misho     416:        }
                    417: 
                    418:        i = j = 0;
                    419:        c = NULL;
                    420:        memset(szLine, 0, STRSIZ);
                    421:        if (*s) {
                    422:                memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
1.8.2.1   misho     423:                for (app = items, i = 0; app < items + MAX_PROMPT_ITEMS - 1 && 
                    424:                                (*app = strsep(&s, " \t")); 
1.3       misho     425:                                *app ? i++ : i, *app ? app++ : app);
                    426: 
                    427:                if (i) {
                    428:                        SLIST_FOREACH(cmd, &buf->line_cmds, cmd_next) {
1.8.2.7 ! misho     429:                                if (cmd->cmd_level & (1 << buf->line_level) && 
1.8.2.1   misho     430:                                                !strncmp(cmd->cmd_name, items[0], 
                    431:                                                        strlen(items[0]))) {
                    432:                                        if (strncmp(cmd->cmd_name, CLI_CMD_SEP, 
                    433:                                                                strlen(CLI_CMD_SEP))) {
1.3       misho     434:                                                j++;
                    435:                                                c = cmd;
                    436:                                                strlcat(szLine, " ", STRSIZ);
                    437:                                                strlcat(szLine, cmd->cmd_name, STRSIZ);
                    438:                                        }
                    439:                                }
                    440:                        }
1.2       misho     441: 
1.3       misho     442:                        if (i > 1 && c) {
                    443:                                /* we are on argument of command and has complition info */
                    444:                                j++;    // always must be j > 1 ;) for arguments
                    445:                                strlcpy(szLine, c->cmd_info, STRSIZ);
                    446:                        }
                    447:                } else {
                    448:                        /* we have valid char but i == 0, this case is illegal */
                    449:                        ret = RETCODE_ERR;
                    450:                        goto endcomp;
1.2       misho     451:                }
1.3       misho     452:        } else {
                    453:                /* we on 0 position of prompt, show commands for this level */
                    454:                SLIST_FOREACH(cmd, &buf->line_cmds, cmd_next) {
1.8.2.7 ! misho     455:                        if (cmd->cmd_level & (1 << buf->line_level))
1.3       misho     456:                                if (strncmp(cmd->cmd_name, CLI_CMD_SEP, strlen(CLI_CMD_SEP))) {
                    457:                                        j++;
                    458:                                        c = cmd;
                    459:                                        strlcat(szLine, " ", STRSIZ);
                    460:                                        strlcat(szLine, cmd->cmd_name, STRSIZ);
                    461:                                }
                    462:                }
                    463:        }
1.2       misho     464: 
1.3       misho     465:        /* completion show actions ... */
                    466:        if (j > 1 && c) {
                    467:                printfNL(buf, 0);
                    468:                write(buf->line_out, szLine, strlen(szLine));
                    469:                printfNL(buf, 1);
                    470:                printfEOL(buf, buf->line_len - 1, 1);
                    471:                printfEOL(buf, -1, 1);
1.2       misho     472:        }
1.3       misho     473:        if (j == 1 && c) {
                    474:                clrscrEOL(buf);
                    475:                cli_freeLine(buf);
                    476: 
                    477:                pos = buf->line_eol - buf->line_bol;
                    478: 
                    479:                buf->line_len += c->cmd_len + 1;
                    480:                buf->line_eol += c->cmd_len + 1;
                    481: 
                    482:                memcpy(buf->line_buf + pos, c->cmd_name, c->cmd_len);
                    483:                buf->line_buf[pos + c->cmd_len] = (u_char) *K_SPACE;
                    484:                buf->line_buf[buf->line_len - 1] = 0;
1.2       misho     485: 
1.3       misho     486:                printfEOL(buf, -1, 1);
1.2       misho     487:        }
                    488: 
1.3       misho     489: endcomp:
1.6       misho     490:        e_free(str);
1.3       misho     491:        return ret;
                    492: }
                    493: 
                    494: static int
1.7       misho     495: bufHelp(int idx, void * __restrict cli_buffer)
1.3       misho     496: {
1.7       misho     497:        linebuffer_t *buf = cli_buffer;
1.3       misho     498: 
1.7       misho     499:        if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3       misho     500:                return RETCODE_ERR;
                    501: 
1.8.2.5   misho     502:        cli_Cmd_Help(buf, buf->line_level, NULL);
1.3       misho     503: 
                    504:        printfEOL(buf, buf->line_len - 1, 1);
                    505:        printfEOL(buf, -1, 1);
                    506:        return RETCODE_OK;
                    507: }
                    508: 
                    509: 
                    510: /*
1.6       misho     511:  * cli_Printf() - Send message to CLI session
                    512:  *
1.7       misho     513:  * @cli_buffer = CLI buffer
1.3       misho     514:  * @fmt = printf format string
                    515:  * @... = arguments defined in fmt
                    516:  * return: none
                    517: */
1.6       misho     518: void
1.7       misho     519: cli_Printf(linebuffer_t * __restrict cli_buffer, char *fmt, ...)
1.3       misho     520: {
                    521:        va_list lst;
                    522:        FILE *f;
                    523: 
                    524:        if (fmt) {
1.7       misho     525:                f = fdopen(cli_buffer->line_out, "a");
1.3       misho     526:                if (!f) {
                    527:                        LOGERR;
                    528:                        return;
                    529:                }
                    530: 
                    531:                va_start(lst, fmt);
                    532:                vfprintf(f, fmt, lst);
                    533:                va_end(lst);
                    534:        } else
1.6       misho     535:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     536: }
                    537: 
                    538: /*
1.6       misho     539:  * cli_PrintHelp() - Print help screen
                    540:  *
1.7       misho     541:  * @cli_buffer = CLI buffer
1.3       misho     542:  * return: none
                    543: */
1.6       misho     544: void
1.7       misho     545: cli_PrintHelp(linebuffer_t * __restrict cli_buffer)
1.3       misho     546: {
1.7       misho     547:        if (cli_buffer) {
                    548:                bufHelp(0, cli_buffer);
                    549:                clrscrEOL(cli_buffer);
1.3       misho     550:        } else
1.6       misho     551:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     552: }
                    553: 
                    554: 
                    555: /*
1.6       misho     556:  * cli_BindKey() - Bind function to key
                    557:  *
1.3       misho     558:  * @key = key structure
1.7       misho     559:  * @cli_buffer = CLI buffer
1.3       misho     560:  * return: RETCODE_ERR error, RETCODE_OK ok, >0 bind at position
                    561: */
                    562: int
1.7       misho     563: cli_BindKey(bindkey_t * __restrict key, linebuffer_t * __restrict cli_buffer)
1.3       misho     564: {
                    565:        register int i;
                    566: 
1.7       misho     567:        if (!key || !cli_buffer) {
1.6       misho     568:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     569:                return RETCODE_ERR;
1.2       misho     570:        }
1.3       misho     571: 
                    572:        for (i = 0; i < MAX_BINDKEY; i++)
1.7       misho     573:                if (key->key_len == cli_buffer->line_keys[i].key_len && 
                    574:                                !memcmp(key->key_ch, cli_buffer->line_keys[i].key_ch, 
                    575:                                        key->key_len)) {
                    576:                        cli_buffer->line_keys[i].key_func = key->key_func;
1.3       misho     577:                        return i;
                    578:                }
                    579: 
                    580:        return RETCODE_OK;
1.2       misho     581: }
                    582: 
                    583: 
1.3       misho     584: /*
1.6       misho     585:  * cli_addCommand() - Add command to CLI session
                    586:  *
1.7       misho     587:  * @cli_buffer = CLI buffer
1.3       misho     588:  * @csCmd = Command name
1.8.2.7 ! misho     589:  * @cliLevel = Level in CLI, -1 view from all levels, 0 hidden, >0 mask levels
1.3       misho     590:  * @funcCmd = Callback function when user call command
                    591:  * @csInfo = Inline information for command
                    592:  * @csHelp = Help line when call help
                    593:  * return: RETCODE_ERR error, RETCODE_OK ok
                    594: */
                    595: int
1.7       misho     596: cli_addCommand(linebuffer_t * __restrict cli_buffer, const char *csCmd, 
                    597:                int cliLevel, cmd_func_t funcCmd, 
1.3       misho     598:                const char *csInfo, const char *csHelp)
1.1       misho     599: {
1.3       misho     600:        struct tagCommand *cmd;
                    601: 
1.7       misho     602:        if (!cli_buffer || !csCmd) {
1.6       misho     603:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     604:                return RETCODE_ERR;
                    605:        }
                    606: 
1.6       misho     607:        cmd = e_malloc(sizeof(struct tagCommand));
1.3       misho     608:        if (!cmd) {
                    609:                LOGERR;
                    610:                return RETCODE_ERR;
                    611:        } else
                    612:                memset(cmd, 0, sizeof(struct tagCommand));
                    613: 
                    614:        cmd->cmd_level = cliLevel;
                    615:        cmd->cmd_func = funcCmd;
                    616:        cmd->cmd_len = strlcpy(cmd->cmd_name, csCmd, STRSIZ);
                    617:        if (csInfo)
                    618:                strlcpy(cmd->cmd_info, csInfo, STRSIZ);
                    619:        if (csHelp)
                    620:                strlcpy(cmd->cmd_help, csHelp, STRSIZ);
1.7       misho     621:        SLIST_INSERT_HEAD(&cli_buffer->line_cmds, cmd, cmd_next);
1.3       misho     622:        return RETCODE_OK;
1.1       misho     623: }
                    624: 
1.3       misho     625: /*
1.6       misho     626:  * cli_delCommand() - Delete command from CLI session
                    627:  *
1.7       misho     628:  * @cli_buffer = CLI buffer
1.3       misho     629:  * @csCmd = Command name
1.8.2.7 ! misho     630:  * @cliLevel = Level in CLI, -1 view from all levels, 0 hidden, >0 mask levels
1.3       misho     631:  * return: RETCODE_ERR error, RETCODE_OK ok
                    632: */
                    633: int
1.7       misho     634: cli_delCommand(linebuffer_t * __restrict cli_buffer, const char *csCmd, int cliLevel)
1.1       misho     635: {
1.3       misho     636:        struct tagCommand *cmd;
                    637:        int ret = RETCODE_OK;
                    638: 
1.7       misho     639:        if (!cli_buffer || !csCmd) {
1.6       misho     640:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     641:                return RETCODE_ERR;
                    642:        }
                    643: 
1.7       misho     644:        SLIST_FOREACH(cmd, &cli_buffer->line_cmds, cmd_next) 
1.3       misho     645:                if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) {
                    646:                        ret = 1;
1.7       misho     647:                        SLIST_REMOVE(&cli_buffer->line_cmds, cmd, tagCommand, cmd_next);
1.6       misho     648:                        e_free(cmd);
1.3       misho     649:                        break;
                    650:                }
                    651: 
                    652:        return ret;
1.1       misho     653: }
                    654: 
1.3       misho     655: /*
1.6       misho     656:  * cli_updCommand() - Update command in CLI session
                    657:  *
1.7       misho     658:  * @cli_buffer = CLI buffer
1.3       misho     659:  * @csCmd = Command name
1.8.2.7 ! misho     660:  * @cliLevel = Level in CLI, -1 view from all levels, 0 hidden, >0 mask levels
1.3       misho     661:  * @funcCmd = Callback function when user call command
                    662:  * @csInfo = Inline information for command
                    663:  * @csHelp = Help line when call help
                    664:  * return: RETCODE_ERR error, RETCODE_OK ok
                    665: */
                    666: int
1.7       misho     667: cli_updCommand(linebuffer_t * __restrict cli_buffer, const char *csCmd, 
                    668:                int cliLevel, cmd_func_t funcCmd, 
1.3       misho     669:                const char *csInfo, const char *csHelp)
1.1       misho     670: {
1.3       misho     671:        struct tagCommand *cmd;
                    672:        int ret = RETCODE_OK;
                    673: 
1.7       misho     674:        if (!cli_buffer || !csCmd) {
1.6       misho     675:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     676:                return RETCODE_ERR;
                    677:        }
                    678: 
1.8.2.7 ! misho     679:        SLIST_FOREACH(cmd, &cli_buffer->line_cmds, cmd_next)
        !           680:                if ((!cmd->cmd_level || cmd->cmd_level == cliLevel) && 
        !           681:                                !strcmp(cmd->cmd_name, csCmd)) {
        !           682:                        if (!cmd->cmd_level)
        !           683:                                cmd->cmd_level = cliLevel;
1.3       misho     684:                        if (funcCmd)
                    685:                                cmd->cmd_func = funcCmd;
                    686:                        if (csInfo)
                    687:                                strlcpy(cmd->cmd_info, csInfo, STRSIZ);
                    688:                        if (csHelp)
                    689:                                strlcpy(cmd->cmd_help, csHelp, STRSIZ);
                    690: 
                    691:                        break;
                    692:                }
1.1       misho     693: 
1.3       misho     694:        return ret;
1.1       misho     695: }
                    696: 
                    697: 
                    698: /*
1.6       misho     699:  * cli_addHistory() - Add line to history
                    700:  *
1.7       misho     701:  * @cli_buffer = CLI buffer
1.3       misho     702:  * @str = Add custom text or if NULL use readed line from CLI buffer
                    703:  * return: RETCODE_ERR error, RETCODE_OK ok
1.1       misho     704: */
1.3       misho     705: int
1.7       misho     706: cli_addHistory(linebuffer_t * __restrict cli_buffer, const char * __restrict str)
1.1       misho     707: {
1.3       misho     708:        struct tagHistory *h;
                    709: 
1.7       misho     710:        if (!cli_buffer) {
1.6       misho     711:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     712:                return RETCODE_ERR;
                    713:        }
                    714: 
1.6       misho     715:        if (!(h = e_malloc(sizeof(struct tagHistory)))) {
1.3       misho     716:                LOGERR;
                    717:                return RETCODE_ERR;
                    718:        } else
                    719:                memset(h, 0, sizeof(struct tagHistory));
                    720: 
                    721:        if (str) {
                    722:                if (!*str) {
1.6       misho     723:                        e_free(h);
1.3       misho     724:                        return RETCODE_OK;
                    725:                }
                    726: 
                    727:                h->hist_len = strlcpy(h->hist_line, str, BUFSIZ);
                    728:        } else {
1.7       misho     729:                if (!*cli_buffer->line_buf || cli_buffer->line_len < 2) {
1.6       misho     730:                        e_free(h);
1.3       misho     731:                        return RETCODE_OK;
                    732:                }
                    733: 
1.7       misho     734:                memcpy(h->hist_line, cli_buffer->line_buf, (h->hist_len = cli_buffer->line_len));
1.6       misho     735:                str_Trim(h->hist_line);
1.3       misho     736:                h->hist_len = strlen(h->hist_line);
                    737:        }
1.1       misho     738: 
1.7       misho     739:        TAILQ_INSERT_HEAD(&cli_buffer->line_history, h, hist_next);
1.3       misho     740:        return h->hist_len;
                    741: }
1.1       misho     742: 
1.3       misho     743: /*
1.6       misho     744:  * cli_saveHistory() - Save history to file
                    745:  *
1.7       misho     746:  * @cli_buffer = CLI buffer
1.3       misho     747:  * @histfile = History filename, if NULL will be use default name
                    748:  * @lines = Maximum history lines to save
                    749:  * return: RETCODE_ERR error, RETCODE_OK ok
                    750: */
                    751: int
1.7       misho     752: cli_saveHistory(linebuffer_t * __restrict cli_buffer, const char *histfile, int lines)
1.3       misho     753: {
                    754:        FILE *f;
                    755:        mode_t mode;
                    756:        char szFName[MAXPATHLEN];
                    757:        struct tagHistory *h;
                    758: 
1.7       misho     759:        if (!cli_buffer) {
1.6       misho     760:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     761:                return RETCODE_ERR;
                    762:        }
                    763:        if (!histfile)
                    764:                strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
                    765:        else
                    766:                strlcpy(szFName, histfile, MAXPATHLEN);
                    767: 
                    768:        mode = umask(0177);
                    769:        f = fopen(szFName, "w");
                    770:        if (!f) {
1.1       misho     771:                LOGERR;
1.3       misho     772:                return RETCODE_ERR;
                    773:        }
                    774: 
1.7       misho     775:        TAILQ_FOREACH(h, &cli_buffer->line_history, hist_next) {
1.3       misho     776:                fprintf(f, "%s\n", h->hist_line);
                    777: 
                    778:                if (lines)
                    779:                        lines--;
                    780:                else
                    781:                        break;
                    782:        }
1.1       misho     783: 
1.3       misho     784:        fclose(f);
                    785:        umask(mode);
                    786: 
                    787:        return RETCODE_OK;
1.1       misho     788: }
                    789: 
1.3       misho     790: /*
1.6       misho     791:  * cli_loadHistory() - Load history from file
                    792:  *
1.7       misho     793:  * @cli_buffer = CLI buffer
1.3       misho     794:  * @histfile = History filename, if NULL will be use default name
                    795:  * return: RETCODE_ERR error, RETCODE_OK ok
                    796: */
                    797: int
1.7       misho     798: cli_loadHistory(linebuffer_t * __restrict cli_buffer, const char *histfile)
1.3       misho     799: {
                    800:        FILE *f;
                    801:        char szFName[MAXPATHLEN], buf[BUFSIZ];
                    802:        struct tagHistory *h;
                    803: 
1.7       misho     804:        if (!cli_buffer) {
1.6       misho     805:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     806:                return RETCODE_ERR;
                    807:        }
                    808:        if (!histfile)
                    809:                strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
                    810:        else
                    811:                strlcpy(szFName, histfile, MAXPATHLEN);
                    812: 
                    813:        f = fopen(szFName, "r");
                    814:        if (!f)
                    815:                return RETCODE_OK;
                    816: 
                    817:        while (fgets(buf, BUFSIZ, f)) {
                    818:                if (!*buf || *buf == '#')
                    819:                        continue;
                    820:                else
1.6       misho     821:                        str_Trim(buf);
1.3       misho     822: 
1.6       misho     823:                if (!(h = e_malloc(sizeof(struct tagHistory)))) {
1.3       misho     824:                        LOGERR;
                    825:                        fclose(f);
                    826:                        return RETCODE_ERR;
                    827:                } else
                    828:                        memset(h, 0, sizeof(struct tagHistory));
                    829: 
                    830:                h->hist_len = strlcpy(h->hist_line, buf, BUFSIZ);
1.7       misho     831:                TAILQ_INSERT_TAIL(&cli_buffer->line_history, h, hist_next);
1.3       misho     832:        }
                    833: 
                    834:        fclose(f);
                    835: 
                    836:        return RETCODE_OK;
                    837: }
1.1       misho     838: 
                    839: /*
1.6       misho     840:  * cli_resetHistory() - Reset history search in CLI session
                    841:  *
1.7       misho     842:  * @cli_buffer = CLI buffer
1.1       misho     843:  * return: none
                    844: */
1.6       misho     845: void
1.7       misho     846: cli_resetHistory(linebuffer_t * __restrict cli_buffer)
1.1       misho     847: {
1.7       misho     848:        cli_buffer->line_h = NULL;
1.1       misho     849: }
                    850: 
1.3       misho     851: 
1.1       misho     852: /*
1.6       misho     853:  * cli_freeLine() - Clear entire line
                    854:  *
1.7       misho     855:  * @cli_buffer = CLI buffer
1.3       misho     856:  * return: RETCODE_ERR error, RETCODE_OK ok
1.2       misho     857: */
1.6       misho     858: int
1.7       misho     859: cli_freeLine(linebuffer_t * __restrict cli_buffer)
1.2       misho     860: {
1.3       misho     861:        int code = RETCODE_ERR;
1.2       misho     862: 
1.7       misho     863:        if (cli_buffer) {
                    864:                if (cli_buffer->line_buf)
                    865:                        e_free(cli_buffer->line_buf);
                    866: 
                    867:                cli_buffer->line_buf = e_malloc(BUFSIZ);
                    868:                if (cli_buffer->line_buf) {
                    869:                        memset(cli_buffer->line_buf, 0, BUFSIZ);
                    870:                        cli_buffer->line_eol = cli_buffer->line_bol;
                    871:                        cli_buffer->line_len = 1 + cli_buffer->line_eol;
1.2       misho     872: 
1.3       misho     873:                        code = RETCODE_OK;
                    874:                } else
                    875:                        LOGERR;
                    876:        } else
1.6       misho     877:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.2       misho     878: 
1.3       misho     879:        return code;
1.2       misho     880: }
                    881: 
                    882: /*
1.6       misho     883:  * cli_setPrompt() - Set new prompt for CLI session
                    884:  *
1.7       misho     885:  * @cli_buffer = CLI buffer
1.3       misho     886:  * @prompt = new text for prompt or if NULL disable prompt
                    887:  * return: none
1.2       misho     888: */
1.6       misho     889: void
1.7       misho     890: cli_setPrompt(linebuffer_t * __restrict cli_buffer, const char *prompt)
1.2       misho     891: {
1.7       misho     892:        if (cli_buffer) {
                    893:                if (cli_buffer->line_prompt) {
                    894:                        e_free(cli_buffer->line_prompt);
                    895:                        cli_buffer->line_prompt = NULL;
                    896:                        cli_buffer->line_bol = 0;
1.3       misho     897:                }
                    898: 
                    899:                if (prompt) {
1.7       misho     900:                        cli_buffer->line_prompt = e_strdup(prompt);
                    901:                        if (cli_buffer->line_prompt) {
                    902:                                cli_buffer->line_bol = strlen(cli_buffer->line_prompt);
                    903:                                cli_buffer->line_eol = cli_buffer->line_bol;
                    904:                                cli_buffer->line_len = 1 + cli_buffer->line_eol;
1.3       misho     905:                        } else
                    906:                                LOGERR;
                    907:                }
                    908:        } else
1.6       misho     909:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.2       misho     910: }
                    911: 
1.3       misho     912: 
1.2       misho     913: /*
1.6       misho     914:  * cliEnd() - Clear data, Free resources and close CLI session
                    915:  *
1.7       misho     916:  * @cli_buffer = CLI buffer
1.3       misho     917:  * return: RETCODE_ERR error, RETCODE_OK ok
1.2       misho     918: */
1.3       misho     919: void
1.7       misho     920: cliEnd(linebuffer_t * __restrict cli_buffer)
1.2       misho     921: {
1.3       misho     922:        struct tagHistory *h;
                    923:        struct tagCommand *c;
                    924: 
1.7       misho     925:        if (cli_buffer) {
                    926:                while ((c = SLIST_FIRST(&cli_buffer->line_cmds))) {
                    927:                        SLIST_REMOVE_HEAD(&cli_buffer->line_cmds, cmd_next);
1.6       misho     928:                        e_free(c);
1.3       misho     929:                }
1.7       misho     930:                while ((h = TAILQ_FIRST(&cli_buffer->line_history))) {
                    931:                        TAILQ_REMOVE(&cli_buffer->line_history, h, hist_next);
1.6       misho     932:                        e_free(h);
1.3       misho     933:                }
                    934: 
1.7       misho     935:                if (cli_buffer->line_prompt)
                    936:                        e_free(cli_buffer->line_prompt);
1.2       misho     937: 
1.7       misho     938:                if (cli_buffer->line_keys)
                    939:                        e_free(cli_buffer->line_keys);
                    940:                if (cli_buffer->line_buf)
                    941:                        e_free(cli_buffer->line_buf);
1.2       misho     942: 
1.7       misho     943:                e_free(cli_buffer);
                    944:                cli_buffer = NULL;
1.3       misho     945:        } else
1.6       misho     946:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho     947: }
                    948: 
                    949: /*
1.6       misho     950:  * cliInit() - Start CLI session, allocate memory for resources and bind keys
                    951:  *
1.3       misho     952:  * @fin = Input device handle
                    953:  * @fout = Output device handle
                    954:  * @prompt = text for prompt, if NULL disable prompt
                    955:  * return: NULL if error or !=NULL CLI buffer
                    956: */
                    957: linebuffer_t *
                    958: cliInit(int fin, int fout, const char *prompt)
                    959: {
1.7       misho     960:        linebuffer_t *cli_buffer;
1.3       misho     961:        bindkey_t *keys;
                    962:        register int i;
                    963: 
                    964:        /* init buffer */
1.7       misho     965:        cli_buffer = e_malloc(sizeof(linebuffer_t));
                    966:        if (!cli_buffer) {
1.3       misho     967:                LOGERR;
                    968:                return NULL;
                    969:        } else {
1.7       misho     970:                memset(cli_buffer, 0, sizeof(linebuffer_t));
1.3       misho     971: 
1.7       misho     972:                cli_buffer->line_in = fin;
                    973:                cli_buffer->line_out = fout;
1.3       misho     974: 
1.7       misho     975:                TAILQ_INIT(&cli_buffer->line_history);
                    976:                SLIST_INIT(&cli_buffer->line_cmds);
1.3       misho     977: 
                    978:                if (prompt) {
1.7       misho     979:                        cli_buffer->line_prompt = e_strdup(prompt);
                    980:                        if (!cli_buffer->line_prompt) {
1.3       misho     981:                                LOGERR;
1.7       misho     982:                                e_free(cli_buffer);
1.3       misho     983:                                return NULL;
                    984:                        } else
1.7       misho     985:                                cli_buffer->line_eol = cli_buffer->line_bol = 
                    986:                                        strlen(cli_buffer->line_prompt);
1.8.2.1   misho     987:                } else
                    988:                        cli_buffer->line_mode = LINEMODE_OVER;
1.3       misho     989:        }
1.7       misho     990:        cli_buffer->line_buf = e_malloc(BUFSIZ);
                    991:        if (!cli_buffer->line_buf) {
1.3       misho     992:                LOGERR;
1.7       misho     993:                if (cli_buffer->line_prompt)
                    994:                        e_free(cli_buffer->line_prompt);
                    995:                e_free(cli_buffer);
1.3       misho     996:                return NULL;
                    997:        } else {
1.7       misho     998:                memset(cli_buffer->line_buf, 0, BUFSIZ);
                    999:                cli_buffer->line_len = 1 + cli_buffer->line_eol;
1.3       misho    1000:        }
1.6       misho    1001:        keys = e_calloc(MAX_BINDKEY + 1, sizeof(bindkey_t));
1.3       misho    1002:        if (!keys) {
                   1003:                LOGERR;
1.7       misho    1004:                if (cli_buffer->line_prompt)
                   1005:                        e_free(cli_buffer->line_prompt);
                   1006:                e_free(cli_buffer->line_buf);
                   1007:                e_free(cli_buffer);
1.3       misho    1008:                return NULL;
                   1009:        } else
                   1010:                memset(keys, 0, sizeof(bindkey_t) * (MAX_BINDKEY + 1));
                   1011: 
                   1012:        /* add helper functions */
1.8.2.7 ! misho    1013:        cli_addCommand(cli_buffer, "exit", 1, cli_Cmd_Exit, "exit <cr>", "Exit from console");
        !          1014:        cli_addCommand(cli_buffer, "help", -1, cli_Cmd_Help, "help [command] <cr>", "Help screen");
        !          1015:        cli_addCommand(cli_buffer, "-------", -1, NULL, "-------------------------", NULL);
        !          1016:        cli_addCommand(cli_buffer, "where", -1, cli_Cmd_WhereAmI, "where <cr>", 
        !          1017:                        "Query current level of console");
        !          1018:        cli_addCommand(cli_buffer, "top", -1, cli_Cmd_Top, "top <cr>", "Top level of console");
        !          1019:        cli_addCommand(cli_buffer, "end", -1, cli_Cmd_End, "end <cr>", "End level of console");
        !          1020:        cli_addCommand(cli_buffer, "config", -1, cli_Cmd_Config, "config <cr>", 
        !          1021:                        "Config next level of console");
        !          1022:        cli_addCommand(cli_buffer, "-------", -1, NULL, "-------------------------", NULL);
1.3       misho    1023: 
                   1024:        /* fill key bindings */
1.6       misho    1025:        /* ascii chars & ctrl+chars */
1.3       misho    1026:        for (i = 0; i < 256; i++) {
                   1027:                *keys[i].key_ch = (u_char) i;
                   1028:                keys[i].key_len = 1;
                   1029: 
                   1030:                if (!i || i == *K_CTRL_D)
                   1031:                        keys[i].key_func = bufEOF;
                   1032:                if (i == *K_CTRL_M || i == *K_CTRL_J)
                   1033:                        keys[i].key_func = bufEOL;
1.8.2.1   misho    1034:                if (cli_buffer->line_prompt && (i == *K_CTRL_H || i == *K_BACKSPACE))
1.3       misho    1035:                        keys[i].key_func = bufBS;
1.8.2.1   misho    1036:                if (cli_buffer->line_prompt && i == *K_CTRL_C)
1.3       misho    1037:                        keys[i].key_func = bufCLR;
1.8.2.1   misho    1038:                if (cli_buffer->line_prompt && i == *K_CTRL_A)
1.3       misho    1039:                        keys[i].key_func = bufBEGIN;
1.8.2.1   misho    1040:                if (cli_buffer->line_prompt && i == *K_CTRL_E)
1.3       misho    1041:                        keys[i].key_func = bufEND;
1.8.2.1   misho    1042:                if (cli_buffer->line_prompt && i == *K_TAB)
1.3       misho    1043:                        keys[i].key_func = bufComp;
                   1044:                if (i >= *K_SPACE && i < *K_BACKSPACE)
                   1045:                        keys[i].key_func = bufCHAR;
                   1046:                if (i > *K_BACKSPACE && i < 0xff)
                   1047:                        keys[i].key_func = bufCHAR;
1.8.2.1   misho    1048:                if (cli_buffer->line_prompt && i == '?')
1.3       misho    1049:                        keys[i].key_func = bufHelp;
                   1050:        }
1.6       misho    1051:        /* alt+chars */
1.3       misho    1052:        for (i = 256; i < 512; i++) {
                   1053:                keys[i].key_ch[0] = 0x1b;
                   1054:                keys[i].key_ch[1] = (u_char) i - 256;
                   1055:                keys[i].key_len = 2;
                   1056:        }
                   1057: 
1.6       misho    1058:        /* 3 bytes */
1.3       misho    1059:        keys[i].key_len = sizeof K_F1 - 1;
                   1060:        memcpy(keys[i].key_ch, K_F1, keys[i].key_len);
                   1061:        i++;
                   1062:        keys[i].key_len = sizeof K_F2 - 1;
                   1063:        memcpy(keys[i].key_ch, K_F2, keys[i].key_len);
                   1064:        i++;
                   1065:        keys[i].key_len = sizeof K_F3 - 1;
                   1066:        memcpy(keys[i].key_ch, K_F3, keys[i].key_len);
                   1067:        i++;
                   1068:        keys[i].key_len = sizeof K_F4 - 1;
                   1069:        memcpy(keys[i].key_ch, K_F4, keys[i].key_len);
                   1070:        i++;
                   1071:        keys[i].key_len = sizeof K_CTRL_SH_F1 - 1;
                   1072:        memcpy(keys[i].key_ch, K_CTRL_SH_F1, keys[i].key_len);
                   1073:        i++;
                   1074:        keys[i].key_len = sizeof K_CTRL_SH_F2 - 1;
                   1075:        memcpy(keys[i].key_ch, K_CTRL_SH_F2, keys[i].key_len);
                   1076:        i++;
                   1077:        keys[i].key_len = sizeof K_CTRL_SH_F3 - 1;
                   1078:        memcpy(keys[i].key_ch, K_CTRL_SH_F3, keys[i].key_len);
                   1079:        i++;
                   1080:        keys[i].key_len = sizeof K_CTRL_SH_F4 - 1;
                   1081:        memcpy(keys[i].key_ch, K_CTRL_SH_F4, keys[i].key_len);
                   1082:        i++;
                   1083:        keys[i].key_len = sizeof K_CTRL_SH_F5 - 1;
                   1084:        memcpy(keys[i].key_ch, K_CTRL_SH_F5, keys[i].key_len);
                   1085:        i++;
                   1086:        keys[i].key_len = sizeof K_CTRL_SH_F6 - 1;
                   1087:        memcpy(keys[i].key_ch, K_CTRL_SH_F6, keys[i].key_len);
                   1088:        i++;
                   1089:        keys[i].key_len = sizeof K_CTRL_SH_F7 - 1;
                   1090:        memcpy(keys[i].key_ch, K_CTRL_SH_F7, keys[i].key_len);
                   1091:        i++;
                   1092:        keys[i].key_len = sizeof K_CTRL_SH_F8 - 1;
                   1093:        memcpy(keys[i].key_ch, K_CTRL_SH_F8, keys[i].key_len);
                   1094:        i++;
                   1095:        keys[i].key_len = sizeof K_CTRL_SH_F9 - 1;
                   1096:        memcpy(keys[i].key_ch, K_CTRL_SH_F9, keys[i].key_len);
                   1097:        i++;
                   1098:        keys[i].key_len = sizeof K_CTRL_SH_F10 - 1;
                   1099:        memcpy(keys[i].key_ch, K_CTRL_SH_F10, keys[i].key_len);
                   1100:        i++;
                   1101:        keys[i].key_len = sizeof K_CTRL_SH_F11 - 1;
                   1102:        memcpy(keys[i].key_ch, K_CTRL_SH_F11, keys[i].key_len);
                   1103:        i++;
                   1104:        keys[i].key_len = sizeof K_CTRL_SH_F12 - 1;
                   1105:        memcpy(keys[i].key_ch, K_CTRL_SH_F12, keys[i].key_len);
                   1106:        i++;
                   1107:        keys[i].key_len = sizeof K_CTRL_F1 - 1;
                   1108:        memcpy(keys[i].key_ch, K_CTRL_F1, keys[i].key_len);
                   1109:        i++;
                   1110:        keys[i].key_len = sizeof K_CTRL_F2 - 1;
                   1111:        memcpy(keys[i].key_ch, K_CTRL_F2, keys[i].key_len);
                   1112:        i++;
                   1113:        keys[i].key_len = sizeof K_CTRL_F3 - 1;
                   1114:        memcpy(keys[i].key_ch, K_CTRL_F3, keys[i].key_len);
                   1115:        i++;
                   1116:        keys[i].key_len = sizeof K_CTRL_F4 - 1;
                   1117:        memcpy(keys[i].key_ch, K_CTRL_F4, keys[i].key_len);
                   1118:        i++;
                   1119:        keys[i].key_len = sizeof K_CTRL_F5 - 1;
                   1120:        memcpy(keys[i].key_ch, K_CTRL_F5, keys[i].key_len);
                   1121:        i++;
                   1122:        keys[i].key_len = sizeof K_CTRL_F6 - 1;
                   1123:        memcpy(keys[i].key_ch, K_CTRL_F6, keys[i].key_len);
                   1124:        i++;
                   1125:        keys[i].key_len = sizeof K_CTRL_F7 - 1;
                   1126:        memcpy(keys[i].key_ch, K_CTRL_F7, keys[i].key_len);
                   1127:        i++;
                   1128:        keys[i].key_len = sizeof K_CTRL_F8 - 1;
                   1129:        memcpy(keys[i].key_ch, K_CTRL_F8, keys[i].key_len);
                   1130:        i++;
                   1131:        keys[i].key_len = sizeof K_CTRL_F9 - 1;
                   1132:        memcpy(keys[i].key_ch, K_CTRL_F9, keys[i].key_len);
                   1133:        i++;
                   1134:        keys[i].key_len = sizeof K_CTRL_F10 - 1;
                   1135:        memcpy(keys[i].key_ch, K_CTRL_F10, keys[i].key_len);
                   1136:        i++;
                   1137:        keys[i].key_len = sizeof K_CTRL_F11 - 1;
                   1138:        memcpy(keys[i].key_ch, K_CTRL_F11, keys[i].key_len);
                   1139:        i++;
                   1140:        keys[i].key_len = sizeof K_CTRL_F12 - 1;
                   1141:        memcpy(keys[i].key_ch, K_CTRL_F12, keys[i].key_len);
                   1142:        i++;
                   1143:        keys[i].key_len = sizeof K_HOME - 1;
1.8.2.1   misho    1144:        if (cli_buffer->line_prompt)
                   1145:                keys[i].key_func = bufBEGIN;
1.3       misho    1146:        memcpy(keys[i].key_ch, K_HOME, keys[i].key_len);
                   1147:        i++;
                   1148:        keys[i].key_len = sizeof K_END - 1;
1.8.2.1   misho    1149:        if (cli_buffer->line_prompt)
                   1150:                keys[i].key_func = bufEND;
1.3       misho    1151:        memcpy(keys[i].key_ch, K_END, keys[i].key_len);
                   1152:        i++;
                   1153:        keys[i].key_len = sizeof K_UP - 1;
1.8.2.1   misho    1154:        if (cli_buffer->line_prompt)
                   1155:                keys[i].key_func = bufUP;
1.3       misho    1156:        memcpy(keys[i].key_ch, K_UP, keys[i].key_len);
                   1157:        i++;
                   1158:        keys[i].key_len = sizeof K_DOWN - 1;
1.8.2.1   misho    1159:        if (cli_buffer->line_prompt)
                   1160:                keys[i].key_func = bufDOWN;
1.3       misho    1161:        memcpy(keys[i].key_ch, K_DOWN, keys[i].key_len);
                   1162:        i++;
                   1163:        keys[i].key_len = sizeof K_RIGHT - 1;
1.8.2.1   misho    1164:        if (cli_buffer->line_prompt)
                   1165:                keys[i].key_func = bufRIGHT;
1.3       misho    1166:        memcpy(keys[i].key_ch, K_RIGHT, keys[i].key_len);
                   1167:        i++;
                   1168:        keys[i].key_len = sizeof K_LEFT - 1;
1.8.2.1   misho    1169:        if (cli_buffer->line_prompt)
                   1170:                keys[i].key_func = bufLEFT;
1.3       misho    1171:        memcpy(keys[i].key_ch, K_LEFT, keys[i].key_len);
                   1172:        i++;
                   1173:        keys[i].key_len = sizeof K_BTAB - 1;
1.8.2.1   misho    1174:        if (cli_buffer->line_prompt)
                   1175:                keys[i].key_func = bufBTAB;
1.3       misho    1176:        memcpy(keys[i].key_ch, K_BTAB, keys[i].key_len);
                   1177:        i++;
1.6       misho    1178:        /* 4 bytes */
1.3       misho    1179:        keys[i].key_len = sizeof K_INS - 1;
1.8.2.1   misho    1180:        if (cli_buffer->line_prompt)
                   1181:                keys[i].key_func = bufMODE;
1.3       misho    1182:        memcpy(keys[i].key_ch, K_INS, keys[i].key_len);
                   1183:        i++;
                   1184:        keys[i].key_len = sizeof K_DEL - 1;
1.8.2.1   misho    1185:        if (cli_buffer->line_prompt)
                   1186:                keys[i].key_func = bufDEL;
1.3       misho    1187:        memcpy(keys[i].key_ch, K_DEL, keys[i].key_len);
                   1188:        i++;
                   1189:        keys[i].key_len = sizeof K_PGUP - 1;
                   1190:        memcpy(keys[i].key_ch, K_PGUP, keys[i].key_len);
                   1191:        i++;
                   1192:        keys[i].key_len = sizeof K_PGDN - 1;
                   1193:        memcpy(keys[i].key_ch, K_PGDN, keys[i].key_len);
                   1194:        i++;
1.6       misho    1195:        /* 5 bytes */
1.3       misho    1196:        keys[i].key_len = sizeof K_F5 - 1;
                   1197:        memcpy(keys[i].key_ch, K_F5, keys[i].key_len);
                   1198:        i++;
                   1199:        keys[i].key_len = sizeof K_F6 - 1;
                   1200:        memcpy(keys[i].key_ch, K_F6, keys[i].key_len);
                   1201:        i++;
                   1202:        keys[i].key_len = sizeof K_F7 - 1;
                   1203:        memcpy(keys[i].key_ch, K_F7, keys[i].key_len);
                   1204:        i++;
                   1205:        keys[i].key_len = sizeof K_F8 - 1;
                   1206:        memcpy(keys[i].key_ch, K_F8, keys[i].key_len);
                   1207:        i++;
                   1208:        keys[i].key_len = sizeof K_F9 - 1;
                   1209:        memcpy(keys[i].key_ch, K_F9, keys[i].key_len);
                   1210:        i++;
                   1211:        keys[i].key_len = sizeof K_F10 - 1;
                   1212:        memcpy(keys[i].key_ch, K_F10, keys[i].key_len);
                   1213:        i++;
                   1214:        keys[i].key_len = sizeof K_F11 - 1;
                   1215:        memcpy(keys[i].key_ch, K_F11, keys[i].key_len);
                   1216:        i++;
                   1217:        keys[i].key_len = sizeof K_F12 - 1;
                   1218:        memcpy(keys[i].key_ch, K_F12, keys[i].key_len);
                   1219:        i++;
                   1220: 
1.7       misho    1221:        cli_buffer->line_keys = keys;
                   1222:        return cli_buffer;
1.2       misho    1223: }
                   1224: 
                   1225: /*
1.6       misho    1226:  * cliInitLine() - Init CLI input line terminal
                   1227:  *
1.7       misho    1228:  * @cli_buffer = CLI buffer
1.2       misho    1229:  * return: none
                   1230: */
1.3       misho    1231: int
1.7       misho    1232: cliInitLine(linebuffer_t * __restrict cli_buffer)
1.2       misho    1233: {
                   1234:        struct termios t;
                   1235: 
                   1236:        memset(&t, 0, sizeof t);
1.7       misho    1237:        tcgetattr(cli_buffer->line_in, &t);
1.8.2.1   misho    1238:        t.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO | 
                   1239:                        ECHOCTL | ECHOE | ECHOK | ECHOKE | ECHONL | ECHOPRT);
1.2       misho    1240:        t.c_iflag |= IGNBRK;
                   1241:        t.c_cc[VMIN] = 1;
                   1242:        t.c_cc[VTIME] = 0;
1.7       misho    1243:        return tcsetattr(cli_buffer->line_in, TCSANOW, &t);
1.3       misho    1244: }
                   1245: 
                   1246: /*
1.6       misho    1247:  * cliReadLine() - Read line from opened CLI session
                   1248:  *
1.7       misho    1249:  * @cli_buffer = CLI buffer
1.6       misho    1250:  * return: NULL if error or !=NULL readed line, must be e_free after use!
1.3       misho    1251: */
                   1252: char *
1.7       misho    1253: cliReadLine(linebuffer_t * __restrict cli_buffer)
1.3       misho    1254: {
                   1255:        int code, readLen;
                   1256:        register int i;
                   1257:        struct pollfd fds;
                   1258:        char buf[BUFSIZ], *str = NULL;
1.2       misho    1259: 
1.7       misho    1260:        if (!cli_buffer) {
1.6       misho    1261:                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho    1262:                return NULL;
                   1263:        }
1.2       misho    1264: 
1.3       misho    1265:        memset(&fds, 0, sizeof fds);
1.7       misho    1266:        fds.fd = cli_buffer->line_in;
1.3       misho    1267:        fds.events = POLLIN;
                   1268: 
1.7       misho    1269:        printfCR(cli_buffer, 1);
1.3       misho    1270:        while (42) {
                   1271:                if (poll(&fds, 1, -1) < 1) {
                   1272:                        LOGERR;
                   1273:                        return str;
                   1274:                }
                   1275: 
                   1276:                memset(buf, 0, sizeof buf);
1.7       misho    1277:                readLen = read(cli_buffer->line_in, buf, BUFSIZ);
1.3       misho    1278:                if (readLen == -1) {
                   1279:                        LOGERR;
                   1280:                        return str;
                   1281:                }
                   1282:                if (!readLen) {
1.7       misho    1283:                        if (cli_buffer->line_buf)
                   1284:                                str = e_strdup(cli_buffer->line_buf);
1.3       misho    1285:                        else
1.6       misho    1286:                                cli_SetErr(EPIPE, "Unknown state ...");
1.3       misho    1287:                        return str;
                   1288:                }
                   1289: 
                   1290: recheck:
                   1291:                for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--)
1.7       misho    1292:                        if (readLen >= cli_buffer->line_keys[i].key_len && 
                   1293:                                        !memcmp(cli_buffer->line_keys[i].key_ch, buf, 
                   1294:                                                cli_buffer->line_keys[i].key_len)) {
                   1295:                                readLen -= cli_buffer->line_keys[i].key_len;
1.3       misho    1296:                                if (readLen)
1.7       misho    1297:                                        memmove(buf, buf + cli_buffer->line_keys[i].key_len, readLen);
1.3       misho    1298:                                else
1.7       misho    1299:                                        memset(buf, 0, cli_buffer->line_keys[i].key_len);
1.3       misho    1300: 
1.7       misho    1301:                                if (cli_buffer->line_keys[i].key_func)
                   1302:                                        if ((code = cli_buffer->line_keys[i].key_func(i, cli_buffer)))
1.3       misho    1303:                                                readLen = 0;
                   1304: 
                   1305:                                if (readLen)
                   1306:                                        goto recheck;
                   1307:                                else
                   1308:                                        break;
                   1309:                        }
                   1310: 
                   1311:                if (code)
                   1312:                        break;
                   1313:        }
1.2       misho    1314: 
1.7       misho    1315:        if (code != RETCODE_ERR && code != RETCODE_EOF && cli_buffer->line_buf)
                   1316:                str = e_strdup(cli_buffer->line_buf);
1.3       misho    1317:        return str;
1.2       misho    1318: }
                   1319: 
1.3       misho    1320: 
1.2       misho    1321: /*
1.6       misho    1322:  * cliNetLoop() - CLI network main loop binded to socket
                   1323:  *
1.7       misho    1324:  * @cli_buffer = CLI buffer
1.3       misho    1325:  * @csHistFile = History file name
1.2       misho    1326:  * @sock = client socket
1.3       misho    1327:  * return: RETCODE_ERR error, RETCODE_OK ok
1.2       misho    1328: */
1.3       misho    1329: int
1.7       misho    1330: cliNetLoop(linebuffer_t * __restrict cli_buffer, const char *csHistFile, int sock)
1.2       misho    1331: {
1.3       misho    1332:        u_char buf[BUFSIZ];
                   1333:        int pid, stat, pty, r, s, alen, flg, attrlen = 0, ret = 0;
1.2       misho    1334:        fd_set fds;
                   1335:        struct timeval tv = { DEFAULT_SOCK_TIMEOUT, 0 };
                   1336:        struct telnetAttrs *a, Attr[10];
                   1337: 
1.3       misho    1338:        switch ((pid = forkpty(&pty, NULL, NULL, NULL))) {
1.2       misho    1339:                case -1:
                   1340:                        LOGERR;
                   1341:                        return -1;
                   1342:                case 0:
1.7       misho    1343:                        if (!cli_buffer) {
1.6       misho    1344:                                cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3       misho    1345:                                return -1;
                   1346:                        } else
                   1347:                                close(sock);
1.2       misho    1348: 
1.7       misho    1349:                        ret = cliLoop(cli_buffer, csHistFile) < 0 ? 1 : 0;
                   1350:                        cliEnd(cli_buffer);
1.2       misho    1351: 
1.8       misho    1352:                        _exit(ret);
1.2       misho    1353:                default:
1.4       misho    1354:                        cli_telnet_SetCmd(Attr + 0, DO, TELOPT_TTYPE);
                   1355:                        cli_telnet_SetCmd(Attr + 1, WILL, TELOPT_ECHO);
                   1356:                        cli_telnet_Set_SubOpt(Attr + 2, TELOPT_LFLOW, LFLOW_OFF, NULL, 0);
                   1357:                        cli_telnet_Set_SubOpt(Attr + 3, TELOPT_LFLOW, LFLOW_RESTART_XON, NULL, 0);
                   1358:                        cli_telnet_SetCmd(Attr + 4, DO, TELOPT_LINEMODE);
                   1359:                        if ((ret = cli_telnetSend(sock, Attr, 5, NULL, 0, 0)) == -1)
1.2       misho    1360:                                return -1;
1.4       misho    1361:                        else
1.2       misho    1362:                                flg = 0;
                   1363: 
                   1364:                        while (42) {
1.3       misho    1365:                                if (waitpid(pid, &stat, WNOHANG))
                   1366:                                        break;
                   1367: 
1.2       misho    1368:                                FD_ZERO(&fds);
                   1369:                                FD_SET(sock, &fds);
                   1370:                                FD_SET(pty, &fds);
                   1371:                                if ((ret = select(FD_SETSIZE, &fds, NULL, NULL, &tv)) < 1) {
                   1372:                                        if (!ret)
                   1373:                                                cli_SetErr(ETIMEDOUT, "Client session timeout ...");
                   1374: 
                   1375:                                        break;
                   1376:                                }
                   1377: 
                   1378:                                r = FD_ISSET(sock, &fds) ? sock : pty;
                   1379:                                s = FD_ISSET(sock, &fds) ? pty : sock;
                   1380: 
1.3       misho    1381:                                if (FD_ISSET(sock, &fds)) {
                   1382:                                        memset(buf, 0, BUFSIZ);
1.4       misho    1383:                                        if ((ret = cli_telnetRecv(sock, &a, &alen, buf, BUFSIZ)) < 0) {
1.3       misho    1384:                                                if (a)
1.6       misho    1385:                                                        e_free(a);
1.3       misho    1386: 
                   1387:                                                if (-2 == ret)
                   1388:                                                        continue;
                   1389:                                                // EOF
                   1390:                                                if (-3 == ret)
                   1391:                                                        shutdown(sock, SHUT_RD);
                   1392:                                                break;
                   1393:                                        }
                   1394:                                        attrlen = 0;
                   1395:                                        if (1 == flg && alen) {
1.4       misho    1396:                                                cli_telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_SGA);
                   1397:                                                cli_telnet_SetCmd(&Attr[attrlen++], DO, TELOPT_ECHO);
1.3       misho    1398:                                        }
                   1399:                                        if (2 == flg && alen) {
1.4       misho    1400:                                                cli_telnet_SetCmd(&Attr[attrlen++], WILL, TELOPT_ECHO);
                   1401:                                                cli_telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW, 
1.3       misho    1402:                                                                LFLOW_OFF, NULL, 0);
1.4       misho    1403:                                                cli_telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW, 
1.3       misho    1404:                                                                LFLOW_RESTART_XON, NULL, 0);
1.4       misho    1405:                                                cli_telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_LINEMODE);
1.3       misho    1406:                                        }
1.2       misho    1407:                                        if (a)
1.6       misho    1408:                                                e_free(a);
1.2       misho    1409: 
1.3       misho    1410:                                        if ((ret = write(pty, buf, ret)) == -1) {
                   1411:                                                LOGERR;
                   1412:                                                break;
                   1413:                                        }
                   1414:                                }
                   1415: 
                   1416:                                if (FD_ISSET(pty, &fds)) {
                   1417:                                        memset(buf, 0, BUFSIZ);
                   1418:                                        if ((ret = read(pty, buf, BUFSIZ)) == -1) {
                   1419:                                                LOGERR;
                   1420:                                                break;
                   1421:                                        }
                   1422: 
1.4       misho    1423:                                        if ((ret = cli_telnetSend(sock, Attr, pty == s ? 0 : attrlen, 
                   1424:                                                                        buf, ret, 0)) == -1)
1.3       misho    1425:                                                break;
1.4       misho    1426:                                        else
1.3       misho    1427:                                                flg++;
1.2       misho    1428:                                }
                   1429:                        }
                   1430: 
                   1431:                        close(pty);
                   1432:        }
                   1433: 
                   1434:        return ret;
                   1435: }
                   1436: 
                   1437: /*
1.6       misho    1438:  * cliLoop() - CLI main loop
                   1439:  *
1.7       misho    1440:  * @cli_buffer = CLI buffer
1.3       misho    1441:  * @csHistFile = History file name
                   1442:  * return: RETCODE_ERR error, RETCODE_OK ok
1.1       misho    1443: */
1.3       misho    1444: int
1.7       misho    1445: cliLoop(linebuffer_t * __restrict cli_buffer, const char *csHistFile)
1.1       misho    1446: {
                   1447:        char *line, *s, *t, **app, *items[MAX_PROMPT_ITEMS];
                   1448:        register int i;
1.3       misho    1449:        int ret = RETCODE_OK;
                   1450:        struct tagCommand *cmd;
1.1       misho    1451: 
                   1452:        /* --- main body of CLI --- */
1.7       misho    1453:        cliInitLine(cli_buffer);
1.1       misho    1454: 
1.7       misho    1455:        if (cli_loadHistory(cli_buffer, csHistFile) == RETCODE_ERR)
1.3       misho    1456:                return RETCODE_ERR;
1.1       misho    1457: 
                   1458:        do {
1.7       misho    1459:                line = cliReadLine(cli_buffer);
1.3       misho    1460:                if (!line) {
1.7       misho    1461:                        printfNL(cli_buffer, 0);
1.1       misho    1462:                        break;
1.3       misho    1463:                } else
1.7       misho    1464:                        cli_addHistory(cli_buffer, NULL);
1.1       misho    1465:                // clear whitespaces
1.4       misho    1466:                for (s = line; isspace((int) *s); s++);
1.1       misho    1467:                if (*s) {
1.4       misho    1468:                        for (t = s + strlen(s) - 1; t > s && isspace((int) *t); t--);
1.1       misho    1469:                        *++t = 0;
                   1470:                }
                   1471: 
                   1472:                if (*s) {
                   1473:                        memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
1.8.2.1   misho    1474:                        for (app = items; app < items + MAX_PROMPT_ITEMS - 1 && 
                   1475:                                        (*app = strsep(&s, " \t")); *app ? app++ : app);
1.1       misho    1476: 
                   1477:                        // exec_cmd ...
1.3       misho    1478:                        i = 0;
1.7       misho    1479:                        SLIST_FOREACH(cmd, &cli_buffer->line_cmds, cmd_next) {
1.8.2.7 ! misho    1480:                                if (!(cmd->cmd_level & (1 << cli_buffer->line_level)))
1.8.2.6   misho    1481:                                        continue;
1.3       misho    1482:                                if (*items[0] && !strncmp(cmd->cmd_name, items[0], strlen(items[0])))
1.1       misho    1483:                                        break;
1.3       misho    1484:                                else
                   1485:                                        i++;
                   1486:                        }
                   1487: 
1.1       misho    1488:                        if (!cmd) {
1.7       misho    1489:                                cli_Printf(cli_buffer, "\nCommand '%s' not found!\n", items[0]);
1.1       misho    1490:                                ret = -1;
                   1491:                        } else
1.3       misho    1492:                                if (cmd->cmd_func) {
1.7       misho    1493:                                        cli_Printf(cli_buffer, "\n");
1.8.2.4   misho    1494:                                        ret = cmd->cmd_func(cli_buffer, 
                   1495:                                                        cli_buffer->line_level, items);
1.3       misho    1496:                                } else {
1.7       misho    1497:                                        clrscrEOL(cli_buffer);
                   1498:                                        printfCR(cli_buffer, 1);
1.3       misho    1499:                                }
1.1       misho    1500:                }
                   1501: 
1.7       misho    1502:                cli_freeLine(cli_buffer);
                   1503:                cli_resetHistory(cli_buffer);
1.6       misho    1504:                e_free(line);
1.1       misho    1505:        } while (ret < 1);
                   1506: 
1.7       misho    1507:        cli_saveHistory(cli_buffer, csHistFile, HISTORY_LINES);
1.1       misho    1508:        return ret;
                   1509: }

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