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>