/*
**  OSSP l2 - Flexible Logging
**  Copyright (c) 2001-2003 Cable & Wireless Deutschland GmbH
**  Copyright (c) 2001-2003 The OSSP Project (http://www.ossp.org/)
**  Copyright (c) 2001-2003 Ralf S. Engelschall <rse@engelschall.com>
**
**  This file is part of OSSP l2, a flexible logging library which
**  can be found at http://www.ossp.org/pkg/lib/l2/.
**
**  Permission to use, copy, modify, and distribute this software for
**  any purpose with or without fee is hereby granted, provided that
**  the above copyright notice and this permission notice appear in all
**  copies.
**
**  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR
**  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.
**
**  l2_ut_level.c: level mask transformations
*/

#include "l2.h"
#include "l2_p.h"

#include <string.h>
#include <ctype.h>

static struct {
    l2_level_t level;
    char *string;
} l2s_table[] = {
    { L2_LEVEL_PANIC,    "panic"    },
    { L2_LEVEL_CRITICAL, "critical" },
    { L2_LEVEL_ERROR,    "error"    },
    { L2_LEVEL_WARNING,  "warning"  },
    { L2_LEVEL_NOTICE,   "notice"   },
    { L2_LEVEL_INFO,     "info"     },
    { L2_LEVEL_TRACE,    "trace"    },
    { L2_LEVEL_DEBUG,    "debug"    },
    { 0,                 NULL       }
};

l2_result_t l2_util_l2s(char *string, size_t maxlen, int sep, unsigned int levelmask)
{
    char hexbuf[2+(sizeof(unsigned int)*2)+1];
    int len;
    int i;
    int l;

    len = maxlen;
    string[0] = '\0';
    for (i = 0; l2s_table[i].level != 0; i++) {
        if (levelmask & l2s_table[i].level) {
            levelmask &= ~(l2s_table[i].level);
            l = strlen(l2s_table[i].string) + 1;
            if (len < l)
                return L2_ERR_MEM;
            sprintf(string+(maxlen-len), "%s%c", l2s_table[i].string, sep);
            len -= l;
        }
    }
    if (levelmask != 0) {
        sprintf(hexbuf, "0x%x", levelmask);
        l = strlen(hexbuf) + 1;
        if (len < l)
            return L2_ERR_MEM;
        sprintf(string+(maxlen-len), "%s%c", hexbuf, sep);
        len -= l;
    }
    /* remove trailing comma */
    if ((maxlen-len) > 0)
        string[(maxlen-len)-1] = '\0';

    return L2_OK;
}

static unsigned int hexval(const char *cpB, const char *cpE)
{
    unsigned int hv;
    unsigned int nibble;

    hv = 0;
    while (cpB < cpE) {
        nibble = tolower((unsigned int)(*cpB++));
        if (isdigit(nibble))
            nibble = nibble - '0';
        else
            nibble = nibble - 'a';
        hv = ((hv << 4) | nibble);
    }
    return hv;
}

static int myishexnumber(int c)
{
    if (isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
        return 1;
    return 0;
}

l2_result_t l2_util_s2l(const char *string, size_t maxlen, int sep, unsigned int *levelmask)
{
    const char *cpB;
    const char *cpE;
    int bFound;
    int i;

    *levelmask = 0;
    cpE = string;
    while (1) {
        cpB = cpE;
        if (cpB >= (string+maxlen))
            break;
        if ((int)(*cpB) == sep)
            cpB++;
        for (cpE = cpB; cpE < (string+maxlen) && (int)(*cpE) != sep; cpE++)
            ;
        if (cpE > (string+maxlen))
            break;
        bFound = 0;
        for (i = 0; l2s_table[i].level != 0; i++) {
            if (strncasecmp(cpB, l2s_table[i].string, cpE-cpB) == 0) {
                *levelmask |= l2s_table[i].level;
                bFound = 1;
                break;
            }
        }
        if (!bFound) {
            if ((cpE > cpB+2) && strncasecmp(cpB, "0x", 2) == 0 && myishexnumber((int)(*(cpB+2)))) {
                *levelmask |= hexval(cpB+2, cpE);
            }
            else
                return L2_ERR_ARG;
        }
    }
    return L2_OK;
}

