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