/*
 *  Hamlib Interface - sprintf toolbox
 *  Copyright (c) 2000-2009 by Stephane Fillod
 *  Copyright (c) 2000-2003 by Frank Singleton
 *
 *
 *   This library is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU Lesser General Public
 *   License as published by the Free Software Foundation; either
 *   version 2.1 of the License, or (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *   Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public
 *   License along with this library; if not, write to the Free Software
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include "hamlib/config.h"

#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */

#include "hamlib/rig.h"
#include "hamlib/rotator.h"
#include "hamlib/amplifier.h"
#include "../rigs/icom/icom.h"


#include "sprintflst.h"
#include "misc.h"

/* #define DUMMY_ALL 0x7ffffffffffffffLL */
#define DUMMY_ALL ((setting_t)-1)

// just doing a warning message for now
// eventually should make this -RIG_EINTERNAL
static int check_buffer_overflow(char *str, int len, int nlen)
{
    if (len + 32 >= nlen) // make sure at least 32 bytes are available
    {
        rig_debug(RIG_DEBUG_ERR,
                  "%s: buffer overflow, len=%d, nlen=%d, str='%s', len+32 must be >= nlen\n",
                  __func__, len, nlen, str);
    }

    return RIG_OK;
}

int rig_sprintf_vfo(char *str, int nlen, vfo_t vfo)
{
    unsigned int i;
    int len = 0;

    rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __func__, rig_strvfo(vfo));
    *str = '\0';

    if (vfo == RIG_VFO_NONE)
    {
        return 0;
    }

    for (i = 0; i < HAMLIB_MAX_VFOS; i++)
    {
        const char *sv = rig_strvfo(vfo & RIG_VFO_N(i));

        if (sv && sv[0] && (strstr(sv, "None") == 0))
        {
            int written = snprintf(str + len, nlen - len, "%s ", sv);

            if (written < 0 || written >= nlen - len)
            {
                // Truncate and break if there's no space left
                rig_debug(RIG_DEBUG_ERR, "%s: buffer overflow\n", __func__);
                len = nlen - 1;
                str[len] = '\0';
                break;
            }

            len += written;
        }

        if (len >= nlen)
        {
            // Ensure null-termination and avoid overflow
            rig_debug(RIG_DEBUG_ERR, "%s: buffer overflow\n", __func__);
            str[nlen - 1] = '\0';
            break;
        }
    }

    return len;
}

int rig_sprintf_mode(char *str, int nlen, rmode_t mode)
{
    unsigned int i, len = 0;

    *str = '\0';

    if (mode == RIG_MODE_NONE)
    {
        return 0;
    }

    for (i = 0; i < HAMLIB_MAX_MODES; i++)
    {
        const char *ms = rig_strrmode(mode & (1ULL << i));

        if (!ms || !ms[0])
        {
            continue;    /* unknown, FIXME! */
        }

        if (i > 0) { strcat(str, " "); }

        strcat(str, ms);
        len += strlen(ms) + 1;
        check_buffer_overflow(str, len, nlen);
    }

    return len;
}

int rig_sprintf_ant(char *str, int str_len, ant_t ant)
{
    int i, len = 0;
    const char *ant_name;

    *str = '\0';

    if (ant == RIG_ANT_NONE)
    {
        snprintf(str, str_len, "ANT_NONE");
        return (int)strlen(str); // Return length of "ANT_NONE"
    }

    for (i = 0; i < RIG_ANT_MAX; i++)
    {
        if (ant & (1UL << i))
        {
            switch (i)
            {
            case 0: ant_name = "ANT1"; break;

            case 1: ant_name = "ANT2"; break;

            case 2: ant_name = "ANT3"; break;

            case 3: ant_name = "ANT4"; break;

            case 4: ant_name = "ANT5"; break;

            case 30: ant_name = "ANT_UNKNOWN"; break;

            case 31: ant_name = "ANT_CURR"; break;

            default:
                ant_name = "ANT_UNK";
                rig_debug(RIG_DEBUG_ERR, "%s: unknown ant=%d\n", __func__, i);
                break;
            }

            int written = snprintf(str + len, str_len - len, "%s ", ant_name);

            if (written < 0 || written >= str_len - len)
            {
                // Truncate if buffer is full
                rig_debug(RIG_DEBUG_ERR, "%s: buffer overflow\n", __func__);
                len = str_len - 1;
                str[len] = '\0';
                break;
            }

            len += written;
        }

        if (len >= str_len)
        {
            // Ensure null-termination
            rig_debug(RIG_DEBUG_ERR, "%s: buffer overflow\n", __func__);
            str[str_len - 1] = '\0';
            break;
        }
    }

    return len;
}

