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

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