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