File:  [ELWIX - Embedded LightWeight unIX -] / libaitcli / src / aitcli.c
Revision 1.2.2.21: download - view: text, annotated - select for diffs - revision graph
Tue Dec 7 16:33:46 2010 UTC (13 years, 8 months ago) by misho
Branches: cli2_0
Diff to: branchpoint 1.2: preferred, unified
little fency fix

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

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