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

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

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