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);