int rig_sprintf_func(char *str, int nlen, setting_t func)
{
    unsigned int i, len = 0;

    *str = '\0';

    if (func == RIG_FUNC_NONE)
    {
        return 0;
    }

    for (i = 0; i < RIG_SETTING_MAX; i++)
    {
        const char *ms = rig_strfunc(func & rig_idx2setting(i));

        if (!ms)
        {
            rig_debug(RIG_DEBUG_ERR, "%s: unknown RIG_FUNC=%x\n", __func__, i);
            continue;    /* unknown, FIXME! */
        }

        if (ms[0])
        {
            strcat(str, ms);
            strcat(str, " ");
            len += strlen(ms) + 1;
            check_buffer_overflow(str, len, nlen);
        }
    }

    return len;
}


int rot_sprintf_func(char *str, int nlen, setting_t func)
{
    unsigned int i, len = 0;

    *str = '\0';

    if (func == ROT_FUNC_NONE)
    {
        return 0;
    }

    for (i = 0; i < RIG_SETTING_MAX; i++)
    {
        const char *ms = rot_strfunc(func & rig_idx2setting(i));

        if (!ms || !ms[0])
        {
            continue;    /* unknown, FIXME! */
        }

        strcat(str, ms);
        strcat(str, " ");
        len += strlen(ms) + 1;
        check_buffer_overflow(str, len, nlen);
    }

    return len;
}


int rig_sprintf_level(char *str, int nlen, setting_t level)
{
    int i, len = 0;

    *str = '\0';

    if (level == RIG_LEVEL_NONE)
    {
        return 0;
    }

    for (i = 0; i < RIG_SETTING_MAX; i++)
    {
        const char *ms = rig_strlevel(level & rig_idx2setting(i));

        if (!ms || !ms[0])
        {
            continue;    /* unknown, FIXME! */
        }

        strcat(str, ms);
        strcat(str, " ");
        len += strlen(ms) + 1;
        check_buffer_overflow(str, len, nlen);
    }

    return len;
}


int rot_sprintf_level(char *str, int nlen, setting_t level)
{
    int i, len = 0;

    *str = '\0';

    if (level == ROT_LEVEL_NONE)
    {
        return 0;
    }

    for (i = 0; i < RIG_SETTING_MAX; i++)
    {
        const char *ms = rot_strlevel(level & rig_idx2setting(i));

        if (!ms || !ms[0])
        {
            continue;    /* unknown, FIXME! */
        }

        strcat(str, ms);
        strcat(str, " ");
        len += strlen(ms) + 1;
        check_buffer_overflow(str, len, nlen);
    }

    return len;
}


int amp_sprintf_level(char *str, int nlen, setting_t level)
{
    int i, len = 0;

    *str = '\0';

    if (level == AMP_LEVEL_NONE)
    {
        return 0;
    }

    for (i = 0; i < RIG_SETTING_MAX; i++)
    {
        const char *ms = amp_strlevel(level & rig_idx2setting(i));

        if (!ms || !ms[0])
        {
            continue;    /* unknown, FIXME! */
        }

        strcat(str, ms);
        strcat(str, " ");
        len += strlen(ms) + 1;
        check_buffer_overflow(str, len, nlen);
    }

    return len;
}


