/*
 * 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/error.h>
#include <common/input/crlf.h>
#include <common/input/private.h>
#include <common/trace.h>


typedef struct input_crlf_ty input_crlf_ty;
struct input_crlf_ty
{
    input_ty        inherited;
    input_ty        *fp;
    long            pos;
    int             delete_on_close;
};


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

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


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

    trace(("input_crlf::get()\n{\n"));
    this = (input_crlf_ty *)p;
    c = input_getc(this->fp);
    if (c == '\r')
    {
        c = input_getc(this->fp);
        if (c != '\n')
        {
            input_ungetc(this->fp, c);
            c = '\r';
        }
    }
    if (c >= 0)
        this->pos++;
#ifdef DEBUG
    if (c < 0)
        trace(("return EOF;\n"));
    else if (c >= ' ' && c <= '~')
        trace(("return '%c';\n", c));
    else
        trace(("return 0x%02X;\n", c));
#endif
    trace(("}\n"));
    return c;
}


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

    this = (input_crlf_ty *)fp;
    trace(("input_crlf::tell => %ld\n", this->pos));
    return this->pos;
}


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

    trace(("input_crlf::name\n"));
    this = (input_crlf_ty *)p;
    return input_name(this->fp);
}


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


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


input_ty *
input_crlf(input_ty *fp, int delete_on_close)
{
    input_ty        *result;
    input_crlf_ty   *this;

    trace(("input_crlf(fp = %08lX)\n{\n", (long)fp));
    result = input_new(&vtbl);
    this = (input_crlf_ty *)result;
    this->fp = fp;
    this->pos = 0;
    this->delete_on_close = delete_on_close;
    trace(("return %08lX\n", (long)result));
    trace(("}\n"));
    return result;
}


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