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