int sprintf_level_ext(char *str, int nlen, const struct confparams *extlevels)
{
    int len = 0;

    *str = '\0';

    if (!extlevels)
    {
        return 0;
    }

    for (; extlevels->token != RIG_CONF_END; extlevels++)
    {
        if (!extlevels->name)
        {
            continue;    /* no name */
        }

        switch (extlevels->type)
        {
        case RIG_CONF_INT:
        case RIG_CONF_CHECKBUTTON:
        case RIG_CONF_COMBO:
        case RIG_CONF_NUMERIC:
        case RIG_CONF_STRING:
        case RIG_CONF_BINARY:
            strcat(str, extlevels->name);
            strcat(str, " ");
            len += strlen(extlevels->name) + 1;
            break;

        case RIG_CONF_BUTTON:
            /* ignore case RIG_CONF_BUTTON */
            break;
        }

        check_buffer_overflow(str, len, nlen);
    }

    return len;
}

int rig_sprintf_level_gran(char *str, int nlen, setting_t level,
                           const gran_t *gran)
{
    int i, len = 0;

    *str = '\0';

    if (level == RIG_LEVEL_NONE)
    {
        return 0;
    }

    for (i = 0; i < RIG_SETTING_MAX; i++)
    {
        const char *ms;

        if (!(level & rig_idx2setting(i)))
        {
            continue;
        }

        ms = rig_strlevel(level & rig_idx2setting(i));

        if (!ms || !ms[0])
        {
            if (level != DUMMY_ALL && level != RIG_LEVEL_SET(DUMMY_ALL))
            {
                rig_debug(RIG_DEBUG_BUG, "unknown level idx %d\n", i);
            }

            continue;
        }

        int written;

        if (RIG_LEVEL_IS_FLOAT(rig_idx2setting(i)))
        {
            written = snprintf(str + len, nlen - len, "%s(%f..%f/%f) ", ms, gran[i].min.f,
                               gran[i].max.f, gran[i].step.f);
        }
        else
        {
            written = snprintf(str + len, nlen - len, "%s(%d..%d/%d) ", ms, gran[i].min.i,
                               gran[i].max.i, gran[i].step.i);
        }

        if (written < 0 || written >= nlen - len)
        {
            // Truncate and stop further processing if the buffer is full
            rig_debug(RIG_DEBUG_ERR, "%s: buffer overflow\n", __func__);
            len = nlen - 1;
            str[len] = '\0';
            break;
        }

        len += written;

        if (len >= nlen)
        {
            // Ensure null-termination and avoid overflow
            rig_debug(RIG_DEBUG_ERR, "%s: buffer overflow\n", __func__);
            str[nlen - 1] = '\0';
            break;
        }
    }

    return len;
}

int rot_sprintf_level_gran(char *str, int nlen, setting_t level,
                           const gran_t *gran)
{
    int i, len = 0;

    *str = '\0';

    if (level == ROT_LEVEL_NONE)
    {
        return 0;
    }

    for (i = 0; i < RIG_SETTING_MAX; i++)
    {
        const char *ms;

        if (!(level & rig_idx2setting(i)))
        {
            continue;
        }

        ms = rot_strlevel(level & rig_idx2setting(i));

        if (!ms || !ms[0])
        {
            if (level != DUMMY_ALL && level != ROT_LEVEL_SET(DUMMY_ALL))
            {
                rig_debug(RIG_DEBUG_BUG, "unknown level idx %d\n", i);
            }

            continue;
        }

        int written;

        if (ROT_LEVEL_IS_FLOAT(rig_idx2setting(i)))
        {
            written = snprintf(str + len, nlen - len, "%s(%f..%f/%f) ", ms, gran[i].min.f,
                               gran[i].max.f, gran[i].step.f);
        }
        else
        {
            written = snprintf(str + len, nlen - len, "%s(%d..%d/%d) ", ms, gran[i].min.i,
                               gran[i].max.i, gran[i].step.i);
        }

        if (written < 0 || written >= nlen - len)
        {
            // Truncate and stop further processing if the buffer is full
            len = nlen - 1;
            rig_debug(RIG_DEBUG_ERR, "%s: buffer overflow\n", __func__);
            str[len] = '\0';
            break;
        }

        len += written;

        if (len >= nlen)
        {
            // Ensure null-termination and avoid overflow
            rig_debug(RIG_DEBUG_ERR, "%s: buffer overflow\n", __func__);
            str[nlen - 1] = '\0';
            break;
        }
    }

    return len;
}

