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

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

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