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

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

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