int rig_sprintf_parm(char *str, int nlen, setting_t parm)
{
    int i, len = 0;

    *str = '\0';

    if (parm == RIG_PARM_NONE)
    {
        return 0;
    }

    for (i = 0; i < RIG_SETTING_MAX; i++)
    {
        const char *ms = rig_strparm(parm & rig_idx2setting(i));

        if (!ms || !ms[0])
        {
            continue;    /* unknown, FIXME! */
        }

        strcat(str, ms);
        strcat(str, " ");
        len += strlen(ms) + 1;
        check_buffer_overflow(str, len, nlen);
    }

    return len;
}

int rot_sprintf_parm(char *str, int nlen, setting_t parm)
{
    int i, len = 0;

    *str = '\0';

    if (parm == ROT_PARM_NONE)
    {
        return 0;
    }

    for (i = 0; i < RIG_SETTING_MAX; i++)
    {
        const char *ms = rot_strparm(parm & rig_idx2setting(i));

        if (!ms || !ms[0])
        {
            continue; /* unknown, FIXME! */
        }

        int written = snprintf(str + len, nlen - len, "%s ", ms);

        if (written < 0 || written >= nlen - len)
        {
            // Truncate and stop further processing if the buffer is full
            rig_debug(RIG_DEBUG_ERR, "%s: buffer overflow\n", __func__);
            len = nlen - 1;
            str[len] = '\0';
            break;
        }

        len += written;

        if (len >= nlen)
        {
            // Ensure null-termination and avoid overflow
            rig_debug(RIG_DEBUG_ERR, "%s: buffer overflow\n", __func__);
            str[nlen - 1] = '\0';
            break;
        }
    }

    return len;
}

int rig_sprintf_parm_gran(char *str, int nlen, setting_t parm,
                          const gran_t *gran)
{
    int i, len = 0;
    *str = '\0';

    if (parm == RIG_PARM_NONE)
    {
        return 0;
    }

    for (i = 0; i < RIG_SETTING_MAX; i++)
    {
        const char *ms;

        if (!(parm & rig_idx2setting(i)))
        {
            continue;
        }

        ms = rig_strparm(parm & rig_idx2setting(i));

        if (!ms || !ms[0])
        {
            if (parm != DUMMY_ALL && parm != RIG_PARM_SET(DUMMY_ALL))
            {
                rig_debug(RIG_DEBUG_BUG, "unknown parm idx %d\n", i);
            }

            continue;
        }

        int written;

        if (RIG_PARM_IS_FLOAT(rig_idx2setting(i)))
        {
            written = snprintf(str + len, nlen - len, "%s(%.g..%.g/%.g) ", ms,
                               gran[i].min.f, gran[i].max.f, gran[i].step.f);
        }
        else if (RIG_PARM_IS_STRING(rig_idx2setting(i)))
        {
            if (gran[i].step.s)
            {
                written = snprintf(str + len, nlen - len, "%s(%s) ", ms, gran[i].step.s);
            }
            else
            {
                continue;
            }
        }
        else
        {
            written = snprintf(str + len, nlen - len, "%s(%d..%d/%d) ", ms, gran[i].min.i,
                               gran[i].max.i, gran[i].step.i);
        }

        if (written < 0 || written >= nlen - len)
        {
            // Truncate and stop further processing if the buffer is full
            rig_debug(RIG_DEBUG_ERR, "%s: buffer overflow\n", __func__);
            len = nlen - 1;
            str[len] = '\0';
            break;
        }

        len += written;

        if (len >= nlen)
        {
            // Ensure null-termination and avoid overflow
            rig_debug(RIG_DEBUG_ERR, "%s: buffer overflow\n", __func__);
            str[nlen - 1] = '\0';
            break;
        }
    }

    return len;
}

