--- libaitcli/inc/aitcli.h 2010/06/04 12:08:32 1.2.2.1 +++ libaitcli/inc/aitcli.h 2022/10/17 22:04:24 1.13 @@ -3,13 +3,58 @@ * by Michael Pounov * * $Author: misho $ -* $Id: aitcli.h,v 1.2.2.1 2010/06/04 12:08:32 misho Exp $ +* $Id: aitcli.h,v 1.13 2022/10/17 22:04:24 misho Exp $ * -*************************************************************************/ +************************************************************************** +The ELWIX and AITNET software is distributed under the following +terms: + +All of the documentation and software included in the ELWIX and AITNET +Releases is copyrighted by ELWIX - Sofia/Bulgaria + +Copyright 2004 - 2022 + by Michael Pounov . All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: +This product includes software developed by Michael Pounov +ELWIX - Embedded LightWeight unIX and its contributors. +4. Neither the name of AITNET nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. +*/ #ifndef __AITCLI_H #define __AITCLI_H +#include +#include + + +#ifndef STRSIZ +#define STRSIZ 256 +#endif + /* Key definitions */ #define K_F1 "\x1b\x4f\x50" @@ -141,8 +186,8 @@ /* History types */ struct tagHistory { - int hist_len; - char hist_line[BUFSIZ]; + int hist_len; + char hist_line[BUFSIZ]; TAILQ_ENTRY(tagHistory) hist_next; }; @@ -150,7 +195,7 @@ typedef TAILQ_HEAD(tqHistoryHead, tagHistory) history_ /* Bind keys structure types */ -typedef int (*bindkey_func_t)(int idx, /*linebuffer_t **/ void * __restrict buffer); +typedef int (*bindkey_func_t)(int idx, /* linebuffer_t * */ void * __restrict cli_buffer); typedef struct { int key_len; unsigned char key_ch[8]; @@ -158,11 +203,34 @@ typedef struct { } bindkey_t; +/* Commands structure for CLI */ + +#define CLI_CMD_DEFINE(x) int (x)(void *, int, char **) +typedef int (*cmd_func_t)(/*linebuffer_t **/ void * __restrict cli_buffer, int idx, + char ** __restrict args); +struct tagCommand { + int cmd_level; + + int cmd_len; + char cmd_name[STRSIZ]; + + char cmd_info[STRSIZ]; + char cmd_help[STRSIZ]; + + cmd_func_t cmd_func; + + SLIST_ENTRY(tagCommand) cmd_next; +}; +typedef SLIST_HEAD(slCommandHead, tagCommand) commands_t; + + /* Main structure, Buffer for CLI work with thread models ;-) special designed by M.Punov */ typedef struct { + int line_kill; char line_mode; + char line_porigin[STRSIZ]; char *line_prompt; int line_bol; @@ -175,118 +243,344 @@ typedef struct { bindkey_t *line_keys; + int line_level; + commands_t line_cmds; + int line_in; int line_out; } linebuffer_t; -/* Commands structure for CLI */ -typedef int (*cmd_func_t)(linebuffer_t * __restrict buffer, int argc, char ** __restrict argv); -typedef struct { - int cmd_level; +/* Error support functions */ - int cmd_min; - int cmd_len; - char cmd_name[STRSIZ]; +// cli_GetErrno() Get error code of last operation +int cli_GetErrno(); +// cli_GetError() Get error text of last operation +const char *cli_GetError(); - char cmd_info[STRSIZ]; - char cmd_help[STRSIZ]; - cmd_func_t *cmd_func; -} commands_t; +/* TELNET support for CLI */ +#define MAX_SUB_LEN 255 -/* Error support functions */ +struct telnetAttrs { + unsigned char ta_cmd; + unsigned char ta_opt; + unsigned char ta_sublen; + unsigned char ta_sub[MAX_SUB_LEN]; +}; -// cli_GetErrno() Get error code of last operation -inline int cli_GetErrno(); -// cli_GetError() Get error text of last operation -inline const char *cli_GetError(); +#ifndef NDEBUG +/* + * cli_telnetDumpAttrs() - Telnet debug attributes list, if NDEBUG defined not include + * + * @attr = attributes list + * @nAttr = attributes list size + * return: none +*/ +void cli_telnetDumpAttrs(struct telnetAttrs *attr, int nAttr); +#else +extern void cli_telnetDumpAttrs(struct telnetAttrs *, int); +#endif -/* CLI Functions */ /* - * cliExec() Execute CLI main loop - * @cmdList = Commands list - * @csPrompt = Prompt text - * return: -1 error, 0 = exit w/^+D, 1 done. + * cli_telnetRecv() - Telnet receive commands, negotiate with telnet peer + * + * @sock = socket for communication + * @attr = received attributes list, must be free after use, but if NULL receive in binary mode + * @nAttr = received attributes list size, if is NULL receive in binary mode + * @pdata = received data in supplied buffer + * @datLen = buffer pdata size + * return: 0 not present data; -1 error:: can`t read; -2 timeout; -3 EOF; >0 number of received bytes */ -int cliExec(cliCommands_t *cmdList, const char *csPrompt); +int cli_telnetRecv(int sock, struct telnetAttrs **attr, int *nAttr, void *data, int datLen); /* - * cliNetExec() Execute net CLI main loop - * @cmdList = Commands list - * @csPrompt = Prompt text - * @sock = client socket - * @term = stdin termios - * @win = window size of tty - * return: -1 error, 0 = exit w/^+D, 1 done. + * cli_telnetSend() - Telnet send commands, negotiate with telnet peer + * + * @sock = socket for communication + * @attr = send attributes list + * @nAttr = send attributes list size + * @data = data for send + * @datLen = data size + * @Term = Terminate with GA (Go Ahead), 1 send after data GA command + * return: 0 not sended commands; -1 error:: can`t send; >0 number of sended bytes */ -int cliNetExec(cliCommands_t *cmdList, const char *csPrompt, int sock, struct termios *term, struct winsize *win); +int cli_telnetSend(int sock, struct telnetAttrs *attr, int nAttr, void *data, int datLen, int Term); +/* + * cli_telnet_Get_SubOpt() - Telnet get sub option function + * + * @attr = input attribute + * @code = sub-option code for opt + * @data = sub-option data + * @datLen = data size set max size in input, output return copy size + * return: -1 can`t get option; !=-1 option code +*/ +int cli_telnet_Get_SubOpt(struct telnetAttrs *attr, unsigned char *code, + void *data, unsigned char *datLen); +/* + * cli_telnet_Set_SubOpt() - Telnet set sub option function + * + * @attr = output attribute + * @opt = attribute option + * @code = sub-option code for opt, if 0xff not specified + * @data = sub-option data, if NULL not specified + * @datLen = data size, if 0 not specified + * return: -1 can`t set sub-otion; 0 ok +*/ +int cli_telnet_Set_SubOpt(struct telnetAttrs *attr, unsigned char opt, unsigned char code, + void *data, unsigned char datLen); +/* + * cli_telnet_GetCmd() - Telnet get command + * + * @attr = input attribute + * return: -1 can`t get command; !=-1 command <<24 return sublen, <<8 return option, <<0 command +*/ +unsigned int cli_telnet_GetCmd(struct telnetAttrs *attr); +/* + * cli_telnet_SetCmd() - Telnet set command + * + * @attr = input attribute + * @cmd = command + * @optz = option, if 0xff not specified + * @arg1 = sub-option code, if 0xff not specified + * @arg2 = sub-option data, if NULL not specified + * @arg3 = sub-option data size, if 0 not specified data + * return: -1 can`t set command; !=-1 ok +*/ +int cli_telnet_SetCmd(struct telnetAttrs *attr, unsigned char cmd, int optz, ...); + +/* + * cli_telnet_Answer() - Automatic generate commands answer to send from telnet + * + * @caps = Array of capability options + * @nCaps = number of capability options + * @attr = input attribute + * @nAttr = number of input attributes + * @ans = output answered attributes, must be e_free() after use + * @Ans = number of output answered attributes + * return: -1 can`t answer; !=-1 ok +*/ +int cli_telnet_Answer(unsigned char *caps, int nCaps, struct telnetAttrs *attr, int nAttr, + struct telnetAttrs **ans, int *Ans); + + +// Add capability option, x = 0 false, 1 true +#define ADD_CAPS(opt, x) ((opt) | (x) ? 0x80 : 0) +// Is supported this option ... +#define SUP_CAPS(caps) ((caps) & 0x80) +// get capability option +#define CAP(caps) ((caps) & 0x7f) + + /* CLI Helper functions */ /* - * cli_Cmd_Unsupported() Builtin helper function for unsupported commands - * @cmds = Commands list - * @idx = Selected command ID - * @out = Output handle + * cli_Cmd_Unsupported() - Builtin helper function for unsupported commands + * + * @cli_buffer = CLI buffer + * @idx = Config level * @args = Parsed arguments array - * return: -1 error, 0 = ok, 1 exit from Cli! + * return: RETCODE_OK ok */ -int cli_Cmd_Unsupported(void *cmds, int idx, FILE *out, char ** __restrict args); +int cli_Cmd_Unsupported(void * __restrict cli_buffer, int idx, char ** __restrict args); + + +/* CLI Functions */ + /* - * cli_Cmd_Help() Builtin helper function for Help screen - * @cmds = Commands list - * @idx = Selected command ID - * @out = Output handle - * @args = Parsed arguments array - * return: -1 error, 0 = ok + * cli_BindKey() - Bind function to key + * + * @key = key structure + * @cli_buffer = CLI buffer + * return: RETCODE_ERR error, RETCODE_OK ok, >0 bind at position */ -int cli_Cmd_Help(void *cmds, int idx, FILE *out, char ** __restrict args); +int cli_BindKey(bindkey_t * __restrict key, linebuffer_t * __restrict cli_buffer); + + /* - * cli_Cmd_Exit() Builtin helper function for Exit from Cli - * @cmds = Commands list - * @idx = Selected command ID - * @out = Output handle - * @args = Parsed arguments array - * return: 1 exit from Cli! + * cli_addCommand() - Add command to CLI session + * + * @cli_buffer = CLI buffer + * @csCmd = Command name + * @cliLevel = Level in CLI, -1 view from all levels, 0 hidden, >0 mask levels + * @funcCmd = Callback function when user call command + * @csInfo = Inline information for command + * @csHelp = Help line when call help + * return: RETCODE_ERR error, RETCODE_OK ok */ -int cli_Cmd_Exit(void *cmds, int idx, FILE *out, char ** __restrict args); +int +cli_addCommand(linebuffer_t * __restrict cli_buffer, const char *csCmd, + int cliLevel, cmd_func_t funcCmd, + const char *csInfo, const char *csHelp); +/* + * cli_delCommand() - Delete command from CLI session + * + * @cli_buffer = CLI buffer + * @csCmd = Command name + * @cliLevel = Level in CLI, -1 view from all levels, 0 hidden, >0 mask levels + * return: RETCODE_ERR error, RETCODE_OK ok +*/ +int +cli_delCommand(linebuffer_t * __restrict cli_buffer, const char *csCmd, int cliLevel); +/* + * cli_updCommand() - Update command in CLI session + * + * @cli_buffer = CLI buffer + * @csCmd = Command name + * @cliLevel = Level in CLI, -1 view from all levels, 0 hidden, >0 mask levels + * @funcCmd = Callback function when user call command + * @csInfo = Inline information for command + * @csHelp = Help line when call help + * return: RETCODE_ERR error, RETCODE_OK ok +*/ +int +cli_updCommand(linebuffer_t * __restrict cli_buffer, const char *csCmd, + int cliLevel, cmd_func_t funcCmd, + const char *csInfo, const char *csHelp); /* - * cli_Register_Commands - Declare helper function for register and export Commands variable + * cli_addHistory() - Add line to history + * + * @cli_buffer = CLI buffer + * @str = Add custom text or if NULL use readed line from CLI buffer + * return: RETCODE_ERR error, RETCODE_OK ok */ -#define CLI_REGISTER_COMMANDS(CMDS) \ - extern commands_t CMDS[]; +int cli_addHistory(linebuffer_t * __restrict cli_buffer, const char * __restrict str); /* - * cli_Make_Comp_Commands - Declare helper function for Commands completion arguments + * cli_saveHistory() - Save history to file + * + * @cli_buffer = CLI buffer + * @histfile = History filename, if NULL will be use default name + * @lines = Maximum history lines to save + * return: RETCODE_ERR error, RETCODE_OK ok */ -#define CLI_MAKE_COMP_COMMANDS(FUNC, CMDS) \ - char *FUNC(const char *text, int state) \ - { \ - register int i; \ - int len = strlen(text); \ - for (i = state; CMDS[i].cmd_name; i++) { \ - if (strncmp(CMDS[i].cmd_name, "---", 3) && \ - !strncmp(CMDS[i].cmd_name, text, len)) \ - return strdup(CMDS[i].cmd_name); \ - } \ - return NULL; \ - } +int cli_saveHistory(linebuffer_t * __restrict cli_buffer, const char *histfile, int lines); +/* + * cli_loadHistory() - Load history from file + * + * @cli_buffer = CLI buffer + * @histfile = History filename, if NULL will be use default name + * return: RETCODE_ERR error, RETCODE_OK ok +*/ +int cli_loadHistory(linebuffer_t * __restrict cli_buffer, const char *histfile); +/* + * cli_resetHistory() - Reset history search in CLI session + * + * @cli_buffer = CLI buffer + * return: none +*/ +void cli_resetHistory(linebuffer_t * __restrict cli_buffer); /* - * cli_Make_Comp_Args - Declare helper function for Arguments completion + * cli_freeLine() - Clear entire line + * + * @cli_buffer = CLI buffer + * return: RETCODE_ERR error, RETCODE_OK ok */ -#define CLI_MAKE_COMP_ARGS(FUNC, ARGS) \ - char *FUNC(const char *text __attribute__((unused)), int state) \ - { \ - while (ARGS[state]) \ - return strdup(ARGS[state]); \ - return NULL; \ - } +int cli_freeLine(linebuffer_t * __restrict cli_buffer); +/* + * cli_setPrompt() - Set new prompt for CLI session + * + * @cli_buffer = CLI buffer + * @prompt = new text for prompt or if NULL disable prompt + * return: none +*/ +void cli_setPrompt(linebuffer_t * __restrict cli_buffer, const char *prompt); +/* + * cli_Printf() - Send message to CLI session + * + * @cli_buffer = CLI buffer + * @fmt = printf format string + * @... = arguments defined in fmt + * return: none +*/ +void cli_Printf(linebuffer_t * __restrict cli_buffer, char *fmt, ...); +/* + * cli_PrintHelp() - Print help screen + * + * @cli_buffer = CLI buffer + * return: none +*/ +void cli_PrintHelp(linebuffer_t * __restrict cli_buffer); + +/* + * cliEnd() - Clear data, Free resources and close CLI session + * + * @cli_buffer = CLI buffer + * return: RETCODE_ERR error, RETCODE_OK ok +*/ +void cliEnd(linebuffer_t * __restrict cli_buffer); +/* + * cliInit() - Start CLI session, allocate memory for resources and bind keys + * + * @fin = Input device handle + * @fout = Output device handle + * @prompt = text for prompt, if NULL disable prompt + * return: NULL if error or !=NULL CLI buffer +*/ +linebuffer_t *cliInit(int fin, int fout, const char *prompt); + +/* + * cliSetLine() - Set CLI input line terminal + * + * @cli_buffer = CLI buffer + * @old = Old terminal settings + * return: -1 error or 0 ok +*/ +int cliSetLine(linebuffer_t * __restrict cli_buffer, struct termios * __restrict old); +/* + * cliResetLine() - Reset CLI input line terminal + * + * @cli_buffer = CLI buffer + * @old = Original terminal settings + * return: -1 error or 0 ok +*/ +int cliResetLine(linebuffer_t * __restrict cli_buffer, struct termios * __restrict orig); +/* + * cliReadLine() - Read line from opened CLI session + * + * @cli_buffer = CLI buffer + * @timeout = Session timeout (-1 infinit) + * return: NULL if error or !=NULL readed line, must be e_free after use! +*/ +char *cliReadLine(linebuffer_t * __restrict cli_buffer, int timeout); + +/* + * cliRun() - CLI run command line + * + * @cli_buffer = CLI buffer + * @psInput = Input command line + * @prompt = Display prompt after command + * return: RETCODE_ERR error, RETCODE_OK ok +*/ +int cliRun(linebuffer_t * __restrict cli_buffer, char *psInput, int prompt); + +/* + * cliLoop() - CLI main loop + * + * @cli_buffer = CLI buffer + * @csHistFile = History file name + * @timeout = Session timeout (-1 infinit) + * return: RETCODE_ERR error, RETCODE_OK ok +*/ +int cliLoop(linebuffer_t * __restrict cli_buffer, const char *csHistFile, int timeout); +/* + * cliNetLoop() - CLI network main loop binded to socket + * + * @cli_buffer = CLI buffer + * @csHistFile = History file name + * @sock = client socket + * @timeout = Session timeout (-1 infinit) + * return: RETCODE_ERR error, RETCODE_OK ok +*/ +int cliNetLoop(linebuffer_t * __restrict cli_buffer, const char *csHistFile, + int sock, int timeout); +#define cliKillLoop(_x) (assert((_x)), (_x)->line_kill = 1) #endif