--- libaitcli/inc/aitcli.h 2010/06/04 11:32:47 1.2 +++ libaitcli/inc/aitcli.h 2011/03/16 17:24:03 1.3 @@ -3,174 +3,381 @@ * by Michael Pounov * * $Author: misho $ -* $Id: aitcli.h,v 1.2 2010/06/04 11:32:47 misho Exp $ +* $Id: aitcli.h,v 1.3 2011/03/16 17:24:03 misho Exp $ * *************************************************************************/ #ifndef __AITCLI_H #define __AITCLI_H -struct tagCLICmd { - const char *cmd_name; - int (*cmd_func)(void *, int, FILE *, char **); - const char *cmd_doc; - const char *cmd_help; - char *(*cmd_comp)(const char *, int); +#include +#include + + +#define STRSIZ 256 + +/* Key definitions */ + +#define K_F1 "\x1b\x4f\x50" +#define K_F2 "\x1b\x4f\x51" +#define K_F3 "\x1b\x4f\x52" +#define K_F4 "\x1b\x4f\x53" +#define K_F5 "\x1b\x5b\x31\x35\x7e" +#define K_F6 "\x1b\x5b\x31\x37\x7e" +#define K_F7 "\x1b\x5b\x31\x38\x7e" +#define K_F8 "\x1b\x5b\x31\x39\x7e" +#define K_F9 "\x1b\x5b\x32\x30\x7e" +#define K_F10 "\x1b\x5b\x32\x31\x7e" +#define K_F11 "\x1b\x5b\x32\x33\x7e" +#define K_F12 "\x1b\x5b\x32\x34\x7e" +#define K_CTRL_F1 "\x1b\x5b\x6b" +#define K_CTRL_F2 "\x1b\x5b\x6c" +#define K_CTRL_F3 "\x1b\x5b\x6d" +#define K_CTRL_F4 "\x1b\x5b\x6e" +#define K_CTRL_F5 "\x1b\x5b\x6f" +#define K_CTRL_F6 "\x1b\x5b\x70" +#define K_CTRL_F7 "\x1b\x5b\x71" +#define K_CTRL_F8 "\x1b\x5b\x72" +#define K_CTRL_F9 "\x1b\x5b\x73" +#define K_CTRL_F10 "\x1b\x5b\x74" +#define K_CTRL_F11 "\x1b\x5b\x75" +#define K_CTRL_F12 "\x1b\x5b\x76" +#define K_CTRL_SH_F1 "\x1b\x5b\x77" +#define K_CTRL_SH_F2 "\x1b\x5b\x78" +#define K_CTRL_SH_F3 "\x1b\x5b\x79" +#define K_CTRL_SH_F4 "\x1b\x5b\x7a" +#define K_CTRL_SH_F5 "\x1b\x5b\x40" +#define K_CTRL_SH_F6 "\x1b\x5b\x5b" +#define K_CTRL_SH_F7 "\x1b\x5b\x5c" +#define K_CTRL_SH_F8 "\x1b\x5b\x5d" +#define K_CTRL_SH_F9 "\x1b\x5b\x5e" +#define K_CTRL_SH_F10 "\x1b\x5b\x5f" +#define K_CTRL_SH_F11 "\x1b\x5b\x60" +#define K_CTRL_SH_F12 "\x1b\x5b\x7b" + +#define K_INS "\x1b\x5b\x32\x7e" +#define K_DEL "\x1b\x5b\x33\x7e" +#define K_PGUP "\x1b\x5b\x35\x7e" +#define K_PGDN "\x1b\x5b\x36\x7e" +#define K_HOME "\x1b\x5b\x48" +#define K_END "\x1b\x5b\x46" +#define K_UP "\x1b\x5b\x41" +#define K_DOWN "\x1b\x5b\x42" +#define K_RIGHT "\x1b\x5b\x43" +#define K_LEFT "\x1b\x5b\x44" + +#define K_NULL "\x0" +#define K_CR "\xd" +#define K_BTAB "\x1b\x5b\x5a" +#define K_TAB "\x9" +#define K_ENTER "\xa" +#define K_ESC "\x1b" +#define K_BACKSPACE "\x7f" +#define K_SPACE "\x20" + +#define K_CTRL_SPACE K_NULL +#define K_CTRL_2 K_NULL +#define K_CTRL_A "\x1" +#define K_CTRL_B "\x2" +#define K_CTRL_C "\x3" +#define K_CTRL_D "\x4" +#define K_CTRL_E "\x5" +#define K_CTRL_F "\x6" +#define K_CTRL_G "\x7" +#define K_CTRL_H "\x8" +#define K_CTRL_I K_TAB +#define K_CTRL_J K_ENTER +#define K_CTRL_K "\xb" +#define K_CTRL_L "\xc" +#define K_CTRL_M K_ENTER // K_CR +#define K_CTRL_N "\xe" +#define K_CTRL_O "\xf" +#define K_CTRL_P "\x10" +#define K_CTRL_Q "\x11" +#define K_CTRL_R "\x12" +#define K_CTRL_S "\x13" +#define K_CTRL_T "\x14" +#define K_CTRL_U "\x15" +#define K_CTRL_V "\x16" +#define K_CTRL_W "\x17" +#define K_CTRL_X "\x18" +#define K_CTRL_Y "\x19" +#define K_CTRL_Z "\x1a" +#define K_CTRL_LBRACE "\x1b" +#define K_CTRL_PIPE "\x1c" +#define K_CTRL_RBRACE "\x1d" +#define K_CTRL_6 "\x1e" +#define K_CTRL__ "\x1f" + + +#define K_X_CTRL_INS "\x1b\x5b\x32\x3b\x35\x7e" +#define K_X_CTRL_DEL "\x1b\x5b\x33\x3b\x35\x7e" +#define K_X_CTRL_PGUP "\x1b\x5b\x35\x3b\x35\x7e" +#define K_X_CTRL_PGDN "\x1b\x5b\x36\x3b\x35\x7e" +#define K_X_CTRL_HOME "\x1b\x5b\x31\x3b\x35\x48" +#define K_X_CTRL_END "\x1b\x5b\x31\x3b\x35\x46" +#define K_X_CTRL_UP "\x1b\x5b\x31\x3b\x35\x41" +#define K_X_CTRL_DOWN "\x1b\x5b\x31\x3b\x35\x42" +#define K_X_CTRL_RIGHT "\x1b\x5b\x31\x3b\x35\x43" +#define K_X_CTRL_LEFT "\x1b\x5b\x31\x3b\x35\x44" + +#define K_X_ALT_INS "\x1b\x5b\x32\x3b\x33\x7e" +#define K_X_ALT_DEL "\x1b\x5b\x33\x3b\x33\x7e" +#define K_X_ALT_PGUP "\x1b\x5b\x35\x3b\x33\x7e" +#define K_X_ALT_PGDN "\x1b\x5b\x36\x3b\x33\x7e" +#define K_X_ALT_HOME "\x1b\x5b\x31\x3b\x33\x48" +#define K_X_ALT_END "\x1b\x5b\x31\x3b\x33\x46" +#define K_X_ALT_UP "\x1b\x5b\x31\x3b\x33\x41" +#define K_X_ALT_DOWN "\x1b\x5b\x31\x3b\x33\x42" +#define K_X_ALT_RIGHT "\x1b\x5b\x31\x3b\x33\x43" +#define K_X_ALT_LEFT "\x1b\x5b\x31\x3b\x33\x44" + +#define K_X_CTL_A_INS "\x1b\x5b\x32\x3b\x37\x7e" +#define K_X_CTL_A_DEL "\x1b\x5b\x33\x3b\x37\x7e" +#define K_X_CTL_A_PGUP "\x1b\x5b\x35\x3b\x37\x7e" +#define K_X_CTL_A_PGDN "\x1b\x5b\x36\x3b\x37\x7e" +#define K_X_CTL_A_HOME "\x1b\x5b\x31\x3b\x37\x48" +#define K_X_CTL_A_END "\x1b\x5b\x31\x3b\x37\x46" +#define K_X_CTL_A_UP "\x1b\x5b\x31\x3b\x37\x41" +#define K_X_CTL_A_DOWN "\x1b\x5b\x31\x3b\x37\x42" +#define K_X_CTL_A_RIGHT "\x1b\x5b\x31\x3b\x37\x43" +#define K_X_CTL_A_LEFT "\x1b\x5b\x31\x3b\x37\x44" + + +/* History types */ + +struct tagHistory { + int hist_len; + char hist_line[BUFSIZ]; + + TAILQ_ENTRY(tagHistory) hist_next; }; +typedef TAILQ_HEAD(tqHistoryHead, tagHistory) history_t; -typedef struct tagCLICmd cliCommands_t; -typedef char *cli_CompEntry_t(const char *, int); -typedef char **cli_Completion_t(const char *, int, int); +/* Bind keys structure types */ +typedef int (*bindkey_func_t)(int idx, /*linebuffer_t **/ void * __restrict buffer); +typedef struct { + int key_len; + unsigned char key_ch[8]; + bindkey_func_t key_func; +} bindkey_t; + +/* Commands structure for CLI */ + +typedef int (*cmd_func_t)(/*linebuffer_t **/ void * __restrict 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 { + char line_mode; + + char *line_prompt; + + int line_bol; + int line_eol; + int line_len; + char *line_buf; + + const struct tagHistory *line_h; + history_t line_history; + + bindkey_t *line_keys; + + int line_level; + commands_t line_cmds; + + int line_in; + int line_out; +} linebuffer_t; + + +/* Error support functions */ + // 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(); + +/* CLI Helper functions */ + /* - * cli_Printf() Printf CLI features - * @out = Output stream - * @csFormat = Printf format string - * return: -1 error, != -1 printed chars + * cli_Cmd_Unsupported() Builtin helper function for unsupported commands + * @buffer = CLI buffer + * @idx = Selected command ID + * @args = Parsed arguments array + * return: RETCODE_OK ok */ -inline int cli_Printf(FILE *out, const char *csFormat, ...); +int cli_Cmd_Unsupported(void * __restrict buffer, int idx, char ** __restrict args); + +/* CLI Functions */ + /* - * cliNetInit() Initialize Readline if CLI bind to socket - * @csProg = program name - * @pty = Master pty - * @term = stdin termios - * return: none + * cli_BindKey() Bind function to key + * @key = key structure + * @buffer = CLI buffer + * return: RETCODE_ERR error, RETCODE_OK ok, >0 bind at position */ -void cliNetInit(const char *csProg, int pty, struct termios *term); +int cli_BindKey(bindkey_t * __restrict key, linebuffer_t * __restrict buffer); + + /* - * cliTTY() Initialize I/O TTY CLI features - * @term = terminal name - * @inp = input handle - * @out = output handle - * @win = window size - * return: -1 error, != -1 ok + * cli_addCommand() Add command to CLI session + * @buffer = CLI buffer + * @csCmd = Command name + * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ... + * @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 */ -inline int cliTTY(const char *term, FILE *inp, FILE *out, struct winsize *win); +int +cli_addCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel, cmd_func_t funcCmd, + const char *csInfo, const char *csHelp); /* - * cliComp() Initialize completion CLI features - * @cmdComplete = Completion function - * @cmdEntry = Compentry function - * return: none + * cli_delCommand() Delete command from CLI session + * @buffer = CLI buffer + * @csCmd = Command name + * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ... + * return: RETCODE_ERR error, RETCODE_OK ok */ -inline void cliComp(cli_Completion_t *cmdComplete, cli_CompEntry_t *cmdEntry); +int +cli_delCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel); /* - * cliExec() Execute CLI main loop - * @cmdList = Commands list - * @csPrompt = Prompt text - * return: -1 error, 0 = exit w/^+D, 1 done. + * cli_updCommand() Update command in CLI session + * @buffer = CLI buffer + * @csCmd = Command name + * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ... + * @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 cliExec(cliCommands_t *cmdList, const char *csPrompt); +int +cli_updCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel, cmd_func_t funcCmd, + const char *csInfo, const char *csHelp); + + /* - * 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_addHistory() Add line to history + * @buffer = CLI buffer + * @str = Add custom text or if NULL use readed line from CLI buffer + * return: RETCODE_ERR error, RETCODE_OK ok */ -int cliNetExec(cliCommands_t *cmdList, const char *csPrompt, int sock, struct termios *term, struct winsize *win); - +int cli_addHistory(linebuffer_t * __restrict buffer, const char * __restrict str); /* - * cli_ReadHistory() Read CLI History from file - * @csFile = history file name, if NULL default history name is ".aitcli.history" - * return: -1 error; != -1 readed ok + * cli_saveHistory() Save history to file + * @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 */ -inline int cli_ReadHistory(const char *csFile); +int cli_saveHistory(linebuffer_t * __restrict buffer, const char *histfile, int lines); /* - * cli_WriteHistory() Write CLI History to file - * @csFile = history file name, if NULL default history name is ".aitcli.history" - * @lineNum = save number of history entry lines, if -1 all lines saved without limit - * return: -1 error; != -1 readed ok + * cli_loadHistory() Load history from file + * @buffer = CLI buffer + * @histfile = History filename, if NULL will be use default name + * return: RETCODE_ERR error, RETCODE_OK ok */ -inline int cli_WriteHistory(const char *csFile, int lineNum); - - +int cli_loadHistory(linebuffer_t * __restrict buffer, const char *histfile); /* - * cli_PrintHelp() Helper print for missing command arguments - * @out = Output stream - * @cmds = Commands list - * @idx = Selected command ID - * return: -1 error, !=-1 ok + * cli_resetHistory() Reset history search in CLI session + * @buffer = CLI buffer * return: none */ -inline int cli_PrintHelp(FILE *out, void *cmds, int idx); +inline void cli_resetHistory(linebuffer_t * __restrict buffer); /* - * cli_Cmd_Unsupported() Builtin helper function for unsupported commands - * @cmds = Commands list - * @idx = Selected command ID - * @out = Output handle - * @args = Parsed arguments array - * return: -1 error, 0 = ok, 1 exit from Cli! + * cli_freeLine() Clear entire line + * @buffer = CLI buffer + * return: RETCODE_ERR error, RETCODE_OK ok */ -int cli_Cmd_Unsupported(void *cmds, int idx, FILE *out, char ** __restrict args); +inline int cli_freeLine(linebuffer_t * __restrict buffer); /* - * 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_setPrompt() Set new prompt for CLI session + * @buffer = CLI buffer + * @prompt = new text for prompt or if NULL disable prompt + * return: none */ -int cli_Cmd_Help(void *cmds, int idx, FILE *out, char ** __restrict args); +inline void cli_setPrompt(linebuffer_t * __restrict buffer, const char *prompt); /* - * 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_Printf() Send message to CLI session + * @buffer = CLI buffer + * @fmt = printf format string + * @... = arguments defined in fmt + * return: none */ -int cli_Cmd_Exit(void *cmds, int idx, FILE *out, char ** __restrict args); +inline void cli_Printf(linebuffer_t * __restrict buffer, char *fmt, ...); +/* + * cli_PrintHelp() Print help screen + * @buffer = CLI buffer + * return: none +*/ +inline void cli_PrintHelp(linebuffer_t * __restrict buffer); - /* - * cli_Register_Commands - Declare helper function for register and export Commands variable + * cliEnd() Clear data, Free resources and close CLI session + * @buffer = CLI buffer + * return: RETCODE_ERR error, RETCODE_OK ok */ -#define CLI_REGISTER_COMMANDS(CMDS) \ - extern cliCommands_t CMDS[]; +void cliEnd(linebuffer_t * __restrict buffer); /* - * cli_Make_Comp_Commands - Declare helper function for Commands completion arguments + * 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 */ -#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; \ - } +linebuffer_t *cliInit(int fin, int fout, const char *prompt); /* - * cli_Make_Comp_Args - Declare helper function for Arguments completion + * cliInitLine() Init CLI input line terminal + * @buffer = CLI buffer + * return: none */ -#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 cliInitLine(linebuffer_t * __restrict buffer); +/* + * cliReadLine() Read line from opened CLI session + * @buffer = CLI buffer + * return: NULL if error or !=NULL readed line, must be free after use! +*/ +char *cliReadLine(linebuffer_t * __restrict buffer); /* - * cli_Comp_Filename() Builtin helper function for filename completion arguments - * @text = Text line - * @state = Position state - * return: NULL not found filename, != NULL filename + * cliLoop() CLI main loop + * @buffer = CLI buffer + * @csHistFile = History file name + * return: RETCODE_ERR error, RETCODE_OK ok */ -char *cli_Comp_Filename(const char *text, int state); +int cliLoop(linebuffer_t * __restrict buffer, const char *csHistFile); +/* + * cliNetLoop() CLI network main loop binded to socket + * @buffer = CLI buffer + * @csHistFile = History file name + * @sock = client socket + * @term = stdin termios + * @win = window size of tty + * return: RETCODE_ERR error, RETCODE_OK ok +*/ +int cliNetLoop(linebuffer_t * __restrict buffer, const char *csHistFile, int sock); #endif