BAL and Maple Release 2.2
Signed-off-by: Shad Ansari <developer@Carbon.local>
diff --git a/bcm68620_release/release/host_reference/cli/bcmcli_session.c b/bcm68620_release/release/host_reference/cli/bcmcli_session.c
new file mode 100644
index 0000000..519eaa8
--- /dev/null
+++ b/bcm68620_release/release/host_reference/cli/bcmcli_session.c
@@ -0,0 +1,587 @@
+/*
+<:copyright-BRCM:2016:DUAL/GPL:standard
+
+ Broadcom Proprietary and Confidential.(c) 2016 Broadcom
+ All Rights Reserved
+
+Unless you and Broadcom execute a separate written software license
+agreement governing use of this software, this software is licensed
+to you under the terms of the GNU General Public License version 2
+(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
+with the following added to such license:
+
+ As a special exception, the copyright holders of this software give
+ you permission to link this software with independent modules, and
+ to copy and distribute the resulting executable under terms of your
+ choice, provided that you also meet, for each linked independent
+ module, the terms and conditions of the license of that module.
+ An independent module is a module which is not derived from this
+ software. The special exception does not apply to any modifications
+ of the software.
+
+Not withstanding the above, under no circumstances may you combine
+this software in any way with any other Broadcom software provided
+under a license other than the GPL, without Broadcom's express prior
+written consent.
+
+:>
+ */
+
+
+/*******************************************************************
+ * bcmcli_session.c
+ *
+ * CLI engine - session management
+ *
+ *******************************************************************/
+
+#include <bcmos_system.h>
+#include <bcmolt_utils.h>
+
+#define BCMCLI_INTERNAL
+#include <bcmcli_session.h>
+
+static bcmos_fastlock session_lock;
+static bcmcli_session *session_list;
+static int session_module_initialized;
+
+/*
+ * Internal functions
+ */
+
+static void _bcmcli_session_update_prompt(bcmcli_session *session)
+{
+ if (!session)
+ return;
+
+ if (session->parms.get_prompt)
+ {
+ session->parms.get_prompt(session, session->prompt_buf, BCMCLI_MAX_PROMPT_LEN);
+ session->prompt_buf[BCMCLI_MAX_PROMPT_LEN - 1] = '\0';
+ }
+ else
+ {
+ session->prompt_buf[0] = '\0';
+ }
+}
+
+static char *_bcmcli_session_gets(bcmcli_session *session, char *buffer, uint32_t size)
+{
+ const char *line = NULL;
+ _bcmcli_session_update_prompt(session);
+#ifdef CONFIG_LIBEDIT
+ if (session && session->el && session->history)
+ {
+ int line_len;
+ line = (el_gets(session->el, &line_len));
+ if (!line)
+ return NULL;
+ if (line_len > size)
+ {
+ bcmos_printf("%s: buffer is too short %u - got %d. Truncated\n",
+ __FUNCTION__, size, line_len);
+ }
+ strncpy(buffer, line, size);
+ if (*line && *line != '\n' && *line != '#')
+ history(session->history, &session->histevent, H_ENTER, line);
+ }
+ else
+#endif
+#ifdef CONFIG_LINENOISE
+ if (session && session->ln_session)
+ {
+ char *ln_line = linenoise(session->ln_session, session->prompt_buf, buffer, size);
+ if (ln_line)
+ {
+ if (strlen(ln_line))
+ {
+ linenoiseHistoryAdd(session->ln_session, ln_line); /* Add to the history. */
+ }
+ else
+ {
+ strncpy(buffer, "\n", size-1);
+ }
+ buffer[size-1] = 0;
+ line = buffer;
+ }
+ }
+ else
+#endif
+ {
+ bcmcli_session_print(session, "%s", session->prompt_buf);
+ if (session && session->parms.gets)
+ line = session->parms.gets(session, buffer, size);
+ else
+ line = fgets(buffer, size, stdin);
+ }
+ return line ? buffer : NULL;
+}
+
+#ifdef CONFIG_LIBEDIT
+
+static char *_bcmcli_editline_prompt(EditLine *e)
+{
+ bcmcli_session *session = NULL;
+ el_get(e, EL_CLIENTDATA, &session);
+ BUG_ON(session == NULL || session->magic != BCMCLI_SESSION_MAGIC);
+ _bcmcli_session_update_prompt(session);
+ return session->prompt_buf;
+}
+
+static int _bcmcli_editline_cfn(EditLine *el, char *c)
+{
+ bcmcli_session *session = NULL;
+ char insert_buf[80];
+ int c1;
+ bcmos_errno rc;
+
+ el_get(el, EL_CLIENTDATA, &session);
+ BUG_ON(session == NULL || session->magic != BCMCLI_SESSION_MAGIC);
+ c1 = session->parms.get_char(session);
+
+ /* ToDo: handle \t parameter extension */
+ while (c1 > 0 && c1 == '\t')
+ {
+
+ const LineInfo *li = el_line(el);
+ char *line = bcmos_alloc(li->cursor - li->buffer + 1);
+ if (!line)
+ continue;
+ memcpy(line, li->buffer, li->cursor - li->buffer);
+ line[li->cursor - li->buffer] = 0;
+ rc = bcmcli_extend(session, line, insert_buf, sizeof(insert_buf));
+ bcmos_free(line);
+ if (rc)
+ {
+ c1 = session->parms.get_char(session);
+ continue;
+ }
+ el_insertstr(el, insert_buf);
+ printf("\r");
+ el_set(el, EL_REFRESH, NULL);
+ c1 = session->parms.get_char(session);
+ }
+ if (c1 < 0)
+ return -1;
+ *c = c1;
+ return 1;
+}
+#endif
+
+/* linenoise line editing library: completion support */
+#ifdef CONFIG_LINENOISE
+
+static int _bcmcli_linenoise_read_char(long fd_in, char *c)
+{
+ bcmcli_session *session = (bcmcli_session *)fd_in;
+ int c1;
+ c1 = session->parms.get_char(session);
+ if (c1 < 0)
+ {
+ return -1;
+ }
+ *c = c1;
+ return 1;
+}
+
+static int _bcmcli_linenoise_write(long fd_out, const char *buf, size_t len)
+{
+ bcmcli_session *session = (bcmcli_session *)fd_out;
+ /* Use a shortcut for len==1 - which is char-by-char input.
+ bcmos_printf("%*s", buf, 1) misbehaves on vxw platform,
+ possibly because it is too slow.
+ */
+ if (len == 1 && !session->parms.write)
+ {
+ bcmos_putchar(buf[0]);
+ return 1;
+ }
+ return bcmcli_session_write(session, buf, len);
+}
+
+static int _bcmcli_linenoise_tab(linenoiseSession *ln_session, const char *buf, int pos)
+{
+ bcmcli_session *session = NULL;
+ char *line;
+ char insert_buf[80]="";
+ bcmos_errno rc;
+ int len;
+
+ session = linenoiseSessionData(ln_session);
+ BUG_ON(session == NULL || session->magic != BCMCLI_SESSION_MAGIC);
+ line = bcmos_alloc(strlen(buf)+1);
+ if (!line)
+ return 0;
+ strcpy(line, buf);
+ rc = bcmcli_extend(session, line, insert_buf, sizeof(insert_buf));
+ bcmos_free(line);
+ if (rc || !strlen(insert_buf))
+ return 0;
+
+ len = strlen(buf);
+ line = bcmos_alloc(strlen(buf)+strlen(insert_buf)+1);
+ if (!line)
+ return 0;
+ if (pos >=0 && pos < len)
+ {
+ strncpy(line, buf, pos);
+ line[pos] = 0;
+ strcat(line, insert_buf);
+ strcat(line, &buf[pos]);
+ pos += strlen(insert_buf);
+ }
+ else
+ {
+ strcpy(line, buf);
+ strcat(line, insert_buf);
+ pos = strlen(line);
+ }
+ linenoiseSetBuffer(ln_session, line, pos);
+ bcmos_free(line);
+ return 1;
+}
+
+#endif
+
+/* Default getc function */
+static int _bcmcli_session_get_char(bcmcli_session *session)
+{
+ return bcmos_getchar();
+}
+
+/** Initialize session management module
+ * \return
+ * 0 =OK\n
+ * <0 =error code
+ */
+static void bcmcli_session_module_init(void)
+{
+ bcmos_fastlock_init(&session_lock, 0);
+ session_module_initialized = 1;
+}
+
+/** Open management session */
+int bcmcli_session_open_user(const bcmcli_session_parm *parm, bcmcli_session **p_session)
+{
+ bcmcli_session *session;
+ bcmcli_session **p_last_next;
+ const char *name;
+ char *name_clone;
+ long flags;
+ int size;
+
+ if (!p_session || !parm)
+ return BCM_ERR_PARM;
+#ifndef CONFIG_EDITLINE
+ if (parm->line_edit_mode == BCMCLI_LINE_EDIT_ENABLE)
+ {
+ bcmos_trace(BCMOS_TRACE_LEVEL_ERROR, "Line editing feature is not compiled in. define CONFIG_EDITLINE\n");
+ return BCM_ERR_NOT_SUPPORTED;
+ }
+#endif
+ if (!session_module_initialized)
+ bcmcli_session_module_init();
+ name = parm->name;
+ if (!name)
+ name = "*unnamed*";
+ size = sizeof(bcmcli_session) + strlen(name) + 1 + parm->extra_size;
+ session=bcmos_calloc(size);
+ if (!session)
+ return BCM_ERR_NOMEM;
+ session->parms = *parm;
+ name_clone = (char *)session + sizeof(bcmcli_session) + parm->extra_size;
+ strcpy(name_clone, name);
+ session->parms.name = name_clone;
+ if (!session->parms.get_char)
+ session->parms.get_char = _bcmcli_session_get_char;
+
+#ifdef CONFIG_LIBEDIT
+ if (!parm->gets && (parm->line_edit_mode == BCMCLI_LINE_EDIT_ENABLE ||
+ parm->line_edit_mode == BCMCLI_LINE_EDIT_DEFAULT))
+ {
+ /* Initialize editline library */
+ session->el = el_init(session->parms.name, stdin, stdout, stderr);
+ session->history = history_init();
+ if (session->el && session->history)
+ {
+ el_set(session->el, EL_EDITOR, "emacs");
+ el_set(session->el, EL_PROMPT, &_bcmcli_editline_prompt);
+ el_set(session->el, EL_TERMINAL, "xterm");
+ el_set(session->el, EL_GETCFN, _bcmcli_editline_cfn);
+ el_set(session->el, EL_CLIENTDATA, session);
+ history(session->history, &session->histevent, H_SETSIZE, 800);
+ el_set(session->el, EL_HIST, history, session->history);
+ }
+ else
+ {
+ bcmos_trace(BCMOS_TRACE_LEVEL_ERROR, "Can't initialize editline library\n");
+ bcmos_free(session);
+ return BCM_ERR_INTERNAL;
+ }
+ }
+#endif
+
+#ifdef CONFIG_LINENOISE
+ /* Set the completion callback. This will be called every time the
+ * user uses the <tab> key. */
+ if (!parm->gets && (parm->line_edit_mode == BCMCLI_LINE_EDIT_ENABLE ||
+ parm->line_edit_mode == BCMCLI_LINE_EDIT_DEFAULT))
+ {
+ linenoiseSessionIO io={.fd_in=(long)session, .fd_out=(long)session,
+ .read_char=_bcmcli_linenoise_read_char,
+ .write=_bcmcli_linenoise_write
+ };
+ if (linenoiseSessionOpen(&io, session, &session->ln_session))
+ {
+ bcmos_trace(BCMOS_TRACE_LEVEL_ERROR, "Can't create linenoise session\n");
+ bcmos_free(session);
+ return BCM_ERR_INTERNAL;
+ }
+ linenoiseSetCompletionCallback(session->ln_session, _bcmcli_linenoise_tab);
+ }
+#endif
+
+ session->magic = BCMCLI_SESSION_MAGIC;
+
+ flags = bcmos_fastlock_lock(&session_lock);
+ p_last_next = &session_list;
+ while(*p_last_next)
+ p_last_next = &((*p_last_next)->next);
+ *p_last_next = session;
+ bcmos_fastlock_unlock(&session_lock, flags);
+
+ *p_session = session;
+
+ return 0;
+}
+
+static int bcmcli_session_string_write(bcmcli_session *session, const char *buf, uint32_t size)
+{
+ bcmolt_string *str = bcmcli_session_user_priv(session);
+ return bcmolt_string_copy(str, buf, size);
+}
+
+bcmos_errno bcmcli_session_open_string(bcmcli_session **session, bcmolt_string *str)
+{
+ bcmcli_session_parm sp = { .user_priv = str, .write = bcmcli_session_string_write };
+
+ return bcmcli_session_open_user(&sp, session);
+}
+
+/** Close management session.
+ * \param[in] session Session handle
+ */
+void bcmcli_session_close(bcmcli_session *session)
+{
+ long flags;
+
+ BUG_ON(session->magic != BCMCLI_SESSION_MAGIC);
+ flags = bcmos_fastlock_lock(&session_lock);
+ if (session==session_list)
+ session_list = session->next;
+ else
+ {
+ bcmcli_session *prev = session_list;
+ while (prev && prev->next != session)
+ prev = prev->next;
+ if (!prev)
+ {
+ bcmos_fastlock_unlock(&session_lock, flags);
+ bcmos_trace(BCMOS_TRACE_LEVEL_ERROR, "%s: can't find session\n", __FUNCTION__);
+ return;
+ }
+ prev->next = session->next;
+ }
+ bcmos_fastlock_unlock(&session_lock, flags);
+
+#ifdef CONFIG_LIBEDIT
+ if (session->history)
+ history_end(session->history);
+ if (session->el)
+ el_end(session->el);
+#endif
+#ifdef CONFIG_LINENOISE
+ if (session->ln_session)
+ linenoiseSessionClose(session->ln_session);
+#endif
+ session->magic = BCMCLI_SESSION_MAGIC_DEL;
+ bcmos_free(session);
+
+}
+
+/** Configure RAW input mode
+ *
+ * \param[in] session Session handle
+ * \param[in] is_raw TRUE=enable raw mode, FALSE=disable raw mode
+ * \return
+ * =0 - OK \n
+ * BCM_ERR_NOT_SUPPORTED - raw mode is not supported\n
+ */
+bcmos_errno bcmcli_session_raw_mode_set(bcmcli_session *session, bcmos_bool is_raw)
+{
+#ifdef CONFIG_LINENOISE
+ int rc;
+ if (session->parms.gets)
+ return BCM_ERR_NOT_SUPPORTED;
+ rc = linenoiseSetRaw(session->ln_session, is_raw);
+ return (rc == 0) ? BCM_ERR_OK : BCM_ERR_NOT_SUPPORTED;
+#else
+ return BCM_ERR_NOT_SUPPORTED;
+#endif
+}
+
+/** Default write callback function
+ * write to stdout
+ */
+static int _bcmcli_session_write(bcmcli_session *session, const char *buf, uint32_t size)
+{
+ return bcmos_printf("%.*s", size, buf);
+}
+
+
+/** Write function.
+ * Write buffer to the current session.
+ * \param[in] session Session handle. NULL=use stdout
+ * \param[in] buffer output buffer
+ * \param[in] size number of bytes to be written
+ * \return
+ * >=0 - number of bytes written\n
+ * <0 - output error
+ */
+int bcmcli_session_write(bcmcli_session *session, const char *buf, uint32_t size)
+{
+ int (*write_cb)(bcmcli_session *session, const char *buf, uint32_t size);
+ if (session && session->parms.write)
+ {
+ BUG_ON(session->magic != BCMCLI_SESSION_MAGIC);
+ write_cb = session->parms.write;
+ }
+ else
+ write_cb = _bcmcli_session_write;
+ return write_cb(session, buf, size);
+}
+
+
+/** Read line
+ * \param[in] session Session handle. NULL=use default
+ * \param[in,out] buf input buffer
+ * \param[in] size buf size
+ * \return
+ * buf if successful
+ * NULL if EOF or error
+ */
+char *bcmcli_session_gets(bcmcli_session *session, char *buf, uint32_t size)
+{
+ return _bcmcli_session_gets(session, buf, size);
+}
+
+
+/** Print function.
+ * Prints in the context of current session.
+ * \param[in] session Session handle. NULL=use stdout
+ * \param[in] format print format - as in printf
+ * \param[in] ap parameters list. Undefined after the call
+ */
+void bcmcli_session_vprint(bcmcli_session *session, const char *format, va_list ap)
+{
+ if (session && session->parms.write)
+ {
+ BUG_ON(session->magic != BCMCLI_SESSION_MAGIC);
+ vsnprintf(session->outbuf, sizeof(session->outbuf), format, ap);
+ bcmcli_session_write(session, session->outbuf, strlen(session->outbuf));
+ }
+ else
+ bcmos_vprintf(format, ap);
+}
+
+
+/** Print function.
+ * Prints in the context of current session.
+ * \param[in] session Session handle. NULL=use stdout
+ * \param[in] format print format - as in printf
+ */
+void bcmcli_session_print(bcmcli_session *session, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ bcmcli_session_vprint(session, format, ap);
+ va_end(ap);
+}
+
+/** Get user_priv provoded in session partameters when it was registered
+ * \param[in] session Session handle. NULL=use stdin
+ * \return usr_priv value
+ */
+void *bcmcli_session_user_priv(bcmcli_session *session)
+{
+ if (!session)
+ return NULL;
+ BUG_ON(session->magic != BCMCLI_SESSION_MAGIC);
+ return session->parms.user_priv;
+}
+
+
+/** Get extra data associated with the session
+ * \param[in] session Session handle. NULL=default session
+ * \return extra_data pointer or NULL if there is no extra data
+ */
+void *bcmcli_session_data(bcmcli_session *session)
+{
+ if (!session)
+ return NULL;
+ BUG_ON(session->magic != BCMCLI_SESSION_MAGIC);
+ if (session->parms.extra_size <= 0)
+ return NULL;
+ return (char *)session + sizeof(*session);
+}
+
+
+/** Get session namedata
+ * \param[in] session Session handle. NULL=default session
+ * \return session name
+ */
+const char *bcmcli_session_name(bcmcli_session *session)
+{
+ if (!session)
+ return NULL;
+ BUG_ON(session->magic != BCMCLI_SESSION_MAGIC);
+ return session->parms.name;
+}
+
+
+/** Get session access righte
+ * \param[in] session Session handle. NULL=default debug session
+ * \return session access right
+ */
+bcmcli_access_right bcmcli_session_access_right(bcmcli_session *session)
+{
+ if (!session)
+ return BCMCLI_ACCESS_DEBUG;
+ BUG_ON(session->magic != BCMCLI_SESSION_MAGIC);
+ return session->parms.access_right;
+}
+
+/** Print buffer in hexadecimal format
+ * \param[in] session Session handle. NULL=use stdout
+ * \param[in] buffer Buffer address
+ * \param[in] offset Start offset in the buffer
+ * \param[in] count Number of bytes to dump
+ * \param[in] indent Optional indentation string
+ */
+void bcmcli_session_hexdump(bcmcli_session *session, const void *buffer, uint32_t offset, uint32_t count, const char *indent)
+{
+ bcmos_hexdump((bcmos_msg_print_cb)bcmcli_session_print, session, buffer, offset, count, indent);
+}
+
+/*
+ * Exports
+ */
+EXPORT_SYMBOL(bcmcli_session_open);
+EXPORT_SYMBOL(bcmcli_session_close);
+EXPORT_SYMBOL(bcmcli_session_write);
+EXPORT_SYMBOL(bcmcli_session_vprint);
+EXPORT_SYMBOL(bcmcli_session_print);
+EXPORT_SYMBOL(bcmcli_session_access_right);
+EXPORT_SYMBOL(bcmcli_session_data);
+EXPORT_SYMBOL(bcmcli_session_name);
+EXPORT_SYMBOL(bcmcli_session_hexdump);