Annotation of libaitcli/src/aitcli.c, revision 1.3.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.3.2.3 ! misho 6: * $Id: aitcli.c,v 1.3.2.2 2011/05/29 22:42:39 misho Exp $
1.1 misho 7: *
1.3.2.3 ! 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:
! 15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
! 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: // ------------------------------------------------
53:
54: int cli_Errno;
55: char cli_Error[STRSIZ];
56:
1.3 misho 57: #pragma GCC visibility pop
58:
59: // cli_GetErrno() Get error code of last operation
60: inline int
61: cli_GetErrno()
62: {
63: return cli_Errno;
64: }
65:
66: // io_GetError() Get error text of last operation
67: inline const char *
68: cli_GetError()
69: {
70: return cli_Error;
71: }
72:
73: // cli_SetErr() Set error to variables for internal use!!!
74: inline void
75: cli_SetErr(int eno, char *estr, ...)
76: {
77: va_list lst;
78:
79: cli_Errno = eno;
80: memset(cli_Error, 0, STRSIZ);
81: va_start(lst, estr);
82: vsnprintf(cli_Error, STRSIZ, estr, lst);
83: va_end(lst);
84: }
1.2 misho 85:
1.3 misho 86: // ------------------------------------------------------------
87:
88: static inline void
89: clrscrEOL(linebuffer_t * __restrict buf)
90: {
91: register int i;
92:
93: if (buf) {
94: write(buf->line_out, K_CR, 1);
1.1 misho 95:
1.3 misho 96: for (i = 0; i < buf->line_len; i++)
97: write(buf->line_out, K_SPACE, 1);
98: }
99: }
1.1 misho 100:
1.3 misho 101: static inline void
102: printfEOL(linebuffer_t * __restrict buf, int len, int prompt)
1.2 misho 103: {
1.3 misho 104: if (buf) {
105: write(buf->line_out, K_CR, 1);
106:
107: if (prompt && buf->line_prompt)
108: write(buf->line_out, buf->line_prompt, buf->line_bol);
109:
110: write(buf->line_out, buf->line_buf, len == -1 ? buf->line_eol - buf->line_bol: len);
111: }
1.2 misho 112: }
113:
1.3 misho 114: static inline void
115: printfCR(linebuffer_t * __restrict buf, int prompt)
1.2 misho 116: {
1.3 misho 117: if (buf) {
118: write(buf->line_out, K_CR, 1);
1.2 misho 119:
1.3 misho 120: if (prompt)
121: if (prompt && buf->line_prompt)
122: write(buf->line_out, buf->line_prompt, buf->line_bol);
1.2 misho 123: }
1.3 misho 124: }
125:
126: static inline void
127: printfNL(linebuffer_t * __restrict buf, int prompt)
128: {
129: if (buf) {
130: write(buf->line_out, K_ENTER, 1);
131:
132: if (prompt)
133: if (prompt && buf->line_prompt)
134: write(buf->line_out, buf->line_prompt, buf->line_bol);
135: }
136: }
137:
138: // ------------------------------------------------------------
139:
140: static int
141: bufCHAR(int idx, void * __restrict buffer)
142: {
143: linebuffer_t *buf = buffer;
144: int pos;
145:
146: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
147: return RETCODE_ERR;
148:
149: pos = buf->line_eol - buf->line_bol;
150:
151: if (buf->line_mode == LINEMODE_INS)
152: memmove(buf->line_buf + pos + buf->line_keys[idx].key_len, buf->line_buf + pos,
153: buf->line_len - buf->line_eol);
154: if (buf->line_mode == LINEMODE_INS || buf->line_eol == buf->line_len - 1)
155: buf->line_len += buf->line_keys[idx].key_len;
156: buf->line_eol += buf->line_keys[idx].key_len;
157:
158: memcpy(buf->line_buf + pos, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
159: buf->line_buf[buf->line_len - 1] = 0;
160:
161: write(buf->line_out, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
162:
163: if (buf->line_mode == LINEMODE_INS) {
164: write(buf->line_out, (const u_char*) buf->line_buf + pos + buf->line_keys[idx].key_len,
165: buf->line_len - buf->line_eol);
166: printfEOL(buf, -1, 1);
1.2 misho 167: }
1.3 misho 168: return RETCODE_OK;
169: }
170:
171: static int
172: bufEOL(int idx, void * __restrict buffer)
173: {
174: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
175: return RETCODE_ERR;
176:
177: printfCR(buffer, 1);
178: return RETCODE_EOL;
179: }
180:
181: static int
182: bufEOF(int idx, void * __restrict buffer)
183: {
184: /*
185: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
186: return RETCODE_ERR;
187: */
188:
189: return RETCODE_EOF;
190: }
191:
192: static int
193: bufUP(int idx, void * __restrict buffer)
194: {
195: linebuffer_t *buf = buffer;
196: int pos;
197:
198: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
199: return RETCODE_ERR;
200:
201: if (!buf->line_h)
202: buf->line_h = TAILQ_FIRST(&buf->line_history);
203: else
204: buf->line_h = TAILQ_NEXT(buf->line_h, hist_next);
205: if (!buf->line_h)
206: return RETCODE_OK;
207:
208: clrscrEOL(buf);
209: cli_freeLine(buf);
210:
211: pos = buf->line_eol - buf->line_bol;
212:
213: buf->line_len += buf->line_h->hist_len;
214: buf->line_eol += buf->line_h->hist_len;
215:
216: memcpy(buf->line_buf + pos, buf->line_h->hist_line, buf->line_h->hist_len);
217: buf->line_buf[buf->line_len - 1] = 0;
218:
219: printfEOL(buf, -1, 1);
220: return RETCODE_OK;
221: }
222:
223: static int
224: bufDOWN(int idx, void * __restrict buffer)
225: {
226: linebuffer_t *buf = buffer;
227: int pos;
228:
229: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
230: return RETCODE_ERR;
231:
232: if (!buf->line_h)
233: buf->line_h = TAILQ_LAST(&buf->line_history, tqHistoryHead);
234: else
235: buf->line_h = TAILQ_PREV(buf->line_h, tqHistoryHead, hist_next);
236: if (!buf->line_h)
237: return RETCODE_OK;
238:
239: clrscrEOL(buf);
240: cli_freeLine(buf);
241:
242: pos = buf->line_eol - buf->line_bol;
243:
244: buf->line_len += buf->line_h->hist_len;
245: buf->line_eol += buf->line_h->hist_len;
246:
247: memcpy(buf->line_buf + pos, buf->line_h->hist_line, buf->line_h->hist_len);
248: buf->line_buf[buf->line_len - 1] = 0;
249:
250: printfEOL(buf, -1, 1);
251: return RETCODE_OK;
252: }
253:
254: static int
255: bufCLR(int idx, void * __restrict buffer)
256: {
257: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
258: return RETCODE_ERR;
259:
260: clrscrEOL(buffer);
261: cli_freeLine(buffer);
262:
263: printfCR(buffer, 1);
264: return RETCODE_OK;
265: }
266:
267: static int
268: bufBS(int idx, void * __restrict buffer)
269: {
270: linebuffer_t *buf = buffer;
271:
272: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
273: return RETCODE_ERR;
274:
275: if (buf->line_bol < buf->line_eol) {
276: clrscrEOL(buf);
277:
278: buf->line_eol--;
279: buf->line_len--;
280: memmove(buf->line_buf + buf->line_eol - buf->line_bol,
281: buf->line_buf + buf->line_eol - buf->line_bol + 1,
282: buf->line_len - buf->line_eol);
283: buf->line_buf[buf->line_len - 1] = 0;
284:
285: printfEOL(buf, buf->line_len - 1, 1);
286: printfEOL(buf, -1, 1);
287: }
288:
289: return RETCODE_OK;
290: }
291:
292: static int
293: bufBTAB(int idx, void * __restrict buffer)
294: {
295: linebuffer_t *buf = buffer;
296:
297: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
298: return RETCODE_ERR;
299:
300: if (buf->line_bol < buf->line_eol) {
301: clrscrEOL(buf);
302:
303: buf->line_len = buf->line_eol - buf->line_bol + 1;
304: buf->line_buf[buf->line_len - 1] = 0;
305:
306: printfEOL(buf, -1, 1);
1.2 misho 307: }
308:
1.3 misho 309: return RETCODE_OK;
310: }
311:
312: static int
313: bufMODE(int idx, void * __restrict buffer)
314: {
315: linebuffer_t *buf = buffer;
316:
317: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
318: return RETCODE_ERR;
319:
320: buf->line_mode = !buf->line_mode ? LINEMODE_OVER : LINEMODE_INS;
321: return RETCODE_OK;
322: }
323:
324: static int
325: bufBEGIN(int idx, void * __restrict buffer)
326: {
327: linebuffer_t *buf = buffer;
328:
329: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
330: return RETCODE_ERR;
331:
332: buf->line_eol = buf->line_bol;
333:
334: printfCR(buf, 1);
335: return RETCODE_OK;
336: }
337:
338: static int
339: bufEND(int idx, void * __restrict buffer)
340: {
341: linebuffer_t *buf = buffer;
342:
343: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
344: return RETCODE_ERR;
345:
346: buf->line_eol = buf->line_len - 1;
347:
348: printfEOL(buf, -1, 1);
349: return RETCODE_OK;
1.2 misho 350: }
351:
1.3 misho 352: static int
353: bufLEFT(int idx, void * __restrict buffer)
1.2 misho 354: {
1.3 misho 355: linebuffer_t *buf = buffer;
356:
357: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
358: return RETCODE_ERR;
359:
360: if (buf->line_bol < buf->line_eol)
361: printfEOL(buf, --buf->line_eol - buf->line_bol, 1);
362:
363: return RETCODE_OK;
364: }
1.2 misho 365:
1.3 misho 366: static int
367: bufRIGHT(int idx, void * __restrict buffer)
368: {
369: linebuffer_t *buf = buffer;
370:
371: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
372: return RETCODE_ERR;
373:
374: if (buf->line_eol < buf->line_len - 1)
375: printfEOL(buf, ++buf->line_eol - buf->line_bol, 1);
376:
377: return RETCODE_OK;
378: }
379:
380: static int
381: bufDEL(int idx, void * __restrict buffer)
382: {
383: linebuffer_t *buf = buffer;
384:
385: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
386: return RETCODE_ERR;
387:
388: clrscrEOL(buf);
389:
390: buf->line_len--;
391: memmove(buf->line_buf + buf->line_eol - buf->line_bol,
392: buf->line_buf + buf->line_eol - buf->line_bol + 1,
393: buf->line_len - buf->line_eol);
394: buf->line_buf[buf->line_len - 1] = 0;
395:
396: printfEOL(buf, buf->line_len - 1, 1);
397: printfEOL(buf, -1, 1);
398:
399: return RETCODE_OK;
400: }
401:
402: static int
403: bufComp(int idx, void * __restrict buffer)
404: {
405: linebuffer_t *buf = buffer;
406: char *str, *s, **app, *items[MAX_PROMPT_ITEMS], szLine[STRSIZ];
407: register int i, j;
408: struct tagCommand *cmd, *c;
409: int pos, ret = RETCODE_OK;
410:
411: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
412: return RETCODE_ERR;
413:
414: str = strdup(buf->line_buf);
415: if (!str)
416: return RETCODE_ERR;
1.2 misho 417: else {
1.3 misho 418: s = str;
419: io_TrimStr((u_char*) s);
420: }
421:
422: i = j = 0;
423: c = NULL;
424: memset(szLine, 0, STRSIZ);
425: if (*s) {
426: memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
427: for (app = items, i = 0; app < items + MAX_PROMPT_ITEMS - 1 && (*app = strsep(&s, " \t"));
428: *app ? i++ : i, *app ? app++ : app);
429:
430: if (i) {
431: SLIST_FOREACH(cmd, &buf->line_cmds, cmd_next) {
432: if (cmd->cmd_level == buf->line_level &&
433: !strncmp(cmd->cmd_name, items[0], strlen(items[0]))) {
434: if (strncmp(cmd->cmd_name, CLI_CMD_SEP, strlen(CLI_CMD_SEP))) {
435: j++;
436: c = cmd;
437: strlcat(szLine, " ", STRSIZ);
438: strlcat(szLine, cmd->cmd_name, STRSIZ);
439: }
440: }
441: }
1.2 misho 442:
1.3 misho 443: if (i > 1 && c) {
444: /* we are on argument of command and has complition info */
445: j++; // always must be j > 1 ;) for arguments
446: strlcpy(szLine, c->cmd_info, STRSIZ);
447: }
448: } else {
449: /* we have valid char but i == 0, this case is illegal */
450: ret = RETCODE_ERR;
451: goto endcomp;
1.2 misho 452: }
1.3 misho 453: } else {
454: /* we on 0 position of prompt, show commands for this level */
455: SLIST_FOREACH(cmd, &buf->line_cmds, cmd_next) {
456: if (cmd->cmd_level == buf->line_level)
457: if (strncmp(cmd->cmd_name, CLI_CMD_SEP, strlen(CLI_CMD_SEP))) {
458: j++;
459: c = cmd;
460: strlcat(szLine, " ", STRSIZ);
461: strlcat(szLine, cmd->cmd_name, STRSIZ);
462: }
463: }
464: }
1.2 misho 465:
1.3 misho 466: /* completion show actions ... */
467: if (j > 1 && c) {
468: printfNL(buf, 0);
469: write(buf->line_out, szLine, strlen(szLine));
470: printfNL(buf, 1);
471: printfEOL(buf, buf->line_len - 1, 1);
472: printfEOL(buf, -1, 1);
1.2 misho 473: }
1.3 misho 474: if (j == 1 && c) {
475: clrscrEOL(buf);
476: cli_freeLine(buf);
477:
478: pos = buf->line_eol - buf->line_bol;
479:
480: buf->line_len += c->cmd_len + 1;
481: buf->line_eol += c->cmd_len + 1;
482:
483: memcpy(buf->line_buf + pos, c->cmd_name, c->cmd_len);
484: buf->line_buf[pos + c->cmd_len] = (u_char) *K_SPACE;
485: buf->line_buf[buf->line_len - 1] = 0;
1.2 misho 486:
1.3 misho 487: printfEOL(buf, -1, 1);
1.2 misho 488: }
489:
1.3 misho 490: endcomp:
491: free(str);
492: return ret;
493: }
494:
495: static int
496: bufHelp(int idx, void * __restrict buffer)
497: {
498: linebuffer_t *buf = buffer;
499:
500: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
501: return RETCODE_ERR;
502:
503: cli_Cmd_Help(buf, -1, NULL);
504:
505: printfEOL(buf, buf->line_len - 1, 1);
506: printfEOL(buf, -1, 1);
507: return RETCODE_OK;
508: }
509:
510: // ---------------------------------------------------------------
511:
512: /*
513: * cli_Printf() Send message to CLI session
514: * @buffer = CLI buffer
515: * @fmt = printf format string
516: * @... = arguments defined in fmt
517: * return: none
518: */
519: inline void
520: cli_Printf(linebuffer_t * __restrict buffer, char *fmt, ...)
521: {
522: va_list lst;
523: FILE *f;
524:
525: if (fmt) {
526: f = fdopen(buffer->line_out, "a");
527: if (!f) {
528: LOGERR;
529: return;
530: }
531:
532: va_start(lst, fmt);
533: vfprintf(f, fmt, lst);
534: va_end(lst);
535: } else
536: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
537: }
538:
539: /*
540: * cli_PrintHelp() Print help screen
541: * @buffer = CLI buffer
542: * return: none
543: */
544: inline void
545: cli_PrintHelp(linebuffer_t * __restrict buffer)
546: {
547: if (buffer) {
548: bufHelp(0, buffer);
549: clrscrEOL(buffer);
550: } else
551: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
552: }
553:
554:
555: /*
556: * cli_BindKey() Bind function to key
557: * @key = key structure
558: * @buffer = CLI buffer
559: * return: RETCODE_ERR error, RETCODE_OK ok, >0 bind at position
560: */
561: int
562: cli_BindKey(bindkey_t * __restrict key, linebuffer_t * __restrict buffer)
563: {
564: register int i;
565:
566: if (!key || !buffer) {
567: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
568: return RETCODE_ERR;
1.2 misho 569: }
1.3 misho 570:
571: for (i = 0; i < MAX_BINDKEY; i++)
572: if (key->key_len == buffer->line_keys[i].key_len &&
573: !memcmp(key->key_ch, buffer->line_keys[i].key_ch, key->key_len)) {
574: buffer->line_keys[i].key_func = key->key_func;
575: return i;
576: }
577:
578: return RETCODE_OK;
1.2 misho 579: }
580:
581:
1.3 misho 582: /*
583: * cli_addCommand() Add command to CLI session
584: * @buffer = CLI buffer
585: * @csCmd = Command name
586: * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
587: * @funcCmd = Callback function when user call command
588: * @csInfo = Inline information for command
589: * @csHelp = Help line when call help
590: * return: RETCODE_ERR error, RETCODE_OK ok
591: */
592: int
593: cli_addCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel, cmd_func_t funcCmd,
594: const char *csInfo, const char *csHelp)
1.1 misho 595: {
1.3 misho 596: struct tagCommand *cmd;
597:
598: if (!buffer || !csCmd) {
599: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
600: return RETCODE_ERR;
601: }
602:
603: cmd = malloc(sizeof(struct tagCommand));
604: if (!cmd) {
605: LOGERR;
606: return RETCODE_ERR;
607: } else
608: memset(cmd, 0, sizeof(struct tagCommand));
609:
610: cmd->cmd_level = cliLevel;
611: cmd->cmd_func = funcCmd;
612: cmd->cmd_len = strlcpy(cmd->cmd_name, csCmd, STRSIZ);
613: if (csInfo)
614: strlcpy(cmd->cmd_info, csInfo, STRSIZ);
615: if (csHelp)
616: strlcpy(cmd->cmd_help, csHelp, STRSIZ);
617: SLIST_INSERT_HEAD(&buffer->line_cmds, cmd, cmd_next);
618: return RETCODE_OK;
1.1 misho 619: }
620:
1.3 misho 621: /*
622: * cli_delCommand() Delete command from CLI session
623: * @buffer = CLI buffer
624: * @csCmd = Command name
625: * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
626: * return: RETCODE_ERR error, RETCODE_OK ok
627: */
628: int
629: cli_delCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel)
1.1 misho 630: {
1.3 misho 631: struct tagCommand *cmd;
632: int ret = RETCODE_OK;
633:
634: if (!buffer || !csCmd) {
635: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
636: return RETCODE_ERR;
637: }
638:
639: SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next)
640: if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) {
641: ret = 1;
642: SLIST_REMOVE(&buffer->line_cmds, cmd, tagCommand, cmd_next);
643: free(cmd);
644: break;
645: }
646:
647: return ret;
1.1 misho 648: }
649:
1.3 misho 650: /*
651: * cli_updCommand() Update command in CLI session
652: * @buffer = CLI buffer
653: * @csCmd = Command name
654: * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
655: * @funcCmd = Callback function when user call command
656: * @csInfo = Inline information for command
657: * @csHelp = Help line when call help
658: * return: RETCODE_ERR error, RETCODE_OK ok
659: */
660: int
661: cli_updCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel, cmd_func_t funcCmd,
662: const char *csInfo, const char *csHelp)
1.1 misho 663: {
1.3 misho 664: struct tagCommand *cmd;
665: int ret = RETCODE_OK;
666:
667: if (!buffer || !csCmd) {
668: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
669: return RETCODE_ERR;
670: }
671:
672: SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next)
673: if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) {
674: ret = 1;
675:
676: if (funcCmd)
677: cmd->cmd_func = funcCmd;
678: if (csInfo)
679: strlcpy(cmd->cmd_info, csInfo, STRSIZ);
680: if (csHelp)
681: strlcpy(cmd->cmd_help, csHelp, STRSIZ);
682:
683: break;
684: }
1.1 misho 685:
1.3 misho 686: return ret;
1.1 misho 687: }
688:
689:
690: /*
1.3 misho 691: * cli_addHistory() Add line to history
692: * @buffer = CLI buffer
693: * @str = Add custom text or if NULL use readed line from CLI buffer
694: * return: RETCODE_ERR error, RETCODE_OK ok
1.1 misho 695: */
1.3 misho 696: int
697: cli_addHistory(linebuffer_t * __restrict buffer, const char * __restrict str)
1.1 misho 698: {
1.3 misho 699: struct tagHistory *h;
700:
701: if (!buffer) {
702: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
703: return RETCODE_ERR;
704: }
705:
706: if (!(h = malloc(sizeof(struct tagHistory)))) {
707: LOGERR;
708: return RETCODE_ERR;
709: } else
710: memset(h, 0, sizeof(struct tagHistory));
711:
712: if (str) {
713: if (!*str) {
714: free(h);
715: return RETCODE_OK;
716: }
717:
718: h->hist_len = strlcpy(h->hist_line, str, BUFSIZ);
719: } else {
720: if (!*buffer->line_buf || buffer->line_len < 2) {
721: free(h);
722: return RETCODE_OK;
723: }
724:
725: memcpy(h->hist_line, buffer->line_buf, (h->hist_len = buffer->line_len));
726: io_TrimStr((u_char*) h->hist_line);
727: h->hist_len = strlen(h->hist_line);
728: }
1.1 misho 729:
1.3 misho 730: TAILQ_INSERT_HEAD(&buffer->line_history, h, hist_next);
731: return h->hist_len;
732: }
1.1 misho 733:
1.3 misho 734: /*
735: * cli_saveHistory() Save history to file
736: * @buffer = CLI buffer
737: * @histfile = History filename, if NULL will be use default name
738: * @lines = Maximum history lines to save
739: * return: RETCODE_ERR error, RETCODE_OK ok
740: */
741: int
742: cli_saveHistory(linebuffer_t * __restrict buffer, const char *histfile, int lines)
743: {
744: FILE *f;
745: mode_t mode;
746: char szFName[MAXPATHLEN];
747: struct tagHistory *h;
748:
749: if (!buffer) {
750: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
751: return RETCODE_ERR;
752: }
753: if (!histfile)
754: strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
755: else
756: strlcpy(szFName, histfile, MAXPATHLEN);
757:
758: mode = umask(0177);
759: f = fopen(szFName, "w");
760: if (!f) {
1.1 misho 761: LOGERR;
1.3 misho 762: return RETCODE_ERR;
763: }
764:
765: TAILQ_FOREACH(h, &buffer->line_history, hist_next) {
766: fprintf(f, "%s\n", h->hist_line);
767:
768: if (lines)
769: lines--;
770: else
771: break;
772: }
1.1 misho 773:
1.3 misho 774: fclose(f);
775: umask(mode);
776:
777: return RETCODE_OK;
1.1 misho 778: }
779:
1.3 misho 780: /*
781: * cli_loadHistory() Load history from file
782: * @buffer = CLI buffer
783: * @histfile = History filename, if NULL will be use default name
784: * return: RETCODE_ERR error, RETCODE_OK ok
785: */
786: int
787: cli_loadHistory(linebuffer_t * __restrict buffer, const char *histfile)
788: {
789: FILE *f;
790: char szFName[MAXPATHLEN], buf[BUFSIZ];
791: struct tagHistory *h;
792:
793: if (!buffer) {
794: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
795: return RETCODE_ERR;
796: }
797: if (!histfile)
798: strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
799: else
800: strlcpy(szFName, histfile, MAXPATHLEN);
801:
802: f = fopen(szFName, "r");
803: if (!f)
804: return RETCODE_OK;
805:
806: while (fgets(buf, BUFSIZ, f)) {
807: if (!*buf || *buf == '#')
808: continue;
809: else
810: io_TrimStr((u_char*) buf);
811:
812: if (!(h = malloc(sizeof(struct tagHistory)))) {
813: LOGERR;
814: fclose(f);
815: return RETCODE_ERR;
816: } else
817: memset(h, 0, sizeof(struct tagHistory));
818:
819: h->hist_len = strlcpy(h->hist_line, buf, BUFSIZ);
820: TAILQ_INSERT_TAIL(&buffer->line_history, h, hist_next);
821: }
822:
823: fclose(f);
824:
825: return RETCODE_OK;
826: }
1.1 misho 827:
828: /*
1.3 misho 829: * cli_resetHistory() Reset history search in CLI session
830: * @buffer = CLI buffer
1.1 misho 831: * return: none
832: */
1.3 misho 833: inline void
834: cli_resetHistory(linebuffer_t * __restrict buffer)
1.1 misho 835: {
1.3 misho 836: buffer->line_h = NULL;
1.1 misho 837: }
838:
1.3 misho 839:
1.1 misho 840: /*
1.3 misho 841: * cli_freeLine() Clear entire line
842: * @buffer = CLI buffer
843: * return: RETCODE_ERR error, RETCODE_OK ok
1.2 misho 844: */
1.3 misho 845: inline int
846: cli_freeLine(linebuffer_t * __restrict buffer)
1.2 misho 847: {
1.3 misho 848: int code = RETCODE_ERR;
1.2 misho 849:
1.3 misho 850: if (buffer) {
851: if (buffer->line_buf)
852: free(buffer->line_buf);
853:
854: buffer->line_buf = malloc(BUFSIZ);
855: if (buffer->line_buf) {
856: memset(buffer->line_buf, 0, BUFSIZ);
857: buffer->line_eol = buffer->line_bol;
858: buffer->line_len = 1 + buffer->line_eol;
1.2 misho 859:
1.3 misho 860: code = RETCODE_OK;
861: } else
862: LOGERR;
863: } else
864: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
1.2 misho 865:
1.3 misho 866: return code;
1.2 misho 867: }
868:
869: /*
1.3 misho 870: * cli_setPrompt() Set new prompt for CLI session
871: * @buffer = CLI buffer
872: * @prompt = new text for prompt or if NULL disable prompt
873: * return: none
1.2 misho 874: */
1.3 misho 875: inline void
876: cli_setPrompt(linebuffer_t * __restrict buffer, const char *prompt)
1.2 misho 877: {
1.3 misho 878: if (buffer) {
879: if (buffer->line_prompt) {
880: free(buffer->line_prompt);
881: buffer->line_prompt = NULL;
882: buffer->line_bol = 0;
883: }
884:
885: if (prompt) {
886: buffer->line_prompt = strdup(prompt);
887: if (buffer->line_prompt) {
888: buffer->line_bol = strlen(buffer->line_prompt);
889: buffer->line_eol = buffer->line_bol;
890: buffer->line_len = 1 + buffer->line_eol;
891: } else
892: LOGERR;
893: }
894: } else
895: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
1.2 misho 896: }
897:
1.3 misho 898:
1.2 misho 899: /*
1.3 misho 900: * cliEnd() Clear data, Free resources and close CLI session
901: * @buffer = CLI buffer
902: * return: RETCODE_ERR error, RETCODE_OK ok
1.2 misho 903: */
1.3 misho 904: void
905: cliEnd(linebuffer_t * __restrict buffer)
1.2 misho 906: {
1.3 misho 907: struct tagHistory *h;
908: struct tagCommand *c;
909:
910: if (buffer) {
911: while ((c = SLIST_FIRST(&buffer->line_cmds))) {
912: SLIST_REMOVE_HEAD(&buffer->line_cmds, cmd_next);
913: free(c);
914: }
915: while ((h = TAILQ_FIRST(&buffer->line_history))) {
916: TAILQ_REMOVE(&buffer->line_history, h, hist_next);
917: free(h);
918: }
919:
920: if (buffer->line_prompt)
921: free(buffer->line_prompt);
1.2 misho 922:
1.3 misho 923: if (buffer->line_keys)
924: free(buffer->line_keys);
925: if (buffer->line_buf)
926: free(buffer->line_buf);
1.2 misho 927:
1.3 misho 928: free(buffer);
929: buffer = NULL;
930: } else
931: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
932: }
933:
934: /*
935: * cliInit() Start CLI session, allocate memory for resources and bind keys
936: * @fin = Input device handle
937: * @fout = Output device handle
938: * @prompt = text for prompt, if NULL disable prompt
939: * return: NULL if error or !=NULL CLI buffer
940: */
941: linebuffer_t *
942: cliInit(int fin, int fout, const char *prompt)
943: {
944: linebuffer_t *buffer;
945: bindkey_t *keys;
946: register int i;
947:
948: /* init buffer */
949: buffer = malloc(sizeof(linebuffer_t));
950: if (!buffer) {
951: LOGERR;
952: return NULL;
953: } else {
954: memset(buffer, 0, sizeof(linebuffer_t));
955:
956: buffer->line_in = fin;
957: buffer->line_out = fout;
958:
959: TAILQ_INIT(&buffer->line_history);
960: SLIST_INIT(&buffer->line_cmds);
961:
962: if (prompt) {
963: buffer->line_prompt = strdup(prompt);
964: if (!buffer->line_prompt) {
965: LOGERR;
966: free(buffer);
967: return NULL;
968: } else
969: buffer->line_eol = buffer->line_bol = strlen(buffer->line_prompt);
970: }
971: }
972: buffer->line_buf = malloc(BUFSIZ);
973: if (!buffer->line_buf) {
974: LOGERR;
975: if (buffer->line_prompt)
976: free(buffer->line_prompt);
977: free(buffer);
978: return NULL;
979: } else {
980: memset(buffer->line_buf, 0, BUFSIZ);
981: buffer->line_len = 1 + buffer->line_eol;
982: }
983: keys = calloc(MAX_BINDKEY + 1, sizeof(bindkey_t));
984: if (!keys) {
985: LOGERR;
986: if (buffer->line_prompt)
987: free(buffer->line_prompt);
988: free(buffer->line_buf);
989: free(buffer);
990: return NULL;
991: } else
992: memset(keys, 0, sizeof(bindkey_t) * (MAX_BINDKEY + 1));
993:
994: /* add helper functions */
995: cli_addCommand(buffer, "exit", 0, cli_Cmd_Exit, "exit <cr>", "Exit from console");
996: cli_addCommand(buffer, "help", 0, cli_Cmd_Help, "help [command] <cr>", "Help screen");
997: cli_addCommand(buffer, "-------", 0, NULL, "-------------------------", NULL);
998:
999: /* fill key bindings */
1000: // ascii chars & ctrl+chars
1001: for (i = 0; i < 256; i++) {
1002: *keys[i].key_ch = (u_char) i;
1003: keys[i].key_len = 1;
1004:
1005: if (!i || i == *K_CTRL_D)
1006: keys[i].key_func = bufEOF;
1007: if (i == *K_CTRL_M || i == *K_CTRL_J)
1008: keys[i].key_func = bufEOL;
1009: if (i == *K_CTRL_H || i == *K_BACKSPACE)
1010: keys[i].key_func = bufBS;
1011: if (i == *K_CTRL_C)
1012: keys[i].key_func = bufCLR;
1013: if (i == *K_CTRL_A)
1014: keys[i].key_func = bufBEGIN;
1015: if (i == *K_CTRL_E)
1016: keys[i].key_func = bufEND;
1017: if (i == *K_TAB)
1018: keys[i].key_func = bufComp;
1019: if (i >= *K_SPACE && i < *K_BACKSPACE)
1020: keys[i].key_func = bufCHAR;
1021: if (i > *K_BACKSPACE && i < 0xff)
1022: keys[i].key_func = bufCHAR;
1023: if (i == '?')
1024: keys[i].key_func = bufHelp;
1025: }
1026: // alt+chars
1027: for (i = 256; i < 512; i++) {
1028: keys[i].key_ch[0] = 0x1b;
1029: keys[i].key_ch[1] = (u_char) i - 256;
1030: keys[i].key_len = 2;
1031: }
1032:
1033: // 3 bytes
1034: keys[i].key_len = sizeof K_F1 - 1;
1035: memcpy(keys[i].key_ch, K_F1, keys[i].key_len);
1036: i++;
1037: keys[i].key_len = sizeof K_F2 - 1;
1038: memcpy(keys[i].key_ch, K_F2, keys[i].key_len);
1039: i++;
1040: keys[i].key_len = sizeof K_F3 - 1;
1041: memcpy(keys[i].key_ch, K_F3, keys[i].key_len);
1042: i++;
1043: keys[i].key_len = sizeof K_F4 - 1;
1044: memcpy(keys[i].key_ch, K_F4, keys[i].key_len);
1045: i++;
1046: keys[i].key_len = sizeof K_CTRL_SH_F1 - 1;
1047: memcpy(keys[i].key_ch, K_CTRL_SH_F1, keys[i].key_len);
1048: i++;
1049: keys[i].key_len = sizeof K_CTRL_SH_F2 - 1;
1050: memcpy(keys[i].key_ch, K_CTRL_SH_F2, keys[i].key_len);
1051: i++;
1052: keys[i].key_len = sizeof K_CTRL_SH_F3 - 1;
1053: memcpy(keys[i].key_ch, K_CTRL_SH_F3, keys[i].key_len);
1054: i++;
1055: keys[i].key_len = sizeof K_CTRL_SH_F4 - 1;
1056: memcpy(keys[i].key_ch, K_CTRL_SH_F4, keys[i].key_len);
1057: i++;
1058: keys[i].key_len = sizeof K_CTRL_SH_F5 - 1;
1059: memcpy(keys[i].key_ch, K_CTRL_SH_F5, keys[i].key_len);
1060: i++;
1061: keys[i].key_len = sizeof K_CTRL_SH_F6 - 1;
1062: memcpy(keys[i].key_ch, K_CTRL_SH_F6, keys[i].key_len);
1063: i++;
1064: keys[i].key_len = sizeof K_CTRL_SH_F7 - 1;
1065: memcpy(keys[i].key_ch, K_CTRL_SH_F7, keys[i].key_len);
1066: i++;
1067: keys[i].key_len = sizeof K_CTRL_SH_F8 - 1;
1068: memcpy(keys[i].key_ch, K_CTRL_SH_F8, keys[i].key_len);
1069: i++;
1070: keys[i].key_len = sizeof K_CTRL_SH_F9 - 1;
1071: memcpy(keys[i].key_ch, K_CTRL_SH_F9, keys[i].key_len);
1072: i++;
1073: keys[i].key_len = sizeof K_CTRL_SH_F10 - 1;
1074: memcpy(keys[i].key_ch, K_CTRL_SH_F10, keys[i].key_len);
1075: i++;
1076: keys[i].key_len = sizeof K_CTRL_SH_F11 - 1;
1077: memcpy(keys[i].key_ch, K_CTRL_SH_F11, keys[i].key_len);
1078: i++;
1079: keys[i].key_len = sizeof K_CTRL_SH_F12 - 1;
1080: memcpy(keys[i].key_ch, K_CTRL_SH_F12, keys[i].key_len);
1081: i++;
1082: keys[i].key_len = sizeof K_CTRL_F1 - 1;
1083: memcpy(keys[i].key_ch, K_CTRL_F1, keys[i].key_len);
1084: i++;
1085: keys[i].key_len = sizeof K_CTRL_F2 - 1;
1086: memcpy(keys[i].key_ch, K_CTRL_F2, keys[i].key_len);
1087: i++;
1088: keys[i].key_len = sizeof K_CTRL_F3 - 1;
1089: memcpy(keys[i].key_ch, K_CTRL_F3, keys[i].key_len);
1090: i++;
1091: keys[i].key_len = sizeof K_CTRL_F4 - 1;
1092: memcpy(keys[i].key_ch, K_CTRL_F4, keys[i].key_len);
1093: i++;
1094: keys[i].key_len = sizeof K_CTRL_F5 - 1;
1095: memcpy(keys[i].key_ch, K_CTRL_F5, keys[i].key_len);
1096: i++;
1097: keys[i].key_len = sizeof K_CTRL_F6 - 1;
1098: memcpy(keys[i].key_ch, K_CTRL_F6, keys[i].key_len);
1099: i++;
1100: keys[i].key_len = sizeof K_CTRL_F7 - 1;
1101: memcpy(keys[i].key_ch, K_CTRL_F7, keys[i].key_len);
1102: i++;
1103: keys[i].key_len = sizeof K_CTRL_F8 - 1;
1104: memcpy(keys[i].key_ch, K_CTRL_F8, keys[i].key_len);
1105: i++;
1106: keys[i].key_len = sizeof K_CTRL_F9 - 1;
1107: memcpy(keys[i].key_ch, K_CTRL_F9, keys[i].key_len);
1108: i++;
1109: keys[i].key_len = sizeof K_CTRL_F10 - 1;
1110: memcpy(keys[i].key_ch, K_CTRL_F10, keys[i].key_len);
1111: i++;
1112: keys[i].key_len = sizeof K_CTRL_F11 - 1;
1113: memcpy(keys[i].key_ch, K_CTRL_F11, keys[i].key_len);
1114: i++;
1115: keys[i].key_len = sizeof K_CTRL_F12 - 1;
1116: memcpy(keys[i].key_ch, K_CTRL_F12, keys[i].key_len);
1117: i++;
1118: keys[i].key_len = sizeof K_HOME - 1;
1119: keys[i].key_func = bufBEGIN;
1120: memcpy(keys[i].key_ch, K_HOME, keys[i].key_len);
1121: i++;
1122: keys[i].key_len = sizeof K_END - 1;
1123: keys[i].key_func = bufEND;
1124: memcpy(keys[i].key_ch, K_END, keys[i].key_len);
1125: i++;
1126: keys[i].key_len = sizeof K_UP - 1;
1127: keys[i].key_func = bufUP;
1128: memcpy(keys[i].key_ch, K_UP, keys[i].key_len);
1129: i++;
1130: keys[i].key_len = sizeof K_DOWN - 1;
1131: keys[i].key_func = bufDOWN;
1132: memcpy(keys[i].key_ch, K_DOWN, keys[i].key_len);
1133: i++;
1134: keys[i].key_len = sizeof K_RIGHT - 1;
1135: keys[i].key_func = bufRIGHT;
1136: memcpy(keys[i].key_ch, K_RIGHT, keys[i].key_len);
1137: i++;
1138: keys[i].key_len = sizeof K_LEFT - 1;
1139: keys[i].key_func = bufLEFT;
1140: memcpy(keys[i].key_ch, K_LEFT, keys[i].key_len);
1141: i++;
1142: keys[i].key_len = sizeof K_BTAB - 1;
1143: keys[i].key_func = bufBTAB;
1144: memcpy(keys[i].key_ch, K_BTAB, keys[i].key_len);
1145: i++;
1146: // 4 bytes
1147: keys[i].key_len = sizeof K_INS - 1;
1148: keys[i].key_func = bufMODE;
1149: memcpy(keys[i].key_ch, K_INS, keys[i].key_len);
1150: i++;
1151: keys[i].key_len = sizeof K_DEL - 1;
1152: keys[i].key_func = bufDEL;
1153: memcpy(keys[i].key_ch, K_DEL, keys[i].key_len);
1154: i++;
1155: keys[i].key_len = sizeof K_PGUP - 1;
1156: memcpy(keys[i].key_ch, K_PGUP, keys[i].key_len);
1157: i++;
1158: keys[i].key_len = sizeof K_PGDN - 1;
1159: memcpy(keys[i].key_ch, K_PGDN, keys[i].key_len);
1160: i++;
1161: // 5 bytes
1162: keys[i].key_len = sizeof K_F5 - 1;
1163: memcpy(keys[i].key_ch, K_F5, keys[i].key_len);
1164: i++;
1165: keys[i].key_len = sizeof K_F6 - 1;
1166: memcpy(keys[i].key_ch, K_F6, keys[i].key_len);
1167: i++;
1168: keys[i].key_len = sizeof K_F7 - 1;
1169: memcpy(keys[i].key_ch, K_F7, keys[i].key_len);
1170: i++;
1171: keys[i].key_len = sizeof K_F8 - 1;
1172: memcpy(keys[i].key_ch, K_F8, keys[i].key_len);
1173: i++;
1174: keys[i].key_len = sizeof K_F9 - 1;
1175: memcpy(keys[i].key_ch, K_F9, keys[i].key_len);
1176: i++;
1177: keys[i].key_len = sizeof K_F10 - 1;
1178: memcpy(keys[i].key_ch, K_F10, keys[i].key_len);
1179: i++;
1180: keys[i].key_len = sizeof K_F11 - 1;
1181: memcpy(keys[i].key_ch, K_F11, keys[i].key_len);
1182: i++;
1183: keys[i].key_len = sizeof K_F12 - 1;
1184: memcpy(keys[i].key_ch, K_F12, keys[i].key_len);
1185: i++;
1186:
1187: buffer->line_keys = keys;
1188: return buffer;
1.2 misho 1189: }
1190:
1191: /*
1.3 misho 1192: * cliInitLine() Init CLI input line terminal
1193: * @buffer = CLI buffer
1.2 misho 1194: * return: none
1195: */
1.3 misho 1196: int
1197: cliInitLine(linebuffer_t * __restrict buffer)
1.2 misho 1198: {
1199: struct termios t;
1200:
1201: memset(&t, 0, sizeof t);
1.3 misho 1202: tcgetattr(buffer->line_in, &t);
1.2 misho 1203: t.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO | ECHOCTL | ECHOE | ECHOK | ECHOKE | ECHONL | ECHOPRT);
1204: t.c_iflag |= IGNBRK;
1205: t.c_cc[VMIN] = 1;
1206: t.c_cc[VTIME] = 0;
1.3 misho 1207: return tcsetattr(buffer->line_in, TCSANOW, &t);
1208: }
1209:
1210: /*
1211: * cliReadLine() Read line from opened CLI session
1212: * @buffer = CLI buffer
1213: * return: NULL if error or !=NULL readed line, must be free after use!
1214: */
1215: char *
1216: cliReadLine(linebuffer_t * __restrict buffer)
1217: {
1218: int code, readLen;
1219: register int i;
1220: struct pollfd fds;
1221: char buf[BUFSIZ], *str = NULL;
1.2 misho 1222:
1.3 misho 1223: if (!buffer) {
1224: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
1225: return NULL;
1226: }
1.2 misho 1227:
1.3 misho 1228: memset(&fds, 0, sizeof fds);
1229: fds.fd = buffer->line_in;
1230: fds.events = POLLIN;
1231:
1232: printfCR(buffer, 1);
1233: while (42) {
1234: if (poll(&fds, 1, -1) < 1) {
1235: LOGERR;
1236: return str;
1237: }
1238:
1239: memset(buf, 0, sizeof buf);
1240: readLen = read(buffer->line_in, buf, BUFSIZ);
1241: if (readLen == -1) {
1242: LOGERR;
1243: return str;
1244: }
1245: if (!readLen) {
1246: if (buffer->line_buf)
1247: str = strdup(buffer->line_buf);
1248: else
1249: cli_SetErr(EPIPE, "Error:: unknown state ...");
1250: return str;
1251: }
1252:
1253: recheck:
1254: for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--)
1255: if (readLen >= buffer->line_keys[i].key_len &&
1256: !memcmp(buffer->line_keys[i].key_ch, buf,
1257: buffer->line_keys[i].key_len)) {
1258: readLen -= buffer->line_keys[i].key_len;
1259: if (readLen)
1260: memmove(buf, buf + buffer->line_keys[i].key_len, readLen);
1261: else
1262: memset(buf, 0, buffer->line_keys[i].key_len);
1263:
1264: if (buffer->line_keys[i].key_func)
1265: if ((code = buffer->line_keys[i].key_func(i, buffer)))
1266: readLen = 0;
1267:
1268: if (readLen)
1269: goto recheck;
1270: else
1271: break;
1272: }
1273:
1274: if (code)
1275: break;
1276: }
1.2 misho 1277:
1.3 misho 1278: if (code != RETCODE_ERR && code != RETCODE_EOF && buffer->line_buf)
1279: str = strdup(buffer->line_buf);
1280: return str;
1.2 misho 1281: }
1282:
1.3 misho 1283:
1.2 misho 1284: /*
1.3 misho 1285: * cliNetLoop() CLI network main loop binded to socket
1286: * @buffer = CLI buffer
1287: * @csHistFile = History file name
1.2 misho 1288: * @sock = client socket
1.3 misho 1289: * return: RETCODE_ERR error, RETCODE_OK ok
1.2 misho 1290: */
1.3 misho 1291: int
1292: cliNetLoop(linebuffer_t * __restrict buffer, const char *csHistFile, int sock)
1.2 misho 1293: {
1.3 misho 1294: u_char buf[BUFSIZ];
1295: int pid, stat, pty, r, s, alen, flg, attrlen = 0, ret = 0;
1.2 misho 1296: fd_set fds;
1297: struct timeval tv = { DEFAULT_SOCK_TIMEOUT, 0 };
1298: struct telnetAttrs *a, Attr[10];
1299:
1.3 misho 1300: switch ((pid = forkpty(&pty, NULL, NULL, NULL))) {
1.2 misho 1301: case -1:
1302: LOGERR;
1303: return -1;
1304: case 0:
1.3 misho 1305: if (!buffer) {
1306: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
1307: return -1;
1308: } else
1309: close(sock);
1.2 misho 1310:
1.3 misho 1311: ret = cliLoop(buffer, csHistFile) < 0 ? 1 : 0;
1312: cliEnd(buffer);
1.2 misho 1313:
1.3 misho 1314: exit(ret);
1.2 misho 1315: default:
1.3.2.1 misho 1316: cli_telnet_SetCmd(Attr + 0, DO, TELOPT_TTYPE);
1317: cli_telnet_SetCmd(Attr + 1, WILL, TELOPT_ECHO);
1318: cli_telnet_Set_SubOpt(Attr + 2, TELOPT_LFLOW, LFLOW_OFF, NULL, 0);
1319: cli_telnet_Set_SubOpt(Attr + 3, TELOPT_LFLOW, LFLOW_RESTART_XON, NULL, 0);
1320: cli_telnet_SetCmd(Attr + 4, DO, TELOPT_LINEMODE);
1321: if ((ret = cli_telnetSend(sock, Attr, 5, NULL, 0, 0)) == -1)
1.2 misho 1322: return -1;
1.3.2.1 misho 1323: else
1.2 misho 1324: flg = 0;
1325:
1326: while (42) {
1.3 misho 1327: if (waitpid(pid, &stat, WNOHANG))
1328: break;
1329:
1.2 misho 1330: FD_ZERO(&fds);
1331: FD_SET(sock, &fds);
1332: FD_SET(pty, &fds);
1333: if ((ret = select(FD_SETSIZE, &fds, NULL, NULL, &tv)) < 1) {
1334: if (!ret)
1335: cli_SetErr(ETIMEDOUT, "Client session timeout ...");
1336:
1337: break;
1338: }
1339:
1340: r = FD_ISSET(sock, &fds) ? sock : pty;
1341: s = FD_ISSET(sock, &fds) ? pty : sock;
1342:
1.3 misho 1343: if (FD_ISSET(sock, &fds)) {
1344: memset(buf, 0, BUFSIZ);
1.3.2.1 misho 1345: if ((ret = cli_telnetRecv(sock, &a, &alen, buf, BUFSIZ)) < 0) {
1.3 misho 1346: if (a)
1347: free(a);
1348:
1349: if (-2 == ret)
1350: continue;
1351: // EOF
1352: if (-3 == ret)
1353: shutdown(sock, SHUT_RD);
1354: break;
1355: }
1356: attrlen = 0;
1357: if (1 == flg && alen) {
1.3.2.1 misho 1358: cli_telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_SGA);
1359: cli_telnet_SetCmd(&Attr[attrlen++], DO, TELOPT_ECHO);
1.3 misho 1360: }
1361: if (2 == flg && alen) {
1.3.2.1 misho 1362: cli_telnet_SetCmd(&Attr[attrlen++], WILL, TELOPT_ECHO);
1363: cli_telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW,
1.3 misho 1364: LFLOW_OFF, NULL, 0);
1.3.2.1 misho 1365: cli_telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW,
1.3 misho 1366: LFLOW_RESTART_XON, NULL, 0);
1.3.2.1 misho 1367: cli_telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_LINEMODE);
1.3 misho 1368: }
1.2 misho 1369: if (a)
1370: free(a);
1371:
1.3 misho 1372: if ((ret = write(pty, buf, ret)) == -1) {
1373: LOGERR;
1374: break;
1375: }
1376: }
1377:
1378: if (FD_ISSET(pty, &fds)) {
1379: memset(buf, 0, BUFSIZ);
1380: if ((ret = read(pty, buf, BUFSIZ)) == -1) {
1381: LOGERR;
1382: break;
1383: }
1384:
1.3.2.1 misho 1385: if ((ret = cli_telnetSend(sock, Attr, pty == s ? 0 : attrlen,
1386: buf, ret, 0)) == -1)
1.3 misho 1387: break;
1.3.2.1 misho 1388: else
1.3 misho 1389: flg++;
1.2 misho 1390: }
1391: }
1392:
1393: close(pty);
1394: }
1395:
1396: return ret;
1397: }
1398:
1399: /*
1.3 misho 1400: * cliLoop() CLI main loop
1401: * @buffer = CLI buffer
1402: * @csHistFile = History file name
1403: * return: RETCODE_ERR error, RETCODE_OK ok
1.1 misho 1404: */
1.3 misho 1405: int
1406: cliLoop(linebuffer_t * __restrict buffer, const char *csHistFile)
1.1 misho 1407: {
1408: char *line, *s, *t, **app, *items[MAX_PROMPT_ITEMS];
1409: register int i;
1.3 misho 1410: int ret = RETCODE_OK;
1411: struct tagCommand *cmd;
1.1 misho 1412:
1413: /* --- main body of CLI --- */
1.3 misho 1414: cliInitLine(buffer);
1.1 misho 1415:
1.3 misho 1416: if (cli_loadHistory(buffer, csHistFile) == RETCODE_ERR)
1417: return RETCODE_ERR;
1.1 misho 1418:
1419: do {
1.3 misho 1420: line = cliReadLine(buffer);
1421: if (!line) {
1422: printfNL(buffer, 0);
1.1 misho 1423: break;
1.3 misho 1424: } else
1425: cli_addHistory(buffer, NULL);
1.1 misho 1426: // clear whitespaces
1.3.2.2 misho 1427: for (s = line; isspace((int) *s); s++);
1.1 misho 1428: if (*s) {
1.3.2.2 misho 1429: for (t = s + strlen(s) - 1; t > s && isspace((int) *t); t--);
1.1 misho 1430: *++t = 0;
1431: }
1432:
1433: if (*s) {
1434: memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
1435: for (app = items; app < items + MAX_PROMPT_ITEMS - 1 && (*app = strsep(&s, " \t"));
1436: *app ? app++ : app);
1437:
1438: // exec_cmd ...
1.3 misho 1439: i = 0;
1440: SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next) {
1441: if (*items[0] && !strncmp(cmd->cmd_name, items[0], strlen(items[0])))
1.1 misho 1442: break;
1.3 misho 1443: else
1444: i++;
1445: }
1446:
1.1 misho 1447: if (!cmd) {
1.3 misho 1448: cli_Printf(buffer, "\nCommand '%s' not found!\n", items[0]);
1.1 misho 1449: ret = -1;
1450: } else
1.3 misho 1451: if (cmd->cmd_func) {
1452: cli_Printf(buffer, "\n");
1453: ret = cmd->cmd_func(buffer, i, items);
1454: } else {
1455: clrscrEOL(buffer);
1456: printfCR(buffer, 1);
1457: }
1.1 misho 1458: }
1459:
1.3 misho 1460: cli_freeLine(buffer);
1461: cli_resetHistory(buffer);
1.1 misho 1462: free(line);
1463: } while (ret < 1);
1464:
1.3 misho 1465: cli_saveHistory(buffer, csHistFile, HISTORY_LINES);
1.1 misho 1466: return ret;
1467: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>