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