/*
 *	fhist - file history and comparison tools
 *	Copyright (C) 1991-1994, 1998-2000, 2002 Peter Miller;
 *	All rights reserved.
 *
 *	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 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, USA.
 *
 * MANIFEST: functions to specify a name for an edit of a module.
 */

#include <ac/ctype.h>
#include <ac/errno.h>
#include <ac/stdio.h>
#include <ac/string.h>

#include <breaks.h>
#include <compare.h>
#include <error_intl.h>
#include <fhist.h>
#include <fileio.h>
#include <name.h>
#include <subroutine.h>


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

void
namehistory(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 */
    int             saveerror;	/* saved error code on errors */
    sub_context_ty  *scp;

    fp = openhistoryfile(OHF_WRITE);
    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;
    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, sc.historyname);
    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.
     */
    fflush(fp);
    if (ferror(fp))
    {
	saveerror = errno;
	errno = 0;
	seekf(fp, sc.tablepos, sc.historyname);
	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 (fflush(fp))
	{
	    scp = sub_context_new();
	    sub_errno_set(scp);
	    sub_var_set_charstar(scp, "File_Name", sc.historyname);
	    error_intl(scp, i18n("write \"$filename\": $errno"));
	    sub_var_set_charstar(scp, "File_Name", sc.historyname);
	    fatal_intl(scp, i18n("file \"$filename\" is damaged"));
	}
	fclose(fp);
	scp = sub_context_new();
	sub_errno_setx(scp, saveerror);
	sub_var_set_charstar(scp, "File_Name", sc.historyname);
	error_intl(scp, i18n("write \"$filename\": $errno"));
	sub_var_set_charstar(scp, "File_Name", sc.historyname);
	fatal_intl(scp, i18n("file \"$filename\" is not damaged"));
    }
    fclose(fp);
    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(char *editname)
{
    char            *cp;		/* current character of name */
    sub_context_ty  *scp;

    for (cp = editname; *cp; cp++)
	if (isupper((unsigned char)*cp))
    	    *cp = tolower((unsigned char)*cp);
    cp = editname;
    if ((strcmp(cp, OLDESTNAME) == 0) || (strcmp(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")
	    );
	}
    }
}
