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

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