Annotation of libaitcli/src/aitcli.c, revision 1.22
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.22 ! misho 6: * $Id: aitcli.c,v 1.21.2.10 2025/12/25 20:33:41 misho Exp $
1.1 misho 7: *
1.4 misho 8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
1.20 misho 15: Copyright 2004 - 2025
1.4 misho 16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
1.1 misho 46: #include "global.h"
1.3 misho 47: #include "cli.h"
1.1 misho 48:
49:
50: #pragma GCC visibility push(hidden)
51:
52: int cli_Errno;
53: char cli_Error[STRSIZ];
54:
1.3 misho 55: #pragma GCC visibility pop
56:
57: // cli_GetErrno() Get error code of last operation
1.6 misho 58: int
1.3 misho 59: cli_GetErrno()
60: {
61: return cli_Errno;
62: }
63:
1.6 misho 64: // cli_GetError() Get error text of last operation
65: const char *
1.3 misho 66: cli_GetError()
67: {
68: return cli_Error;
69: }
70:
71: // cli_SetErr() Set error to variables for internal use!!!
1.6 misho 72: void
1.3 misho 73: cli_SetErr(int eno, char *estr, ...)
74: {
75: va_list lst;
76:
77: cli_Errno = eno;
1.6 misho 78: memset(cli_Error, 0, sizeof cli_Error);
1.3 misho 79: va_start(lst, estr);
1.6 misho 80: vsnprintf(cli_Error, sizeof cli_Error, estr, lst);
1.3 misho 81: va_end(lst);
82: }
1.2 misho 83:
1.3 misho 84: // ------------------------------------------------------------
85:
86: static inline void
1.22 ! misho 87: rewindin(linebuffer_t * __restrict buf, int len)
! 88: {
! 89: int ign __attribute__((unused));
! 90:
! 91: if (buf) {
! 92: if (len == -1)
! 93: len = buf->line_posin;
! 94: while (len-- > 0)
! 95: ign = write(buf->line_out, K_CTRL_H, 1);
! 96: }
! 97: }
! 98:
! 99: static inline void
! 100: clrscrEOLin(linebuffer_t * __restrict buf)
! 101: {
! 102: register int i;
! 103: int ign __attribute__((unused));
! 104:
! 105: if (buf) {
! 106: rewindin(buf, -1);
! 107:
! 108: for (i = 0; i < buf->line_lenin; i++)
! 109: ign = write(buf->line_out, K_SPACE, 1);
! 110: }
! 111: }
! 112:
! 113: static inline void
1.3 misho 114: clrscrEOL(linebuffer_t * __restrict buf)
115: {
116: register int i;
1.19 misho 117: int ign __attribute__((unused));
1.3 misho 118:
1.9 misho 119: if (buf && buf->line_prompt) {
1.19 misho 120: ign = write(buf->line_out, K_CR, 1);
1.1 misho 121:
1.3 misho 122: for (i = 0; i < buf->line_len; i++)
1.19 misho 123: ign = write(buf->line_out, K_SPACE, 1);
1.3 misho 124: }
125: }
1.1 misho 126:
1.3 misho 127: static inline void
1.22 ! misho 128: printfEOLin(linebuffer_t * __restrict buf)
! 129: {
! 130: int ign __attribute__((unused));
! 131:
! 132: if (buf)
! 133: ign = write(buf->line_out, buf->line_input, buf->line_lenin);
! 134: }
! 135:
! 136: static inline void
1.3 misho 137: printfEOL(linebuffer_t * __restrict buf, int len, int prompt)
1.2 misho 138: {
1.19 misho 139: int ign __attribute__((unused));
140:
1.3 misho 141: if (buf) {
1.22 ! misho 142: ign = write(buf->line_out, K_CR, 1);
! 143:
! 144: if (prompt && buf->line_prompt)
1.19 misho 145: ign = write(buf->line_out, buf->line_prompt, buf->line_bol);
1.3 misho 146:
1.19 misho 147: ign = write(buf->line_out, buf->line_buf, len == -1 ?
1.13 misho 148: buf->line_eol - buf->line_bol : len);
1.3 misho 149: }
1.2 misho 150: }
151:
1.3 misho 152: static inline void
153: printfCR(linebuffer_t * __restrict buf, int prompt)
1.2 misho 154: {
1.19 misho 155: int ign __attribute__((unused));
156:
1.22 ! misho 157: ign = write(buf->line_out, K_CR, 1);
! 158: if (buf && prompt && buf->line_prompt)
1.19 misho 159: ign = write(buf->line_out, buf->line_prompt, buf->line_bol);
1.3 misho 160: }
161:
162: static inline void
163: printfNL(linebuffer_t * __restrict buf, int prompt)
164: {
1.19 misho 165: int ign __attribute__((unused));
166:
1.3 misho 167: if (buf) {
1.19 misho 168: ign = write(buf->line_out, K_ENTER, 1);
1.3 misho 169:
170: if (prompt)
171: if (prompt && buf->line_prompt)
1.19 misho 172: ign = write(buf->line_out, buf->line_prompt, buf->line_bol);
1.3 misho 173: }
174: }
175:
176: // ------------------------------------------------------------
177:
178: static int
1.22 ! misho 179: bufCHARin(int idx, void * __restrict cli_buffer)
! 180: {
! 181: linebuffer_t *buf = cli_buffer;
! 182: int pos;
! 183: int ign __attribute__((unused));
! 184:
! 185: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
! 186: return RETCODE_ERR;
! 187:
! 188: pos = buf->line_posin;
! 189:
! 190: if (buf->line_mode == LINEMODE_INS)
! 191: memmove(buf->line_input + pos + buf->line_inkeys[idx].key_len, buf->line_input + pos,
! 192: buf->line_lenin - buf->line_posin);
! 193: if (buf->line_mode == LINEMODE_INS || buf->line_posin == buf->line_lenin)
! 194: buf->line_lenin += buf->line_inkeys[idx].key_len;
! 195: buf->line_posin += buf->line_inkeys[idx].key_len;
! 196:
! 197: memcpy(buf->line_input + pos, buf->line_inkeys[idx].key_ch, buf->line_inkeys[idx].key_len);
! 198: buf->line_input[buf->line_lenin] = 0;
! 199:
! 200: rewindin(buf, buf->line_posin - buf->line_inkeys[idx].key_len);
! 201: printfEOLin(buf);
! 202: rewindin(buf, buf->line_lenin - buf->line_posin);
! 203:
! 204: return RETCODE_OK;
! 205: }
! 206:
! 207: static int
1.7 misho 208: bufCHAR(int idx, void * __restrict cli_buffer)
1.3 misho 209: {
1.7 misho 210: linebuffer_t *buf = cli_buffer;
1.3 misho 211: int pos;
1.19 misho 212: int ign __attribute__((unused));
1.3 misho 213:
1.7 misho 214: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3 misho 215: return RETCODE_ERR;
216:
217: pos = buf->line_eol - buf->line_bol;
218:
219: if (buf->line_mode == LINEMODE_INS)
220: memmove(buf->line_buf + pos + buf->line_keys[idx].key_len, buf->line_buf + pos,
221: buf->line_len - buf->line_eol);
222: if (buf->line_mode == LINEMODE_INS || buf->line_eol == buf->line_len - 1)
223: buf->line_len += buf->line_keys[idx].key_len;
224: buf->line_eol += buf->line_keys[idx].key_len;
225:
226: memcpy(buf->line_buf + pos, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
227: buf->line_buf[buf->line_len - 1] = 0;
228:
1.13 misho 229: if (buf->line_prompt)
1.19 misho 230: ign = write(buf->line_out, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
1.3 misho 231:
232: if (buf->line_mode == LINEMODE_INS) {
1.19 misho 233: ign = write(buf->line_out, (const u_char*) buf->line_buf + pos + buf->line_keys[idx].key_len,
1.3 misho 234: buf->line_len - buf->line_eol);
235: printfEOL(buf, -1, 1);
1.2 misho 236: }
1.3 misho 237: return RETCODE_OK;
238: }
239:
240: static int
1.22 ! misho 241: bufEOLin(int idx, void * __restrict cli_buffer)
! 242: {
! 243: linebuffer_t *buf = cli_buffer;
! 244: int ign __attribute__((unused));
! 245:
! 246: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
! 247: return RETCODE_ERR;
! 248:
! 249: ign = write(buf->line_out, K_ENTER, 1);
! 250: return RETCODE_EOL;
! 251: }
! 252:
! 253: static int
1.7 misho 254: bufEOL(int idx, void * __restrict cli_buffer)
1.3 misho 255: {
1.7 misho 256: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3 misho 257: return RETCODE_ERR;
258:
1.7 misho 259: printfCR(cli_buffer, 1);
1.3 misho 260: return RETCODE_EOL;
261: }
262:
263: static int
1.7 misho 264: bufEOF(int idx, void * __restrict cli_buffer)
1.3 misho 265: {
1.20 misho 266: int ret;
267:
1.3 misho 268: /*
1.7 misho 269: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3 misho 270: return RETCODE_ERR;
271: */
272:
1.20 misho 273: printfNL(cli_buffer, 0);
274: ret = cli_Cmd_End(cli_buffer, idx, NULL);
275: printfCR(cli_buffer, (ret != RETCODE_EOF));
276:
277: return ret;
1.3 misho 278: }
279:
280: static int
1.7 misho 281: bufUP(int idx, void * __restrict cli_buffer)
1.3 misho 282: {
1.7 misho 283: linebuffer_t *buf = cli_buffer;
1.3 misho 284: int pos;
285:
1.7 misho 286: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3 misho 287: return RETCODE_ERR;
288:
289: if (!buf->line_h)
290: buf->line_h = TAILQ_FIRST(&buf->line_history);
291: else
292: buf->line_h = TAILQ_NEXT(buf->line_h, hist_next);
293: if (!buf->line_h)
294: return RETCODE_OK;
295:
296: clrscrEOL(buf);
297: cli_freeLine(buf);
298:
299: pos = buf->line_eol - buf->line_bol;
300:
301: buf->line_len += buf->line_h->hist_len;
302: buf->line_eol += buf->line_h->hist_len;
303:
304: memcpy(buf->line_buf + pos, buf->line_h->hist_line, buf->line_h->hist_len);
305: buf->line_buf[buf->line_len - 1] = 0;
306:
307: printfEOL(buf, -1, 1);
308: return RETCODE_OK;
309: }
310:
311: static int
1.7 misho 312: bufDOWN(int idx, void * __restrict cli_buffer)
1.3 misho 313: {
1.7 misho 314: linebuffer_t *buf = cli_buffer;
1.3 misho 315: int pos;
316:
1.7 misho 317: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3 misho 318: return RETCODE_ERR;
319:
320: if (!buf->line_h)
321: buf->line_h = TAILQ_LAST(&buf->line_history, tqHistoryHead);
322: else
323: buf->line_h = TAILQ_PREV(buf->line_h, tqHistoryHead, hist_next);
324: if (!buf->line_h)
325: return RETCODE_OK;
326:
327: clrscrEOL(buf);
328: cli_freeLine(buf);
329:
330: pos = buf->line_eol - buf->line_bol;
331:
332: buf->line_len += buf->line_h->hist_len;
333: buf->line_eol += buf->line_h->hist_len;
334:
335: memcpy(buf->line_buf + pos, buf->line_h->hist_line, buf->line_h->hist_len);
336: buf->line_buf[buf->line_len - 1] = 0;
337:
338: printfEOL(buf, -1, 1);
339: return RETCODE_OK;
340: }
341:
342: static int
1.22 ! misho 343: bufCLRin(int idx, void * __restrict cli_buffer)
! 344: {
! 345: linebuffer_t *buf = cli_buffer;
! 346:
! 347: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
! 348: return RETCODE_ERR;
! 349:
! 350: clrscrEOLin(buf);
! 351: rewindin(buf, buf->line_lenin);
! 352: cli_freeInput(cli_buffer);
! 353: return RETCODE_OK;
! 354: }
! 355:
! 356: static int
1.7 misho 357: bufCLR(int idx, void * __restrict cli_buffer)
1.3 misho 358: {
1.7 misho 359: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3 misho 360: return RETCODE_ERR;
361:
1.7 misho 362: clrscrEOL(cli_buffer);
363: cli_freeLine(cli_buffer);
1.3 misho 364:
1.7 misho 365: printfCR(cli_buffer, 1);
1.3 misho 366: return RETCODE_OK;
367: }
368:
369: static int
1.22 ! misho 370: bufBSin(int idx, void * __restrict cli_buffer)
! 371: {
! 372: linebuffer_t *buf = cli_buffer;
! 373:
! 374: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
! 375: return RETCODE_ERR;
! 376:
! 377: if (buf->line_posin > 0) {
! 378: clrscrEOLin(buf);
! 379: rewindin(buf, -1);
! 380:
! 381: buf->line_posin--;
! 382: buf->line_lenin--;
! 383: memmove(buf->line_input + buf->line_posin,
! 384: buf->line_input + buf->line_posin + 1,
! 385: buf->line_lenin - buf->line_posin);
! 386: buf->line_input[buf->line_lenin] = 0;
! 387:
! 388: rewindin(buf, buf->line_lenin - buf->line_posin);
! 389: printfEOLin(buf);
! 390: rewindin(buf, buf->line_lenin - buf->line_posin);
! 391: }
! 392:
! 393: return RETCODE_OK;
! 394: }
! 395:
! 396: static int
1.7 misho 397: bufBS(int idx, void * __restrict cli_buffer)
1.3 misho 398: {
1.7 misho 399: linebuffer_t *buf = cli_buffer;
1.3 misho 400:
1.7 misho 401: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3 misho 402: return RETCODE_ERR;
403:
404: if (buf->line_bol < buf->line_eol) {
405: clrscrEOL(buf);
406:
407: buf->line_eol--;
408: buf->line_len--;
409: memmove(buf->line_buf + buf->line_eol - buf->line_bol,
410: buf->line_buf + buf->line_eol - buf->line_bol + 1,
411: buf->line_len - buf->line_eol);
412: buf->line_buf[buf->line_len - 1] = 0;
413:
414: printfEOL(buf, buf->line_len - 1, 1);
415: printfEOL(buf, -1, 1);
416: }
417:
418: return RETCODE_OK;
419: }
420:
421: static int
1.7 misho 422: bufBTAB(int idx, void * __restrict cli_buffer)
1.3 misho 423: {
1.7 misho 424: linebuffer_t *buf = cli_buffer;
1.3 misho 425:
1.7 misho 426: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3 misho 427: return RETCODE_ERR;
428:
429: if (buf->line_bol < buf->line_eol) {
430: clrscrEOL(buf);
431:
432: buf->line_len = buf->line_eol - buf->line_bol + 1;
433: buf->line_buf[buf->line_len - 1] = 0;
434:
435: printfEOL(buf, -1, 1);
1.2 misho 436: }
437:
1.3 misho 438: return RETCODE_OK;
439: }
440:
441: static int
1.7 misho 442: bufMODE(int idx, void * __restrict cli_buffer)
1.3 misho 443: {
1.7 misho 444: linebuffer_t *buf = cli_buffer;
1.3 misho 445:
1.7 misho 446: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3 misho 447: return RETCODE_ERR;
448:
449: buf->line_mode = !buf->line_mode ? LINEMODE_OVER : LINEMODE_INS;
450: return RETCODE_OK;
451: }
452:
453: static int
1.22 ! misho 454: bufBEGINin(int idx, void * __restrict cli_buffer)
! 455: {
! 456: linebuffer_t *buf = cli_buffer;
! 457:
! 458: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
! 459: return RETCODE_ERR;
! 460:
! 461: rewindin(buf, -1);
! 462: buf->line_posin ^= buf->line_posin;
! 463:
! 464: return RETCODE_OK;
! 465: }
! 466:
! 467: static int
1.7 misho 468: bufBEGIN(int idx, void * __restrict cli_buffer)
1.3 misho 469: {
1.7 misho 470: linebuffer_t *buf = cli_buffer;
1.3 misho 471:
1.7 misho 472: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3 misho 473: return RETCODE_ERR;
474:
475: buf->line_eol = buf->line_bol;
476:
477: printfCR(buf, 1);
478: return RETCODE_OK;
479: }
480:
481: static int
1.22 ! misho 482: bufENDin(int idx, void * __restrict cli_buffer)
! 483: {
! 484: linebuffer_t *buf = cli_buffer;
! 485:
! 486: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
! 487: return RETCODE_ERR;
! 488:
! 489: rewindin(buf, -1);
! 490: printfEOLin(buf);
! 491: buf->line_posin = buf->line_lenin;
! 492:
! 493: return RETCODE_OK;
! 494: }
! 495:
! 496: static int
1.7 misho 497: bufEND(int idx, void * __restrict cli_buffer)
1.3 misho 498: {
1.7 misho 499: linebuffer_t *buf = cli_buffer;
1.3 misho 500:
1.7 misho 501: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3 misho 502: return RETCODE_ERR;
503:
504: buf->line_eol = buf->line_len - 1;
505:
506: printfEOL(buf, -1, 1);
507: return RETCODE_OK;
1.2 misho 508: }
509:
1.3 misho 510: static int
1.22 ! misho 511: bufLEFTin(int idx, void * __restrict cli_buffer)
! 512: {
! 513: linebuffer_t *buf = cli_buffer;
! 514:
! 515: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
! 516: return RETCODE_ERR;
! 517:
! 518: if (buf->line_posin > 0) {
! 519: rewindin(buf, 1);
! 520: buf->line_posin--;
! 521: }
! 522:
! 523: return RETCODE_OK;
! 524: }
! 525:
! 526: static int
1.7 misho 527: bufLEFT(int idx, void * __restrict cli_buffer)
1.2 misho 528: {
1.7 misho 529: linebuffer_t *buf = cli_buffer;
1.3 misho 530:
1.7 misho 531: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3 misho 532: return RETCODE_ERR;
533:
534: if (buf->line_bol < buf->line_eol)
535: printfEOL(buf, --buf->line_eol - buf->line_bol, 1);
536:
537: return RETCODE_OK;
538: }
1.2 misho 539:
1.3 misho 540: static int
1.22 ! misho 541: bufRIGHTin(int idx, void * __restrict cli_buffer)
! 542: {
! 543: linebuffer_t *buf = cli_buffer;
! 544:
! 545: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
! 546: return RETCODE_ERR;
! 547:
! 548: if (buf->line_posin < buf->line_lenin) {
! 549: write(buf->line_out, buf->line_input + buf->line_posin, 1);
! 550: buf->line_posin++;
! 551: }
! 552:
! 553: return RETCODE_OK;
! 554: }
! 555:
! 556: static int
1.7 misho 557: bufRIGHT(int idx, void * __restrict cli_buffer)
1.3 misho 558: {
1.7 misho 559: linebuffer_t *buf = cli_buffer;
1.3 misho 560:
1.7 misho 561: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3 misho 562: return RETCODE_ERR;
563:
564: if (buf->line_eol < buf->line_len - 1)
565: printfEOL(buf, ++buf->line_eol - buf->line_bol, 1);
566:
567: return RETCODE_OK;
568: }
569:
570: static int
1.22 ! misho 571: bufDELin(int idx, void * __restrict cli_buffer)
! 572: {
! 573: linebuffer_t *buf = cli_buffer;
! 574:
! 575: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
! 576: return RETCODE_ERR;
! 577:
! 578: if (buf->line_lenin > 0 && buf->line_posin < buf->line_lenin) {
! 579: clrscrEOLin(buf);
! 580: rewindin(buf, buf->line_lenin);
! 581:
! 582: buf->line_lenin--;
! 583: memmove(buf->line_input + buf->line_posin,
! 584: buf->line_input + buf->line_posin + 1,
! 585: buf->line_lenin - buf->line_posin);
! 586: buf->line_input[buf->line_lenin] = 0;
! 587:
! 588: printfEOLin(buf);
! 589: rewindin(buf, buf->line_lenin - buf->line_posin);
! 590: }
! 591:
! 592: return RETCODE_OK;
! 593: }
! 594:
! 595: static int
1.7 misho 596: bufDEL(int idx, void * __restrict cli_buffer)
1.3 misho 597: {
1.7 misho 598: linebuffer_t *buf = cli_buffer;
1.3 misho 599:
1.7 misho 600: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3 misho 601: return RETCODE_ERR;
602:
1.22 ! misho 603: if (buf->line_bol < buf->line_eol && buf->line_eol < buf->line_len) {
! 604: clrscrEOL(buf);
1.3 misho 605:
1.22 ! misho 606: buf->line_len--;
! 607: memmove(buf->line_buf + buf->line_eol - buf->line_bol,
! 608: buf->line_buf + buf->line_eol - buf->line_bol + 1,
! 609: buf->line_len - buf->line_eol);
! 610: buf->line_buf[buf->line_len - 1] = 0;
1.3 misho 611:
1.22 ! misho 612: printfEOL(buf, buf->line_len - 1, 1);
! 613: printfEOL(buf, -1, 1);
! 614: }
1.3 misho 615:
616: return RETCODE_OK;
617: }
618:
619: static int
1.7 misho 620: bufComp(int idx, void * __restrict cli_buffer)
1.3 misho 621: {
1.7 misho 622: linebuffer_t *buf = cli_buffer;
1.3 misho 623: char *str, *s, **app, *items[MAX_PROMPT_ITEMS], szLine[STRSIZ];
624: register int i, j;
625: struct tagCommand *cmd, *c;
626: int pos, ret = RETCODE_OK;
1.19 misho 627: int ign __attribute__((unused));
1.3 misho 628:
1.7 misho 629: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3 misho 630: return RETCODE_ERR;
631:
1.6 misho 632: str = e_strdup(buf->line_buf);
1.3 misho 633: if (!str)
634: return RETCODE_ERR;
1.2 misho 635: else {
1.3 misho 636: s = str;
1.6 misho 637: str_Trim(s);
1.3 misho 638: }
639:
1.20 misho 640: j = 0;
1.3 misho 641: c = NULL;
642: memset(szLine, 0, STRSIZ);
643: if (*s) {
644: memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
1.9 misho 645: for (app = items, i = 0; app < items + MAX_PROMPT_ITEMS - 1 &&
646: (*app = strsep(&s, " \t"));
1.3 misho 647: *app ? i++ : i, *app ? app++ : app);
648:
649: if (i) {
650: SLIST_FOREACH(cmd, &buf->line_cmds, cmd_next) {
1.9 misho 651: if (cmd->cmd_level & (1 << buf->line_level) &&
652: !strncmp(cmd->cmd_name, items[0],
653: strlen(items[0]))) {
654: if (strncmp(cmd->cmd_name, CLI_CMD_SEP,
655: strlen(CLI_CMD_SEP))) {
1.3 misho 656: j++;
657: c = cmd;
658: strlcat(szLine, " ", STRSIZ);
659: strlcat(szLine, cmd->cmd_name, STRSIZ);
660: }
661: }
662: }
1.2 misho 663:
1.3 misho 664: if (i > 1 && c) {
665: /* we are on argument of command and has complition info */
666: j++; // always must be j > 1 ;) for arguments
667: strlcpy(szLine, c->cmd_info, STRSIZ);
668: }
669: } else {
670: /* we have valid char but i == 0, this case is illegal */
671: ret = RETCODE_ERR;
672: goto endcomp;
1.2 misho 673: }
1.3 misho 674: } else {
675: /* we on 0 position of prompt, show commands for this level */
676: SLIST_FOREACH(cmd, &buf->line_cmds, cmd_next) {
1.9 misho 677: if (cmd->cmd_level & (1 << buf->line_level))
1.3 misho 678: if (strncmp(cmd->cmd_name, CLI_CMD_SEP, strlen(CLI_CMD_SEP))) {
679: j++;
680: c = cmd;
681: strlcat(szLine, " ", STRSIZ);
682: strlcat(szLine, cmd->cmd_name, STRSIZ);
683: }
684: }
685: }
1.2 misho 686:
1.3 misho 687: /* completion show actions ... */
688: if (j > 1 && c) {
689: printfNL(buf, 0);
1.19 misho 690: ign = write(buf->line_out, szLine, strlen(szLine));
1.3 misho 691: printfNL(buf, 1);
692: printfEOL(buf, buf->line_len - 1, 1);
693: printfEOL(buf, -1, 1);
1.2 misho 694: }
1.3 misho 695: if (j == 1 && c) {
696: clrscrEOL(buf);
697: cli_freeLine(buf);
698:
699: pos = buf->line_eol - buf->line_bol;
700:
701: buf->line_len += c->cmd_len + 1;
702: buf->line_eol += c->cmd_len + 1;
703:
704: memcpy(buf->line_buf + pos, c->cmd_name, c->cmd_len);
705: buf->line_buf[pos + c->cmd_len] = (u_char) *K_SPACE;
706: buf->line_buf[buf->line_len - 1] = 0;
1.2 misho 707:
1.3 misho 708: printfEOL(buf, -1, 1);
1.2 misho 709: }
710:
1.3 misho 711: endcomp:
1.6 misho 712: e_free(str);
1.3 misho 713: return ret;
714: }
715:
716: static int
1.7 misho 717: bufHelp(int idx, void * __restrict cli_buffer)
1.3 misho 718: {
1.7 misho 719: linebuffer_t *buf = cli_buffer;
1.3 misho 720:
1.7 misho 721: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
1.3 misho 722: return RETCODE_ERR;
723:
1.9 misho 724: cli_Cmd_Help(buf, buf->line_level, NULL);
1.3 misho 725:
726: printfEOL(buf, buf->line_len - 1, 1);
727: printfEOL(buf, -1, 1);
728: return RETCODE_OK;
729: }
730:
1.9 misho 731: static int
732: bufEndNode(int idx, void * __restrict cli_buffer)
733: {
734: linebuffer_t *buf = cli_buffer;
1.20 misho 735: char szPrompt[STRSIZ + 16] = {[0 ... STRSIZ + 15] = 0};
1.9 misho 736:
737: if (!cli_buffer || idx < 0 || idx > MAX_BINDKEY)
738: return RETCODE_ERR;
739:
740: if (buf->line_level > 0) {
741: printfNL(cli_buffer, 0);
742: buf->line_level--;
1.20 misho 743: snprintf(szPrompt, sizeof szPrompt, "%s{%d}> ", buf->line_porigin, buf->line_level);
744: cli_setPrompt(buf, szPrompt);
1.9 misho 745: cli_Printf(buf, "Enter to config level %d\n", buf->line_level);
746: }
747:
748: return bufCLR(idx, cli_buffer);
749: }
750:
1.3 misho 751:
752: /*
1.6 misho 753: * cli_Printf() - Send message to CLI session
754: *
1.7 misho 755: * @cli_buffer = CLI buffer
1.3 misho 756: * @fmt = printf format string
757: * @... = arguments defined in fmt
758: * return: none
759: */
1.6 misho 760: void
1.7 misho 761: cli_Printf(linebuffer_t * __restrict cli_buffer, char *fmt, ...)
1.3 misho 762: {
763: va_list lst;
764: FILE *f;
1.22 ! misho 765: int fd;
1.3 misho 766:
767: if (fmt) {
1.22 ! misho 768: if ((fd = dup(cli_buffer->line_out)) == -1) {
! 769: LOGERR;
! 770: return;
! 771: }
! 772: f = fdopen(fd, "a");
1.3 misho 773: if (!f) {
774: LOGERR;
775: return;
776: }
777:
778: va_start(lst, fmt);
779: vfprintf(f, fmt, lst);
780: va_end(lst);
1.20 misho 781:
782: fclose(f);
1.3 misho 783: } else
1.6 misho 784: cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3 misho 785: }
786:
787: /*
1.6 misho 788: * cli_PrintHelp() - Print help screen
789: *
1.7 misho 790: * @cli_buffer = CLI buffer
1.3 misho 791: * return: none
792: */
1.6 misho 793: void
1.7 misho 794: cli_PrintHelp(linebuffer_t * __restrict cli_buffer)
1.3 misho 795: {
1.7 misho 796: if (cli_buffer) {
797: bufHelp(0, cli_buffer);
798: clrscrEOL(cli_buffer);
1.3 misho 799: } else
1.6 misho 800: cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3 misho 801: }
802:
803:
804: /*
1.6 misho 805: * cli_BindKey() - Bind function to key
806: *
1.3 misho 807: * @key = key structure
1.7 misho 808: * @cli_buffer = CLI buffer
1.3 misho 809: * return: RETCODE_ERR error, RETCODE_OK ok, >0 bind at position
810: */
811: int
1.7 misho 812: cli_BindKey(bindkey_t * __restrict key, linebuffer_t * __restrict cli_buffer)
1.3 misho 813: {
814: register int i;
815:
1.7 misho 816: if (!key || !cli_buffer) {
1.6 misho 817: cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3 misho 818: return RETCODE_ERR;
1.2 misho 819: }
1.3 misho 820:
821: for (i = 0; i < MAX_BINDKEY; i++)
1.7 misho 822: if (key->key_len == cli_buffer->line_keys[i].key_len &&
823: !memcmp(key->key_ch, cli_buffer->line_keys[i].key_ch,
824: key->key_len)) {
825: cli_buffer->line_keys[i].key_func = key->key_func;
1.3 misho 826: return i;
827: }
828:
829: return RETCODE_OK;
1.2 misho 830: }
831:
832:
1.3 misho 833: /*
1.6 misho 834: * cli_addCommand() - Add command to CLI session
835: *
1.7 misho 836: * @cli_buffer = CLI buffer
1.3 misho 837: * @csCmd = Command name
1.9 misho 838: * @cliLevel = Level in CLI, -1 view from all levels, 0 hidden, >0 mask levels
1.3 misho 839: * @funcCmd = Callback function when user call command
840: * @csInfo = Inline information for command
841: * @csHelp = Help line when call help
842: * return: RETCODE_ERR error, RETCODE_OK ok
843: */
844: int
1.7 misho 845: cli_addCommand(linebuffer_t * __restrict cli_buffer, const char *csCmd,
846: int cliLevel, cmd_func_t funcCmd,
1.3 misho 847: const char *csInfo, const char *csHelp)
1.1 misho 848: {
1.3 misho 849: struct tagCommand *cmd;
850:
1.7 misho 851: if (!cli_buffer || !csCmd) {
1.6 misho 852: cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3 misho 853: return RETCODE_ERR;
854: }
855:
1.6 misho 856: cmd = e_malloc(sizeof(struct tagCommand));
1.3 misho 857: if (!cmd) {
858: LOGERR;
859: return RETCODE_ERR;
860: } else
861: memset(cmd, 0, sizeof(struct tagCommand));
862:
863: cmd->cmd_level = cliLevel;
864: cmd->cmd_func = funcCmd;
865: cmd->cmd_len = strlcpy(cmd->cmd_name, csCmd, STRSIZ);
866: if (csInfo)
867: strlcpy(cmd->cmd_info, csInfo, STRSIZ);
868: if (csHelp)
869: strlcpy(cmd->cmd_help, csHelp, STRSIZ);
1.7 misho 870: SLIST_INSERT_HEAD(&cli_buffer->line_cmds, cmd, cmd_next);
1.3 misho 871: return RETCODE_OK;
1.1 misho 872: }
873:
1.3 misho 874: /*
1.6 misho 875: * cli_delCommand() - Delete command from CLI session
876: *
1.7 misho 877: * @cli_buffer = CLI buffer
1.3 misho 878: * @csCmd = Command name
1.9 misho 879: * @cliLevel = Level in CLI, -1 view from all levels, 0 hidden, >0 mask levels
1.3 misho 880: * return: RETCODE_ERR error, RETCODE_OK ok
881: */
882: int
1.7 misho 883: cli_delCommand(linebuffer_t * __restrict cli_buffer, const char *csCmd, int cliLevel)
1.1 misho 884: {
1.3 misho 885: struct tagCommand *cmd;
886: int ret = RETCODE_OK;
887:
1.7 misho 888: if (!cli_buffer || !csCmd) {
1.6 misho 889: cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3 misho 890: return RETCODE_ERR;
891: }
892:
1.7 misho 893: SLIST_FOREACH(cmd, &cli_buffer->line_cmds, cmd_next)
1.3 misho 894: if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) {
895: ret = 1;
1.7 misho 896: SLIST_REMOVE(&cli_buffer->line_cmds, cmd, tagCommand, cmd_next);
1.6 misho 897: e_free(cmd);
1.3 misho 898: break;
899: }
900:
901: return ret;
1.1 misho 902: }
903:
1.3 misho 904: /*
1.6 misho 905: * cli_updCommand() - Update command in CLI session
906: *
1.7 misho 907: * @cli_buffer = CLI buffer
1.3 misho 908: * @csCmd = Command name
1.9 misho 909: * @cliLevel = Level in CLI, -1 view from all levels, 0 hidden, >0 mask levels
1.3 misho 910: * @funcCmd = Callback function when user call command
911: * @csInfo = Inline information for command
912: * @csHelp = Help line when call help
913: * return: RETCODE_ERR error, RETCODE_OK ok
914: */
915: int
1.7 misho 916: cli_updCommand(linebuffer_t * __restrict cli_buffer, const char *csCmd,
917: int cliLevel, cmd_func_t funcCmd,
1.3 misho 918: const char *csInfo, const char *csHelp)
1.1 misho 919: {
1.3 misho 920: struct tagCommand *cmd;
921: int ret = RETCODE_OK;
922:
1.7 misho 923: if (!cli_buffer || !csCmd) {
1.6 misho 924: cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3 misho 925: return RETCODE_ERR;
926: }
927:
1.9 misho 928: SLIST_FOREACH(cmd, &cli_buffer->line_cmds, cmd_next)
929: if ((!cmd->cmd_level || cmd->cmd_level == cliLevel) &&
930: !strcmp(cmd->cmd_name, csCmd)) {
931: if (!cmd->cmd_level)
932: cmd->cmd_level = cliLevel;
1.3 misho 933: if (funcCmd)
934: cmd->cmd_func = funcCmd;
935: if (csInfo)
936: strlcpy(cmd->cmd_info, csInfo, STRSIZ);
937: if (csHelp)
938: strlcpy(cmd->cmd_help, csHelp, STRSIZ);
939:
940: break;
941: }
1.1 misho 942:
1.3 misho 943: return ret;
1.1 misho 944: }
945:
946:
947: /*
1.6 misho 948: * cli_addHistory() - Add line to history
949: *
1.7 misho 950: * @cli_buffer = CLI buffer
1.3 misho 951: * @str = Add custom text or if NULL use readed line from CLI buffer
952: * return: RETCODE_ERR error, RETCODE_OK ok
1.1 misho 953: */
1.3 misho 954: int
1.7 misho 955: cli_addHistory(linebuffer_t * __restrict cli_buffer, const char * __restrict str)
1.1 misho 956: {
1.3 misho 957: struct tagHistory *h;
958:
1.7 misho 959: if (!cli_buffer) {
1.6 misho 960: cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3 misho 961: return RETCODE_ERR;
962: }
963:
1.6 misho 964: if (!(h = e_malloc(sizeof(struct tagHistory)))) {
1.3 misho 965: LOGERR;
966: return RETCODE_ERR;
967: } else
968: memset(h, 0, sizeof(struct tagHistory));
969:
970: if (str) {
971: if (!*str) {
1.6 misho 972: e_free(h);
1.3 misho 973: return RETCODE_OK;
974: }
975:
976: h->hist_len = strlcpy(h->hist_line, str, BUFSIZ);
977: } else {
1.7 misho 978: if (!*cli_buffer->line_buf || cli_buffer->line_len < 2) {
1.6 misho 979: e_free(h);
1.3 misho 980: return RETCODE_OK;
981: }
982:
1.7 misho 983: memcpy(h->hist_line, cli_buffer->line_buf, (h->hist_len = cli_buffer->line_len));
1.6 misho 984: str_Trim(h->hist_line);
1.3 misho 985: h->hist_len = strlen(h->hist_line);
986: }
1.1 misho 987:
1.7 misho 988: TAILQ_INSERT_HEAD(&cli_buffer->line_history, h, hist_next);
1.3 misho 989: return h->hist_len;
990: }
1.1 misho 991:
1.3 misho 992: /*
1.6 misho 993: * cli_saveHistory() - Save history to file
994: *
1.7 misho 995: * @cli_buffer = CLI buffer
1.3 misho 996: * @histfile = History filename, if NULL will be use default name
997: * @lines = Maximum history lines to save
998: * return: RETCODE_ERR error, RETCODE_OK ok
999: */
1000: int
1.7 misho 1001: cli_saveHistory(linebuffer_t * __restrict cli_buffer, const char *histfile, int lines)
1.3 misho 1002: {
1003: FILE *f;
1004: mode_t mode;
1005: char szFName[MAXPATHLEN];
1006: struct tagHistory *h;
1007:
1.7 misho 1008: if (!cli_buffer) {
1.6 misho 1009: cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3 misho 1010: return RETCODE_ERR;
1011: }
1012: if (!histfile)
1013: strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
1014: else
1015: strlcpy(szFName, histfile, MAXPATHLEN);
1016:
1017: mode = umask(0177);
1018: f = fopen(szFName, "w");
1019: if (!f) {
1.1 misho 1020: LOGERR;
1.3 misho 1021: return RETCODE_ERR;
1022: }
1023:
1.7 misho 1024: TAILQ_FOREACH(h, &cli_buffer->line_history, hist_next) {
1.3 misho 1025: fprintf(f, "%s\n", h->hist_line);
1026:
1027: if (lines)
1028: lines--;
1029: else
1030: break;
1031: }
1.1 misho 1032:
1.3 misho 1033: fclose(f);
1034: umask(mode);
1035:
1036: return RETCODE_OK;
1.1 misho 1037: }
1038:
1.3 misho 1039: /*
1.6 misho 1040: * cli_loadHistory() - Load history from file
1041: *
1.7 misho 1042: * @cli_buffer = CLI buffer
1.3 misho 1043: * @histfile = History filename, if NULL will be use default name
1044: * return: RETCODE_ERR error, RETCODE_OK ok
1045: */
1046: int
1.7 misho 1047: cli_loadHistory(linebuffer_t * __restrict cli_buffer, const char *histfile)
1.3 misho 1048: {
1049: FILE *f;
1050: char szFName[MAXPATHLEN], buf[BUFSIZ];
1051: struct tagHistory *h;
1052:
1.7 misho 1053: if (!cli_buffer) {
1.6 misho 1054: cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3 misho 1055: return RETCODE_ERR;
1056: }
1057: if (!histfile)
1058: strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
1059: else
1060: strlcpy(szFName, histfile, MAXPATHLEN);
1061:
1062: f = fopen(szFName, "r");
1063: if (!f)
1064: return RETCODE_OK;
1065:
1066: while (fgets(buf, BUFSIZ, f)) {
1067: if (!*buf || *buf == '#')
1068: continue;
1069: else
1.6 misho 1070: str_Trim(buf);
1.3 misho 1071:
1.6 misho 1072: if (!(h = e_malloc(sizeof(struct tagHistory)))) {
1.3 misho 1073: LOGERR;
1074: fclose(f);
1075: return RETCODE_ERR;
1076: } else
1077: memset(h, 0, sizeof(struct tagHistory));
1078:
1079: h->hist_len = strlcpy(h->hist_line, buf, BUFSIZ);
1.7 misho 1080: TAILQ_INSERT_TAIL(&cli_buffer->line_history, h, hist_next);
1.3 misho 1081: }
1082:
1083: fclose(f);
1084:
1085: return RETCODE_OK;
1086: }
1.1 misho 1087:
1088: /*
1.6 misho 1089: * cli_resetHistory() - Reset history search in CLI session
1090: *
1.7 misho 1091: * @cli_buffer = CLI buffer
1.1 misho 1092: * return: none
1093: */
1.6 misho 1094: void
1.7 misho 1095: cli_resetHistory(linebuffer_t * __restrict cli_buffer)
1.1 misho 1096: {
1.7 misho 1097: cli_buffer->line_h = NULL;
1.1 misho 1098: }
1099:
1.3 misho 1100:
1.1 misho 1101: /*
1.22 ! misho 1102: * cli_freeInput() - Clear entire input
! 1103: *
! 1104: * @cli_buffer = CLI buffer
! 1105: * return: RETCODE_ERR error, RETCODE_OK ok
! 1106: */
! 1107: int
! 1108: cli_freeInput(linebuffer_t * __restrict cli_buffer)
! 1109: {
! 1110: int code = RETCODE_ERR;
! 1111:
! 1112: if (cli_buffer) {
! 1113: memset(cli_buffer->line_input, 0, BUFSIZ);
! 1114: cli_buffer->line_posin ^= cli_buffer->line_posin;
! 1115: cli_buffer->line_lenin ^= cli_buffer->line_lenin;
! 1116:
! 1117: code = RETCODE_OK;
! 1118: } else
! 1119: cli_SetErr(EINVAL, "Invalid input parameters ...");
! 1120:
! 1121: return code;
! 1122: }
! 1123: /*
1.6 misho 1124: * cli_freeLine() - Clear entire line
1125: *
1.7 misho 1126: * @cli_buffer = CLI buffer
1.3 misho 1127: * return: RETCODE_ERR error, RETCODE_OK ok
1.2 misho 1128: */
1.6 misho 1129: int
1.7 misho 1130: cli_freeLine(linebuffer_t * __restrict cli_buffer)
1.2 misho 1131: {
1.3 misho 1132: int code = RETCODE_ERR;
1.2 misho 1133:
1.7 misho 1134: if (cli_buffer) {
1.22 ! misho 1135: memset(cli_buffer->line_buf, 0, BUFSIZ);
! 1136: cli_buffer->line_eol = cli_buffer->line_bol;
! 1137: cli_buffer->line_len = 1 + cli_buffer->line_eol;
1.7 misho 1138:
1.22 ! misho 1139: code = RETCODE_OK;
1.3 misho 1140: } else
1.6 misho 1141: cli_SetErr(EINVAL, "Invalid input parameters ...");
1.2 misho 1142:
1.3 misho 1143: return code;
1.2 misho 1144: }
1145:
1146: /*
1.6 misho 1147: * cli_setPrompt() - Set new prompt for CLI session
1148: *
1.7 misho 1149: * @cli_buffer = CLI buffer
1.3 misho 1150: * @prompt = new text for prompt or if NULL disable prompt
1151: * return: none
1.2 misho 1152: */
1.6 misho 1153: void
1.7 misho 1154: cli_setPrompt(linebuffer_t * __restrict cli_buffer, const char *prompt)
1.2 misho 1155: {
1.7 misho 1156: if (cli_buffer) {
1157: if (cli_buffer->line_prompt) {
1158: e_free(cli_buffer->line_prompt);
1159: cli_buffer->line_prompt = NULL;
1160: cli_buffer->line_bol = 0;
1.3 misho 1161: }
1162:
1163: if (prompt) {
1.7 misho 1164: cli_buffer->line_prompt = e_strdup(prompt);
1165: if (cli_buffer->line_prompt) {
1166: cli_buffer->line_bol = strlen(cli_buffer->line_prompt);
1167: cli_buffer->line_eol = cli_buffer->line_bol;
1168: cli_buffer->line_len = 1 + cli_buffer->line_eol;
1.3 misho 1169: } else
1170: LOGERR;
1171: }
1172: } else
1.6 misho 1173: cli_SetErr(EINVAL, "Invalid input parameters ...");
1.2 misho 1174: }
1175:
1.3 misho 1176:
1.2 misho 1177: /*
1.6 misho 1178: * cliEnd() - Clear data, Free resources and close CLI session
1179: *
1.7 misho 1180: * @cli_buffer = CLI buffer
1.3 misho 1181: * return: RETCODE_ERR error, RETCODE_OK ok
1.2 misho 1182: */
1.3 misho 1183: void
1.7 misho 1184: cliEnd(linebuffer_t * __restrict cli_buffer)
1.2 misho 1185: {
1.3 misho 1186: struct tagHistory *h;
1187: struct tagCommand *c;
1188:
1.7 misho 1189: if (cli_buffer) {
1190: while ((c = SLIST_FIRST(&cli_buffer->line_cmds))) {
1191: SLIST_REMOVE_HEAD(&cli_buffer->line_cmds, cmd_next);
1.6 misho 1192: e_free(c);
1.3 misho 1193: }
1.7 misho 1194: while ((h = TAILQ_FIRST(&cli_buffer->line_history))) {
1195: TAILQ_REMOVE(&cli_buffer->line_history, h, hist_next);
1.6 misho 1196: e_free(h);
1.3 misho 1197: }
1198:
1.7 misho 1199: if (cli_buffer->line_prompt)
1200: e_free(cli_buffer->line_prompt);
1.2 misho 1201:
1.7 misho 1202: if (cli_buffer->line_keys)
1203: e_free(cli_buffer->line_keys);
1204: if (cli_buffer->line_buf)
1205: e_free(cli_buffer->line_buf);
1.2 misho 1206:
1.22 ! misho 1207: if (cli_buffer->line_inkeys)
! 1208: e_free(cli_buffer->line_inkeys);
! 1209: if (cli_buffer->line_input)
! 1210: e_free(cli_buffer->line_input);
! 1211:
1.7 misho 1212: e_free(cli_buffer);
1213: cli_buffer = NULL;
1.3 misho 1214: } else
1.6 misho 1215: cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3 misho 1216: }
1217:
1218: /*
1.6 misho 1219: * cliInit() - Start CLI session, allocate memory for resources and bind keys
1220: *
1.3 misho 1221: * @fin = Input device handle
1222: * @fout = Output device handle
1223: * @prompt = text for prompt, if NULL disable prompt
1224: * return: NULL if error or !=NULL CLI buffer
1225: */
1226: linebuffer_t *
1227: cliInit(int fin, int fout, const char *prompt)
1228: {
1.7 misho 1229: linebuffer_t *cli_buffer;
1.22 ! misho 1230: bindkey_t *keys, *inkeys;
1.3 misho 1231: register int i;
1.18 misho 1232: char szPrompt[STRSIZ + 16] = {[0 ... STRSIZ + 15] = 0};
1.3 misho 1233:
1234: /* init buffer */
1.7 misho 1235: cli_buffer = e_malloc(sizeof(linebuffer_t));
1236: if (!cli_buffer) {
1.3 misho 1237: LOGERR;
1238: return NULL;
1239: } else {
1.7 misho 1240: memset(cli_buffer, 0, sizeof(linebuffer_t));
1.3 misho 1241:
1.7 misho 1242: cli_buffer->line_in = fin;
1243: cli_buffer->line_out = fout;
1.3 misho 1244:
1.7 misho 1245: TAILQ_INIT(&cli_buffer->line_history);
1246: SLIST_INIT(&cli_buffer->line_cmds);
1.3 misho 1247:
1248: if (prompt) {
1.16 misho 1249: strlcpy(cli_buffer->line_porigin, prompt, sizeof cli_buffer->line_porigin);
1250: snprintf(szPrompt, sizeof szPrompt, "%s{%d}> ", cli_buffer->line_porigin, cli_buffer->line_level);
1251: cli_buffer->line_prompt = e_strdup(szPrompt);
1.7 misho 1252: if (!cli_buffer->line_prompt) {
1.3 misho 1253: LOGERR;
1.7 misho 1254: e_free(cli_buffer);
1.3 misho 1255: return NULL;
1256: } else
1.7 misho 1257: cli_buffer->line_eol = cli_buffer->line_bol =
1258: strlen(cli_buffer->line_prompt);
1.9 misho 1259: } else
1260: cli_buffer->line_mode = LINEMODE_OVER;
1.3 misho 1261: }
1.7 misho 1262: cli_buffer->line_buf = e_malloc(BUFSIZ);
1263: if (!cli_buffer->line_buf) {
1.3 misho 1264: LOGERR;
1.7 misho 1265: if (cli_buffer->line_prompt)
1266: e_free(cli_buffer->line_prompt);
1267: e_free(cli_buffer);
1.3 misho 1268: return NULL;
1269: } else {
1.7 misho 1270: memset(cli_buffer->line_buf, 0, BUFSIZ);
1271: cli_buffer->line_len = 1 + cli_buffer->line_eol;
1.3 misho 1272: }
1.22 ! misho 1273: cli_buffer->line_input = e_malloc(BUFSIZ);
! 1274: if (!cli_buffer->line_input) {
! 1275: LOGERR;
! 1276: if (cli_buffer->line_prompt)
! 1277: e_free(cli_buffer->line_prompt);
! 1278: e_free(cli_buffer->line_buf);
! 1279: e_free(cli_buffer);
! 1280: return NULL;
! 1281: } else {
! 1282: memset(cli_buffer->line_input, 0, BUFSIZ);
! 1283: cli_buffer->line_lenin = cli_buffer->line_posin;
! 1284: }
1.6 misho 1285: keys = e_calloc(MAX_BINDKEY + 1, sizeof(bindkey_t));
1.3 misho 1286: if (!keys) {
1287: LOGERR;
1.7 misho 1288: if (cli_buffer->line_prompt)
1289: e_free(cli_buffer->line_prompt);
1.22 ! misho 1290: e_free(cli_buffer->line_input);
1.7 misho 1291: e_free(cli_buffer->line_buf);
1292: e_free(cli_buffer);
1.3 misho 1293: return NULL;
1294: } else
1295: memset(keys, 0, sizeof(bindkey_t) * (MAX_BINDKEY + 1));
1.22 ! misho 1296: inkeys = e_calloc(MAX_BINDKEY + 1, sizeof(bindkey_t));
! 1297: if (!inkeys) {
! 1298: LOGERR;
! 1299: e_free(keys);
! 1300: if (cli_buffer->line_prompt)
! 1301: e_free(cli_buffer->line_prompt);
! 1302: e_free(cli_buffer->line_input);
! 1303: e_free(cli_buffer->line_buf);
! 1304: e_free(cli_buffer);
! 1305: return NULL;
! 1306: } else
! 1307: memset(inkeys, 0, sizeof(bindkey_t) * (MAX_BINDKEY + 1));
1.3 misho 1308:
1309: /* add helper functions */
1.9 misho 1310: cli_addCommand(cli_buffer, "exit", 1, cli_Cmd_Exit, "exit <cr>", "Exit from console");
1311: cli_addCommand(cli_buffer, "help", -1, cli_Cmd_Help, "help [command] <cr>", "Help screen");
1312: cli_addCommand(cli_buffer, "-------", -1, NULL, "-------------------------", NULL);
1313: cli_addCommand(cli_buffer, "where", -1, cli_Cmd_WhereAmI, "where <cr>",
1314: "Query current level of console");
1315: cli_addCommand(cli_buffer, "top", -1, cli_Cmd_Top, "top <cr>", "Top level of console");
1316: cli_addCommand(cli_buffer, "end", -1, cli_Cmd_End, "end <cr>", "End level of console");
1317: cli_addCommand(cli_buffer, "config", -1, cli_Cmd_Config, "config <cr>",
1318: "Config next level of console");
1319: cli_addCommand(cli_buffer, "-------", -1, NULL, "-------------------------", NULL);
1.3 misho 1320:
1321: /* fill key bindings */
1.6 misho 1322: /* ascii chars & ctrl+chars */
1.3 misho 1323: for (i = 0; i < 256; i++) {
1.22 ! misho 1324: *keys[i].key_ch = *inkeys[i].key_ch = (u_char) i;
! 1325: keys[i].key_len = inkeys[i].key_len = 1;
1.3 misho 1326:
1327: if (!i || i == *K_CTRL_D)
1328: keys[i].key_func = bufEOF;
1.22 ! misho 1329: if (i == *K_CTRL_M || i == *K_CTRL_J) {
1.3 misho 1330: keys[i].key_func = bufEOL;
1.22 ! misho 1331: inkeys[i].key_func = bufEOLin;
! 1332: }
! 1333: if (i == *K_CTRL_H || i == *K_BACKSPACE) {
! 1334: if (cli_buffer->line_prompt)
! 1335: keys[i].key_func = bufBS;
! 1336: inkeys[i].key_func = bufBSin;
! 1337: }
! 1338: if (i == *K_CTRL_C) {
1.3 misho 1339: keys[i].key_func = bufCLR;
1.22 ! misho 1340: inkeys[i].key_func = bufCLRin;
! 1341: }
! 1342: if (i == *K_CTRL_A) {
! 1343: if (cli_buffer->line_prompt)
! 1344: keys[i].key_func = bufBEGIN;
! 1345: inkeys[i].key_func = bufBEGINin;
! 1346: }
! 1347: if (i == *K_CTRL_E) {
! 1348: if (cli_buffer->line_prompt)
! 1349: keys[i].key_func = bufEND;
! 1350: inkeys[i].key_func = bufENDin;
! 1351: }
1.9 misho 1352: if (cli_buffer->line_prompt && i == *K_TAB)
1.3 misho 1353: keys[i].key_func = bufComp;
1.13 misho 1354: if (i == *K_CTRL_Z)
1.9 misho 1355: keys[i].key_func = bufEndNode;
1.22 ! misho 1356: if (i >= *K_SPACE && i < *K_BACKSPACE) {
1.3 misho 1357: keys[i].key_func = bufCHAR;
1.22 ! misho 1358: inkeys[i].key_func = bufCHARin;
! 1359: }
! 1360: if (i > *K_BACKSPACE && i < 0xff) {
1.3 misho 1361: keys[i].key_func = bufCHAR;
1.22 ! misho 1362: inkeys[i].key_func = bufCHARin;
! 1363: }
1.9 misho 1364: if (cli_buffer->line_prompt && i == '?')
1.3 misho 1365: keys[i].key_func = bufHelp;
1366: }
1.6 misho 1367: /* alt+chars */
1.3 misho 1368: for (i = 256; i < 512; i++) {
1.22 ! misho 1369: keys[i].key_ch[0] = inkeys[i].key_ch[0] = 0x1b;
! 1370: keys[i].key_ch[1] = inkeys[i].key_ch[1] = (u_char) i - 256;
! 1371: keys[i].key_len = inkeys[i].key_len = 2;
1.3 misho 1372: }
1373:
1.6 misho 1374: /* 3 bytes */
1.22 ! misho 1375: keys[i].key_len = inkeys[i].key_len = sizeof K_F1 - 1;
1.3 misho 1376: memcpy(keys[i].key_ch, K_F1, keys[i].key_len);
1.22 ! misho 1377: memcpy(inkeys[i].key_ch, K_F1, inkeys[i].key_len);
1.3 misho 1378: i++;
1.22 ! misho 1379: keys[i].key_len = inkeys[i].key_len = sizeof K_F2 - 1;
1.3 misho 1380: memcpy(keys[i].key_ch, K_F2, keys[i].key_len);
1.22 ! misho 1381: memcpy(inkeys[i].key_ch, K_F2, inkeys[i].key_len);
1.3 misho 1382: i++;
1.22 ! misho 1383: keys[i].key_len = inkeys[i].key_len = sizeof K_F3 - 1;
1.3 misho 1384: memcpy(keys[i].key_ch, K_F3, keys[i].key_len);
1.22 ! misho 1385: memcpy(inkeys[i].key_ch, K_F3, inkeys[i].key_len);
1.3 misho 1386: i++;
1.22 ! misho 1387: keys[i].key_len = inkeys[i].key_len = sizeof K_F4 - 1;
1.3 misho 1388: memcpy(keys[i].key_ch, K_F4, keys[i].key_len);
1.22 ! misho 1389: memcpy(inkeys[i].key_ch, K_F4, inkeys[i].key_len);
1.3 misho 1390: i++;
1.22 ! misho 1391: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F1 - 1;
1.3 misho 1392: memcpy(keys[i].key_ch, K_CTRL_SH_F1, keys[i].key_len);
1.22 ! misho 1393: memcpy(inkeys[i].key_ch, K_CTRL_SH_F1, inkeys[i].key_len);
1.3 misho 1394: i++;
1.22 ! misho 1395: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F2 - 1;
1.3 misho 1396: memcpy(keys[i].key_ch, K_CTRL_SH_F2, keys[i].key_len);
1.22 ! misho 1397: memcpy(inkeys[i].key_ch, K_CTRL_SH_F2, inkeys[i].key_len);
1.3 misho 1398: i++;
1.22 ! misho 1399: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F3 - 1;
1.3 misho 1400: memcpy(keys[i].key_ch, K_CTRL_SH_F3, keys[i].key_len);
1.22 ! misho 1401: memcpy(inkeys[i].key_ch, K_CTRL_SH_F3, inkeys[i].key_len);
1.3 misho 1402: i++;
1.22 ! misho 1403: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F4 - 1;
1.3 misho 1404: memcpy(keys[i].key_ch, K_CTRL_SH_F4, keys[i].key_len);
1.22 ! misho 1405: memcpy(inkeys[i].key_ch, K_CTRL_SH_F4, inkeys[i].key_len);
1.3 misho 1406: i++;
1.22 ! misho 1407: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F5 - 1;
1.3 misho 1408: memcpy(keys[i].key_ch, K_CTRL_SH_F5, keys[i].key_len);
1.22 ! misho 1409: memcpy(inkeys[i].key_ch, K_CTRL_SH_F5, inkeys[i].key_len);
1.3 misho 1410: i++;
1.22 ! misho 1411: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F6 - 1;
1.3 misho 1412: memcpy(keys[i].key_ch, K_CTRL_SH_F6, keys[i].key_len);
1.22 ! misho 1413: memcpy(inkeys[i].key_ch, K_CTRL_SH_F6, inkeys[i].key_len);
1.3 misho 1414: i++;
1.22 ! misho 1415: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F7 - 1;
1.3 misho 1416: memcpy(keys[i].key_ch, K_CTRL_SH_F7, keys[i].key_len);
1.22 ! misho 1417: memcpy(inkeys[i].key_ch, K_CTRL_SH_F7, inkeys[i].key_len);
1.3 misho 1418: i++;
1.22 ! misho 1419: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F8 - 1;
1.3 misho 1420: memcpy(keys[i].key_ch, K_CTRL_SH_F8, keys[i].key_len);
1.22 ! misho 1421: memcpy(inkeys[i].key_ch, K_CTRL_SH_F8, inkeys[i].key_len);
1.3 misho 1422: i++;
1.22 ! misho 1423: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F9 - 1;
1.3 misho 1424: memcpy(keys[i].key_ch, K_CTRL_SH_F9, keys[i].key_len);
1.22 ! misho 1425: memcpy(inkeys[i].key_ch, K_CTRL_SH_F9, inkeys[i].key_len);
1.3 misho 1426: i++;
1.22 ! misho 1427: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F10 - 1;
1.3 misho 1428: memcpy(keys[i].key_ch, K_CTRL_SH_F10, keys[i].key_len);
1.22 ! misho 1429: memcpy(inkeys[i].key_ch, K_CTRL_SH_F10, inkeys[i].key_len);
1.3 misho 1430: i++;
1.22 ! misho 1431: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F11 - 1;
1.3 misho 1432: memcpy(keys[i].key_ch, K_CTRL_SH_F11, keys[i].key_len);
1.22 ! misho 1433: memcpy(inkeys[i].key_ch, K_CTRL_SH_F11, inkeys[i].key_len);
1.3 misho 1434: i++;
1.22 ! misho 1435: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_SH_F12 - 1;
1.3 misho 1436: memcpy(keys[i].key_ch, K_CTRL_SH_F12, keys[i].key_len);
1.22 ! misho 1437: memcpy(inkeys[i].key_ch, K_CTRL_SH_F12, inkeys[i].key_len);
1.3 misho 1438: i++;
1.22 ! misho 1439: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F1 - 1;
1.3 misho 1440: memcpy(keys[i].key_ch, K_CTRL_F1, keys[i].key_len);
1.22 ! misho 1441: memcpy(inkeys[i].key_ch, K_CTRL_F1, inkeys[i].key_len);
1.3 misho 1442: i++;
1.22 ! misho 1443: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F2 - 1;
1.3 misho 1444: memcpy(keys[i].key_ch, K_CTRL_F2, keys[i].key_len);
1.22 ! misho 1445: memcpy(inkeys[i].key_ch, K_CTRL_F2, inkeys[i].key_len);
1.3 misho 1446: i++;
1.22 ! misho 1447: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F3 - 1;
1.3 misho 1448: memcpy(keys[i].key_ch, K_CTRL_F3, keys[i].key_len);
1.22 ! misho 1449: memcpy(inkeys[i].key_ch, K_CTRL_F3, inkeys[i].key_len);
1.3 misho 1450: i++;
1.22 ! misho 1451: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F4 - 1;
1.3 misho 1452: memcpy(keys[i].key_ch, K_CTRL_F4, keys[i].key_len);
1.22 ! misho 1453: memcpy(inkeys[i].key_ch, K_CTRL_F4, inkeys[i].key_len);
1.3 misho 1454: i++;
1.22 ! misho 1455: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F5 - 1;
1.3 misho 1456: memcpy(keys[i].key_ch, K_CTRL_F5, keys[i].key_len);
1.22 ! misho 1457: memcpy(inkeys[i].key_ch, K_CTRL_F5, inkeys[i].key_len);
1.3 misho 1458: i++;
1.22 ! misho 1459: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F6 - 1;
1.3 misho 1460: memcpy(keys[i].key_ch, K_CTRL_F6, keys[i].key_len);
1.22 ! misho 1461: memcpy(inkeys[i].key_ch, K_CTRL_F6, inkeys[i].key_len);
1.3 misho 1462: i++;
1.22 ! misho 1463: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F7 - 1;
1.3 misho 1464: memcpy(keys[i].key_ch, K_CTRL_F7, keys[i].key_len);
1.22 ! misho 1465: memcpy(inkeys[i].key_ch, K_CTRL_F7, inkeys[i].key_len);
1.3 misho 1466: i++;
1.22 ! misho 1467: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F8 - 1;
1.3 misho 1468: memcpy(keys[i].key_ch, K_CTRL_F8, keys[i].key_len);
1.22 ! misho 1469: memcpy(inkeys[i].key_ch, K_CTRL_F8, inkeys[i].key_len);
1.3 misho 1470: i++;
1.22 ! misho 1471: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F9 - 1;
1.3 misho 1472: memcpy(keys[i].key_ch, K_CTRL_F9, keys[i].key_len);
1.22 ! misho 1473: memcpy(inkeys[i].key_ch, K_CTRL_F9, inkeys[i].key_len);
1.3 misho 1474: i++;
1.22 ! misho 1475: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F10 - 1;
1.3 misho 1476: memcpy(keys[i].key_ch, K_CTRL_F10, keys[i].key_len);
1.22 ! misho 1477: memcpy(inkeys[i].key_ch, K_CTRL_F10, inkeys[i].key_len);
1.3 misho 1478: i++;
1.22 ! misho 1479: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F11 - 1;
1.3 misho 1480: memcpy(keys[i].key_ch, K_CTRL_F11, keys[i].key_len);
1.22 ! misho 1481: memcpy(inkeys[i].key_ch, K_CTRL_F11, inkeys[i].key_len);
1.3 misho 1482: i++;
1.22 ! misho 1483: keys[i].key_len = inkeys[i].key_len = sizeof K_CTRL_F12 - 1;
1.3 misho 1484: memcpy(keys[i].key_ch, K_CTRL_F12, keys[i].key_len);
1.22 ! misho 1485: memcpy(inkeys[i].key_ch, K_CTRL_F12, inkeys[i].key_len);
1.3 misho 1486: i++;
1.22 ! misho 1487: keys[i].key_len = inkeys[i].key_len = sizeof K_HOME - 1;
1.9 misho 1488: if (cli_buffer->line_prompt)
1489: keys[i].key_func = bufBEGIN;
1.3 misho 1490: memcpy(keys[i].key_ch, K_HOME, keys[i].key_len);
1.22 ! misho 1491: memcpy(inkeys[i].key_ch, K_HOME, inkeys[i].key_len);
1.3 misho 1492: i++;
1.22 ! misho 1493: keys[i].key_len = inkeys[i].key_len = sizeof K_END - 1;
1.9 misho 1494: if (cli_buffer->line_prompt)
1495: keys[i].key_func = bufEND;
1.3 misho 1496: memcpy(keys[i].key_ch, K_END, keys[i].key_len);
1.22 ! misho 1497: memcpy(inkeys[i].key_ch, K_END, inkeys[i].key_len);
1.3 misho 1498: i++;
1.22 ! misho 1499: keys[i].key_len = inkeys[i].key_len = sizeof K_UP - 1;
1.9 misho 1500: if (cli_buffer->line_prompt)
1501: keys[i].key_func = bufUP;
1.3 misho 1502: memcpy(keys[i].key_ch, K_UP, keys[i].key_len);
1.22 ! misho 1503: memcpy(inkeys[i].key_ch, K_UP, inkeys[i].key_len);
1.3 misho 1504: i++;
1.22 ! misho 1505: keys[i].key_len = inkeys[i].key_len = sizeof K_DOWN - 1;
1.9 misho 1506: if (cli_buffer->line_prompt)
1507: keys[i].key_func = bufDOWN;
1.3 misho 1508: memcpy(keys[i].key_ch, K_DOWN, keys[i].key_len);
1.22 ! misho 1509: memcpy(inkeys[i].key_ch, K_DOWN, inkeys[i].key_len);
1.3 misho 1510: i++;
1.22 ! misho 1511: keys[i].key_len = inkeys[i].key_len = sizeof K_RIGHT - 1;
1.9 misho 1512: if (cli_buffer->line_prompt)
1513: keys[i].key_func = bufRIGHT;
1.22 ! misho 1514: inkeys[i].key_func = bufRIGHTin;
1.3 misho 1515: memcpy(keys[i].key_ch, K_RIGHT, keys[i].key_len);
1.22 ! misho 1516: memcpy(inkeys[i].key_ch, K_RIGHT, inkeys[i].key_len);
1.3 misho 1517: i++;
1.22 ! misho 1518: keys[i].key_len = inkeys[i].key_len = sizeof K_LEFT - 1;
1.9 misho 1519: if (cli_buffer->line_prompt)
1520: keys[i].key_func = bufLEFT;
1.22 ! misho 1521: inkeys[i].key_func = bufLEFTin;
1.3 misho 1522: memcpy(keys[i].key_ch, K_LEFT, keys[i].key_len);
1.22 ! misho 1523: memcpy(inkeys[i].key_ch, K_LEFT, inkeys[i].key_len);
1.3 misho 1524: i++;
1.22 ! misho 1525: keys[i].key_len = inkeys[i].key_len = sizeof K_BTAB - 1;
1.9 misho 1526: if (cli_buffer->line_prompt)
1527: keys[i].key_func = bufBTAB;
1.3 misho 1528: memcpy(keys[i].key_ch, K_BTAB, keys[i].key_len);
1.22 ! misho 1529: memcpy(inkeys[i].key_ch, K_BTAB, inkeys[i].key_len);
1.3 misho 1530: i++;
1.6 misho 1531: /* 4 bytes */
1.22 ! misho 1532: keys[i].key_len = inkeys[i].key_len = sizeof K_INS - 1;
1.9 misho 1533: if (cli_buffer->line_prompt)
1534: keys[i].key_func = bufMODE;
1.22 ! misho 1535: inkeys[i].key_func = bufMODE;
1.3 misho 1536: memcpy(keys[i].key_ch, K_INS, keys[i].key_len);
1.22 ! misho 1537: memcpy(inkeys[i].key_ch, K_INS, inkeys[i].key_len);
1.3 misho 1538: i++;
1.22 ! misho 1539: keys[i].key_len = inkeys[i].key_len = sizeof K_DEL - 1;
1.9 misho 1540: if (cli_buffer->line_prompt)
1541: keys[i].key_func = bufDEL;
1.22 ! misho 1542: inkeys[i].key_func = bufDELin;
1.3 misho 1543: memcpy(keys[i].key_ch, K_DEL, keys[i].key_len);
1.22 ! misho 1544: memcpy(inkeys[i].key_ch, K_DEL, inkeys[i].key_len);
1.3 misho 1545: i++;
1.22 ! misho 1546: keys[i].key_len = inkeys[i].key_len = sizeof K_PGUP - 1;
1.3 misho 1547: memcpy(keys[i].key_ch, K_PGUP, keys[i].key_len);
1.22 ! misho 1548: memcpy(inkeys[i].key_ch, K_PGUP, inkeys[i].key_len);
1.3 misho 1549: i++;
1.22 ! misho 1550: keys[i].key_len = inkeys[i].key_len = sizeof K_PGDN - 1;
1.3 misho 1551: memcpy(keys[i].key_ch, K_PGDN, keys[i].key_len);
1.22 ! misho 1552: memcpy(inkeys[i].key_ch, K_PGDN, inkeys[i].key_len);
1.3 misho 1553: i++;
1.6 misho 1554: /* 5 bytes */
1.22 ! misho 1555: keys[i].key_len = inkeys[i].key_len = sizeof K_F5 - 1;
1.3 misho 1556: memcpy(keys[i].key_ch, K_F5, keys[i].key_len);
1.22 ! misho 1557: memcpy(inkeys[i].key_ch, K_F5, inkeys[i].key_len);
1.3 misho 1558: i++;
1.22 ! misho 1559: keys[i].key_len = inkeys[i].key_len = sizeof K_F6 - 1;
1.3 misho 1560: memcpy(keys[i].key_ch, K_F6, keys[i].key_len);
1.22 ! misho 1561: memcpy(inkeys[i].key_ch, K_F6, inkeys[i].key_len);
1.3 misho 1562: i++;
1.22 ! misho 1563: keys[i].key_len = inkeys[i].key_len = sizeof K_F7 - 1;
1.3 misho 1564: memcpy(keys[i].key_ch, K_F7, keys[i].key_len);
1.22 ! misho 1565: memcpy(inkeys[i].key_ch, K_F7, inkeys[i].key_len);
1.3 misho 1566: i++;
1.22 ! misho 1567: keys[i].key_len = inkeys[i].key_len = sizeof K_F8 - 1;
1.3 misho 1568: memcpy(keys[i].key_ch, K_F8, keys[i].key_len);
1.22 ! misho 1569: memcpy(inkeys[i].key_ch, K_F8, inkeys[i].key_len);
1.3 misho 1570: i++;
1.22 ! misho 1571: keys[i].key_len = inkeys[i].key_len = sizeof K_F9 - 1;
1.3 misho 1572: memcpy(keys[i].key_ch, K_F9, keys[i].key_len);
1.22 ! misho 1573: memcpy(inkeys[i].key_ch, K_F9, inkeys[i].key_len);
1.3 misho 1574: i++;
1.22 ! misho 1575: keys[i].key_len = inkeys[i].key_len = sizeof K_F10 - 1;
1.3 misho 1576: memcpy(keys[i].key_ch, K_F10, keys[i].key_len);
1.22 ! misho 1577: memcpy(inkeys[i].key_ch, K_F10, inkeys[i].key_len);
1.3 misho 1578: i++;
1.22 ! misho 1579: keys[i].key_len = inkeys[i].key_len = sizeof K_F11 - 1;
1.3 misho 1580: memcpy(keys[i].key_ch, K_F11, keys[i].key_len);
1.22 ! misho 1581: memcpy(inkeys[i].key_ch, K_F11, inkeys[i].key_len);
1.3 misho 1582: i++;
1.22 ! misho 1583: keys[i].key_len = inkeys[i].key_len = sizeof K_F12 - 1;
1.3 misho 1584: memcpy(keys[i].key_ch, K_F12, keys[i].key_len);
1.22 ! misho 1585: memcpy(inkeys[i].key_ch, K_F12, inkeys[i].key_len);
1.3 misho 1586: i++;
1587:
1.7 misho 1588: cli_buffer->line_keys = keys;
1.22 ! misho 1589: cli_buffer->line_inkeys = inkeys;
1.7 misho 1590: return cli_buffer;
1.2 misho 1591: }
1592:
1593: /*
1.18 misho 1594: * cliSetLine() - Set CLI input line terminal
1.6 misho 1595: *
1.7 misho 1596: * @cli_buffer = CLI buffer
1.18 misho 1597: * @old = Old terminal settings
1598: * return: -1 error or 0 ok
1.2 misho 1599: */
1.3 misho 1600: int
1.18 misho 1601: cliSetLine(linebuffer_t * __restrict cli_buffer, struct termios * __restrict old)
1.2 misho 1602: {
1603: struct termios t;
1604:
1605: memset(&t, 0, sizeof t);
1.7 misho 1606: tcgetattr(cli_buffer->line_in, &t);
1.18 misho 1607: if (old)
1608: memcpy(old, &t, sizeof(struct termios));
1.9 misho 1609: t.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO |
1610: ECHOCTL | ECHOE | ECHOK | ECHOKE | ECHONL | ECHOPRT);
1.2 misho 1611: t.c_iflag |= IGNBRK;
1612: t.c_cc[VMIN] = 1;
1613: t.c_cc[VTIME] = 0;
1.7 misho 1614: return tcsetattr(cli_buffer->line_in, TCSANOW, &t);
1.3 misho 1615: }
1616:
1617: /*
1.18 misho 1618: * cliResetLine() - Reset CLI input line terminal
1619: *
1620: * @cli_buffer = CLI buffer
1621: * @old = Original terminal settings
1622: * return: -1 error or 0 ok
1623: */
1624: int
1625: cliResetLine(linebuffer_t * __restrict cli_buffer, struct termios * __restrict orig)
1626: {
1627: return tcsetattr(cli_buffer->line_in, TCSANOW, orig);
1628: }
1629:
1630: /*
1.22 ! misho 1631: * cliEcho() - Switch echo on or off
! 1632: *
! 1633: * @cli_buffer = CLI buffer
! 1634: * @on = On or off for echo on input handler
! 1635: * return: -1 error or 0 ok
! 1636: */
! 1637: int
! 1638: cliEcho(linebuffer_t * __restrict cli_buffer, int on)
! 1639: {
! 1640: struct termios t;
! 1641:
! 1642: if (tcgetattr(cli_buffer->line_in, &t) == -1) {
! 1643: cli_SetErr(errno, "tcgetattr(%d) - %s", cli_buffer->line_in, strerror(errno));
! 1644: return -1;
! 1645: }
! 1646:
! 1647: if (on)
! 1648: t.c_lflag |= (ECHO);
! 1649: else
! 1650: t.c_lflag &= ~(ECHO);
! 1651:
! 1652: return tcsetattr(cli_buffer->line_in, TCSANOW, &t);
! 1653: }
! 1654:
! 1655: /*
1.6 misho 1656: * cliReadLine() - Read line from opened CLI session
1657: *
1.7 misho 1658: * @cli_buffer = CLI buffer
1.10 misho 1659: * @timeout = Session timeout (-1 infinit)
1.6 misho 1660: * return: NULL if error or !=NULL readed line, must be e_free after use!
1.3 misho 1661: */
1662: char *
1.12 misho 1663: cliReadLine(linebuffer_t * __restrict cli_buffer, int timeout)
1.3 misho 1664: {
1.10 misho 1665: int code, readLen, ret;
1.3 misho 1666: register int i;
1667: struct pollfd fds;
1668: char buf[BUFSIZ], *str = NULL;
1.2 misho 1669:
1.7 misho 1670: if (!cli_buffer) {
1.6 misho 1671: cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3 misho 1672: return NULL;
1.11 misho 1673: } else if (timeout > 0)
1.10 misho 1674: timeout *= 1000; /* convert from sec to ms */
1.2 misho 1675:
1.3 misho 1676: memset(&fds, 0, sizeof fds);
1.7 misho 1677: fds.fd = cli_buffer->line_in;
1.3 misho 1678: fds.events = POLLIN;
1679:
1.7 misho 1680: printfCR(cli_buffer, 1);
1.3 misho 1681: while (42) {
1.10 misho 1682: if ((ret = poll(&fds, 1, timeout)) < 1) {
1.22 ! misho 1683: if (!ret)
1.12 misho 1684: cli_buffer->line_kill = 1;
1.22 ! misho 1685: else
1.10 misho 1686: LOGERR;
1.22 ! misho 1687: return NULL;
1.3 misho 1688: }
1689:
1690: memset(buf, 0, sizeof buf);
1.22 ! misho 1691: readLen = read(cli_buffer->line_in, buf, sizeof buf - 1);
1.14 misho 1692: if (readLen < 1) {
1693: if (readLen)
1694: LOGERR;
1695: return NULL;
1.3 misho 1696: }
1697:
1.22 ! misho 1698: while (readLen)
! 1699: for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--)
! 1700: if (readLen >= cli_buffer->line_keys[i].key_len &&
! 1701: !memcmp(cli_buffer->line_keys[i].key_ch, buf,
! 1702: cli_buffer->line_keys[i].key_len)) {
! 1703: readLen -= cli_buffer->line_keys[i].key_len;
! 1704: if (readLen)
! 1705: memmove(buf, buf + cli_buffer->line_keys[i].key_len, readLen);
! 1706: else
! 1707: memset(buf, 0, cli_buffer->line_keys[i].key_len);
! 1708:
! 1709: if (cli_buffer->line_keys[i].key_func)
! 1710: if ((code = cli_buffer->line_keys[i].key_func(i, cli_buffer)))
! 1711: readLen = 0;
! 1712: }
1.3 misho 1713:
1714: if (code)
1715: break;
1716: }
1.2 misho 1717:
1.7 misho 1718: if (code != RETCODE_ERR && code != RETCODE_EOF && cli_buffer->line_buf)
1719: str = e_strdup(cli_buffer->line_buf);
1.3 misho 1720: return str;
1.2 misho 1721: }
1722:
1.22 ! misho 1723: /*
! 1724: * cliInputLine() - Input line from opened CLI session
! 1725: *
! 1726: * @cli_buffer = CLI buffer
! 1727: * @timeout = Session timeout (-1 infinit)
! 1728: * return: NULL if error or !=NULL readed line, must be e_free after use!
! 1729: */
! 1730: char *
! 1731: cliInputLine(linebuffer_t * __restrict cli_buffer, int timeout)
! 1732: {
! 1733: int code, readLen, ret;
! 1734: register int i;
! 1735: struct pollfd fds;
! 1736: char buf[BUFSIZ], *str = NULL;
! 1737:
! 1738: if (!cli_buffer) {
! 1739: cli_SetErr(EINVAL, "Invalid input parameters ...");
! 1740: return NULL;
! 1741: } else if (timeout > 0)
! 1742: timeout *= 1000; /* convert from sec to ms */
! 1743:
! 1744: memset(&fds, 0, sizeof fds);
! 1745: fds.fd = cli_buffer->line_in;
! 1746: fds.events = POLLIN;
! 1747:
! 1748: while (42) {
! 1749: if ((ret = poll(&fds, 1, timeout)) < 1) {
! 1750: if (ret == -1)
! 1751: LOGERR;
! 1752: return NULL;
! 1753: }
! 1754:
! 1755: memset(buf, 0, sizeof buf);
! 1756: readLen = read(cli_buffer->line_in, buf, sizeof buf - 1);
! 1757: if (readLen < 1) {
! 1758: if (readLen)
! 1759: LOGERR;
! 1760: return NULL;
! 1761: }
! 1762:
! 1763: while (readLen)
! 1764: for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--)
! 1765: if (readLen >= cli_buffer->line_inkeys[i].key_len &&
! 1766: !memcmp(cli_buffer->line_inkeys[i].key_ch, buf,
! 1767: cli_buffer->line_inkeys[i].key_len)) {
! 1768: readLen -= cli_buffer->line_inkeys[i].key_len;
! 1769: if (readLen)
! 1770: memmove(buf, buf + cli_buffer->line_inkeys[i].key_len, readLen);
! 1771: else
! 1772: memset(buf, 0, cli_buffer->line_inkeys[i].key_len);
! 1773:
! 1774: if (cli_buffer->line_inkeys[i].key_func)
! 1775: if ((code = cli_buffer->line_inkeys[i].key_func(i, cli_buffer)))
! 1776: readLen = 0;
! 1777: }
! 1778:
! 1779: if (code)
! 1780: break;
! 1781: }
! 1782:
! 1783: if (code != RETCODE_ERR && code != RETCODE_EOF && cli_buffer->line_input)
! 1784: str = e_strdup(cli_buffer->line_input);
! 1785: return str;
! 1786: }
! 1787:
1.3 misho 1788:
1.2 misho 1789: /*
1.6 misho 1790: * cliNetLoop() - CLI network main loop binded to socket
1791: *
1.7 misho 1792: * @cli_buffer = CLI buffer
1.3 misho 1793: * @csHistFile = History file name
1.2 misho 1794: * @sock = client socket
1.10 misho 1795: * @timeout = Session timeout (-1 infinit)
1.3 misho 1796: * return: RETCODE_ERR error, RETCODE_OK ok
1.2 misho 1797: */
1.3 misho 1798: int
1.10 misho 1799: cliNetLoop(linebuffer_t * __restrict cli_buffer, const char *csHistFile,
1.12 misho 1800: int sock, int timeout)
1.2 misho 1801: {
1.3 misho 1802: u_char buf[BUFSIZ];
1.15 misho 1803: int pid, stat, pty, s, alen, flg, attrlen = 0, ret = 0;
1.2 misho 1804: fd_set fds;
1805: struct timeval tv = { DEFAULT_SOCK_TIMEOUT, 0 };
1806: struct telnetAttrs *a, Attr[10];
1807:
1.3 misho 1808: switch ((pid = forkpty(&pty, NULL, NULL, NULL))) {
1.2 misho 1809: case -1:
1810: LOGERR;
1811: return -1;
1812: case 0:
1.7 misho 1813: if (!cli_buffer) {
1.6 misho 1814: cli_SetErr(EINVAL, "Invalid input parameters ...");
1.3 misho 1815: return -1;
1816: } else
1817: close(sock);
1.2 misho 1818:
1.12 misho 1819: ret = cliLoop(cli_buffer, csHistFile, timeout) < 0 ? 1 : 0;
1.7 misho 1820: cliEnd(cli_buffer);
1.2 misho 1821:
1.8 misho 1822: _exit(ret);
1.2 misho 1823: default:
1.4 misho 1824: cli_telnet_SetCmd(Attr + 0, DO, TELOPT_TTYPE);
1825: cli_telnet_SetCmd(Attr + 1, WILL, TELOPT_ECHO);
1826: cli_telnet_Set_SubOpt(Attr + 2, TELOPT_LFLOW, LFLOW_OFF, NULL, 0);
1827: cli_telnet_Set_SubOpt(Attr + 3, TELOPT_LFLOW, LFLOW_RESTART_XON, NULL, 0);
1828: cli_telnet_SetCmd(Attr + 4, DO, TELOPT_LINEMODE);
1829: if ((ret = cli_telnetSend(sock, Attr, 5, NULL, 0, 0)) == -1)
1.2 misho 1830: return -1;
1.4 misho 1831: else
1.2 misho 1832: flg = 0;
1833:
1834: while (42) {
1.3 misho 1835: if (waitpid(pid, &stat, WNOHANG))
1836: break;
1837:
1.2 misho 1838: FD_ZERO(&fds);
1839: FD_SET(sock, &fds);
1840: FD_SET(pty, &fds);
1841: if ((ret = select(FD_SETSIZE, &fds, NULL, NULL, &tv)) < 1) {
1842: if (!ret)
1843: cli_SetErr(ETIMEDOUT, "Client session timeout ...");
1844:
1845: break;
1846: }
1847:
1848: s = FD_ISSET(sock, &fds) ? pty : sock;
1849:
1.3 misho 1850: if (FD_ISSET(sock, &fds)) {
1851: memset(buf, 0, BUFSIZ);
1.4 misho 1852: if ((ret = cli_telnetRecv(sock, &a, &alen, buf, BUFSIZ)) < 0) {
1.3 misho 1853: if (a)
1.6 misho 1854: e_free(a);
1.3 misho 1855:
1856: if (-2 == ret)
1857: continue;
1858: // EOF
1859: if (-3 == ret)
1860: shutdown(sock, SHUT_RD);
1861: break;
1862: }
1863: attrlen = 0;
1864: if (1 == flg && alen) {
1.4 misho 1865: cli_telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_SGA);
1866: cli_telnet_SetCmd(&Attr[attrlen++], DO, TELOPT_ECHO);
1.3 misho 1867: }
1868: if (2 == flg && alen) {
1.4 misho 1869: cli_telnet_SetCmd(&Attr[attrlen++], WILL, TELOPT_ECHO);
1870: cli_telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW,
1.3 misho 1871: LFLOW_OFF, NULL, 0);
1.4 misho 1872: cli_telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW,
1.3 misho 1873: LFLOW_RESTART_XON, NULL, 0);
1.4 misho 1874: cli_telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_LINEMODE);
1.3 misho 1875: }
1.2 misho 1876: if (a)
1.6 misho 1877: e_free(a);
1.2 misho 1878:
1.3 misho 1879: if ((ret = write(pty, buf, ret)) == -1) {
1880: LOGERR;
1881: break;
1882: }
1883: }
1884:
1885: if (FD_ISSET(pty, &fds)) {
1886: memset(buf, 0, BUFSIZ);
1.14 misho 1887: if ((ret = read(pty, buf, BUFSIZ)) < 1) {
1888: if (ret)
1889: LOGERR;
1.3 misho 1890: break;
1891: }
1892:
1.4 misho 1893: if ((ret = cli_telnetSend(sock, Attr, pty == s ? 0 : attrlen,
1894: buf, ret, 0)) == -1)
1.3 misho 1895: break;
1.4 misho 1896: else
1.3 misho 1897: flg++;
1.2 misho 1898: }
1899: }
1900:
1901: close(pty);
1902: }
1903:
1904: return ret;
1905: }
1906:
1907: /*
1.17 misho 1908: * cliRun() - CLI run command line
1909: *
1910: * @cli_buffer = CLI buffer
1911: * @psInput = Input command line
1912: * @prompt = Display prompt after command
1913: * return: RETCODE_ERR error, RETCODE_OK ok
1914: */
1915: int
1916: cliRun(linebuffer_t * __restrict cli_buffer, char *psInput, int prompt)
1917: {
1918: char *line, *s, *t, **app, *items[MAX_PROMPT_ITEMS];
1919: int ret = RETCODE_OK;
1920: struct tagCommand *cmd;
1921:
1922: if (!psInput)
1923: return RETCODE_ERR;
1924: else
1925: line = psInput;
1926:
1927: // clear whitespaces
1928: for (s = line; isspace((int) *s); s++);
1929: if (*s) {
1930: for (t = s + strlen(s) - 1; t > s && isspace((int) *t); t--);
1931: *++t = 0;
1932: }
1933:
1934: if (*s) {
1935: memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
1936: for (app = items; app < items + MAX_PROMPT_ITEMS - 1 &&
1937: (*app = strsep(&s, " \t")); *app ? app++ : app);
1938:
1939: // exec_cmd ...
1940: SLIST_FOREACH(cmd, &cli_buffer->line_cmds, cmd_next) {
1941: if (!(cmd->cmd_level & (1 << cli_buffer->line_level)))
1942: continue;
1943: if (*items[0] && !strncmp(cmd->cmd_name, items[0], strlen(items[0])))
1944: break;
1945: }
1946:
1947: if (!cmd) {
1948: cli_Printf(cli_buffer, "%sCommand '%s' not found!\n",
1949: cli_buffer->line_prompt ? "\n" : "", items[0]);
1950: ret = RETCODE_ERR;
1951: } else
1952: if (cmd->cmd_func) {
1953: if (prompt && cli_buffer->line_prompt)
1954: cli_Printf(cli_buffer, "\n");
1955: ret = cmd->cmd_func(cli_buffer,
1956: cli_buffer->line_level, items);
1957: } else if (prompt) {
1958: clrscrEOL(cli_buffer);
1959: printfCR(cli_buffer, 1);
1960: }
1961: }
1962:
1963: return ret;
1964: }
1965:
1966: /*
1.6 misho 1967: * cliLoop() - CLI main loop
1968: *
1.7 misho 1969: * @cli_buffer = CLI buffer
1.3 misho 1970: * @csHistFile = History file name
1.10 misho 1971: * @timeout = Session timeout (-1 infinit)
1.3 misho 1972: * return: RETCODE_ERR error, RETCODE_OK ok
1.1 misho 1973: */
1.3 misho 1974: int
1.12 misho 1975: cliLoop(linebuffer_t * __restrict cli_buffer, const char *csHistFile, int timeout)
1.1 misho 1976: {
1.17 misho 1977: char *line;
1.3 misho 1978: int ret = RETCODE_OK;
1.18 misho 1979: struct termios t;
1.1 misho 1980:
1981: /* --- main body of CLI --- */
1.18 misho 1982: cliSetLine(cli_buffer, &t);
1.1 misho 1983:
1.7 misho 1984: if (cli_loadHistory(cli_buffer, csHistFile) == RETCODE_ERR)
1.3 misho 1985: return RETCODE_ERR;
1.1 misho 1986:
1987: do {
1.12 misho 1988: line = cliReadLine(cli_buffer, timeout);
1.3 misho 1989: if (!line) {
1.7 misho 1990: printfNL(cli_buffer, 0);
1.1 misho 1991: break;
1.3 misho 1992: } else
1.7 misho 1993: cli_addHistory(cli_buffer, NULL);
1.3 misho 1994:
1.17 misho 1995: ret = cliRun(cli_buffer, line, 42);
1.1 misho 1996:
1.7 misho 1997: cli_freeLine(cli_buffer);
1998: cli_resetHistory(cli_buffer);
1.6 misho 1999: e_free(line);
1.19 misho 2000: } while (!cli_buffer->line_kill);
1.1 misho 2001:
1.7 misho 2002: cli_saveHistory(cli_buffer, csHistFile, HISTORY_LINES);
1.18 misho 2003:
2004: /* --- restore tty --- */
2005: cliResetLine(cli_buffer, &t);
2006:
1.1 misho 2007: return ret;
2008: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>