int rot_sprintf_parm_gran(char *str, int nlen, setting_t parm,
                          const gran_t *gran)
{
    int i, len = 0;
    *str = '\0';

    if (parm == ROT_PARM_NONE)
    {
        return 0;
    }

    for (i = 0; i < RIG_SETTING_MAX; i++)
    {
        const char *ms;

        if (!(parm & rig_idx2setting(i)))
        {
            continue;
        }

        ms = rot_strparm(parm & rig_idx2setting(i));

        if (!ms || !ms[0])
        {
            if (parm != DUMMY_ALL && parm != ROT_PARM_SET(DUMMY_ALL))
            {
                rig_debug(RIG_DEBUG_BUG, "unknown parm idx %d\n", i);
            }

            continue;
        }

        int written;

        if (ROT_PARM_IS_FLOAT(rig_idx2setting(i)))
        {
            written = snprintf(str + len, nlen - len, "%s(%f..%f/%f) ", ms, gran[i].min.f,
                               gran[i].max.f, gran[i].step.f);
        }
        else
        {
            written = snprintf(str + len, nlen - len, "%s(%d..%d/%d) ", ms, gran[i].min.i,
                               gran[i].max.i, gran[i].step.i);
        }

        if (written < 0 || written >= nlen - len)
        {
            // Truncate and stop further processing if the buffer is full
            rig_debug(RIG_DEBUG_ERR, "%s: buffer overflow\n", __func__);
            len = nlen - 1;
            str[len] = '\0';
            break;
        }

        len += written;

        if (len >= nlen)
        {
            // Ensure null-termination and avoid overflow
            rig_debug(RIG_DEBUG_ERR, "%s: buffer overflow\n", __func__);
            str[nlen - 1] = '\0';
            break;
        }
    }

    return len;
}

int rig_sprintf_vfop(char *str, int nlen, vfo_op_t op)
{
    int i, len = 0;

    *str = '\0';

    if (op == RIG_OP_NONE)
    {
        return 0;
    }

    for (i = 0; i < HAMLIB_MAX_VFO_OPS; i++)
    {
        const char *ms = rig_strvfop(op & (1UL << i));

        if (!ms || !ms[0])
        {
            continue;    /* unknown, FIXME! */
        }

        strcat(str, ms);
        strcat(str, " ");
        len += strlen(ms) + 1;
        check_buffer_overflow(str, len, nlen);
    }

    return len;
}


int rig_sprintf_scan(char *str, int nlen, scan_t rscan)
{
    int i, len = 0;

    *str = '\0';

    if (rscan == RIG_SCAN_NONE)
    {
        return 0;
    }

    for (i = 0; i < HAMLIB_MAX_RSCANS; i++)
    {
        const char *ms = rig_strscan(rscan & (1UL << i));

        if (!ms || !ms[0])
        {
            continue;    /* unknown, FIXME! */
        }

        strcat(str, ms);
        strcat(str, " ");
        len += strlen(ms) + 1;
        check_buffer_overflow(str, len, nlen);
    }

    return len;
}

int rot_sprintf_status(char *str, int nlen, rot_status_t status)
{
    int len = 0;
    unsigned long i;

    rig_debug(RIG_DEBUG_TRACE, "%s: status=%08x\n", __func__, status);
    *str = '\0';

    if (status == ROT_STATUS_NONE)
    {
        return 0;
    }

    for (i = 0; i < HAMLIB_MAX_ROTORS; i++)
    {
        const char *sv = rot_strstatus(status & ROT_STATUS_N(i));

        if (sv && sv[0] && (strstr(sv, "None") == 0))
        {
            int written = snprintf(str + len, nlen - len, "%s ", sv);

            if (written < 0 || written >= nlen - len)
            {
                // Truncate and break if there's no space left
                rig_debug(RIG_DEBUG_ERR, "%s: buffer overflow\n", __func__);
                len = nlen - 1;
                str[len] = '\0';
                break;
            }

            len += written;
        }

        if (len >= nlen)
        {
            // Ensure null-termination and avoid overflow
            rig_debug(RIG_DEBUG_ERR, "%s: buffer overflow\n", __func__);
            str[nlen - 1] = '\0';
            break;
        }
    }

    return len;
}


