/*
 * 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/assert.h>
#include <common/ac/ctype.h>
#include <common/ac/errno.h>
#include <common/ac/stdio.h>
#include <common/ac/string.h>
#include <libexplain/fflush.h>
#include <libexplain/strdup.h>

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

#include <fhist/breaks.h>
#include <fhist/fhist.h>
#include <fhist/name.h>
#include <fhist/subroutine.h>


/*
 * Create a new name for an edit of a module.
 * Currently this only works for the latest edit.
 */

void
namehistory(const char *editname)
{
    FILE            *fp;        /* history file */
    POS             *pp;        /* current entry in position table */
    POS             *postable;  /* position table */
    char            *oldnames;  /* old names for edit */
    char            *newnames;  /* new names for edit */
    int             namelen;    /* length of new name */
    long            edit;       /* current edit number */
    sub_context_ty  *scp;

    fp = openhistoryfile(OHF_WRITE);
    assert(fp);
    if (fc.verbosity)
    {
        scp = sub_context_new();
        sub_var_set_charstar(scp, "Module", sc.modulename);
        sub_var_set_long(scp, "Number", sc.lastedit);
        sub_var_set_charstar(scp, "Name", editname);
        error_intl
        (
            scp,
         i18n("latest edit $number of module \"$module\" being named \"$name\"")
        );
        sub_context_delete(scp);
    }
    postable = readpostable(fp);
    postable++;                 /* ignore unused entry */
    pp = postable;
    oldnames = pp->p_names;
    if (oldnames == NULL)               /* single new name */
        pp->p_names = editname ? explain_strdup_or_die(editname) : 0;
    else
    {
        /* put name in front of other names */
        namelen = strlen(editname);
        newnames = allocstr((unsigned long)(strlen(oldnames) + namelen + 2));
        strcpy(newnames, editname);
        newnames[namelen] = ' ';
        strcpy(&newnames[namelen+1], oldnames);
        pp->p_names = newnames;
    }
    breaksoff();

    /*
     * Now position back to the beginning of the position table, and write
     * back the table with the new name.  Errors will be handled later.
     */
    seekf(fp, sc.tablepos);
    pp = postable;
    for (edit = sc.lastedit; edit >= sc.firstedit; edit--, pp++)
    {
        fprintf(fp, (pp->p_names ? "%c %ld %ld %s\n" : "%c %ld %ld\n"),
            T_POSITION, edit, pp->p_pos, pp->p_names);
    }
    fprintf(fp, "%c %ld\n", T_EOF, ftell(fp));

    /*
     * Force the last bit of the output to the file, then check for errors.
     * If an error occurred, write back the original position table without
     * the new name.  This should succeed since it was there previously.
     */
    if (explain_fflush_on_error(fp))
    {
        errno = 0;
        seekf(fp, sc.tablepos);
        pp = postable;
        pp->p_names = oldnames;
        for (edit = sc.lastedit; edit >= sc.firstedit; edit--, pp++)
        {
            fprintf(fp, (pp->p_names ?  "%c %ld %ld %s\n" : "%c %ld %ld\n"),
                T_POSITION, edit, pp->p_pos, pp->p_names);
        }
        fprintf(fp, "%c %ld\n", T_EOF, ftell(fp));
        if (explain_fflush_on_error(fp))
        {
            scp = sub_context_new();
            sub_var_set_charstar(scp, "File_Name", sc.historyname);
            fatal_intl(scp, i18n("file \"$filename\" is damaged"));
        }
        fclose(fp);
        fp = 0;
        scp = sub_context_new();
        sub_var_set_charstar(scp, "File_Name", sc.historyname);
        fatal_intl(scp, i18n("file \"$filename\" is not damaged"));
    }
    fclose(fp);
    fp = 0;
    breakson();
}


/*
 * Check to see if a new edit name is valid.
 * Valid names cannot begin with a digit, or contain a plus or minus sign.
 * This routine also lower cases the name.
 */

void
checkeditname(const char *editname)
{
    const char      *cp;                /* current character of name */
    sub_context_ty  *scp;

    cp = editname;
    if ((strcasecmp(cp, OLDESTNAME) == 0) || (strcasecmp(cp, NEWESTNAME) == 0))
    {
        scp = sub_context_new();
        sub_var_set_charstar(scp, "Name", editname);
        fatal_intl(scp, i18n("edit name \"$name\" is reserved"));
    }
    if (isdigit((unsigned char)*cp))
    {
        scp = sub_context_new();
        sub_var_set_charstar(scp, "Name", editname);
        fatal_intl(scp, i18n("edit name \"$name\" cannot begin with a digit"));
    }
    while (*cp)
    {
        if ((*cp == '+') || (*cp++ == '-'))
        {
            scp = sub_context_new();
            sub_var_set_charstar(scp, "Name", editname);
            fatal_intl
            (
                scp,
                i18n("edit name \"$name\" cannot contain plus or minus signs")
            );
        }
    }
}


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