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