int rig_sprintf_spectrum_modes(char *str, int nlen,
                               const enum rig_spectrum_mode_e *modes)
{
    int i, len = 0;

    *str = '\0';

    for (i = 0; i < HAMLIB_MAX_SPECTRUM_MODES; i++)
    {
        const char *sm;
        int lentmp;

        if (modes[i] == RIG_SPECTRUM_MODE_NONE)
        {
            break;
        }

        sm = rig_strspectrummode(modes[i]);

        if (!sm || !sm[0])
        {
            break;
        }

        lentmp = snprintf(str + len, nlen - len, "%d=%s ", modes[i], sm);

        if (len < 0 || lentmp >= nlen - len)
        {
            rig_debug(RIG_DEBUG_ERR, "%s(%d): overflowed str buffer\n", __FILE__, __LINE__);
            break;
        }

        len += lentmp;

        check_buffer_overflow(str, len, nlen);

    }

    return len;
}

int rig_sprintf_spectrum_spans(char *str, int nlen, const freq_t *spans)
{
    int i, len = 0;

    *str = '\0';

    for (i = 0; i < HAMLIB_MAX_SPECTRUM_SPANS; i++)
    {
        int lentmp;

        if (spans[i] == 0)
        {
            break;
        }

        lentmp = snprintf(str + len, nlen - len, "%.0f ", spans[i]);

        if (len < 0 || lentmp >= nlen - len)
        {
            rig_debug(RIG_DEBUG_ERR, "%s(%d): overflowed str buffer\n", __FILE__, __LINE__);
            break;
        }

        len += lentmp;
        check_buffer_overflow(str, len, nlen);
    }

    return len;
}

int rig_sprintf_spectrum_avg_modes(char *str, int nlen,
                                   const struct rig_spectrum_avg_mode *avg_modes)
{
    int i, len = 0;

    *str = '\0';

    for (i = 0; i < HAMLIB_MAX_SPECTRUM_MODES; i++)
    {
        int lentmp;

        if (avg_modes[i].name == NULL || avg_modes[i].id < 0)
        {
            break;
        }

        lentmp = snprintf(str + len, nlen - len, "%d=\"%s\" ", avg_modes[i].id,
                          avg_modes[i].name);

        if (len < 0 || lentmp >= nlen - len)
        {
            rig_debug(RIG_DEBUG_ERR, "%s(%d): overflowed str buffer\n", __FILE__, __LINE__);
            break;
        }

        len += lentmp;
        check_buffer_overflow(str, len, nlen);
    }

    return len;
}

int rig_sprintf_tuning_steps(char *str, int nlen,
                             const struct tuning_step_list *tuning_step_list)
{
    int i, len = 0;

    *str = '\0';

    for (i = 0; i < HAMLIB_TSLSTSIZ; i++)
    {
        int lentmp;

        if (tuning_step_list[i].modes == RIG_MODE_NONE)
        {
            break;
        }

        lentmp = snprintf(str + len, nlen - len, "%s%d", i > 0 ? ", " : "",
                          (int)tuning_step_list[i].ts);

        if (len < 0 || lentmp >= nlen - len)
        {
            rig_debug(RIG_DEBUG_ERR, "%s(%d): overflowed str buffer\n", __FILE__, __LINE__);
            break;
        }

        len += lentmp;
        check_buffer_overflow(str, len, nlen);
    }

    return len;

}

char *get_rig_conf_type(enum rig_conf_e type)
{
    switch (type)
    {
    case RIG_CONF_STRING:
        return "STRING";

    case RIG_CONF_COMBO:
        return "COMBO";

    case RIG_CONF_NUMERIC:
        return "NUMERIC";

    case RIG_CONF_CHECKBUTTON:
        return "CHECKBUTTON";

    case RIG_CONF_BUTTON:
        return "BUTTON";

    case RIG_CONF_BINARY:
        return "BINARY";

    case RIG_CONF_INT:
        return "INT";
    }

    return "UNKNOWN";
}

