// $Id: tclbee.cpp,v 1.2 2003/03/23 06:20:50 fukasawa Exp $

//=============================================================================
/**
 *  @file    tclbee.cpp
 *
 *  @author Fukasawa Mitsuo
 *
 *
 *    Copyright (C) 1998-2002 BEE Co.,Ltd. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
//=============================================================================

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <stdarg.h>
#include "bee.h"
#include "tcl.h"

/*---------------------------------------------------------------------------*/
/*                                                                           */
/* hex dump                                                                  */
/*                                                                           */
/*---------------------------------------------------------------------------*/
static void tcl_dumpword(Tcl_Interp * interp, char * startp, size_t size,
                         bool ch, int mode);
static void tcl_dumpbyte(Tcl_Interp * interp, char * startp, size_t size,
                         bool ch, int mode);

#ifndef BOUNDARY
#define BOUNDARY     0
#define NO_BOUNDARY  1
#endif

#ifndef DUMP_BYTE
#define DUMP_BYTE       0x0000
#define DUMP_WORD       0x0001
#define DUMP_CHARCODE   0x0002
#endif

void bee_memdump(Tcl_Interp * interp, char * startp, size_t size, int chmod)
{
    bool view_ch = (chmod & DUMP_CHARCODE) ? true : false;
    if ((chmod & DUMP_WORD) != 0)
    {
        tcl_dumpword(interp, startp, size, view_ch, NO_BOUNDARY);
    }
    else
    {
        tcl_dumpbyte(interp, startp, size, view_ch, NO_BOUNDARY);
    }
}

static char lower_code[] = "0123456789abcdef";
static char upper_code[] = "0123456789ABCDEF";


#define WORD_HEX_POINT      0
#define WORD_SEPARATE_POINT 43
#define WORD_CHAR_POINT     45
static char word_linebuf[] =
    "1234 1234  1234 1234  1234 1234  1234 1234  : 1234 1234 1234 1234\n";

/*---------------------------------------------------------------------------*/
/* word format                                                               */
/*---------------------------------------------------------------------------*/
void tcl_dumpword(Tcl_Interp * interp, char * startp, size_t size, bool ch,
                  int mode)
{
    char * endp = startp + size;
    char * curptr;
    UINT   dumpnt;
    char   c;
    char * hexp;
    char * charp;
    char * hexcodep;
    char linebuf[128];
    long base = 0;                    // position

    Tcl_AppendResult(interp, "{ \\\n", NULL);
    if (mode == BOUNDARY)
    {   /* bound start print position */
        curptr = (char *)((ULONG)startp & ~0x0F);
        base &= ~0x0F;
    }
    else
        curptr = startp;

    hexcodep = (char *)lower_code;     /* bin to hexchar table */
    strcpy(linebuf, word_linebuf);

/*---------------------------------------------------------------------------*/
/* dump hex data                                                             */
/*---------------------------------------------------------------------------*/
    for ( ; curptr < endp; curptr += 16)
    {
        hexp = (char *)(linebuf + WORD_HEX_POINT);
        charp = (char *)(linebuf + WORD_CHAR_POINT);

        for (dumpnt = 0; *(hexp + dumpnt) != '\n'; dumpnt++)
            *(hexp + dumpnt) = ' ';
        *(hexp + WORD_SEPARATE_POINT) = ':';

        for (dumpnt = 0; dumpnt < 16; dumpnt++)
        {
            c = *(curptr + dumpnt);
            if (dumpnt != 0 && (dumpnt & 0x01) == 0)
                hexp++;
            if (dumpnt != 0 && (dumpnt & 0x03) == 0)
            {
                hexp++;
                charp++;
            }
/*---------------------------------------------------------------------------*/
/* dump character                                                            */
/*---------------------------------------------------------------------------*/
            if ((curptr + dumpnt) < startp || (curptr + dumpnt) >= endp)
            {
                hexp += 2;
                charp++;
            }
            else
            {
                *hexp++ = hexcodep[(c >> 4) & 0x0F];
                *hexp++ = hexcodep[c & 0x0F];
                if (c < ' ' || c > '~')
                    *charp++ = '.';
                else
                    *charp++ = c;
            }
        }
        if (ch != true)
        {   // Cut printed character code
            linebuf[WORD_SEPARATE_POINT] = '\0';
        }
        char buf[128 + 32];
        sprintf(buf, "%08lx %s \\\n", base, linebuf);
        Tcl_AppendResult(interp, buf, NULL);
        base += 8;
    }
    Tcl_AppendResult(interp, "}", NULL);
}


#define BYTE_HEX_POINT      0
#define BYTE_SEPARATE_POINT 49
#define BYTE_CHAR_POINT     51
static char byte_linebuf[] =
    "12 12 12 12 12 12 12 12  12 12 12 12 12 12 12 12 : 12345678 12345678 \n";

