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