File:  [ELWIX - Embedded LightWeight unIX -] / libaitcli / src / aitcli.c
Revision 1.2.2.15: download - view: text, annotated - select for diffs - revision graph
Tue Jun 8 08:43:47 2010 UTC (14 years, 1 month ago) by misho
Branches: cli2_0
Diff to: branchpoint 1.2: preferred, unified
add separator ability

    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.15 2010/06/08 08:43:47 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: 	else
  513: 		cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
  514: }
  515: 
  516: 
  517: /*
  518:  * cli_BindKey() Bind function to key
  519:  * @key = key structure
  520:  * @buffer = CLI buffer
  521:  * return: RETCODE_ERR error, RETCODE_OK ok, >0 bind at position
  522: */
  523: int
  524: cli_BindKey(bindkey_t * __restrict key, linebuffer_t * __restrict buffer)
  525: {
  526: 	register int i;
  527: 
  528: 	if (!key || !buffer) {
  529: 		cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
  530: 		return RETCODE_ERR;
  531: 	}
  532: 
  533: 	for (i = 0; i < MAX_BINDKEY; i++)
  534: 		if (key->key_len == buffer->line_keys[i].key_len && 
  535: 				!memcmp(key->key_ch, buffer->line_keys[i].key_ch, key->key_len)) {
  536: 			buffer->line_keys[i].key_func = key->key_func;
  537: 			return i;
  538: 		}
  539: 
  540: 	return RETCODE_OK;
  541: }
  542: 
  543: 
  544: /*
  545:  * cli_addCommand() Add command to CLI session
  546:  * @buffer = CLI buffer
  547:  * @csCmd = Command name
  548:  * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
  549:  * @funcCmd = Callback function when user call command
  550:  * @csInfo = Inline information for command
  551:  * @csHelp = Help line when call help
  552:  * return: RETCODE_ERR error, RETCODE_OK ok
  553: */
  554: int
  555: cli_addCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel, cmd_func_t funcCmd, 
  556: 		const char *csInfo, const char *csHelp)
  557: {
  558: 	struct tagCommand *cmd;
  559: 
  560: 	if (!buffer || !csCmd) {
  561: 		cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
  562: 		return RETCODE_ERR;
  563: 	}
  564: 
  565: 	cmd = malloc(sizeof(struct tagCommand));
  566: 	if (!cmd) {
  567: 		LOGERR;
  568: 		return RETCODE_ERR;
  569: 	} else
  570: 		memset(cmd, 0, sizeof(struct tagCommand));
  571: 
  572: 	cmd->cmd_level = cliLevel;
  573: 	cmd->cmd_func = funcCmd;
  574: 	cmd->cmd_len = strlcpy(cmd->cmd_name, csCmd, STRSIZ);
  575: 	if (csInfo)
  576: 		strlcpy(cmd->cmd_info, csInfo, STRSIZ);
  577: 	if (csHelp)
  578: 		strlcpy(cmd->cmd_help, csHelp, STRSIZ);
  579: 	SLIST_INSERT_HEAD(&buffer->line_cmds, cmd, cmd_next);
  580: 	return RETCODE_OK;
  581: }
  582: 
  583: /*
  584:  * cli_delCommand() Delete command from CLI session
  585:  * @buffer = CLI buffer
  586:  * @csCmd = Command name
  587:  * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
  588:  * return: RETCODE_ERR error, RETCODE_OK ok
  589: */
  590: int
  591: cli_delCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel)
  592: {
  593: 	struct tagCommand *cmd;
  594: 	int ret = RETCODE_OK;
  595: 
  596: 	if (!buffer || !csCmd) {
  597: 		cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
  598: 		return RETCODE_ERR;
  599: 	}
  600: 
  601: 	SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next) 
  602: 		if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) {
  603: 			ret = 1;
  604: 			SLIST_REMOVE(&buffer->line_cmds, cmd, tagCommand, cmd_next);
  605: 			free(cmd);
  606: 			break;
  607: 		}
  608: 
  609: 	return ret;
  610: }
  611: 
  612: /*
  613:  * cli_updCommand() Update command in CLI session
  614:  * @buffer = CLI buffer
  615:  * @csCmd = Command name
  616:  * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
  617:  * @funcCmd = Callback function when user call command
  618:  * @csInfo = Inline information for command
  619:  * @csHelp = Help line when call help
  620:  * return: RETCODE_ERR error, RETCODE_OK ok
  621: */
  622: int
  623: cli_updCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel, cmd_func_t funcCmd, 
  624: 		const char *csInfo, const char *csHelp)
  625: {
  626: 	struct tagCommand *cmd;
  627: 	int ret = RETCODE_OK;
  628: 
  629: 	if (!buffer || !csCmd) {
  630: 		cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
  631: 		return RETCODE_ERR;
  632: 	}
  633: 
  634: 	SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next) 
  635: 		if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) {
  636: 			ret = 1;
  637: 
  638: 			if (funcCmd)
  639: 				cmd->cmd_func = funcCmd;
  640: 			if (csInfo)
  641: 				strlcpy(cmd->cmd_info, csInfo, STRSIZ);
  642: 			if (csHelp)
  643: 				strlcpy(cmd->cmd_help, csHelp, STRSIZ);
  644: 
  645: 			break;
  646: 		}
  647: 
  648: 	return ret;
  649: }
  650: 
  651: 
  652: /*
  653:  * cli_addHistory() Add line to history
  654:  * @buffer = CLI buffer
  655:  * @str = Add custom text or if NULL use readed line from CLI buffer
  656:  * return: RETCODE_ERR error, RETCODE_OK ok
  657: */
  658: int
  659: cli_addHistory(linebuffer_t * __restrict buffer, const char * __restrict str)
  660: {
  661: 	struct tagHistory *h;
  662: 
  663: 	if (!buffer) {
  664: 		cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
  665: 		return RETCODE_ERR;
  666: 	}
  667: 
  668: 	if (!(h = malloc(sizeof(struct tagHistory)))) {
  669: 		LOGERR;
  670: 		return RETCODE_ERR;
  671: 	} else
  672: 		memset(h, 0, sizeof(struct tagHistory));
  673: 
  674: 	if (str) {
  675: 		if (!*str) {
  676: 			free(h);
  677: 			return RETCODE_OK;
  678: 		}
  679: 
  680: 		h->hist_len = strlcpy(h->hist_line, str, BUFSIZ);
  681: 	} else {
  682: 		if (!*buffer->line_buf || buffer->line_len < 2) {
  683: 			free(h);
  684: 			return RETCODE_OK;
  685: 		}
  686: 
  687: 		memcpy(h->hist_line, buffer->line_buf, (h->hist_len = buffer->line_len));
  688: 		io_TrimStr((u_char*) h->hist_line);
  689: 		h->hist_len = strlen(h->hist_line);
  690: 	}
  691: 
  692: 	TAILQ_INSERT_HEAD(&buffer->line_history, h, hist_next);
  693: 	return h->hist_len;
  694: }
  695: 
  696: /*
  697:  * cli_saveHistory() Save history to file
  698:  * @buffer = CLI buffer
  699:  * @histfile = History filename, if NULL will be use default name
  700:  * @lines = Maximum history lines to save
  701:  * return: RETCODE_ERR error, RETCODE_OK ok
  702: */
  703: int
  704: cli_saveHistory(linebuffer_t * __restrict buffer, const char *histfile, int lines)
  705: {
  706: 	FILE *f;
  707: 	mode_t mode;
  708: 	char szFName[MAXPATHLEN];
  709: 	struct tagHistory *h;
  710: 
  711: 	if (!buffer) {
  712: 		cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
  713: 		return RETCODE_ERR;
  714: 	}
  715: 	if (!histfile)
  716: 		strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
  717: 	else
  718: 		strlcpy(szFName, histfile, MAXPATHLEN);
  719: 
  720: 	mode = umask(0177);
  721: 	f = fopen(szFName, "w");
  722: 	if (!f) {
  723: 		LOGERR;
  724: 		return RETCODE_ERR;
  725: 	}
  726: 
  727: 	TAILQ_FOREACH(h, &buffer->line_history, hist_next) {
  728: 		fprintf(f, "%s\n", h->hist_line);
  729: 
  730: 		if (lines)
  731: 			lines--;
  732: 		else
  733: 			break;
  734: 	}
  735: 
  736: 	fclose(f);
  737: 	umask(mode);
  738: 
  739: 	return RETCODE_OK;
  740: }
  741: 
  742: /*
  743:  * cli_loadHistory() Load history from file
  744:  * @buffer = CLI buffer
  745:  * @histfile = History filename, if NULL will be use default name
  746:  * return: RETCODE_ERR error, RETCODE_OK ok
  747: */
  748: int
  749: cli_loadHistory(linebuffer_t * __restrict buffer, const char *histfile)
  750: {
  751: 	FILE *f;
  752: 	char szFName[MAXPATHLEN], buf[BUFSIZ];
  753: 	struct tagHistory *h;
  754: 
  755: 	if (!buffer) {
  756: 		cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
  757: 		return RETCODE_ERR;
  758: 	}
  759: 	if (!histfile)
  760: 		strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
  761: 	else
  762: 		strlcpy(szFName, histfile, MAXPATHLEN);
  763: 
  764: 	f = fopen(szFName, "r");
  765: 	if (!f)
  766: 		return RETCODE_OK;
  767: 
  768: 	while (fgets(buf, BUFSIZ, f)) {
  769: 		if (!*buf || *buf == '#')
  770: 			continue;
  771: 		else
  772: 			io_TrimStr((u_char*) buf);
  773: 
  774: 		if (!(h = malloc(sizeof(struct tagHistory)))) {
  775: 			LOGERR;
  776: 			fclose(f);
  777: 			return RETCODE_ERR;
  778: 		} else
  779: 			memset(h, 0, sizeof(struct tagHistory));
  780: 
  781: 		h->hist_len = strlcpy(h->hist_line, buf, BUFSIZ);
  782: 		TAILQ_INSERT_TAIL(&buffer->line_history, h, hist_next);
  783: 	}
  784: 
  785: 	fclose(f);
  786: 
  787: 	return RETCODE_OK;
  788: }
  789: 
  790: /*
  791:  * cli_resetHistory() Reset history search in CLI session
  792:  * @buffer = CLI buffer
  793:  * return: none
  794: */
  795: inline void
  796: cli_resetHistory(linebuffer_t * __restrict buffer)
  797: {
  798: 	buffer->line_h = NULL;
  799: }
  800: 
  801: 
  802: /*
  803:  * cli_freeLine() Clear entire line
  804:  * @buffer = CLI buffer
  805:  * return: RETCODE_ERR error, RETCODE_OK ok
  806: */
  807: inline int
  808: cli_freeLine(linebuffer_t * __restrict buffer)
  809: {
  810: 	int code = RETCODE_ERR;
  811: 
  812: 	if (buffer) {
  813: 		if (buffer->line_buf)
  814: 			free(buffer->line_buf);
  815: 
  816: 		buffer->line_buf = malloc(BUFSIZ);
  817: 		if (buffer->line_buf) {
  818: 			memset(buffer->line_buf, 0, BUFSIZ);
  819: 			buffer->line_eol = buffer->line_bol;
  820: 			buffer->line_len = 1 + buffer->line_eol;
  821: 
  822: 			code = RETCODE_OK;
  823: 		} else
  824: 			LOGERR;
  825: 	} else
  826: 		cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
  827: 
  828: 	return code;
  829: }
  830: 
  831: /*
  832:  * cli_setPrompt() Set new prompt for CLI session
  833:  * @buffer = CLI buffer
  834:  * @prompt = new text for prompt or if NULL disable prompt
  835:  * return: none
  836: */
  837: inline void
  838: cli_setPrompt(linebuffer_t * __restrict buffer, const char *prompt)
  839: {
  840: 	if (buffer) {
  841: 		if (buffer->line_prompt) {
  842: 			free(buffer->line_prompt);
  843: 			buffer->line_prompt = NULL;
  844: 			buffer->line_bol = 0;
  845: 		}
  846: 
  847: 		if (prompt) {
  848: 			buffer->line_prompt = strdup(prompt);
  849: 			if (buffer->line_prompt) {
  850: 				buffer->line_bol = strlen(buffer->line_prompt);
  851: 				buffer->line_eol = buffer->line_bol;
  852: 				buffer->line_len = 1 + buffer->line_eol;
  853: 			} else
  854: 				LOGERR;
  855: 		}
  856: 	} else
  857: 		cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
  858: }
  859: 
  860: 
  861: /*
  862:  * cliEnd() Clear data, Free resources and close CLI session
  863:  * @buffer = CLI buffer
  864:  * return: RETCODE_ERR error, RETCODE_OK ok
  865: */
  866: void
  867: cliEnd(linebuffer_t * __restrict buffer)
  868: {
  869: 	struct tagHistory *h;
  870: 	struct tagCommand *c;
  871: 
  872: 	if (buffer) {
  873: 		while ((c = SLIST_FIRST(&buffer->line_cmds))) {
  874: 			SLIST_REMOVE_HEAD(&buffer->line_cmds, cmd_next);
  875: 			free(c);
  876: 		}
  877: 		while ((h = TAILQ_FIRST(&buffer->line_history))) {
  878: 			TAILQ_REMOVE(&buffer->line_history, h, hist_next);
  879: 			free(h);
  880: 		}
  881: 
  882: 		if (buffer->line_prompt)
  883: 			free(buffer->line_prompt);
  884: 
  885: 		if (buffer->line_keys)
  886: 			free(buffer->line_keys);
  887: 		if (buffer->line_buf)
  888: 			free(buffer->line_buf);
  889: 
  890: 		free(buffer);
  891: 		buffer = NULL;
  892: 	} else
  893: 		cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
  894: }
  895: 
  896: /*
  897:  * cliInit() Start CLI session, allocate memory for resources and bind keys
  898:  * @fin = Input device handle
  899:  * @fout = Output device handle
  900:  * @prompt = text for prompt, if NULL disable prompt
  901:  * return: NULL if error or !=NULL CLI buffer
  902: */
  903: linebuffer_t *
  904: cliInit(int fin, int fout, const char *prompt)
  905: {
  906: 	linebuffer_t *buffer;
  907: 	bindkey_t *keys;
  908: 	register int i;
  909: 	struct termios t;
  910: 
  911: 	memset(&t, 0, sizeof t);
  912: 	/* init buffer */
  913: 	buffer = malloc(sizeof (linebuffer_t));
  914: 	if (!buffer) {
  915: 		LOGERR;
  916: 		return NULL;
  917: 	} else {
  918: 		memset(buffer, 0, sizeof(linebuffer_t));
  919: 
  920: 		buffer->line_in = fin;
  921: 		buffer->line_out = fout;
  922: 
  923: 		TAILQ_INIT(&buffer->line_history);
  924: 		SLIST_INIT(&buffer->line_cmds);
  925: 
  926: 		if (prompt) {
  927: 			buffer->line_prompt = strdup(prompt);
  928: 			if (!buffer->line_prompt) {
  929: 				LOGERR;
  930: 				free(buffer);
  931: 				return NULL;
  932: 			} else
  933: 				buffer->line_eol = buffer->line_bol = strlen(buffer->line_prompt);
  934: 		}
  935: 	}
  936: 	buffer->line_buf = malloc(BUFSIZ);
  937: 	if (!buffer->line_buf) {
  938: 		LOGERR;
  939: 		if (buffer->line_prompt)
  940: 			free(buffer->line_prompt);
  941: 		free(buffer);
  942: 		return NULL;
  943: 	} else {
  944: 		memset(buffer->line_buf, 0, BUFSIZ);
  945: 		buffer->line_len = 1 + buffer->line_eol;
  946: 	}
  947: 	keys = calloc(MAX_BINDKEY + 1, sizeof(bindkey_t));
  948: 	if (!keys) {
  949: 		LOGERR;
  950: 		if (buffer->line_prompt)
  951: 			free(buffer->line_prompt);
  952: 		free(buffer->line_buf);
  953: 		free(buffer);
  954: 		return NULL;
  955: 	} else
  956: 		memset(keys, 0, sizeof(bindkey_t) * (MAX_BINDKEY + 1));
  957: 
  958: 	/* add helper functions */
  959: 	cli_addCommand(buffer, "exit", 0, cli_Cmd_Exit, "exit <cr>", "Exit from console");
  960: 	cli_addCommand(buffer, "help", 0, cli_Cmd_Help, "help [command] <cr>", "Help screen");
  961: 	cli_addCommand(buffer, "-------", 0, NULL, "-------------------------", NULL);
  962: 
  963: 	/* fill key bindings */
  964: 	// ascii chars & ctrl+chars
  965: 	for (i = 0; i < 256; i++) {
  966: 		*keys[i].key_ch = (u_char) i;
  967: 		keys[i].key_len = 1;
  968: 
  969: 		if (!i || i == *K_CTRL_D)
  970: 			keys[i].key_func = bufEOF;
  971: 		if (i == *K_CTRL_M || i == *K_CTRL_J)
  972: 			keys[i].key_func = bufEOL;
  973: 		if (i == *K_CTRL_H || i == *K_BACKSPACE)
  974: 			keys[i].key_func = bufBS;
  975: 		if (i == *K_CTRL_C)
  976: 			keys[i].key_func = bufCLR;
  977: 		if (i == *K_CTRL_A)
  978: 			keys[i].key_func = bufBEGIN;
  979: 		if (i == *K_CTRL_E)
  980: 			keys[i].key_func = bufEND;
  981: 		if (i == *K_TAB)
  982: 			keys[i].key_func = bufComp;
  983: 		if (i >= *K_SPACE && i < *K_BACKSPACE)
  984: 			keys[i].key_func = bufCHAR;
  985: 		if (i > *K_BACKSPACE && i < 0xff)
  986: 			keys[i].key_func = bufCHAR;
  987: 		if (i == '?')
  988: 			keys[i].key_func = bufHelp;
  989: 	}
  990: 	// alt+chars
  991: 	for (i = 256; i < 512; i++) {
  992: 		keys[i].key_ch[0] = 0x1b;
  993: 		keys[i].key_ch[1] = (u_char) i - 256;
  994: 		keys[i].key_len = 2;
  995: 	}
  996: 
  997: 	// 3 bytes
  998: 	keys[i].key_len = sizeof K_F1 - 1;
  999: 	memcpy(keys[i].key_ch, K_F1, keys[i].key_len);
 1000: 	i++;
 1001: 	keys[i].key_len = sizeof K_F2 - 1;
 1002: 	memcpy(keys[i].key_ch, K_F2, keys[i].key_len);
 1003: 	i++;
 1004: 	keys[i].key_len = sizeof K_F3 - 1;
 1005: 	memcpy(keys[i].key_ch, K_F3, keys[i].key_len);
 1006: 	i++;
 1007: 	keys[i].key_len = sizeof K_F4 - 1;
 1008: 	memcpy(keys[i].key_ch, K_F4, keys[i].key_len);
 1009: 	i++;
 1010: 	keys[i].key_len = sizeof K_CTRL_SH_F1 - 1;
 1011: 	memcpy(keys[i].key_ch, K_CTRL_SH_F1, keys[i].key_len);
 1012: 	i++;
 1013: 	keys[i].key_len = sizeof K_CTRL_SH_F2 - 1;
 1014: 	memcpy(keys[i].key_ch, K_CTRL_SH_F2, keys[i].key_len);
 1015: 	i++;
 1016: 	keys[i].key_len = sizeof K_CTRL_SH_F3 - 1;
 1017: 	memcpy(keys[i].key_ch, K_CTRL_SH_F3, keys[i].key_len);
 1018: 	i++;
 1019: 	keys[i].key_len = sizeof K_CTRL_SH_F4 - 1;
 1020: 	memcpy(keys[i].key_ch, K_CTRL_SH_F4, keys[i].key_len);
 1021: 	i++;
 1022: 	keys[i].key_len = sizeof K_CTRL_SH_F5 - 1;
 1023: 	memcpy(keys[i].key_ch, K_CTRL_SH_F5, keys[i].key_len);
 1024: 	i++;
 1025: 	keys[i].key_len = sizeof K_CTRL_SH_F6 - 1;
 1026: 	memcpy(keys[i].key_ch, K_CTRL_SH_F6, keys[i].key_len);
 1027: 	i++;
 1028: 	keys[i].key_len = sizeof K_CTRL_SH_F7 - 1;
 1029: 	memcpy(keys[i].key_ch, K_CTRL_SH_F7, keys[i].key_len);
 1030: 	i++;
 1031: 	keys[i].key_len = sizeof K_CTRL_SH_F8 - 1;
 1032: 	memcpy(keys[i].key_ch, K_CTRL_SH_F8, keys[i].key_len);
 1033: 	i++;
 1034: 	keys[i].key_len = sizeof K_CTRL_SH_F9 - 1;
 1035: 	memcpy(keys[i].key_ch, K_CTRL_SH_F9, keys[i].key_len);
 1036: 	i++;
 1037: 	keys[i].key_len = sizeof K_CTRL_SH_F10 - 1;
 1038: 	memcpy(keys[i].key_ch, K_CTRL_SH_F10, keys[i].key_len);
 1039: 	i++;
 1040: 	keys[i].key_len = sizeof K_CTRL_SH_F11 - 1;
 1041: 	memcpy(keys[i].key_ch, K_CTRL_SH_F11, keys[i].key_len);
 1042: 	i++;
 1043: 	keys[i].key_len = sizeof K_CTRL_SH_F12 - 1;
 1044: 	memcpy(keys[i].key_ch, K_CTRL_SH_F12, keys[i].key_len);
 1045: 	i++;
 1046: 	keys[i].key_len = sizeof K_CTRL_F1 - 1;
 1047: 	memcpy(keys[i].key_ch, K_CTRL_F1, keys[i].key_len);
 1048: 	i++;
 1049: 	keys[i].key_len = sizeof K_CTRL_F2 - 1;
 1050: 	memcpy(keys[i].key_ch, K_CTRL_F2, keys[i].key_len);
 1051: 	i++;
 1052: 	keys[i].key_len = sizeof K_CTRL_F3 - 1;
 1053: 	memcpy(keys[i].key_ch, K_CTRL_F3, keys[i].key_len);
 1054: 	i++;
 1055: 	keys[i].key_len = sizeof K_CTRL_F4 - 1;
 1056: 	memcpy(keys[i].key_ch, K_CTRL_F4, keys[i].key_len);
 1057: 	i++;
 1058: 	keys[i].key_len = sizeof K_CTRL_F5 - 1;
 1059: 	memcpy(keys[i].key_ch, K_CTRL_F5, keys[i].key_len);
 1060: 	i++;
 1061: 	keys[i].key_len = sizeof K_CTRL_F6 - 1;
 1062: 	memcpy(keys[i].key_ch, K_CTRL_F6, keys[i].key_len);
 1063: 	i++;
 1064: 	keys[i].key_len = sizeof K_CTRL_F7 - 1;
 1065: 	memcpy(keys[i].key_ch, K_CTRL_F7, keys[i].key_len);
 1066: 	i++;
 1067: 	keys[i].key_len = sizeof K_CTRL_F8 - 1;
 1068: 	memcpy(keys[i].key_ch, K_CTRL_F8, keys[i].key_len);
 1069: 	i++;
 1070: 	keys[i].key_len = sizeof K_CTRL_F9 - 1;
 1071: 	memcpy(keys[i].key_ch, K_CTRL_F9, keys[i].key_len);
 1072: 	i++;
 1073: 	keys[i].key_len = sizeof K_CTRL_F10 - 1;
 1074: 	memcpy(keys[i].key_ch, K_CTRL_F10, keys[i].key_len);
 1075: 	i++;
 1076: 	keys[i].key_len = sizeof K_CTRL_F11 - 1;
 1077: 	memcpy(keys[i].key_ch, K_CTRL_F11, keys[i].key_len);
 1078: 	i++;
 1079: 	keys[i].key_len = sizeof K_CTRL_F12 - 1;
 1080: 	memcpy(keys[i].key_ch, K_CTRL_F12, keys[i].key_len);
 1081: 	i++;
 1082: 	keys[i].key_len = sizeof K_HOME - 1;
 1083: 	keys[i].key_func = bufBEGIN;
 1084: 	memcpy(keys[i].key_ch, K_HOME, keys[i].key_len);
 1085: 	i++;
 1086: 	keys[i].key_len = sizeof K_END - 1;
 1087: 	keys[i].key_func = bufEND;
 1088: 	memcpy(keys[i].key_ch, K_END, keys[i].key_len);
 1089: 	i++;
 1090: 	keys[i].key_len = sizeof K_UP - 1;
 1091: 	keys[i].key_func = bufUP;
 1092: 	memcpy(keys[i].key_ch, K_UP, keys[i].key_len);
 1093: 	i++;
 1094: 	keys[i].key_len = sizeof K_DOWN - 1;
 1095: 	keys[i].key_func = bufDOWN;
 1096: 	memcpy(keys[i].key_ch, K_DOWN, keys[i].key_len);
 1097: 	i++;
 1098: 	keys[i].key_len = sizeof K_RIGHT - 1;
 1099: 	keys[i].key_func = bufRIGHT;
 1100: 	memcpy(keys[i].key_ch, K_RIGHT, keys[i].key_len);
 1101: 	i++;
 1102: 	keys[i].key_len = sizeof K_LEFT - 1;
 1103: 	keys[i].key_func = bufLEFT;
 1104: 	memcpy(keys[i].key_ch, K_LEFT, keys[i].key_len);
 1105: 	i++;
 1106: 	keys[i].key_len = sizeof K_BTAB - 1;
 1107: 	keys[i].key_func = bufBTAB;
 1108: 	memcpy(keys[i].key_ch, K_BTAB, keys[i].key_len);
 1109: 	i++;
 1110: 	// 4 bytes
 1111: 	keys[i].key_len = sizeof K_INS - 1;
 1112: 	keys[i].key_func = bufMODE;
 1113: 	memcpy(keys[i].key_ch, K_INS, keys[i].key_len);
 1114: 	i++;
 1115: 	keys[i].key_len = sizeof K_DEL - 1;
 1116: 	keys[i].key_func = bufDEL;
 1117: 	memcpy(keys[i].key_ch, K_DEL, keys[i].key_len);
 1118: 	i++;
 1119: 	keys[i].key_len = sizeof K_PGUP - 1;
 1120: 	memcpy(keys[i].key_ch, K_PGUP, keys[i].key_len);
 1121: 	i++;
 1122: 	keys[i].key_len = sizeof K_PGDN - 1;
 1123: 	memcpy(keys[i].key_ch, K_PGDN, keys[i].key_len);
 1124: 	i++;
 1125: 	// 5 bytes
 1126: 	keys[i].key_len = sizeof K_F5 - 1;
 1127: 	memcpy(keys[i].key_ch, K_F5, keys[i].key_len);
 1128: 	i++;
 1129: 	keys[i].key_len = sizeof K_F6 - 1;
 1130: 	memcpy(keys[i].key_ch, K_F6, keys[i].key_len);
 1131: 	i++;
 1132: 	keys[i].key_len = sizeof K_F7 - 1;
 1133: 	memcpy(keys[i].key_ch, K_F7, keys[i].key_len);
 1134: 	i++;
 1135: 	keys[i].key_len = sizeof K_F8 - 1;
 1136: 	memcpy(keys[i].key_ch, K_F8, keys[i].key_len);
 1137: 	i++;
 1138: 	keys[i].key_len = sizeof K_F9 - 1;
 1139: 	memcpy(keys[i].key_ch, K_F9, keys[i].key_len);
 1140: 	i++;
 1141: 	keys[i].key_len = sizeof K_F10 - 1;
 1142: 	memcpy(keys[i].key_ch, K_F10, keys[i].key_len);
 1143: 	i++;
 1144: 	keys[i].key_len = sizeof K_F11 - 1;
 1145: 	memcpy(keys[i].key_ch, K_F11, keys[i].key_len);
 1146: 	i++;
 1147: 	keys[i].key_len = sizeof K_F12 - 1;
 1148: 	memcpy(keys[i].key_ch, K_F12, keys[i].key_len);
 1149: 	i++;
 1150: 
 1151: 	tcgetattr(buffer->line_in, &t);
 1152: 	t.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO | ECHOCTL | ECHOE | ECHOK | ECHOKE | ECHONL | ECHOPRT);
 1153: 	t.c_iflag |= IGNBRK;
 1154: 	t.c_cc[VMIN] = 1;
 1155: 	t.c_cc[VTIME] = 0;
 1156: 	tcsetattr(buffer->line_in, TCSANOW, &t);
 1157: 
 1158: 	buffer->line_keys = keys;
 1159: 	return buffer;
 1160: }
 1161: 
 1162: /*
 1163:  * cliReadLine() Read line from opened CLI session
 1164:  * @buffer = CLI buffer
 1165:  * return: NULL if error or !=NULL readed line, must be free after use!
 1166: */
 1167: char *
 1168: cliReadLine(linebuffer_t * __restrict buffer)
 1169: {
 1170: 	int code, readLen;
 1171: 	register int i;
 1172: 	struct pollfd fds;
 1173: 	char buf[BUFSIZ], *str = NULL;
 1174: 
 1175: 	if (!buffer) {
 1176: 		cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
 1177: 		return NULL;
 1178: 	}
 1179: 
 1180: 	memset(&fds, 0, sizeof fds);
 1181: 	fds.fd = buffer->line_in;
 1182: 	fds.events = POLLIN;
 1183: 
 1184: 	printfCR(buffer, 1);
 1185: 	while (42) {
 1186: 		if (poll(&fds, 1, -1) < 1) {
 1187: 			LOGERR;
 1188: 			return str;
 1189: 		}
 1190: 
 1191: 		memset(buf, 0, sizeof buf);
 1192: 		readLen = read(buffer->line_in, buf, BUFSIZ);
 1193: 		if (readLen == -1) {
 1194: 			LOGERR;
 1195: 			return str;
 1196: 		}
 1197: 		if (!readLen) {
 1198: 			if (buffer->line_buf)
 1199: 				str = strdup(buffer->line_buf);
 1200: 			else
 1201: 				cli_SetErr(EPIPE, "Error:: unknown state ...");
 1202: 			return str;
 1203: 		}
 1204: 
 1205: recheck:
 1206: 		for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--)
 1207: 			if (readLen >= buffer->line_keys[i].key_len && 
 1208: 					!memcmp(buffer->line_keys[i].key_ch, buf, 
 1209: 						buffer->line_keys[i].key_len)) {
 1210: 				readLen -= buffer->line_keys[i].key_len;
 1211: 				if (readLen)
 1212: 					memmove(buf, buf + buffer->line_keys[i].key_len, readLen);
 1213: 				else
 1214: 					memset(buf, 0, buffer->line_keys[i].key_len);
 1215: 
 1216: 				if (buffer->line_keys[i].key_func)
 1217: 					if ((code = buffer->line_keys[i].key_func(i, buffer)))
 1218: 						readLen = 0;
 1219: 
 1220: 				if (readLen)
 1221: 					goto recheck;
 1222: 				else
 1223: 					break;
 1224: 			}
 1225: 
 1226: 		if (code)
 1227: 			break;
 1228: 	}
 1229: 
 1230: 	if (code != RETCODE_ERR && code != RETCODE_EOF && buffer->line_buf)
 1231: 		str = strdup(buffer->line_buf);
 1232: 	return str;
 1233: }
 1234: 
 1235: 
 1236: /*
 1237:  * cliNetLoop() CLI network main loop binded to socket
 1238:  * @buffer = CLI buffer
 1239:  * @csHistFile = History file name
 1240:  * @sock = client socket
 1241:  * @term = stdin termios
 1242:  * @win = window size of tty
 1243:  * return: RETCODE_ERR error, RETCODE_OK ok
 1244: */
 1245: int
 1246: cliNetLoop(linebuffer_t * __restrict buffer, const char *csHistFile, int sock, 
 1247: 		struct termios *term, struct winsize *win)
 1248: {
 1249: 	u_char buf[BUFSIZ];
 1250: 	int pty, r, s, alen, attrlen, flg, ret = 0;
 1251: 	fd_set fds;
 1252: 	struct timeval tv = { DEFAULT_SOCK_TIMEOUT, 0 };
 1253: 	struct telnetAttrs *a, Attr[10];
 1254: 
 1255: 	switch (forkpty(&pty, NULL, term, win)) {
 1256: 		case -1:
 1257: 			LOGERR;
 1258: 			return -1;
 1259: 		case 0:
 1260: 			close(sock);
 1261: 
 1262: 			if (buffer)
 1263: 				ret = cliLoop(buffer, csHistFile) < 0 ? 1 : 0;
 1264: 			else
 1265: 				cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
 1266: 
 1267: 			/* spawn Shell mode */
 1268: 			/*
 1269: 			execl("/bin/tcsh", "tcsh", NULL);
 1270: 			*/
 1271: 
 1272: 			_exit(ret);
 1273: 		default:
 1274: 			/* spawn Shell mode */
 1275: 			telnet_SetCmd(Attr + 0, DO, TELOPT_TTYPE);
 1276: 			telnet_SetCmd(Attr + 1, WILL, TELOPT_ECHO);
 1277: 			telnet_Set_SubOpt(Attr + 2, TELOPT_LFLOW, LFLOW_OFF, NULL, 0);
 1278: 			telnet_Set_SubOpt(Attr + 3, TELOPT_LFLOW, LFLOW_RESTART_XON, NULL, 0);
 1279: 			telnet_SetCmd(Attr + 4, DO, TELOPT_LINEMODE);
 1280: 			if ((ret = telnetSend(sock, Attr, 5, NULL, 0, 0)) == -1) {
 1281: 				cli_Errno = telnet_GetErrno();
 1282: 				strlcpy(cli_Error, telnet_GetError(), STRSIZ);
 1283: 				return -1;
 1284: 			} else
 1285: 				flg = 0;
 1286: 
 1287: 			while (42) {
 1288: 				FD_ZERO(&fds);
 1289: 				FD_SET(sock, &fds);
 1290: 				FD_SET(pty, &fds);
 1291: 				if ((ret = select(FD_SETSIZE, &fds, NULL, NULL, &tv)) < 1) {
 1292: 					if (!ret)
 1293: 						cli_SetErr(ETIMEDOUT, "Client session timeout ...");
 1294: 
 1295: 					break;
 1296: 				}
 1297: 
 1298: 				r = FD_ISSET(sock, &fds) ? sock : pty;
 1299: 				s = FD_ISSET(sock, &fds) ? pty : sock;
 1300: 
 1301: 				if ((ret = telnetRecv(r, &a, &alen, buf, BUFSIZ)) < 0) {
 1302: 					if (a)
 1303: 						free(a);
 1304: 
 1305: 					if (-2 == ret)
 1306: 						continue;
 1307: 					// EOF
 1308: 					if (-3 == ret)
 1309: 						shutdown(r, SHUT_RD);
 1310: 					else {
 1311: 						cli_Errno = telnet_GetErrno();
 1312: 						strlcpy(cli_Error, telnet_GetError(), STRSIZ);
 1313: 					}
 1314: 					break;
 1315: 				}
 1316: 				attrlen = 0;
 1317: 				if (1 == flg && alen) {
 1318: 					telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_SGA);
 1319: 					telnet_SetCmd(&Attr[attrlen++], DO, TELOPT_ECHO);
 1320: 				}
 1321: 				if (2 == flg && alen) {
 1322: 					telnet_SetCmd(&Attr[attrlen++], WILL, TELOPT_ECHO);
 1323: 					telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW, 
 1324: 							LFLOW_OFF, NULL, 0);
 1325: 					telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW, 
 1326: 							LFLOW_RESTART_XON, NULL, 0);
 1327: 					telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_LINEMODE);
 1328: 				}
 1329: 				if (a)
 1330: 					free(a);
 1331: 
 1332: 				if ((ret = telnetSend(s, Attr, pty == s ? 0 : attrlen, buf, ret, 0)) == -1) {
 1333: 					cli_Errno = telnet_GetErrno();
 1334: 					strlcpy(cli_Error, telnet_GetError(), STRSIZ);
 1335: 					break;
 1336: 				} else
 1337: 					flg++;
 1338: 			}
 1339: 
 1340: 			close(pty);
 1341: 	}
 1342: 
 1343: 	return ret;
 1344: }
 1345: 
 1346: /*
 1347:  * cliLoop() CLI main loop
 1348:  * @buffer = CLI buffer
 1349:  * @csHistFile = History file name
 1350:  * return: RETCODE_ERR error, RETCODE_OK ok
 1351: */
 1352: int
 1353: cliLoop(linebuffer_t * __restrict buffer, const char *csHistFile)
 1354: {
 1355: 	char *line, *s, *t, **app, *items[MAX_PROMPT_ITEMS];
 1356: 	register int i;
 1357: 	int ret = RETCODE_OK;
 1358: 	struct tagCommand *cmd;
 1359: 
 1360: 	/* --- main body of CLI --- */
 1361: 
 1362: 	if (cli_loadHistory(buffer, csHistFile) == RETCODE_ERR)
 1363: 		return RETCODE_ERR;
 1364: 
 1365: 	do {
 1366: 		line = cliReadLine(buffer);
 1367: 		if (!line) {
 1368: 			printfNL(buffer, 0);
 1369: 			break;
 1370: 		} else
 1371: 			cli_addHistory(buffer, NULL);
 1372: 		// clear whitespaces
 1373: 		for (s = line; isspace(*s); s++);
 1374: 		if (*s) {
 1375: 			for (t = s + strlen(s) - 1; t > s && isspace(*t); t--);
 1376: 			*++t = 0;
 1377: 		}
 1378: 
 1379: 		if (*s) {
 1380: 			memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
 1381: 			for (app = items; app < items + MAX_PROMPT_ITEMS - 1 && (*app = strsep(&s, " \t")); 
 1382: 					*app ? app++ : app);
 1383: 
 1384: 			// exec_cmd ...
 1385: 			i = 0;
 1386: 			SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next) {
 1387: 				if (*items[0] && !strncmp(cmd->cmd_name, items[0], strlen(items[0])))
 1388: 					break;
 1389: 				else
 1390: 					i++;
 1391: 			}
 1392: 
 1393: 			if (!cmd) {
 1394: 				cli_Printf(buffer, "\nCommand '%s' not found!\n", items[0]);
 1395: 				ret = -1;
 1396: 			} else
 1397: 				if (cmd->cmd_func)
 1398: 					ret = cmd->cmd_func(buffer, i, items);
 1399: 				else {
 1400: 					clrscrEOL(buffer);
 1401: 					printfCR(buffer, 1);
 1402: 				}
 1403: 		}
 1404: 
 1405: 		cli_freeLine(buffer);
 1406: 		cli_resetHistory(buffer);
 1407: 		free(line);
 1408: 	} while (ret < 1);
 1409: 
 1410: 	cli_saveHistory(buffer, csHistFile, HISTORY_LINES);
 1411: 	return ret;
 1412: }

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