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