/*---------------------------------------------------------------------------*/
/* byte format                                                               */
/*---------------------------------------------------------------------------*/
void tcl_dumpbyte(Tcl_Interp * interp, char * startp, size_t size, bool ch,
                  int mode)
{
    char * endp = startp + size;
    char * curptr;
    UINT   dumpnt;
    char   c;
    char * hexp;
    char * charp;
    char * hexcodep;
    char linebuf[128];
    long base = 0;                    // position

    Tcl_AppendResult(interp, "{ \\\n", NULL);
    if (mode == BOUNDARY)
    {   /* bound start print position */
        curptr = (char *)((ULONG)startp & ~0x0F);
        base &= ~0x0F;
    }
    else
        curptr = startp;

    hexcodep = (char *)lower_code;
    strcpy(linebuf, byte_linebuf);

/*---------------------------------------------------------------------------*/
/* dump hex data                                                             */
/*---------------------------------------------------------------------------*/
    for ( ; curptr < endp; curptr += 16)
    {
        hexp = (char *)(linebuf + BYTE_HEX_POINT);
        charp = (char *)(linebuf + BYTE_CHAR_POINT);

        for (dumpnt = 0; *(hexp + dumpnt) != '\n'; dumpnt++)
            *(hexp + dumpnt) = ' ';
        *(hexp + BYTE_SEPARATE_POINT) = ':';

        for (dumpnt = 0; dumpnt < 16; dumpnt++)
        {
            c = *(curptr + dumpnt);
            hexp++;
            if (dumpnt != 0 && (dumpnt & 0x07) == 0)
            {
                hexp++;
                charp++;
            }
/*---------------------------------------------------------------------------*/
/* dump character                                                            */
/*---------------------------------------------------------------------------*/
            if ((curptr + dumpnt) < startp || (curptr + dumpnt) >= endp)
            {
                hexp += 2;
                charp++;
            }
            else
            {
                *hexp++ = hexcodep[(c >> 4) & 0x0F];
                *hexp++ = hexcodep[c & 0x0F];
                if (c < ' ' || c > '~')
                    *charp++ = '.';
                else
                    *charp++ = c;
            }
        }
        if (ch != true)
        {   // Cut printed character code
            linebuf[BYTE_SEPARATE_POINT] = '\0';
        }
        char buf[128 + 32];
        sprintf(buf, "%08lx %s \\\n", base, linebuf);
        Tcl_AppendResult(interp, buf, NULL);
        base += 16;
    }
    Tcl_AppendResult(interp, "}", NULL);
}

//------------------------------------------------------------------------------
//  Parse text which is dumped memory
//------------------------------------------------------------------------------
//
// Dumped format is byte
//
int bee_parsebytes(Tcl_Interp * interp, char * datastr, BYTE ** bufpp,
                   size_t * size)
{
    int  result;
    int  count, i, j;
    const char **lists;
    ULONG hex;
    BYTE * databuf;

    result = Tcl_SplitList(interp, datastr, &count, &lists);
    if (result != TCL_OK)
        return result;

    if ((databuf = (BYTE *)malloc(count)) == NULL)
    {
        Tcl_AppendResult(interp, " empty memory ", (char *)NULL);
        return TCL_ERROR;
    }

    for (i = j = 0; i < count; i++)
    {
        if (i == 0 || (i % 17) == 0)
        {   // skip position's token
            continue;
        }
        hex = strtoul(lists[i], NULL, 16);
        databuf[j++] = (BYTE)(hex & 0xFF);
    }
    Tcl_Free((char *)lists);            // free splitted list
    *bufpp = databuf;
    *size = j;                          // set byte size
    return TCL_OK;
}

//-----------------------------------------------------------------------------
// Dumped format is word
//
int bee_parsewords(Tcl_Interp * interp, char * datastr, BYTE ** bufpp,
                   size_t * size)
{
    int  result;
    int  count, i, j;
    const char **lists;
    ULONG hex;
    BYTE * databuf;

    result = Tcl_SplitList(interp, datastr, &count, &lists);
    if (result != TCL_OK)
        return result;

    if ((databuf = (BYTE *)malloc(count * sizeof(USHORT))) == NULL)
    {
        Tcl_AppendResult(interp, " empty memory ", (char *)NULL);
        return TCL_ERROR;
    }

    for (i = j = 0; i < count; i++)
    {
        if (i == 0 || (i % 9) == 0)
        {   // skip position's token
            continue;
        }
        hex = strtoul(lists[i], NULL, 16);
        databuf[j++] = (BYTE)((hex >> 8) & 0xFF);
        databuf[j++] = (BYTE)(hex & 0xFF);
    }
    Tcl_Free((char *)lists);            // free splitted list
    *bufpp = databuf;
    *size = j;                          // set word size
    return TCL_OK;
}


