/*
 * fhist - file history and comparison tools
 * Copyright (C) 2000, 2002, 2008, 2010, 2012 Peter Miller
 *
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 */

#include <common/ac/ctype.h>
#include <common/ac/stdio.h> /* for sprintf */

#include <common/error.h>
#include <common/input/hexify.h>
#include <common/input/private.h>
#include <common/trace.h>


typedef struct input_hexify_ty input_hexify_ty;
struct input_hexify_ty
{
    input_ty        inherited;
    input_ty        *deeper;
    int             delete_on_close;
    int             buf_pos;
    char            buffer[16];
};


static void
destruct(input_ty *p)
{
    input_hexify_ty *this;

    trace(("input_hexify::destruct()\n{\n"));
    this = (input_hexify_ty *)p;
    input_pushback_transfer(this->deeper, p);
    if (this->delete_on_close)
        input_delete(this->deeper);
    this->deeper = 0; /* paranoia */
    trace(("}\n"));
}


static int
get(input_ty *p)
{
    input_hexify_ty *this;
    int             c;

    trace(("input_hexify::get()\n{\n"));
    this = (input_hexify_ty *)p;
    if (this->buffer[this->buf_pos] == 0)
    {
        const char *ctrl = "";
        const char *meta = "";
        int c2;
        c = input_getc(this->deeper);
        if (c < 0)
        {
            trace(("return EOF;\n"));
            return -1;
        }
        c2 = c;
        if (c2 & 0x80)
        {
            meta = "M-";
            c2 &= 0x7F;
        }
        if (!isprint(c2))
        {
            ctrl = "^";
            c2 ^= 0x40;
        }
        sprintf(this->buffer, "0x%02X  %s%s%c\n", c, meta, ctrl, c2);
        this->buf_pos = 0;
    }
    c = this->buffer[this->buf_pos++];
    trace(("return %d;\n", c));
    trace(("}\n"));
    return c;
}


static long
itell(input_ty *fp)
{
    input_hexify_ty *this;

    this = (input_hexify_ty *)fp;
    trace(("input_hexify::tell => %ld\n", this->buf_pos));
    return input_ftell(this->deeper);
}


static const char *
name(input_ty *p)
{
    input_hexify_ty *this;

    trace(("input_hexify::name\n"));
    this = (input_hexify_ty *)p;
    return input_name(this->deeper);
}


static long
length(input_ty *p)
{
    (void)p;
    trace(("input_hexify::length => -1\n"));
    return -1;
}


static input_vtbl_ty vtbl =
{
    sizeof(input_hexify_ty),
    destruct,
    input_generic_read,
    get,
    itell,
    name,
    length,
};


input_ty *
input_hexify(input_ty *deeper, int delete_on_close)
{
    input_ty        *result;
    input_hexify_ty *this;

    trace(("input_hexify(fp = %08lX)\n{\n", (long)deeper));
    result = input_new(&vtbl);
    this = (input_hexify_ty *)result;
    this->deeper = deeper;
    this->delete_on_close = delete_on_close;
    this->buf_pos = 0;
    this->buffer[0] = 0;
    trace(("return %08lX\n", (long)result));
    trace(("}\n"));
    return result;
}


/* vim: set ts=8 sw=4 et : */