int print_ext_param(const struct confparams *cfp, rig_ptr_t ptr)
{
    int i;
    fprintf((FILE *)ptr, "\t%s\n", cfp->name);
    fprintf((FILE *)ptr, "\t\tType: %s\n", get_rig_conf_type(cfp->type));
    fprintf((FILE *)ptr, "\t\tDefault: %s\n", cfp->dflt != NULL ? cfp->dflt : "");
    fprintf((FILE *)ptr, "\t\tLabel: %s\n", cfp->label != NULL ? cfp->label : "");
    fprintf((FILE *)ptr, "\t\tTooltip: %s\n",
            cfp->tooltip != NULL ? cfp->tooltip : "");

    switch (cfp->type)
    {
    case RIG_CONF_NUMERIC:
        fprintf((FILE *)ptr, "\t\tRange: %f..%f/%f\n", cfp->u.n.min, cfp->u.n.max,
                cfp->u.n.step);
        break;

    case RIG_CONF_INT:
        fprintf((FILE *)ptr, "\t\tRange: %d..%d/%d\n", (int) cfp->u.n.min,
                (int) cfp->u.n.max,
                (int) cfp->u.n.step);
        break;

    case RIG_CONF_COMBO:
        fprintf((FILE *)ptr, "\t\tValues:");

        for (i = 0; i < RIG_COMBO_MAX && cfp->u.c.combostr[i] != NULL; i++)
        {
            fprintf((FILE *)ptr, " %d=\"%s\"", i, cfp->u.c.combostr[i]);
        }

        fprintf((FILE *)ptr, "\n");
        break;

    default:
        break;
    }

    return 1;       /* process them all */
}

int rig_sprintf_agc_levels(RIG *rig, char *str, int lenstr)
{
    const struct icom_priv_caps *priv_caps =
        (const struct icom_priv_caps *) rig->caps->priv;

    int len = 0;
    int i;
    char tmpbuf[256];

    str[len] = 0;

    if (priv_caps && RIG_BACKEND_NUM(rig->caps->rig_model) == RIG_ICOM
            && priv_caps->agc_levels_present)
    {
        for (i = 0; i <= HAMLIB_MAX_AGC_LEVELS
                && priv_caps->agc_levels[i].level != RIG_AGC_LAST
                ; i++)
        {
            if (strlen(str) > 0) { strcat(str, " "); }

            snprintf(tmpbuf, sizeof(tmpbuf), "%d=%s", priv_caps->agc_levels[i].icom_level,
                     rig_stragclevel(priv_caps->agc_levels[i].level));

            if (strlen(str) + strlen(tmpbuf) < lenstr - 1)
            {
                strncat(str, tmpbuf, lenstr - 1);
            }
            else
            {
                rig_debug(RIG_DEBUG_ERR, "%s: buffer overrun!!  len=%d > maxlen=%d\n",
                          __func__, (int)(strlen(str) + strlen(tmpbuf)), lenstr - 1);
            }
        }
    }
    else
    {
        for (i = 0; i < HAMLIB_MAX_AGC_LEVELS && i < rig->caps->agc_level_count; i++)
        {
            if (strlen(str) > 0) { strcat(str, " "); }

            snprintf(tmpbuf, sizeof(tmpbuf), "%d=%s", rig->caps->agc_levels[i],
                     rig_stragclevel(rig->caps->agc_levels[i]));

            if (strlen(str) + strlen(tmpbuf) < lenstr - 1)
            {
                strncat(str, tmpbuf, lenstr - 1);
            }
            else
            {
                rig_debug(RIG_DEBUG_ERR, "%s: buffer overrun!!  len=%d > maxlen=%d\n",
                          __func__, (int)(strlen(str) + strlen(tmpbuf)), lenstr - 1);
            }
        }
    }

    return strlen(str);
}
