/*
 * fhist - file history and comparison tools
 * Copyright (C) 1991-1994, 1998-2000, 2002, 2008, 2010, 2012 Peter Miller
 *
 * Derived from a work
 * Copyright (C) 1990 David I. Bell.
 *
 * 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/libintl.h>
#include <common/ac/stdio.h>
#include <libexplain/fclose.h>
#include <libexplain/fopen.h>

#include <common/cmalloc.h>
#include <common/compare.h>
#include <common/error_intl.h>
#include <common/fcheck.h>
#include <common/fileio.h>

#include <fhist/fhist.h>
#include <fhist/list.h>
#include <fhist/subroutine.h>


/*
 * List information about a single edit.
 * The information is written to the usual output file.
 */

static void
listone(FILE *fp, long edit, POS *pp, FILE *of)
{
    char            *cp;            /* current line */
    long            tempedit;       /* edit number */

    cp = get_a_line(fp, pp->p_pos, T_BEGINEDIT, sc.historyname);
    if (cp == NULL)
    {
        sub_context_ty  *scp;

        scp = sub_context_new();
        sub_var_set_long(scp, "Number", edit);
        fatal_intl
        (
            scp,
            i18n("position failed to beginning of edit $number")
        );
    }
    cp = getnumber(cp, &tempedit);
    if ((cp == NULL) || (edit != tempedit))
    {
        sub_context_ty  *scp;

        scp = sub_context_new();
        sub_var_set_long(scp, "Number", edit);
        fatal_intl
        (
            scp,
            i18n("bad number at beginning of edit $number")
        );
    }
    cp = get_a_line(fp, NOSEEK, T_REMARK, sc.historyname);
    if (cp == NULL)
        fatal_intl(0, i18n("cannot read identification line"));

    /*
     * If the quick flag was specified, then only list the raw
     * edit number, otherwise list the number and the names.
     */
    if (fc.quickflag)
        fprintf(of, "%ld\n", edit);
    else
    {
        fprintf(of, "Edit %ld:   %s", edit, cp);
        if (pp->p_names)
        {
            fputs("Named: ", of);
            fputs(pp->p_names, of);
            fputs("\n", of);
        }
    }

    while ((cp = get_a_line(fp, NOSEEK, T_REMARK, sc.historyname)) != 0)
        writefx(of, cp, sc.linelen);
}


/*
 * List out information about the edits.
 * If no edit names are given, then all edits are displayed.
 * If one edit name is given, then just that edit is displayed.
 * If two edit names are given, then the specified range of edits is displayed.
 *
 * The history (.e) file is binary, because we need to seek in it.
 * The source (.s) file is text, because we don't need to seek in it.
 * The input files are text, by definition.
 * The output files are text, by definition.
 */

void
listhistory(const char *editname1, const char *editname2,
    const char *outputname)
{
    FILE    *fp;            /* history file */
    FILE    *of;            /* output file */
    POS     *pp;            /* current edit position entry */
    POS     *postable;      /* position table */
    long    begedit;        /* beginning edit number to display */
    long    endedit;        /* ending edit number to display */
    int     step;           /* step value for loop */

    fp = openhistoryfile(OHF_READ);
    begedit = sc.lastedit;
    endedit = sc.firstedit;
    if (editname1)
    {
        begedit = findeditnumber(fp, editname1);
        endedit = begedit;
    }
    if (editname2)
        endedit = findeditnumber(fp, editname2);
    if (outputname)
    {
        of = explain_fopen_or_die(outputname, "w");
    }
    else
    {
        of = stdout;
        outputname = gettext("standard output");
    }
    postable = readpostable(fp);
    if (!fc.quickflag)
        fprintf(of, "Module \"%s\":\n", sc.modulename);
    pp = postable + (sc.lastedit - begedit + 1);
    step = 1;
    if (begedit > endedit)
        step = -1;
    for (;;)
    {
        listone(fp, begedit, pp, of);
        if (begedit == endedit)
            break;
        begedit += step;
        pp -= step;
        fputs("\n", of);
    }
    cm_free(postable);
    explain_fclose_or_die(fp);
    explain_fclose_or_die(of);
}


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