File:  [ELWIX - Embedded LightWeight unIX -] / libaitcli / src / aitcli.c
Revision 1.5: download - view: text, annotated - select for diffs - revision graph
Sun Jul 22 22:37:08 2012 UTC (11 years, 11 months ago) by misho
Branches: MAIN
CVS tags: cli3_0, cli2_3, HEAD, CLI2_3, CLI2_2
version 2.2

    1: /*************************************************************************
    2: * (C) 2010 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
    3: *  by Michael Pounov <misho@openbsd-bg.org>
    4: *
    5: * $Author: misho $
    6: * $Id: aitcli.c,v 1.5 2012/07/22 22:37:08 misho Exp $
    7: *
    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, 2012
   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: */
   46: #include "global.h"
   47: #include "cli.h"
   48: 
   49: 
   50: #pragma GCC visibility push(hidden)
   51: 
   52: // ------------------------------------------------
   53: 
   54: int cli_Errno;
   55: char cli_Error[STRSIZ];
   56: 
   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: }
   85: 
   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);
   95: 
   96: 		for (i = 0; i < buf->line_len; i++)
   97: 			write(buf->line_out, K_SPACE, 1);
   98: 	}
   99: }
  100: 
  101: static inline void
  102: printfEOL(linebuffer_t * __restrict buf, int len, int prompt)
  103: {
  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: 	}
  112: }
  113: 
  114: static inline void
  115: printfCR(linebuffer_t * __restrict buf, int prompt)
  116: {
  117: 	if (buf) {
  118: 		write(buf->line_out, K_CR, 1);
  119: 
  120: 		if (prompt)
  121: 			if (prompt && buf->line_prompt)
  122: 				write(buf->line_out, buf->line_prompt, buf->line_bol);
  123: 	}
  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);
  167: 	}
  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);
  307: 	}
  308: 
  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;
  350: }
  351: 
  352: static int
  353: bufLEFT(int idx, void * __restrict buffer)
  354: {
  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: }
  365: 
  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 = io_strdup(buf->line_buf);
  415: 	if (!str)
  416: 		return RETCODE_ERR;
  417: 	else {
  418: 		s = str;
  419: 		io_TrimStr(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: 			}
  442: 
  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;
  452: 		}
  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: 	}
  465: 
  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);
  473: 	}
  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;
  486: 
  487: 		printfEOL(buf, -1, 1);
  488: 	}
  489: 
  490: endcomp:
  491: 	io_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;
  569: 	}
  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;
  579: }
  580: 
  581: 
  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)
  595: {
  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 = io_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;
  619: }
  620: 
  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)
  630: {
  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: 			io_free(cmd);
  644: 			break;
  645: 		}
  646: 
  647: 	return ret;
  648: }
  649: 
  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)
  663: {
  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: 		}
  685: 
  686: 	return ret;
  687: }
  688: 
  689: 
  690: /*
  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
  695: */
  696: int
  697: cli_addHistory(linebuffer_t * __restrict buffer, const char * __restrict str)
  698: {
  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 = io_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: 			io_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: 			io_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(h->hist_line);
  727: 		h->hist_len = strlen(h->hist_line);
  728: 	}
  729: 
  730: 	TAILQ_INSERT_HEAD(&buffer->line_history, h, hist_next);
  731: 	return h->hist_len;
  732: }
  733: 
  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) {
  761: 		LOGERR;
  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: 	}
  773: 
  774: 	fclose(f);
  775: 	umask(mode);
  776: 
  777: 	return RETCODE_OK;
  778: }
  779: 
  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(buf);
  811: 
  812: 		if (!(h = io_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: }
  827: 
  828: /*
  829:  * cli_resetHistory() Reset history search in CLI session
  830:  * @buffer = CLI buffer
  831:  * return: none
  832: */
  833: inline void
  834: cli_resetHistory(linebuffer_t * __restrict buffer)
  835: {
  836: 	buffer->line_h = NULL;
  837: }
  838: 
  839: 
  840: /*
  841:  * cli_freeLine() Clear entire line
  842:  * @buffer = CLI buffer
  843:  * return: RETCODE_ERR error, RETCODE_OK ok
  844: */
  845: inline int
  846: cli_freeLine(linebuffer_t * __restrict buffer)
  847: {
  848: 	int code = RETCODE_ERR;
  849: 
  850: 	if (buffer) {
  851: 		if (buffer->line_buf)
  852: 			io_free(buffer->line_buf);
  853: 
  854: 		buffer->line_buf = io_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;
  859: 
  860: 			code = RETCODE_OK;
  861: 		} else
  862: 			LOGERR;
  863: 	} else
  864: 		cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
  865: 
  866: 	return code;
  867: }
  868: 
  869: /*
  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
  874: */
  875: inline void
  876: cli_setPrompt(linebuffer_t * __restrict buffer, const char *prompt)
  877: {
  878: 	if (buffer) {
  879: 		if (buffer->line_prompt) {
  880: 			io_free(buffer->line_prompt);
  881: 			buffer->line_prompt = NULL;
  882: 			buffer->line_bol = 0;
  883: 		}
  884: 
  885: 		if (prompt) {
  886: 			buffer->line_prompt = io_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 ...");
  896: }
  897: 
  898: 
  899: /*
  900:  * cliEnd() Clear data, Free resources and close CLI session
  901:  * @buffer = CLI buffer
  902:  * return: RETCODE_ERR error, RETCODE_OK ok
  903: */
  904: void
  905: cliEnd(linebuffer_t * __restrict buffer)
  906: {
  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: 			io_free(c);
  914: 		}
  915: 		while ((h = TAILQ_FIRST(&buffer->line_history))) {
  916: 			TAILQ_REMOVE(&buffer->line_history, h, hist_next);
  917: 			io_free(h);
  918: 		}
  919: 
  920: 		if (buffer->line_prompt)
  921: 			io_free(buffer->line_prompt);
  922: 
  923: 		if (buffer->line_keys)
  924: 			io_free(buffer->line_keys);
  925: 		if (buffer->line_buf)
  926: 			io_free(buffer->line_buf);
  927: 
  928: 		io_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 = io_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 = io_strdup(prompt);
  964: 			if (!buffer->line_prompt) {
  965: 				LOGERR;
  966: 				io_free(buffer);
  967: 				return NULL;
  968: 			} else
  969: 				buffer->line_eol = buffer->line_bol = strlen(buffer->line_prompt);
  970: 		}
  971: 	}
  972: 	buffer->line_buf = io_malloc(BUFSIZ);
  973: 	if (!buffer->line_buf) {
  974: 		LOGERR;
  975: 		if (buffer->line_prompt)
  976: 			io_free(buffer->line_prompt);
  977: 		io_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 = io_calloc(MAX_BINDKEY + 1, sizeof(bindkey_t));
  984: 	if (!keys) {
  985: 		LOGERR;
  986: 		if (buffer->line_prompt)
  987: 			io_free(buffer->line_prompt);
  988: 		io_free(buffer->line_buf);
  989: 		io_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;
 1189: }
 1190: 
 1191: /*
 1192:  * cliInitLine() Init CLI input line terminal
 1193:  * @buffer = CLI buffer
 1194:  * return: none
 1195: */
 1196: int
 1197: cliInitLine(linebuffer_t * __restrict buffer)
 1198: {
 1199: 	struct termios t;
 1200: 
 1201: 	memset(&t, 0, sizeof t);
 1202: 	tcgetattr(buffer->line_in, &t);
 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;
 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 io_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;
 1222: 
 1223: 	if (!buffer) {
 1224: 		cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
 1225: 		return NULL;
 1226: 	}
 1227: 
 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 = io_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: 	}
 1277: 
 1278: 	if (code != RETCODE_ERR && code != RETCODE_EOF && buffer->line_buf)
 1279: 		str = io_strdup(buffer->line_buf);
 1280: 	return str;
 1281: }
 1282: 
 1283: 
 1284: /*
 1285:  * cliNetLoop() CLI network main loop binded to socket
 1286:  * @buffer = CLI buffer
 1287:  * @csHistFile = History file name
 1288:  * @sock = client socket
 1289:  * return: RETCODE_ERR error, RETCODE_OK ok
 1290: */
 1291: int
 1292: cliNetLoop(linebuffer_t * __restrict buffer, const char *csHistFile, int sock)
 1293: {
 1294: 	u_char buf[BUFSIZ];
 1295: 	int pid, stat, pty, r, s, alen, flg, attrlen = 0, ret = 0;
 1296: 	fd_set fds;
 1297: 	struct timeval tv = { DEFAULT_SOCK_TIMEOUT, 0 };
 1298: 	struct telnetAttrs *a, Attr[10];
 1299: 
 1300: 	switch ((pid = forkpty(&pty, NULL, NULL, NULL))) {
 1301: 		case -1:
 1302: 			LOGERR;
 1303: 			return -1;
 1304: 		case 0:
 1305: 			if (!buffer) {
 1306: 				cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
 1307: 				return -1;
 1308: 			} else
 1309: 				close(sock);
 1310: 
 1311: 			ret = cliLoop(buffer, csHistFile) < 0 ? 1 : 0;
 1312: 			cliEnd(buffer);
 1313: 
 1314: 			exit(ret);
 1315: 		default:
 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)
 1322: 				return -1;
 1323: 			else
 1324: 				flg = 0;
 1325: 
 1326: 			while (42) {
 1327: 				if (waitpid(pid, &stat, WNOHANG))
 1328: 					break;
 1329: 
 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: 
 1343: 				if (FD_ISSET(sock, &fds)) {
 1344: 					memset(buf, 0, BUFSIZ);
 1345: 					if ((ret = cli_telnetRecv(sock, &a, &alen, buf, BUFSIZ)) < 0) {
 1346: 						if (a)
 1347: 							io_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) {
 1358: 						cli_telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_SGA);
 1359: 						cli_telnet_SetCmd(&Attr[attrlen++], DO, TELOPT_ECHO);
 1360: 					}
 1361: 					if (2 == flg && alen) {
 1362: 						cli_telnet_SetCmd(&Attr[attrlen++], WILL, TELOPT_ECHO);
 1363: 						cli_telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW, 
 1364: 								LFLOW_OFF, NULL, 0);
 1365: 						cli_telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW, 
 1366: 								LFLOW_RESTART_XON, NULL, 0);
 1367: 						cli_telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_LINEMODE);
 1368: 					}
 1369: 					if (a)
 1370: 						io_free(a);
 1371: 
 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: 
 1385: 					if ((ret = cli_telnetSend(sock, Attr, pty == s ? 0 : attrlen, 
 1386: 									buf, ret, 0)) == -1)
 1387: 						break;
 1388: 					else
 1389: 						flg++;
 1390: 				}
 1391: 			}
 1392: 
 1393: 			close(pty);
 1394: 	}
 1395: 
 1396: 	return ret;
 1397: }
 1398: 
 1399: /*
 1400:  * cliLoop() CLI main loop
 1401:  * @buffer = CLI buffer
 1402:  * @csHistFile = History file name
 1403:  * return: RETCODE_ERR error, RETCODE_OK ok
 1404: */
 1405: int
 1406: cliLoop(linebuffer_t * __restrict buffer, const char *csHistFile)
 1407: {
 1408: 	char *line, *s, *t, **app, *items[MAX_PROMPT_ITEMS];
 1409: 	register int i;
 1410: 	int ret = RETCODE_OK;
 1411: 	struct tagCommand *cmd;
 1412: 
 1413: 	/* --- main body of CLI --- */
 1414: 	cliInitLine(buffer);
 1415: 
 1416: 	if (cli_loadHistory(buffer, csHistFile) == RETCODE_ERR)
 1417: 		return RETCODE_ERR;
 1418: 
 1419: 	do {
 1420: 		line = cliReadLine(buffer);
 1421: 		if (!line) {
 1422: 			printfNL(buffer, 0);
 1423: 			break;
 1424: 		} else
 1425: 			cli_addHistory(buffer, NULL);
 1426: 		// clear whitespaces
 1427: 		for (s = line; isspace((int) *s); s++);
 1428: 		if (*s) {
 1429: 			for (t = s + strlen(s) - 1; t > s && isspace((int) *t); t--);
 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 ...
 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])))
 1442: 					break;
 1443: 				else
 1444: 					i++;
 1445: 			}
 1446: 
 1447: 			if (!cmd) {
 1448: 				cli_Printf(buffer, "\nCommand '%s' not found!\n", items[0]);
 1449: 				ret = -1;
 1450: 			} else
 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: 				}
 1458: 		}
 1459: 
 1460: 		cli_freeLine(buffer);
 1461: 		cli_resetHistory(buffer);
 1462: 		io_free(line);
 1463: 	} while (ret < 1);
 1464: 
 1465: 	cli_saveHistory(buffer, csHistFile, HISTORY_LINES);
 1466: 	return ret;
 1467: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>