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